xmsgeom  1.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
GmMultiPolyIntersectionSorterTerse.cpp
Go to the documentation of this file.
1 //------------------------------------------------------------------------------
7 //------------------------------------------------------------------------------
8 
9 //----- Included files ---------------------------------------------------------
10 
11 // 1. Precompiled header
12 
13 // 2. My header
15 
16 // 3. Standard Library Headers
17 #include <cfloat>
18 
19 // 4. External Library Headers
20 #include <xmscore/math/math.h> // EQ_EPS
21 #include <xmscore/misc/XmError.h> // XM_*
22 #include <xmscore/misc/xmstype.h> // XM_NONE
23 #include <xmscore/stl/set.h> // Set*
24 #include <xmscore/stl/vector.h> // Vec*
25 #include <xmsgeom/geometry/GmMultiPolyIntersectorData.h> // GmMultiPolyIntersectorData
26 #include <xmsgeom/geometry/geoms.h> // gmComputeCentroid, gmTurn
27 
28 // 5. Shared Headers
29 
30 // 6. Non-shared Headers
31 
32 //----- Forward declarations ---------------------------------------------------
33 
34 //----- External globals -------------------------------------------------------
35 
36 //----- Namespace declaration --------------------------------------------------
37 
38 namespace xms {
39 //----- Constants / Enumerations -----------------------------------------------
40 
41 //----- Classes / Structs ------------------------------------------------------
42 
43 namespace { // unnamed namespace
44 } // unnamed namespace
45 
56 //------------------------------------------------------------------------------
64 //------------------------------------------------------------------------------
66  GmMultiPolyIntersectorData &a_data, std::vector<int> &polyids,
67  std::vector<double> &tvalues, std::vector<Pt3d> &a_pts, double a_tol) {
68  m_d = &a_data;
69  m_tol = a_tol;
72  SwapAdjacents();
73  IntersectionsToPolyIdsAndTValues(polyids, tvalues, a_pts);
74  FixArrays(polyids, tvalues, a_pts);
75 } // GmMultiPolyIntersectionSorterTerse::Sort
76 //------------------------------------------------------------------------------
82 //------------------------------------------------------------------------------
85 
86  VecInt tChange;
87  FindWhereTValuesChange(tChange);
88 
89  VecInt toRemove;
90 
91  // Loop through tChanges
92  for (size_t i = 0; i < tChange.size() - 1; ++i) {
93  if (tChange[i + 1] - tChange[i] > 1) {
94  VecInt inNeither;
95  FindPreviousNextNeither(tChange, (int)i, nullptr, nullptr, &inNeither);
96 
97  if ((i > 0 && i + 2 < tChange.size()) || inNeither.size() > 1 ||
98  (i == 0 && tChange[1] - tChange[0] > 1)) {
99  toRemove.insert(toRemove.end(), inNeither.begin(), inNeither.end());
100  }
101  }
102  }
103 
104  // Remove them, working backwards
105  for (size_t i = toRemove.size(); i-- > 0;) {
106  m_d->m_ixs.erase(m_d->m_ixs.begin() + toRemove[i]);
107  }
108 } // GmMultiPolyIntersectionSorterTerse::RemoveCornerTouches
109 //------------------------------------------------------------------------------
112 //------------------------------------------------------------------------------
115 
116  VecInt tChange;
117  FindWhereTValuesChange(tChange);
118 
119  VecInt toRemove;
120 
121  // Loop through tChanges
122  for (size_t i = 0; i < tChange.size() - 1; ++i) {
123  if (tChange[i + 1] - tChange[i] > 1) {
124  VecInt inNext;
125  // Get intersections in this tvalue group that also appear in next group.
126  // These are the first points of the edges.
127  FindPreviousNextNeither(tChange, (int)i, nullptr, &inNext, nullptr);
128 
129  if (inNext.size() > 1) {
130  // Get intersections in next tvalue group that match those in current.
131  // These are the last points of the edges.
132  VecInt inPrev;
133  FindPreviousNextNeither(tChange, (int)i + 1, &inPrev, nullptr, nullptr);
134  // XM_ASSERT(inPrev.size() == inNext.size());
135  // Not sure why the assert above was put in. Even when it asserts,
136  // we still seem to get good results in the end.
137 
138  // Keep only the polygons that are on the right of the line
139  bool found = false; // Should be just 2 so stop if we find one
140  for (size_t j = 0; j < inNext.size() && !found; ++j) {
141  // Find the other end of this edge
142  int edgeBeg = inNext[j]; // index into m_d->m_ixs of beginning of edge
143  int edgeEnd = XM_NONE; // index into m_d->m_ixs of end of edge
144  for (size_t k = 0; k < inPrev.size() && edgeEnd == XM_NONE; ++k) {
145  if (m_d->m_ixs[inPrev[k]].m_i == m_d->m_ixs[edgeBeg].m_i)
146  edgeEnd = inPrev[k];
147  }
148  XM_ASSERT(edgeEnd != XM_NONE);
149 
150  int polyIdx = m_d->m_ixs[edgeBeg].m_i - 1;
151  // Create the poly as a vector of Pt3ds for gmComputeCentroid
152  VecPt3d poly;
153  for (size_t k = 0; k < m_d->m_polys[polyIdx].size(); ++k) {
154  poly.push_back(m_d->m_points[m_d->m_polys[polyIdx][k]]);
155  }
156  Pt3d centroid = gmComputeCentroid(poly);
157  Turn_enum turn = gmTurn(m_d->m_ixs[edgeBeg].m_pt,
158  m_d->m_ixs[edgeEnd].m_pt, centroid);
159  if (turn != TURN_RIGHT) {
160  toRemove.push_back(edgeBeg);
161  toRemove.push_back(edgeEnd);
162  found = true;
163  }
164  }
165  }
166  }
167  }
168 
169  // Remove them, working backwards
170  std::sort(toRemove.begin(), toRemove.end());
171  for (size_t i = toRemove.size(); i-- > 0;) {
172  m_d->m_ixs.erase(m_d->m_ixs.begin() + toRemove[i]);
173  }
174 } // GmMultiPolyIntersectionSorterTerse::RemoveDuplicateEdges
175 //------------------------------------------------------------------------------
177 //------------------------------------------------------------------------------
180 
181  // 2 intersections
182  if (m_d->m_ixs.size() == 2) {
183  if ((!m_d->m_polys1.empty() &&
184  m_d->m_polys1.find(m_d->m_ixs[0].m_i) == m_d->m_polys1.end()) ||
185  (!m_d->m_polys2.empty() &&
186  m_d->m_polys2.find(m_d->m_ixs[1].m_i) == m_d->m_polys2.end())) {
187  Swap(0, 1);
188  }
189  return;
190  }
191 
192  // 3 or more intersections
193  int i = 1;
194  // Do first one outside of loop
195  if (EQ_EPS(m_d->m_ixs[1].m_t, m_d->m_ixs[0].m_t, FLT_EPSILON) &&
196  (m_d->m_ixs[0].m_i == m_d->m_ixs[2].m_i ||
197  (m_d->m_ixs.size() > 3 && m_d->m_ixs[0].m_i == m_d->m_ixs[3].m_i))) {
198  Swap(0, 1);
199  ++i;
200  }
201 
202  for (; i < (int)m_d->m_ixs.size(); ++i) {
203  if (EQ_EPS(m_d->m_ixs[i].m_t, m_d->m_ixs[i - 1].m_t, FLT_EPSILON)) {
204  // look back
205  if (i - 2 >= 0 && m_d->m_ixs[i].m_i == m_d->m_ixs[i - 2].m_i) {
206  Swap(i, i - 1);
207  }
208  }
209  }
210 } // GmMultiPolyIntersectionSorterTerse::SwapAdjacents
211 //------------------------------------------------------------------------------
217 //------------------------------------------------------------------------------
219  VecInt &polyids, VecDbl &tvalues, std::vector<Pt3d> &a_pts) const {
220  if (m_d->m_ixs.size() == 2) {
221  if (EQ_EPS(m_d->m_ixs[0].m_t, m_d->m_ixs[1].m_t, FLT_EPSILON)) {
222  if (!m_d->m_polys1.empty() && !m_d->m_polys2.empty() &&
223  m_d->m_polys1 != m_d->m_polys2) {
224  // test2InIn. Combine 2 into 1 getting entrance into second poly
225  if (m_d->m_polys1.find(m_d->m_ixs[0].m_i) != m_d->m_polys1.end()) {
226  AddToPolyIdsAndTValues(m_d->m_ixs[1], polyids, tvalues, a_pts);
227  } else {
228  AddToPolyIdsAndTValues(m_d->m_ixs[0], polyids, tvalues, a_pts);
229  }
230  } else {
231  AddToPolyIdsAndTValues(m_d->m_ixs[0], polyids, tvalues, a_pts);
232  AddToPolyIdsAndTValues(m_d->m_ixs[1], polyids, tvalues, a_pts);
233  }
234  } else {
235  AddToPolyIdsAndTValues(m_d->m_ixs[0], polyids, tvalues, a_pts);
236  AddToPolyIdsAndTValues(m_d->m_ixs[1], polyids, tvalues, a_pts);
237  }
238  return;
239  }
240 } // GmMultiPolyIntersectionSorterTerse::IntersectionsToPolyIdsAndTValuesFor2
241 //------------------------------------------------------------------------------
247 //------------------------------------------------------------------------------
250  std::vector<Pt3d> &a_pts) const {
252 
253  // Mark where we have a change in t values
254  VecInt tChange;
255  FindWhereTValuesChange(tChange);
256 
257  SetInt setIds, setIdsPrev; // ids we're adding now, & that we added previously
258  // Loop through tChanges
259  for (int i = 0; i < (int)tChange.size() - 1; ++i) {
260  if (tChange[i + 1] - tChange[i] > 1) {
261  VecInt inPrev, inNext, inNeither;
262  FindPreviousNextNeither(tChange, i, &inPrev, &inNext, &inNeither);
263 
264  if (i == 0) {
265  // If we don't have any in "inNeither", use next as inNeither.
266  if (inPrev.empty() && inNeither.empty())
267  inNeither = inNext;
268 
269  // Take the ones that are not found
270  for (size_t j = 0; j < inNeither.size(); ++j) {
271  setIds.insert(m_d->m_ixs[inNeither[j]].m_i);
272  AddToPolyIdsAndTValues(m_d->m_ixs[inNeither[j]], polyids, tvalues,
273  a_pts);
274  }
275  } else {
276  // Take the ones that were found in the previous group, that were
277  // not added previously
278  for (size_t j = 0; j < inPrev.size(); ++j) {
279  if (setIdsPrev.find(m_d->m_ixs[inPrev[j]].m_i) == setIdsPrev.end()) {
280  setIds.insert(m_d->m_ixs[inPrev[j]].m_i);
281  AddToPolyIdsAndTValues(m_d->m_ixs[inPrev[j]], polyids, tvalues,
282  a_pts);
283  }
284  }
285 
286  if (setIds.empty()) {
287  // Since we haven't added any yet, add those from next that weren't
288  // added previously
289  for (size_t j = 0; j < inNext.size(); ++j) {
290  if (setIdsPrev.find(m_d->m_ixs[inNext[j]].m_i) ==
291  setIdsPrev.end()) {
292  setIds.insert(m_d->m_ixs[inNext[j]].m_i);
293  AddToPolyIdsAndTValues(m_d->m_ixs[inNext[j]], polyids, tvalues,
294  a_pts);
295  }
296  }
297  }
298 
299  // Then take the ones that were not found
300  for (size_t j = 0; j < inNeither.size(); ++j) {
301  setIds.insert(m_d->m_ixs[inNeither[j]].m_i);
302  AddToPolyIdsAndTValues(m_d->m_ixs[inNeither[j]], polyids, tvalues,
303  a_pts);
304  }
305 
306  if (setIds.empty()) {
307  // Since we haven't added any yet, add those from previous group
308  for (size_t j = 0; j < inPrev.size(); ++j) {
309  setIds.insert(m_d->m_ixs[inPrev[j]].m_i);
310  AddToPolyIdsAndTValues(m_d->m_ixs[inPrev[j]], polyids, tvalues,
311  a_pts);
312  }
313  }
314  }
315  } else {
316  setIds.insert(m_d->m_ixs[tChange[i]].m_i);
317  AddToPolyIdsAndTValues(m_d->m_ixs[tChange[i]], polyids, tvalues, a_pts);
318  }
319 
320  setIdsPrev = setIds;
321  setIds.clear();
322  }
323 
324 } // IntersectionsToPolyIdsAndTValuesFor3OrMore
325 //------------------------------------------------------------------------------
330 //------------------------------------------------------------------------------
332  VecInt &polyids, VecDbl &tvalues, std::vector<Pt3d> &a_pts) const {
333  polyids.clear();
334  tvalues.clear();
335  a_pts.clear();
336 
338 
339  // 1 intersection
340  if (m_d->m_ixs.size() == 1) {
341  polyids.push_back(m_d->m_ixs[0].m_i);
342  tvalues.push_back(m_d->m_ixs[0].m_t);
343  a_pts.push_back(m_d->m_ixs[0].m_pt);
344  return;
345  }
346 
347  // 2 intersections
348  if (m_d->m_ixs.size() == 2) {
349  IntersectionsToPolyIdsAndTValuesFor2(polyids, tvalues, a_pts);
350  return;
351  }
352 
353  // 3 or more intersections
354  IntersectionsToPolyIdsAndTValuesFor3OrMore(polyids, tvalues, a_pts);
355 
356 } // GmMultiPolyIntersectionSorterTerse::IntersectionsToPolyIdsAndTValues
357 //------------------------------------------------------------------------------
363 //------------------------------------------------------------------------------
365  VecDbl &tvalues,
366  VecPt3d &a_pts) const {
367  XM_ENSURE_TRUE_VOID_NO_ASSERT(!polyids.empty());
368 
369  // Make sure we have at least two values - an entrance and exit
370  if (polyids.size() == 1) {
371  // Only one intersection. Add an exit that is the same
372  polyids.push_back(polyids.back());
373  tvalues.push_back(tvalues.back());
374  a_pts.push_back(a_pts.back());
375  }
376 
377  // If crossing a vertex, make sure we have an exit
378  if (m_d->m_polys2.empty() && polyids.back() != polyids[polyids.size() - 2]) {
379  polyids.push_back(polyids.back());
380  tvalues.push_back(tvalues.back());
381  a_pts.push_back(a_pts.back());
382  }
383 
384  // Make sure we always end with -1
385  if (polyids.size() > 1) {
386  polyids.back() = -1;
387  }
388 
389  // If we leave and reenter, set exit to -1
390  for (size_t i = 1; i < polyids.size(); ++i) {
391  if (polyids[i] == polyids[i - 1]) {
392  polyids[i] = -1;
393  }
394  }
395 
396 } // GmMultiPolyIntersectionSorterTerse::FixArrays
397 //------------------------------------------------------------------------------
404 //------------------------------------------------------------------------------
406  const ix &a_ix, VecInt &polyids, VecDbl &tvalues,
407  std::vector<Pt3d> &a_pts) const {
408  polyids.push_back(a_ix.m_i);
409  tvalues.push_back(a_ix.m_t);
410  a_pts.push_back(a_ix.m_pt);
411 } // GmMultiPolyIntersectionSorterTerse::AddToPolyIdsAndTValues
412 //------------------------------------------------------------------------------
424 //------------------------------------------------------------------------------
426  const VecInt &tChange, const int idx, VecInt *inPrev, VecInt *inNext,
427  VecInt *inNeither) const {
428  if (inPrev)
429  inPrev->clear();
430  if (inNext)
431  inNext->clear();
432  if (inNeither)
433  inNeither->clear();
434  for (int j = tChange[idx]; j < tChange[idx + 1]; ++j) {
435  // Corners at the start of the list of intersections appear the same
436  // as edges so we can't remove them because we don't have a previous
437  // set of tvalues to look at.
438  bool foundPrev = false;
439  if (idx > 0) {
440  for (int k = tChange[idx - 1]; k < tChange[idx] && !foundPrev; ++k) {
441  if (m_d->m_ixs[j].m_i == m_d->m_ixs[k].m_i) {
442  foundPrev = true;
443  }
444  }
445  }
446 
447  // Corners at the end of the list of intersections appear the same
448  // as edges so we can't remove them because we don't have a inNext set
449  // of tvalues to look at.
450  bool foundNext = false;
451  if (!foundPrev && idx + 2 < (int)tChange.size()) {
452  for (int k = tChange[idx + 1]; k < (int)tChange[idx + 2] && !foundNext;
453  ++k) {
454  if (m_d->m_ixs[j].m_i == m_d->m_ixs[k].m_i) {
455  foundNext = true;
456  }
457  }
458  }
459 
460  if (foundPrev) {
461  if (inPrev)
462  inPrev->push_back(j);
463  } else if (foundNext) {
464  if (inNext)
465  inNext->push_back(j);
466  } else {
467  if (inNeither)
468  inNeither->push_back(j);
469  }
470  }
471 } // GmMultiPolyIntersectionSorterTerse::FindPreviousNextNeither
472 //------------------------------------------------------------------------------
476 //------------------------------------------------------------------------------
478  ix temp = m_d->m_ixs[a];
479  m_d->m_ixs[a] = m_d->m_ixs[b];
480  m_d->m_ixs[b] = temp;
481 } // GmMultiPolyIntersectionSorterTerse::Swap
482 //------------------------------------------------------------------------------
485 //------------------------------------------------------------------------------
487  VecInt &tChange) const {
488  tChange.assign(1, 0);
489  for (size_t i = 1; i < m_d->m_ixs.size(); ++i) {
490  if (!EQ_TOL(m_d->m_ixs[i].m_t, m_d->m_ixs[i - 1].m_t, m_tol)) {
491  tChange.push_back((int)i);
492  }
493  }
494  tChange.push_back((int)m_d->m_ixs.size()); // for convenience
495 } // GmMultiPolyIntersectionSorterTerse::FindWhereTValuesChange
496 
497 } // namespace xms
std::vector< std::vector< int > > m_polys
0-based? indices into m_points to form polygons
void SwapAdjacents()
Swap adjacent identical intersections if necessary.
void FixArrays(std::vector< int > &polyids, std::vector< double > &tvalues, std::vector< Pt3d > &a_pts) const
Make sure we always have at least two tvalues, an entrance and an exit, and that the last polyid = -1...
void IntersectionsToPolyIdsAndTValues(std::vector< int > &polyids, std::vector< double > &tvalues, std::vector< Pt3d > &a_pts) const
Copy intersections to polyids and tvalues, removing duplicates.
bool EQ_TOL(const _T &A, const _U &B, const _V &tolerance)
#define XM_NONE
GmMultiPolyIntersectorData * m_d
Intersection data from GmMultiPolyIntersector.
double m_tol
Tolerance used when comparing t values.
An intersection point of a line with a polygon.
std::set< int > m_polys2
polygon IDs (1-based) that 2nd point is inside on on
void IntersectionsToPolyIdsAndTValuesFor2(std::vector< int > &polyids, std::vector< double > &tvalues, std::vector< Pt3d > &a_pts) const
Copy intersections to polyids and tvalues when there are 2 intersections.
void FindPreviousNextNeither(const std::vector< int > &tChange, const int idx, std::vector< int > *inPrev, std::vector< int > *inNext, std::vector< int > *inNeither) const
Look at each poly in this set of t values and see if it exists in the previous or next set of t value...
std::vector< int > VecInt
void RemoveCornerTouches()
Remove polys that only touch the line at a corner. We try to identify these corner polys using the fo...
std::set< int > SetInt
Pt3d m_pt
Intersection location.
int m_i
The polygon id (1 based)
void FindWhereTValuesChange(std::vector< int > &tChange) const
Mark where we have a change in t values.
double m_t
t values
Functions dealing with geometry.
void AddToPolyIdsAndTValues(const ix &a_ix, std::vector< int > &polyids, std::vector< double > &tvalues, std::vector< Pt3d > &a_pts) const
Add the intersection info to the arrays.
std::vector< double > VecDbl
std::set< int > m_polys1
polygon IDs (1-based) that 1st point is inside or on
#define XM_ENSURE_TRUE_VOID_NO_ASSERT(...)
std::vector< Pt3d > VecPt3d
std::vector< ix > m_ixs
Intersections.
#define XM_ASSERT(x)
Struct used by GmMultiPolyIntersector.
bool EQ_EPS(_T A, _U B, _V epsilon)
virtual void Sort(GmMultiPolyIntersectorData &a_data, std::vector< int > &polyids, std::vector< double > &tvalues, std::vector< Pt3d > &a_pts, double a_tol) override
Sort the intersections, remove redundant info.
void RemoveDuplicateEdges()
If the line goes along an edge we may have polygons on both sides of the edge. Perhaps we want only t...
void Swap(int a, int b)
Swap the order of the intersections a and b.
void IntersectionsToPolyIdsAndTValuesFor3OrMore(std::vector< int > &polyids, std::vector< double > &tvalues, std::vector< Pt3d > &a_pts) const
Copy intersections to polyids and tvalues when there are 3 or more intersections. ...
std::vector< Pt3d > m_points
All points used by all polygons.