Commit 5d40c7b6 authored by Matthias Betz's avatar Matthias Betz
Browse files

CityDoctor2 validation open source release

parents
/*-
* Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart
*
* This file is part of CityDoctor2.
*
* CityDoctor2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CityDoctor2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CityDoctor2. If not, see <https://www.gnu.org/licenses/>.
*/
package de.hft.stuttgart.citydoctor2.edge;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.TreeSet;
public class IntersectPolygonAndStraight2d {
/**
* @param pcPolygon A polygon
*
* @param rcIntersectingStraight The straight which have been intersected
* with the given polygon
*
* @param rIntersectionValues The calculated parameters of the
* intersection
*
* @param rIntersectedPolygonPoints A set of values, containing parameter values
* where the straight intersects the polygon in
* a corner point.
*
* @return rIntersectionIntervals A list of computed intersection intervals of
* the straight with the polygon
*
* This methods computes the intervals of the intersection between the
* given straight and polygon. It gets only parameters where the
* straight hits the polygon.
*
* The additional set of intersected polygon points is neccessary,
* because each intersection of a corner point with the straight results
* in the computation of the same intersection parameter twice, because
* at every corner point of the polygon two edges are joining. These
* points has to be treated special.
*
*/
public static List<Interval> intersect(Polygon2d mcpPolygon, GmBoundedStraight2d mIntStraight, double eps) {
List<Interval> mIntersectionIntervals = new ArrayList<>();
TreeSet<Double> intersectionValues = new TreeSet<>(Global.getDoubleTolCompare(eps));
TreeSet<Double> intersectedPolygonPoints = new TreeSet<>(Global.getDoubleTolCompare(eps));
List<HalfEdge2d> halfEdges = mcpPolygon.getHalfEdges();
for (HalfEdge2d heIt : halfEdges) {
GmBoundedStraight2d hEStraight = heIt.getStraight();
GmStraight2dIntersectionResult res = hEStraight.intersect(mIntStraight);
if (res.areParallel()) {
Vector2d dir = mIntStraight.getDirection();
Vector2d diffVec = mIntStraight.getOrigin().minus(hEStraight.getOrigin());
// calculate the do product to check if the vector connecting the
// origin points of the straight is orthogonal to the direction
// if so ==> the parallel straights overlap
double diffVecDotPerpDir = diffVec.dot(dir.getPerpendicularVector());
if (Math.abs(diffVecDotPerpDir) < Global.getHighAccuracyTolerance()) {
// Straights are identical
Point2d p1 = hEStraight.getOrigin();
Point2d p2 = hEStraight.getTarget();
Point2d orig = mIntStraight.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 IllegalArgumentException(
"Directional vector of identical straights is equal to the zero vector");
}
// Point2d pnt = mIntStraight.evaluate( params[0] );
// cout << "got ( " << pnt.getU() << ", " << pnt.getV() << " ) as int point with
// param " << params[0] << endl;
// pnt = mIntStraight.evaluate( params[1] );
// cout << "got ( " << pnt.getU() << ", " << pnt.getV() << " ) as int point with
// param " << params[1] << endl;
assignParameterToCorrectList(params[0], intersectionValues, intersectedPolygonPoints);
assignParameterToCorrectList(params[1], intersectionValues, intersectedPolygonPoints);
}
} else {
if (hEStraight.isWithinBoundaries(res.getParamHE())) {
// Point2d pnt = mIntStraight.evaluate( paramInt );
// cout << "got ( " << pnt.getU() << ", " << pnt.getV() << " ) as int point with
// param " << paramInt << endl;
assignParameterToCorrectList(res.getParamInt(), intersectionValues, intersectedPolygonPoints);
}
}
}
processIntersectionIntervals(mcpPolygon, mIntStraight, intersectionValues, intersectedPolygonPoints,
mIntersectionIntervals);
return mIntersectionIntervals;
}
/**
*
* This methods computes the intervals of the intersection between the given
* straight and polygon. It gets only parameters where the straight hits the
* polygon.
*
* <br>
* The additional set of intersected polygon points is necessary, because each
* intersection of a corner point with the straight results in the computation
* of the same intersection parameter twice, because at every corner point of
* the polygon two edges are joining. These points has to be treated special.
*
* @param crIntersectionValues The calculated parameters of the
* intersection
*
* @param crIntersectedPolygonPoints A set of values, containing parameter
* values where the straight intersects the
* polygon in a corner point.
*
*
*/
private static void processIntersectionIntervals(Polygon2d mcpPolygon, GmStraight2d mIntStraight,
TreeSet<Double> crIntersectionValues, TreeSet<Double> crIntersectedPolygonPoints,
List<Interval> mIntersectionIntervals) {
// create intervals
if (!crIntersectionValues.isEmpty()) {
// if (crIntersectionValues.size() > 1) {
Iterator<Double> it1 = crIntersectionValues.iterator();
double vit1 = it1.next();
while (it1.hasNext()) {
double vit2 = it1.next();
// check if the point between the values (midpoint) is inside of the
// polygon; this don't need to be true for concave polygons
// if the midpoint is inside, than we have an interval, if it's outside
// it's not. i can
Point2d pnt = mIntStraight.evaluate((vit1 + vit2) / 2);
if (mcpPolygon.isPointInsidePolygon(pnt)) {
Interval intIntv = new Interval(vit1, vit2);
mIntersectionIntervals.add(intIntv);
}
vit1 = vit2;
}
}
// insert points intervals, if they are no part of an already existing
// interval
for (Double d : crIntersectedPolygonPoints) {
boolean pntIsPartOfExistingInterval = false;
for (Interval interval : mIntersectionIntervals) {
if (pntIsPartOfExistingInterval) {
break;
}
if (interval.getStart() == d || interval.getEnd() == d) {
pntIsPartOfExistingInterval = true;
}
}
// the current value is not part of an existing interval, so insert it
if (!pntIsPartOfExistingInterval) {
mIntersectionIntervals.add(new Interval(d, d));
}
}
}
/**
*
*
* Util method. Checks if the given parameter has been already inserted as
* intersection parameter. If this is true, the parameter will be added as
* intersected polygon corner point. Otherwise it's just a normal intersection
* parameter till now.
*
* Just a util method to purge the code
*
* @param param Calculated intersection parameter
*
* @param orIntersectionValues Set of intersection parameters
*
* @param orIntersectedPolygonPoints Set of intersected polygon corner points
*
*/
private static void assignParameterToCorrectList(double param, TreeSet<Double> orIntersectionValues,
TreeSet<Double> orIntersectedPolygonPoints) {
if (!orIntersectionValues.contains(param)) {
orIntersectionValues.add(param);
} else {
// value is already present ==> this must be a point of the polygon
// note, it's assumed, that the polygon do not intersect itself
orIntersectedPolygonPoints.add(param);
}
}
}
Markdown is supported
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