Commit 1d8506eb authored by Riegel's avatar Riegel
Browse files

Extracted methods to reduce cognitive complexity. Ref #69

parent e284489e
Pipeline #10052 passed with stage
in 1 minute and 16 seconds
...@@ -82,20 +82,7 @@ public class IntersectPlanarPolygons { ...@@ -82,20 +82,7 @@ public class IntersectPlanarPolygons {
for (Interval in2 : intervals2) { for (Interval in2 : intervals2) {
if (in1.isOverlapping(in2)) { if (in1.isOverlapping(in2)) {
Interval overlap = in1.overlap(in2); Interval overlap = in1.overlap(in2);
Point3d start = straight.evaluate(overlap.getStart()); handleIntersectionIntervalOverlap(cpPolygon1, cpPolygon2, straight, intersections, epsilon, overlap);
if (overlap.getLength() < Global.getHighAccuracyTolerance() * 1e6) {
checkAndAddRealIntersectionPoint(cpPolygon1, cpPolygon2, start, intersections, epsilon);
} else {
Point3d end = straight.evaluate(overlap.getEnd());
PolyLine pPL = new PolyLine(new Coordinate3d(start), new Coordinate3d(end));
if (!isPolyLineASharedEdge(cpPolygon1, pPL)) {
PolygonPolygonIntersection pPPI = new PolygonPolygonIntersection(cpPolygon1, cpPolygon2,
pPL);
intersections.add(pPPI);
}
}
} else if (Math.abs(in1.getStart() - in2.getEnd()) < Global.getHighAccuracyTolerance()) { } else if (Math.abs(in1.getStart() - in2.getEnd()) < Global.getHighAccuracyTolerance()) {
// check if the overlaps with a tolerance (numeric errors) // check if the overlaps with a tolerance (numeric errors)
Point3d point = straight.evaluate(in1.getStart()); Point3d point = straight.evaluate(in1.getStart());
...@@ -108,6 +95,25 @@ public class IntersectPlanarPolygons { ...@@ -108,6 +95,25 @@ public class IntersectPlanarPolygons {
} }
} }
private static void handleIntersectionIntervalOverlap(EdgePolygon cpPolygon1, EdgePolygon cpPolygon2,
GmStraight straight, List<PolygonPolygonIntersection> intersections, double epsilon, Interval overlap) {
Point3d start = straight.evaluate(overlap.getStart());
if (overlap.getLength() < Global.getHighAccuracyTolerance() * 1e6) {
checkAndAddRealIntersectionPoint(cpPolygon1, cpPolygon2, start, intersections, epsilon);
} else {
Point3d end = straight.evaluate(overlap.getEnd());
PolyLine pPL = new PolyLine(new Coordinate3d(start), new Coordinate3d(end));
if (!isPolyLineASharedEdge(cpPolygon1, pPL)) {
PolygonPolygonIntersection pPPI = new PolygonPolygonIntersection(cpPolygon1, cpPolygon2,
pPL);
intersections.add(pPPI);
}
}
}
private static boolean isPolyLineASharedEdge(EdgePolygon p1, PolyLine polyLine) { private static boolean isPolyLineASharedEdge(EdgePolygon p1, PolyLine polyLine) {
// get coordinates of the poly line // get coordinates of the poly line
Point3d polyLineStart = polyLine.getStart().getPoint(); Point3d polyLineStart = polyLine.getStart().getPoint();
...@@ -136,10 +142,12 @@ public class IntersectPlanarPolygons { ...@@ -136,10 +142,12 @@ public class IntersectPlanarPolygons {
/** /**
* *
* Checks if the given point is a "real" intersection point and add's it to the * Checks if the given point is a 'real' intersection point and adds it to the
* intersection segments member variable. Real means, that this point isn't * intersection segments member variable. 'Real' meaning, that this point isn't
* shared by both polygons as corner point. * a shared corner point of both polygons.
* *
* @param p1 First polygon
* @param p2 Second polygon
* @param point A possible intersection point * @param point A possible intersection point
*/ */
private static void checkAndAddRealIntersectionPoint(EdgePolygon p1, EdgePolygon p2, Point3d point, private static void checkAndAddRealIntersectionPoint(EdgePolygon p1, EdgePolygon p2, Point3d point,
...@@ -200,7 +208,6 @@ public class IntersectPlanarPolygons { ...@@ -200,7 +208,6 @@ public class IntersectPlanarPolygons {
* with the exception, that the straight and the half edges of the polygon will * with the exception, that the straight and the half edges of the polygon will
* be projected on the plane of the polygon, so the calculation of the * be projected on the plane of the polygon, so the calculation of the
* intersection will be reduced to a 2d problem. * intersection will be reduced to a 2d problem.
*
* The intersection intervals contains pairs of parameters from the intersection * The intersection intervals contains pairs of parameters from the intersection
* straight. If an intersection between the straight and the polygon contains * straight. If an intersection between the straight and the polygon contains
* only a point, the according interval will contain the same parameter twice * only a point, the according interval will contain the same parameter twice
...@@ -271,39 +278,7 @@ public class IntersectPlanarPolygons { ...@@ -271,39 +278,7 @@ public class IntersectPlanarPolygons {
GmBoundedStraight2d heStraight2d = polyPlane.projectOn2dStraight(heStraight); GmBoundedStraight2d heStraight2d = polyPlane.projectOn2dStraight(heStraight);
GmStraight2dIntersectionResult intersectionResult = heStraight2d.intersect(intersectingStraight2d); GmStraight2dIntersectionResult intersectionResult = heStraight2d.intersect(intersectingStraight2d);
if (intersectionResult.areParallel()) { analyseProjectedIntersection(intersectionResult, intersectingStraight2d, heStraight2d, intersectionValues, intersectedPolygonPoints);
Vector2d dir = intersectingStraight2d.getDirection();
Vector2d diffVec = heStraight2d.getOrigin().minus(intersectingStraight2d.getOrigin());
double diffVecDotPerpDir = diffVec.dot(dir.getPerpendicularVector());
if (Math.abs(diffVecDotPerpDir) < Global.getZeroAngleCosine()) {
// Straights are identical
Point2d p1 = heStraight2d.getOrigin();
Point2d p2 = heStraight2d.getTarget();
Point2d orig = intersectingStraight2d.getOrigin();
double[] params = new double[2];
if (Math.abs(dir.getX()) > Global.getHighAccuracyTolerance()) {
params[0] = (p1.getX() - orig.getX()) / dir.getX();
params[1] = (p2.getX() - orig.getX()) / dir.getX();
} else if (Math.abs(dir.getY()) > Global.getHighAccuracyTolerance()) {
params[0] = (p1.getY() - orig.getY()) / dir.getY();
params[1] = (p2.getY() - orig.getY()) / dir.getY();
} else {
throw new IllegalStateException(
"Directional vector of identical straights is equal to the zero vector " + dir);
}
assignParameterToCorrectList(params[0], intersectionValues, intersectedPolygonPoints);
assignParameterToCorrectList(params[1], intersectionValues, intersectedPolygonPoints);
}
} else {
if (heStraight2d.isWithinBoundaries(intersectionResult.paramHE(), 1e-9)) {
assignParameterToCorrectList(intersectionResult.paramInt(), intersectionValues,
intersectedPolygonPoints);
}
}
} }
processIntersectionIntervals(p, intersectingStraight, intersectionValues, intersectedPolygonPoints, processIntersectionIntervals(p, intersectingStraight, intersectionValues, intersectedPolygonPoints,
...@@ -312,6 +287,42 @@ public class IntersectPlanarPolygons { ...@@ -312,6 +287,42 @@ public class IntersectPlanarPolygons {
} }
private static void analyseProjectedIntersection(GmStraight2dIntersectionResult intersectionResult, GmStraight2d intersectingStraight2d, GmBoundedStraight2d heStraight2d, TreeSet<Double> intersectionValues, TreeSet<Double> intersectedPolygonPoints) {
if (intersectionResult.areParallel()) {
Vector2d dir = intersectingStraight2d.getDirection();
Vector2d diffVec = heStraight2d.getOrigin().minus(intersectingStraight2d.getOrigin());
double diffVecDotPerpDir = diffVec.dot(dir.getPerpendicularVector());
if (Math.abs(diffVecDotPerpDir) < Global.getZeroAngleCosine()) {
// Straights are identical
Point2d p1 = heStraight2d.getOrigin();
Point2d p2 = heStraight2d.getTarget();
Point2d orig = intersectingStraight2d.getOrigin();
double[] params = new double[2];
if (Math.abs(dir.getX()) > Global.getHighAccuracyTolerance()) {
params[0] = (p1.getX() - orig.getX()) / dir.getX();
params[1] = (p2.getX() - orig.getX()) / dir.getX();
} else if (Math.abs(dir.getY()) > Global.getHighAccuracyTolerance()) {
params[0] = (p1.getY() - orig.getY()) / dir.getY();
params[1] = (p2.getY() - orig.getY()) / dir.getY();
} else {
throw new IllegalStateException(
"Directional vector of identical straights is equal to the zero vector " + dir);
}
assignParameterToCorrectList(params[0], intersectionValues, intersectedPolygonPoints);
assignParameterToCorrectList(params[1], intersectionValues, intersectedPolygonPoints);
}
} else {
if (heStraight2d.isWithinBoundaries(intersectionResult.paramHE(), 1e-9)) {
assignParameterToCorrectList(intersectionResult.paramInt(), intersectionValues,
intersectedPolygonPoints);
}
}
}
/** /**
* This methods computes the intervals of the intersection between the given * This methods computes the intervals of the intersection between the given
* straight and polygon. It gets only parameters where the straight hits the * straight and polygon. It gets only parameters where the straight hits the
...@@ -350,43 +361,18 @@ public class IntersectPlanarPolygons { ...@@ -350,43 +361,18 @@ public class IntersectPlanarPolygons {
List<Double> valuesList = new ArrayList<>(intersectionValues); List<Double> valuesList = new ArrayList<>(intersectionValues);
for (int i = 0; i < valuesList.size(); i++) { for (int i = 0; i < valuesList.size(); i++) {
double i1 = valuesList.get(i); double i1 = valuesList.get(i);
i = i + 1; int j = i + 1;
if (i < valuesList.size()) { if (j < valuesList.size()) {
double i2 = valuesList.get(i); double i2 = valuesList.get(j);
// check if the double values are corner points of the polygon // check if the double values are corner points of the polygon
boolean gotPolygonPoint = intersectedPolygonPoints.contains(i1) || boolean gotPolygonPoint = intersectedPolygonPoints.contains(i1) ||
intersectedPolygonPoints.contains(i2); intersectedPolygonPoints.contains(i2);
if (gotPolygonPoint) { if (gotPolygonPoint) {
// maybe an interval Interval newLineInt = checkIntersectionInvervalPoints(pcPolygon, intersectingStraight,
// check if the point between the two parameters is inside the intersectionIntervals, i1, i2);
// polygon or outside ( i.e. i1 and i2 are both corner points of if (newLineInt != null) {
// a concave polygon, so the connection line don't need to lie
// inside the polygon )
Point3d pnt = intersectingStraight.evaluate((i1 + i2) / 2);
if (pcPolygon.isPointInsidePolygon(pnt, 1e-9)) {
Interval newLineInt = new Interval(i1, i2);
// there is already at least one point interval present. We need
// to remove this first, otherwise we would get a normal interval
// and one or two point intervals at the end of the normal int.
Iterator<Interval> intervalIterator = intersectionIntervals.iterator();
while (intervalIterator.hasNext() && !intersectionIntervals.isEmpty()) {
for (Interval inter = intervalIterator.next(); intervalIterator
.hasNext(); inter = intervalIterator.next()) {
if (Math.abs(inter.getLength()) < Global.getHighAccuracyTolerance()) {
if (Math.abs(inter.getStart() - i1) < 1e-9
|| Math.abs(inter.getStart() - i2) < 1e-9) {
intervalIterator.remove();
intervalIterator = intersectionIntervals.iterator();
break;
}
}
}
}
intersectionIntervals.add(newLineInt); intersectionIntervals.add(newLineInt);
} else {
i--;
} }
} else { } else {
intersectionIntervals.add(new Interval(i1, i2)); intersectionIntervals.add(new Interval(i1, i2));
...@@ -403,6 +389,37 @@ public class IntersectPlanarPolygons { ...@@ -403,6 +389,37 @@ public class IntersectPlanarPolygons {
} }
} }
private static Interval checkIntersectionInvervalPoints(EdgePolygon pcPolygon, GmStraight intersectingStraight, List<Interval> intersectionIntervals, double i1, double i2) {
// maybe an interval
// check if the point between the two parameters is inside the
// polygon or outside ( i.e. i1 and i2 are both corner points of
// a concave polygon, so the connection line don't need to lie
// inside the polygon )
Point3d pnt = intersectingStraight.evaluate((i1 + i2) / 2);
if (pcPolygon.isPointInsidePolygon(pnt, 1e-9)) {
Interval newLineInt = new Interval(i1, i2);
// there is already at least one point interval present. We need
// to remove this first, otherwise we would get a normal interval
// and one or two point intervals at the end of the normal int.
Iterator<Interval> intervalIterator = intersectionIntervals.iterator();
while (intervalIterator.hasNext() && !intersectionIntervals.isEmpty()) {
for (Interval inter = intervalIterator.next(); intervalIterator
.hasNext(); inter = intervalIterator.next()) {
if (Math.abs(inter.getLength()) < Global.getHighAccuracyTolerance() &&
(Math.abs(inter.getStart() - i1) < 1e-9 || Math.abs(inter.getStart() - i2) < 1e-9)) {
intervalIterator.remove();
intervalIterator = intersectionIntervals.iterator();
break;
}
}
}
return newLineInt;
}
return null;
}
/** /**
* Util method. Checks if the given parameter has already been inserted as * Util method. Checks if the given parameter has already been inserted as
* intersection parameter. If this is true, the parameter will be added as * intersection parameter. If this is true, the parameter will be added as
...@@ -442,46 +459,9 @@ public class IntersectPlanarPolygons { ...@@ -442,46 +459,9 @@ public class IntersectPlanarPolygons {
List<HalfEdge> heList = new ArrayList<>(p1.getHalfEdges()); List<HalfEdge> heList = new ArrayList<>(p1.getHalfEdges());
heList.addAll(p2.getHalfEdges()); heList.addAll(p2.getHalfEdges());
List<HalfEdge> heListColinear = new ArrayList<>(); List<HalfEdge> heListCollinear = getCollinearHalfEdgeList(p1, p2, straight, epsilon, angleEpsilon, heList);
for (HalfEdge he : heList) {
if (null != he.getPartner()) {
// this half edge is shared by both polygons ==> no intersection
// NOTE: The issue of more than 2 half edges per edge is solved by
// circular pointer, so we have to cycle threw all partners
HalfEdge pStartHE = he;
HalfEdge pPartnerHE = pStartHE.getPartner();
boolean bothPolysShareThisEdge = false;
while (pStartHE != pPartnerHE && !bothPolysShareThisEdge) {
if (pPartnerHE.getPolygon() == p1 || pPartnerHE.getPolygon() == p2) {
bothPolysShareThisEdge = true;
}
pPartnerHE = pPartnerHE.getPartner();
}
if (bothPolysShareThisEdge) {
continue;
}
}
GmBoundedStraight straightHe = he.getStraight();
Point3d origin = straightHe.getOrigin();
Point3d target = straightHe.getTarget();
boolean straightsAreColinear = IntersectPlanarPolygons.areStraightsColinear(straightHe, straight, epsilon,
angleEpsilon);
ProjectedPoint3d projPoint1 = straight.project(origin);
ProjectedPoint3d projPoint2 = straight.project(target);
boolean originLiesOnIntStraight = projPoint1.getPoint().isAlmostEqual(origin, for (HalfEdge he : heListCollinear) {
PROJECTED_POINT_DISTANCE_EPSILON);
boolean targetLiesOnIntStraight = projPoint2.getPoint().isAlmostEqual(target,
PROJECTED_POINT_DISTANCE_EPSILON);
if (straightsAreColinear && (originLiesOnIntStraight || targetLiesOnIntStraight)) {
heListColinear.add(he);
}
}
for (HalfEdge he : heListColinear) {
// 1.2) determine if fully or partially or not at all embedded // 1.2) determine if fully or partially or not at all embedded
// create parameter interval of the first projected half edge // create parameter interval of the first projected half edge
Point3d startPoint1 = he.getStraight().getOrigin(); Point3d startPoint1 = he.getStraight().getOrigin();
...@@ -489,7 +469,7 @@ public class IntersectPlanarPolygons { ...@@ -489,7 +469,7 @@ public class IntersectPlanarPolygons {
ProjectedPoint3d projP1 = straight.project(startPoint1); ProjectedPoint3d projP1 = straight.project(startPoint1);
ProjectedPoint3d projP2 = straight.project(endPoint1); ProjectedPoint3d projP2 = straight.project(endPoint1);
Interval int1 = new Interval(projP1.getParameter(), projP2.getParameter()); Interval int1 = new Interval(projP1.getParameter(), projP2.getParameter());
for (HalfEdge he2 : heListColinear) { for (HalfEdge he2 : heListCollinear) {
if (he == he2) { if (he == he2) {
continue; continue;
} }
...@@ -526,8 +506,63 @@ public class IntersectPlanarPolygons { ...@@ -526,8 +506,63 @@ public class IntersectPlanarPolygons {
} }
} }
private static boolean areStraightsColinear(GmBoundedStraight straight1, GmStraight straight2, double epsilon, private static List<HalfEdge> getCollinearHalfEdgeList(EdgePolygon p1, EdgePolygon p2, GmStraight straight, double epsilon, double angleEpsilon, List<HalfEdge> heList) {
double angleEpsilon) { List<HalfEdge> heListCollinear = new ArrayList<>();
for (HalfEdge he : heList) {
if (isHalfEdgeSharedByPolygons(he, p1, p2)){
// If the HalfEdge is shared, it is not collinear.
// Ignore it and continue with next HalfEdge.
continue;
}
GmBoundedStraight straightHe = he.getStraight();
Point3d origin = straightHe.getOrigin();
Point3d target = straightHe.getTarget();
boolean straightsAreCollinear = IntersectPlanarPolygons.areStraightsCollinear(straightHe, straight, epsilon,
angleEpsilon);
ProjectedPoint3d projPoint1 = straight.project(origin);
ProjectedPoint3d projPoint2 = straight.project(target);
boolean originLiesOnIntStraight = projPoint1.getPoint().isAlmostEqual(origin,
PROJECTED_POINT_DISTANCE_EPSILON);
boolean targetLiesOnIntStraight = projPoint2.getPoint().isAlmostEqual(target,
PROJECTED_POINT_DISTANCE_EPSILON);
if (straightsAreCollinear && (originLiesOnIntStraight || targetLiesOnIntStraight)) {
heListCollinear.add(he);
}
}
return heListCollinear;
}
/**
* Checks whether a specific HalfEdge is shared by two EdgePolygons.
*
*
* @param he The HalfEdge in question
* @param p1 First Polygon
* @param p2 Second Polygon
* @return true if the HalfEdge is shared
*/
private static boolean isHalfEdgeSharedByPolygons(HalfEdge he, EdgePolygon p1, EdgePolygon p2) {
boolean bothPolysShareThisEdge = false;
if (he.getPartner() != null) {
// NOTE: The issue of more than 2 half edges per edge is solved by
// circular pointer, so we have to cycle threw all partners
HalfEdge pPartnerHE = he.getPartner();
while (he != pPartnerHE && !bothPolysShareThisEdge) {
if (pPartnerHE.getPolygon() == p1 || pPartnerHE.getPolygon() == p2) {
bothPolysShareThisEdge = true;
}
pPartnerHE = pPartnerHE.getPartner();
}
}
return bothPolysShareThisEdge;
}
private static boolean areStraightsCollinear(GmBoundedStraight straight1, GmStraight straight2, double epsilon,
double angleEpsilon) {
UnitVector3d rDir1 = straight1.getDir(); UnitVector3d rDir1 = straight1.getDir();
UnitVector3d rDir2 = straight2.getDir(); UnitVector3d rDir2 = straight2.getDir();
...@@ -541,12 +576,9 @@ public class IntersectPlanarPolygons { ...@@ -541,12 +576,9 @@ public class IntersectPlanarPolygons {
ProjectedPoint3d foot1 = straight2.project(rOrigin); ProjectedPoint3d foot1 = straight2.project(rOrigin);
Point3d rTarget = straight1.getTarget(); Point3d rTarget = straight1.getTarget();
ProjectedPoint3d foot2 = straight2.project(rTarget); ProjectedPoint3d foot2 = straight2.project(rTarget);
if ((foot1.getPoint().minus(rOrigin)).getLength() > epsilon return !(((foot1.getPoint().minus(rOrigin)).getLength() > epsilon)
|| (foot2.getPoint().minus(rTarget)).getLength() > epsilon) { || ((foot2.getPoint().minus(rTarget)).getLength() > epsilon));
return false; }
}
return true;
}
private static List<PolygonPolygonIntersection> handlePolygonsInSamePlane(GmPlane plane, EdgePolygon p1, private static List<PolygonPolygonIntersection> handlePolygonsInSamePlane(GmPlane plane, EdgePolygon p1,
EdgePolygon p2, double epsilon) { EdgePolygon p2, double epsilon) {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment