1 #include <boost/version.hpp> 5 #if BOOST_VERSION < 106300 && BOOST_VERSION >= 106200 9 #include <boost/geometry/algorithms/disjoint.hpp> 10 #include <boost/geometry/geometries/box.hpp> 11 #include <boost/geometry/geometries/pointing_segment.hpp> 12 #include <boost/geometry/index/rtree.hpp> 28 constexpr
double SmallNum = 1.e-10;
29 constexpr std::size_t RtreeThres = 50;
32 inline LineParams calculateLineParams(
double a,
double b,
double c,
double d,
double e,
double den) {
37 return {0.0, 1.0, e, c};
43 lp.sN = (b * e - c *
d);
44 lp.tN = (a * e - b *
d);
49 }
else if (lp.sN > lp.sD) {
58 template <
typename Po
intT>
60 std::pair<PointT, PointT> projectedPoint(PointT
p1, PointT
p2, PointT q1, PointT q2) {
70 auto den = a * c - b * b;
72 auto lp = calculateLineParams(a, b, c, d, e, den);
85 }
else if (lp.tN > lp.tD) {
90 }
else if ((-d + b) > a) {
98 double sc = (std::abs(lp.sN) < SmallNum ? 0.0 : lp.sN / lp.sD);
99 double tc = (std::abs(lp.tN) < SmallNum ? 0.0 : lp.tN / lp.tD);
101 return {p1 + (sc * u), q1 + (tc * v)};
104 template <
typename Po
intT>
106 PointT projectedPoint(PointT l1, PointT l2, PointT
p) {
110 const auto c1 = w.dot(v);
114 const auto c2 = v.dot(v);
118 const auto b = c1 / c2;
122 template <
typename RangeT,
typename Func>
123 void distForAllSegments(
const RangeT& r, Func f) {
125 f(r.front(), r.front());
127 for (
auto first = r.begin(), second = r.begin() + 1; second != r.end(); ++first, ++second) {
128 if (f(*first, *second) == 0.) {
135 namespace bgi = bg::index;
136 namespace bgm = boost::geometry::model;
138 template <
typename Po
int1T,
typename Po
int2T,
typename BasicPo
intT>
139 struct ProjectedPoint2L2Result {
140 using Point1 = Point1T;
141 using Point2 = Point2T;
142 using Segm1 = Segment<Point1T>;
143 using Segm2 = Segment<Point2T>;
146 bool valid()
const {
return !!
distance; }
150 const auto dNew = (projPair.first - projPair.second).norm();
155 this->p1 = projPair.first;
156 this->p2 = projPair.second;
160 std::pair<BasicPoint, BasicPoint> projectedPoints()
const {
return std::make_pair(p1, p2); }
171 template <
typename LineString1T,
typename LineString2T>
172 using ProjectedPointL2LOnLinestring = ProjectedPoint2L2Result<traits::ConstPointT<traits::PointType<LineString1T>>,
173 traits::ConstPointT<traits::PointType<LineString2T>>,
174 traits::BasicPointT<traits::PointType<LineString1T>>>;
176 template <
typename Po
intT,
typename BasicPo
intT>
177 struct ProjectedPointL2PResult {
178 using Point = PointT;
179 using Segm = Segment<PointT>;
182 bool valid()
const {
return !!
distance; }
183 double update(Segm
segm, BasicPoint p) {
185 const auto dNew = (projP -
p).norm();
193 Segment<Point> segment()
const {
return segm; }
200 template <
typename LineStringT>
201 using ProjectedPointL2POnLinestring = ProjectedPointL2PResult<traits::ConstPointT<traits::PointType<LineStringT>>,
202 traits::BasicPointT<traits::PointType<LineStringT>>>;
204 template <
typename Po
intT>
205 auto toSegment(
const bgm::pointing_segment<const PointT>& s) {
206 return std::make_pair(*s.first, *s.second);
209 template <
typename Po
intT>
210 auto toBasicSegment(
const bgm::pointing_segment<const PointT>& s) {
214 template <
typename LineString1T,
typename LineString2T>
215 ProjectedPointL2LOnLinestring<LineString1T, LineString2T> projectedPointL2LWithTree(
const LineString1T& smallerRange,
216 const LineString2T& greaterRange) {
217 using TreePointT = traits::ConstPointT<traits::PointType<LineString2T>>;
218 using TreeSegmT = Segment<TreePointT>;
220 using Box = bgm::box<bgm::point<double, static_cast<int>(Dim), boost::geometry::cs::cartesian>>;
221 using Node = std::pair<Box, TreeSegmT>;
222 using RTree = bgi::rtree<Node, bgi::linear<8>>;
224 utils::transform(bg::segments_begin(greaterRange), bg::segments_end(greaterRange), [](
const auto&
segm) {
226 boost::geometry::envelope(
segm, box);
227 return Node(box, toSegment(
segm));
229 RTree tree(values.begin(), values.end());
231 using PointT = traits::ConstPointT<traits::PointType<LineString1T>>;
232 auto result = ProjectedPointL2LOnLinestring<LineString1T, LineString2T>{};
233 distForAllSegments(smallerRange, [&](
auto&& psmall1,
auto&& psmall2) {
236 bg::envelope(segsmall, queryBox);
237 for (
auto qIt = tree.qbegin(bgi::nearest(queryBox,
unsigned(tree.size()))); qIt != tree.qend(); ++qIt) {
238 const auto& nearest = *qIt;
240 if (!!result.distance && *(result.distance) < dBox) {
243 result.update(std::make_pair(psmall1, psmall2), nearest.second);
245 return *result.distance;
250 template <
typename LineString1T,
typename LineString2T>
251 ProjectedPointL2LOnLinestring<LineString1T, LineString2T> projectedPointL2LBruteForce(
252 const LineString1T& smallerRange,
const LineString2T& greaterRange) {
253 auto result = ProjectedPointL2LOnLinestring<LineString1T, LineString2T>{};
254 distForAllSegments(smallerRange, [&](
auto&& psmall1,
auto&& psmall2) {
255 distForAllSegments(greaterRange, [&](
auto&& pgreat1,
auto&& pgreat2) {
256 return result.update(std::make_pair(psmall1, psmall2), std::make_pair(pgreat1, pgreat2));
258 return *result.distance;
263 template <
typename LineStringT>
264 ProjectedPointL2POnLinestring<LineStringT> projectedPointL2PBruteForce(
266 auto result = ProjectedPointL2POnLinestring<LineStringT>{};
267 distForAllSegments(ls, [&](
auto&& pl1,
auto&& pl2) {
return result.update(std::make_pair(pl1, pl2), point); });
271 template <
typename LineStringT>
272 ProjectedPointL2POnLinestring<LineStringT> projectedPointL2PWithTree(
274 using TreePointT = traits::ConstPointT<traits::PointType<LineStringT>>;
275 using TreeSegmT = Segment<TreePointT>;
277 using Box = bgm::box<bgm::point<double, static_cast<int>(Dim), boost::geometry::cs::cartesian>>;
278 using Node = std::pair<Box, TreeSegmT>;
279 using RTree = bgi::rtree<Node, bgi::linear<8>>;
281 const auto values =
utils::transform(bg::segments_begin(ls), bg::segments_end(ls), [](
const auto&
segm) {
284 return Node(box, toSegment(
segm));
286 RTree tree(values.begin(), values.end());
288 auto result = ProjectedPointL2POnLinestring<LineStringT>{};
289 for (
auto qIt = tree.qbegin(bgi::nearest(p,
unsigned(tree.size()))); qIt != tree.qend(); ++qIt) {
290 const auto& nearest = *qIt;
292 if (!!result.distance && *(result.distance) < dBox) {
295 if (result.update(nearest.second, p) == 0.) {
302 template <
typename LineString1T,
typename LineString2T>
303 auto projectedPointOrdered(
const LineString1T& smallerRange,
const LineString2T& greaterRange) {
304 if (smallerRange.size() == 0) {
305 throw InvalidInputError(
"ProjectedPoint called with empty linestring as input!");
307 if (greaterRange.size() < RtreeThres) {
308 return projectedPointL2LBruteForce(smallerRange, greaterRange);
310 return projectedPointL2LWithTree(smallerRange, greaterRange);
313 template <
typename LineString1T,
typename LineString2T>
314 auto projectedPointL2LImpl(
const LineString1T& l1,
const LineString2T& l2) {
315 if (l1.size() < l2.size()) {
316 return projectedPointOrdered(l1, l2);
318 return projectedPointOrdered(l2, l1).swap();
321 template <
typename LineStringT>
322 auto projectedPointL2PImpl(
const LineStringT& ls,
const traits::BasicPointT<traits::PointType<LineStringT>>& p) {
323 if (ls.size() < RtreeThres) {
324 return projectedPointL2PBruteForce(ls, p);
326 return projectedPointL2PWithTree(ls, p);
334 return projectedPointL2LImpl(l1, l2).projectedPoints();
339 return projectedPointL2LImpl(l1, l2).projectedPoints();
344 return projectedPointL2LImpl(l1, l2).projectedPoints();
349 return projectedPointL2LImpl(l1, l2).projectedPoints();
353 return projectedPointL2LImpl(l1, l2).projectedPoints();
357 return projectedPointL2LImpl(l1, l2).projectedPoints();
361 return projectedPointL2LImpl(l1, l2).projectedPoints();
366 return projectedPointL2LImpl(l1, l2).projectedPoints();
371 return projectedPointL2LImpl(l1, l2).projectedPoints();
377 return projectedPointL2LImpl(l1, l2).projectedPoints();
382 return projectedPointL2LImpl(l1, l2).projectedPoints();
387 return projectedPointL2LImpl(l1, l2).projectedPoints();
392 return projectedPointL2LImpl(l1, l2).projectedPoints();
396 return projectedPointL2LImpl(l1, l2).projectedPoints();
400 return projectedPointL2LImpl(l1, l2).projectedPoints();
404 return projectedPointL2LImpl(l1, l2).projectedPoints();
409 return projectedPointL2LImpl(l1, l2).projectedPoints();
414 return projectedPointL2LImpl(l1, l2).projectedPoints();
419 return projectedPointL2PImpl(lineString, pointToProject).p;
422 return projectedPointL2PImpl(lineString, pointToProject).p;
426 return projectedPointL2PImpl(lineString, pointToProject).p;
429 return projectedPointL2PImpl(lineString, pointToProject).p;
433 return projectedPointL2PImpl(lineString, pointToProject).p;
436 return projectedPointL2PImpl(lineString, pointToProject).p;
443 return projectedPointL2PImpl(lineString, pointToProject).segment();
446 return projectedPointL2PImpl(lineString, pointToProject).segment();
450 return projectedPointL2PImpl(lineString, pointToProject).segment();
453 return projectedPointL2PImpl(lineString, pointToProject).segment();
457 return projectedPointL2PImpl(lineString, pointToProject).segment();
460 return projectedPointL2PImpl(lineString, pointToProject).segment();
464 return projectedPointL2PImpl(lineString, pointToProject).segment();
467 return projectedPointL2PImpl(lineString, pointToProject).segment();
471 return projectedPointL2PImpl(lineString, pointToProject).segment();
474 return projectedPointL2PImpl(lineString, pointToProject).segment();
478 return projectedPoint(segment.first, segment.second, pointToProject);
481 return projectedPoint(segment.first, segment.second, pointToProject);
Polygon with access to primitive points.
BasicPoints3d BasicLineString3d
A Linestring that returns BasicPoint2d instead of Point2d.
typename PointTraits< PointT >::BasicPoint BasicPointT
A Compound linestring in 3d (returns Point3d)
auto transform(Iterator begin, Iterator end, const Func f)
Eigen::Vector3d BasicPoint3d
a simple 3d-point
Combines multiple linestrings to one polygon in 3d that returns BasicPoint3d.
std::pair< PointT, PointT > Segment
Segment< BasicPoint3d > BasicSegment3d
A hybrid compound linestring in 2d (returns BasicPoint2d)
BasicPoint3d project(const LineString3dT &lineString, const BasicPoint3d &pointToProject)
Projects the given point in 3d to the LineString.
A normal 3d linestring with immutable data.
IfLS< LineString2dT, std::pair< BasicPoint2d, BasicPoint2d > > projectedPoint2d(const LineString2dT &l1, const LineString2dT &l2)
Computes the projected points on the two linestrings for the shortest distance.
std::pair< BasicPoint2d, BasicPoint2d > projectedBorderPoint2d(const CompoundHybridPolygon2d &l1, const CompoundHybridPolygon2d &l2)
Polygon with access to primitive points.
A Compound linestring in 2d (returns Point2d)
BasicPoints2d BasicLineString2d
Optional< double > distance
A Linestring that returns BasicPoint3d instead of Point3d.
Eigen::Matrix< double, 2, 1, Eigen::DontAlign > BasicPoint2d
a simple 2d-point
auto toBasicSegment(const Segment< PointT > &s)
Segment< BasicPoint2d > closestSegment(const BasicLineString2d &lineString, const BasicPoint2d &pointToProject)
find the segment on a 2d line string that is closest to a given point, determined by boost::geometry:...
A hybrid compound linestring in 3d (returns BasicPoint3d)
Combines multiple linestrings to one polygon in 2d that returns BasicPoint2d.
auto toBasicPoint(const PointT &point) -> std::enable_if_t< PointTraits< PointT >::IsPrimitive, BasicPointT< PointT >>
IfLS< LineString3dT, std::pair< BasicPoint3d, BasicPoint3d > > projectedPoint3d(const LineString3dT &l1, const LineString3dT &l2)
Computes the projected points on the two linestrings for the shortest distance.
IfPoly< Polygon3dT, std::pair< BasicPoint3d, BasicPoint3d > > projectedBorderPoint3d(const Polygon3dT &l1, const Polygon3dT &l2)
A normal 2d linestring with immutable data.
Segment< BasicPoint2d > BasicSegment2d
static constexpr Dimensions Dimension