Mantid
Loading...
Searching...
No Matches
PolygonIntersection.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
7//------------------------------------------------------------------------------
8// Includes
9//------------------------------------------------------------------------------
13#include "MantidKernel/Logger.h"
14#include "MantidKernel/V2D.h"
15
16using namespace Mantid::Kernel;
17
18namespace Mantid::Geometry {
19
20namespace {
21
22//------------------------------------------------------------------------------
23// Anonymous helpers
24//------------------------------------------------------------------------------
25
27Kernel::Logger g_log("PolygonIntersection");
28
29// Uncomment this to get detailed statements of the exact progress of the
30// intersection
31// calculation
32//#define DEBUG_INTERSECTION
33
37#ifdef DEBUG_INTERSECTION
38#define VERBOSE(X) X
39#else
40#define VERBOSE(X)
41#endif
42
43enum eEdgeIn {
44 Unknown,
45 PIsInside,
46 QIsInside
47};
48
57void advanceVertex(ConvexPolygon::Iterator &iter, ConvexPolygon &out, const V2D &lastIntersect, const bool inside) {
58 ++iter;
59 const auto &curPolyPt = *iter;
60 if (inside && (lastIntersect != curPolyPt)) {
61 // Add an intersection as the point is inside the polygon
62 out.insert(curPolyPt);
63 VERBOSE(std::cout << "Advance adds cross pt: (" << curPolyPt.X() << "," << curPolyPt.Y() << ")\n");
64 }
65}
66
67} // Anonymous namespace
68
69//------------------------------------------------------------------------------
70// Public functions
71//------------------------------------------------------------------------------
85bool MANTID_GEOMETRY_DLL intersection(const ConvexPolygon &P, const ConvexPolygon &Q, ConvexPolygon &out) {
86
87 // The algorithm requires that the polygon with the greatest unsigned area
88 // be on the "Left"
89 VERBOSE(std::cout << "Area of P (" << P.area() << "). Area of Q (" << Q.area() << ")\n");
90 if (P.area() < Q.area()) {
91 VERBOSE(std::cout << "Area of P < Area of Q. Swapping order.\n");
92 return intersection(Q, P, out);
93 }
94
95 V2D iPnt, startPnt, curIntersection;
96 ConvexPolygon::Iterator pIter(P), qIter(Q);
97 eEdgeIn inflag = Unknown;
98 int phase = 1;
99 size_t maxItns = 2 * (P.npoints() + Q.npoints());
100 for (size_t i = 1; i <= maxItns; ++i) {
101 VERBOSE(std::cout << "Iteration " << i << " Phase = " << phase << '\n');
102 const PolygonEdge edgeP = pIter.edge();
103 const PolygonEdge edgeQ = qIter.edge();
104 PointClassification pclass = classify(edgeP.end(), edgeQ);
105
106 VERBOSE(std::cout << "Class P Pt\n");
107 VERBOSE(std::cout << "Class Pt: (" << edgeP.end().X() << "," << edgeP.end().Y() << ")\n");
108 VERBOSE(std::cout << "Edge Orig Pt (" << edgeQ.start().X() << "," << edgeQ.start().Y() << ")\n");
109 VERBOSE(std::cout << "Edge Dest Pt (" << edgeQ.end().X() << "," << edgeQ.end().Y() << ")\n");
110 VERBOSE(std::cout << "P pt class: " << pclass << '\n');
111
112 PointClassification qclass = classify(edgeQ.end(), edgeP);
113 VERBOSE(std::cout << "Class Q Pt\n");
114 VERBOSE(std::cout << "Class Pt: (" << edgeQ.end().X() << "," << edgeQ.end().Y() << ")\n");
115 VERBOSE(std::cout << "Edge Orig Pt (" << edgeP.start().X() << "," << edgeP.start().Y() << ")\n");
116 VERBOSE(std::cout << "Edge Dest Pt (" << edgeP.end().X() << "," << edgeP.end().Y() << ")\n");
117 VERBOSE(std::cout << "Q pt class: " << qclass << '\n');
118
119 PolygonEdge::Orientation crossType = crossingPoint(edgeP, edgeQ, iPnt);
120 VERBOSE(std::cout << "PQ Orient: " << crossType << '\n');
121
122 if (crossType == PolygonEdge::SkewCross) {
123 if (phase == 1) {
124 phase = 2;
125 VERBOSE(std::cout << "Found a crossing pt: (" << iPnt.X() << ",");
126 VERBOSE(std::cout << iPnt.Y() << ")\n");
127
128 curIntersection = iPnt;
129 out.insert(iPnt);
130 startPnt = iPnt;
131 } else if (iPnt != curIntersection) {
132 VERBOSE(std::cout << "Found a crossing pt: (" << iPnt.X() << ",");
133 VERBOSE(std::cout << iPnt.Y() << ")\n");
134 if (iPnt != startPnt) {
135 curIntersection = iPnt;
136 out.insert(iPnt);
137 } else // Back to the start, we're done
138 {
139 // Return the head if it is a valid polygon
140 return out.isValid();
141 }
142 }
143 if (pclass == OnRight) {
144 inflag = PIsInside;
145 } else if (qclass == OnRight) {
146 inflag = QIsInside;
147 } else {
148 inflag = Unknown;
149 }
150 } else if ((crossType == PolygonEdge::Collinear) && (pclass != Behind) && (qclass != Behind)) {
151 inflag = Unknown;
152 }
153 VERBOSE(std::cout << "Current in flag: " << inflag << '\n');
154
155 bool pAIMSq = edgeAimsAt(edgeP, edgeQ, pclass, crossType);
156 bool qAIMSp = edgeAimsAt(edgeQ, edgeP, qclass, crossType);
157
158 VERBOSE(std::cout << "P aims at Q:" << pAIMSq << '\n');
159 VERBOSE(std::cout << "Q aims at P:" << qAIMSp << '\n');
160 if (pAIMSq && qAIMSp) {
161 if ((inflag == QIsInside) || ((inflag == Unknown) && (pclass == OnLeft))) {
162 VERBOSE(std::cout << "Move edge on P\n");
163 advanceVertex(pIter, out, curIntersection, false);
164 } else {
165 VERBOSE(std::cout << "Move edge on Q\n");
166 advanceVertex(qIter, out, curIntersection, false);
167 }
168 } else if (pAIMSq) {
169 VERBOSE(std::cout << "Move edge on P\n");
170 advanceVertex(pIter, out, curIntersection, inflag == PIsInside);
171 } else if (qAIMSp) {
172 VERBOSE(std::cout << "Move edge on Q\n");
173 advanceVertex(qIter, out, curIntersection, inflag == QIsInside);
174 } else {
175 if ((inflag == QIsInside) || ((inflag == Unknown) && (pclass == OnLeft))) {
176 VERBOSE(std::cout << "Move edge on P\n");
177 advanceVertex(pIter, out, curIntersection, false);
178 } else {
179 VERBOSE(std::cout << "Move edge on Q\n");
180 advanceVertex(qIter, out, curIntersection, false);
181 }
182 }
183 } // end-for
184
185 // Reaching this point means we have no intersections
186 // of the polygon edges. There is the possiblity that
187 // the larger polygon completely encloses the smaller
188 // in which case no edge intersections would be found
189 // but there is an overlap
190 if (P.contains(Q)) {
191 // standard assignment won't work as the object is a reference
192 // and we don't know the exact type
193 out = Q.toPoly();
194 return true;
195 }
196
197 return false;
198}
199
200} // namespace Mantid::Geometry
#define VERBOSE(X)
Define a macro to include the logging statements if requested.
PolygonEdge edge() const
Create a directed edge between this and the next point.
An implementation of a convex polygon.
Definition: ConvexPolygon.h:36
virtual size_t npoints() const
Return the number of vertices.
void insert(const Kernel::V2D &pt)
Insert a new vertex.
virtual double area() const
Compute the area of the polygon using triangulation.
bool isValid() const
Check if polygon is valid.
virtual bool contains(const Kernel::V2D &point) const
Is a point inside this polygon.
virtual ConvexPolygon toPoly() const
Return a new Polygon based on the current type.
PolygonEdge Defines a directed edge between two points on a polygon.
Definition: PolygonEdge.h:23
const Kernel::V2D & end() const
Access the end point.
Definition: PolygonEdge.h:39
const Kernel::V2D & start() const
Access the start point.
Definition: PolygonEdge.h:37
Orientation
Defines the orientation with respect to another edge.
Definition: PolygonEdge.h:26
@ Collinear
Edges lie on the same line.
Definition: PolygonEdge.h:27
@ SkewCross
Edges are at an angle and intersect.
Definition: PolygonEdge.h:30
The Logger class is in charge of the publishing messages from the framework through various channels.
Definition: Logger.h:52
Implements a 2-dimensional vector embedded in a 3D space, i.e.
Definition: V2D.h:29
double Y() const
Y position.
Definition: V2D.h:49
double X() const
X position.
Definition: V2D.h:44
Mantid::Kernel::Logger g_log("Goniometer")
MANTID_GEOMETRY_DLL PointClassification classify(const Kernel::V2D &pt, const PolygonEdge &edge)
Helper function for classification.
Definition: PolygonEdge.cpp:47
MANTID_GEOMETRY_DLL bool edgeAimsAt(const PolygonEdge &a, const PolygonEdge &b, PointClassification aclass, PolygonEdge::Orientation crossType)
Return if the edges aim at each other.
MANTID_GEOMETRY_DLL PolygonEdge::Orientation crossingPoint(const PolygonEdge &edgeOne, const PolygonEdge &edgeTwo, Kernel::V2D &crossPoint)
Calculate the crossing point of one edge with wrt another.
bool MANTID_GEOMETRY_DLL intersection(const ConvexPolygon &P, const ConvexPolygon &Q, ConvexPolygon &out)
Compute the instersection of two convex polygons.
PointClassification
Enumeration for point type w.r.t an edge.
Definition: PolygonEdge.h:58
@ OnRight
Point is to right of edge.
Definition: PolygonEdge.h:60
@ OnLeft
Point is to left of edge.
Definition: PolygonEdge.h:59
@ Behind
Point is left of edge origin.
Definition: PolygonEdge.h:62