Hei,
.. how about getting the overlap result from
intersect = Geometry1.intersect(Geometry2)
and then calculating some stuff based on that geometry.
I once did a very slow(!) implementation of that to calculate
displacement vectors (perpendicular to the centroid connection). Please
see the attached class and for my comment:
"calc disp vector and save as linestring"
(but you can not use the full class directly since I used other
resources too).
stefan
/***********************************************
* created on 01.10.2004
* last modified: 20.12.2004 (LineString conflictMatrix & List added)
*
* author: sstein
*
* description:
* tests if the distance among two polygons is under a threshold
* and returns the displacement vectors (for centroid or outer ring
points),
* before apply calcDisplacementVectors();
*
* to get the conflicts use getMwcList()
***********************************************/
package ch.unizh.geo.measures;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.jmat.MatlabSyntax;
import org.jmat.data.Matrix;
import ch.unizh.geo.algorithms.Rotate;
import ch.unizh.geo.geomutilities.FirstGeodeticTask2d;
import ch.unizh.geo.geomutilities.PointLineDistance;
import ch.unizh.geo.geomutilities.SecondGeodeticTask2d;
import ch.unizh.geo.measures.supportclasses.MWConflictList;
import ch.unizh.geo.measures.supportclasses.MinWidthConflict;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.IntersectionMatrix;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;
import com.vividsolutions.jts.operation.distance.DistanceOp;
import com.vividsolutions.jts.operation.distance.GeometryLocation;
/**
* @description
* checks if two polygons:<p>
* - intersects<p>
* - touches (have one common edge)<p>
* - (do not intersect and touch) have a distance,<p>
* <p>
* and (if under a given threshold) use calcDisplacementVectors();
* to calculates the displacement vectors for the conflict points
* (of outer ring) or centroid - which depends on type of conflict,<p>
* <p>
* to get the conflicts use getMwcList()
*
* @author sstein
*
*/
public class PolygonDistance {
public List geometryList = new ArrayList();
private double angle;
private Polygon p1;
private Polygon p2;
private Geometry bufferGeom = null;
// for not intersecting polygons
// private ArrayList minWidthDoubleList = new ArrayList();
private List dispVecPtEgLSthisPolyList = new ArrayList();
private List dispVecPtPtLSthisPolyList = new ArrayList();
private List dispVecPtEgLSOtherPolyList = new ArrayList();
private List dispVecPtPtLSOtherPolyList = new ArrayList();
private Matrix dxConflictMatrix;
private Matrix dyConflictMatrix;
//private List minEdgeLineStringList = new ArrayList();
//private List minVertexPointList = new ArrayList();
private double shortestDistance = 999999.99; //init value 999km
// for intersecting polys
private LineString dispVectorPolyIntersection = null;
private Geometry polygonIntersection = null;
// ---
private boolean hasConflict = false;
private boolean linesCross = false;
private boolean commonEdge = false;
private boolean areToClose = false;
private double threshold = 0;
//-- if dist[m] < field: "crucialDistance" it is complicate to give a
// displacement direction
private double crucialDistance = 0.1;
private MWConflictList mwclist = new MWConflictList();
private double[] dispVectorComponents ={0,0};
/**
* tests if two polygons have a distance conflict
* - check for a common edge
* - check for intersection
* - checks if the minimum buffer is joint/touched
* to calculate the dsiplacement use calcDisplacementVectors();
*
* @param p1
* @param p2
* @param threshold
*/
public PolygonDistance(Polygon poly1, Polygon poly2, double threshold){
this.threshold = threshold;
this.p1 = poly1;
this.p2 = poly2;
//--IntersectionMatrix
IntersectionMatrix myIM = p1.relate(p2);
/*
System.out.println("IntersectionMat: tr-bl : "
+ myIM.get(0,0) + " " + myIM.get(0,1) + " " + myIM.get(0,2)
+ ","
+ myIM.get(1,0) + " " + myIM.get(1,1) + " " + myIM.get(1,2)
+ ","
+ myIM.get(2,0) + " " + myIM.get(2,1) + " " + myIM.get(2,2)
);
*/
//-- test if polygons have common edge
if (myIM.matches("F***1****") == true){
this.commonEdge = true;
}
//-- test if Polygons cross/intersect (JTS function)
// but exclude case there one point is on on edge => I1 + E2 =-1 && E1+
I2 = +1
//if ( (myIM.matches("FF*FF****") == false) &&
(myIM.matches("F***0****") == false)){
if (myIM.matches("FF*FF****") == false){
/********** rings intersect
* here displacement vector is calculated for centroid
****************************/
this.hasConflict = true;
this.linesCross = true;
}
//else{
this.bufferGeom = p1.buffer(this.threshold);
if (bufferGeom.disjoint(p2) == false){
// false disjoint = intersects
this.hasConflict = true;
this.areToClose = true;
}
//}
}
/**
* calculate the displacement vectors for the specific
* conflict case
* a) overlapping polygons: dispVectorPolyIntersection for
* intersecting/overlapping polygons for application on
* the centroid of p1.
* b) polygon 2 is within the minimum distance: Displacement
* vectors on the specific vertex, which are to narrow.
* given back via dispVecPointEdgeLStringList and
* dispVecPointPointLStringList and further a mean disp. vector
* is calculated for the centroid of p1 (given back via
* dispVectorPolyIntersection).
*/
public void calcDisplacementVectors(){
//-- init disp matrix for snakes displacement
// should be set even if no conflicts appear
// to avaoid error messages
int nrPtBaseRing = p1.getExteriorRing().getNumPoints();
int nrPtTestRing = p2.getExteriorRing().getNumPoints();
this.dxConflictMatrix = MatlabSyntax.zeros(nrPtBaseRing,nrPtTestRing);
this.dyConflictMatrix = MatlabSyntax.zeros(nrPtBaseRing,nrPtTestRing);
if (this.commonEdge == true){
// don't do something .. but you can merge the polys
}
else if(this.linesCross == true){
this.calcDispVectorForIntersection((Polygon)p1.clone(),(Polygon)p2.clone());
}
else if(this.areToClose == true){
//-- if polygons are disjoint but within the buffer (treshold)
// test cross wise (point to edge)
this.testWithOtherRings(p1.getExteriorRing(),
p2.getExteriorRing(),1);
this.testWithOtherRings(p2.getExteriorRing(),
p1.getExteriorRing(),2);
//-- TODO: eventually use calcDispVectorForIntersection# with
// one buffererd polygon to make results better
this.calcMeanDisplacement();
}
};
/**
* If polygons are disjoint:
* Test distance of points from one Linestring to edges of another
LineString
* @param baseRing
* @param testRing
* @param orignalPolygon which of them is the base polygon
* need to change direction of displacement vector
*/
private void testWithOtherRings(LineString baseRing,
LineString
testRing,
int
originalPolygon){
/*********** if rings are seperated **************/
GeometryFactory myGF = new GeometryFactory();
LineString tempLine = null;
double dist = 0;
// ==== loop for over all points from Ring =====
// -1; otherwise last point will be tested twice
for (int i = 0; i < baseRing.getNumPoints()-1 ; i++) {
Point myPoint = baseRing.getPointN(i);
// -1; since edge(j,j+1)
for (int j = 0; j < testRing.getNumPoints()-1; j++){
//reduce calculations concerning adjacent edges
Coordinate A = testRing.getCoordinateN(j);
Coordinate B = testRing.getCoordinateN(j+1);
Coordinate P = myPoint.getCoordinate();
PointLineDistance pld = new PointLineDistance(P,A,B);
dist = pld.getDistance();
boolean isPerpendicularPoint = pld.isPointOnLine();
Coordinate rp = pld.getClosestPoint().getCoordinate();
//-- calc displacementVector
if (dist < this.getThreshold()){
//========== calc disp vector and save as
linestring =======
double xNew=0, yNew=0, dxMove=0, dyMove=0;
// dist > 10cm .. since numerical problems lead to
distance like 3.1*10^-14
if(dist > this.crucialDistance){
double dxAct,dyAct, dxRef, dyRef;
dxAct = P.x - rp.x;
dyAct = P.y - rp.y;
dxRef = dxAct * this.threshold / dist;
dyRef = dyAct * this.threshold / dist;
dxMove = dxRef - dxAct;
dyMove = dyRef - dyAct;
xNew = myPoint.getX() + dxMove;
yNew = myPoint.getY() + dyMove;
}
else{
//-- if dist = 0, then calc disp vector towards
poly centroid
Point centroid = this.p1.getCentroid();
double angle =
SecondGeodeticTask2d.calcAngle2Points(myPoint,centroid);
Point newPoint =
FirstGeodeticTask2d.getPoint(myPoint,angle,this.getThreshold());
xNew = newPoint.getX();
yNew = newPoint.getY();
dxMove = newPoint.getX() - myPoint.getX();
dyMove = newPoint.getY() - myPoint.getY();
}
Coordinate[] dispVectorCoord = new Coordinate[2];
dispVectorCoord[0] = myPoint.getCoordinate();
dispVectorCoord[1] = new Coordinate(xNew, yNew);
LineString dispVector =
myGF.createLineString(dispVectorCoord);
//======== save ===========
Double Ddist = new Double(dist);
//this.minWidthDoubleList.add(Ddist);
// displacement for point into right direction
dxMove = -1*dxMove;
dyMove = -1*dyMove;
// if not using object.clone the list links point
on the
// the last checked point and checked edge
//this.minEdgeLineStringList.add(tempLine.clone());
//this.minVertexPointList.add(myPoint.clone());
// ===== save to conflict list ======/
MinWidthConflict mwc = new MinWidthConflict();
if(originalPolygon == 1){
mwc.ptHoleIdx = 0;
mwc.edgeHoleIdx = 1;
}
else{
mwc.ptHoleIdx = 1;
mwc.edgeHoleIdx = 0;
}
mwc.ptIdx = i;
mwc.edgeStartPtIdx = j;
mwc.edgeEndPtIdx = j+1;
mwc.distance = dist;
mwc.ptDispDx = dxMove;
mwc.ptDispDy = dyMove;
mwc.ptEdgeConflict = isPerpendicularPoint;
mwclist.add(mwc);
//====================
if(isPerpendicularPoint){ //pt-edge conflict
if(originalPolygon == 1){
// conflict detected by base line
this.dispVecPtEgLSthisPolyList.add(dispVector.clone());
dxConflictMatrix.set(i,j,dxMove);
dyConflictMatrix.set(i,j,dyMove);
}
else{
// displacement for point into right
direction
// turned back since detected by other line
dxMove = -1*dxMove;
dyMove = -1*dyMove;
// if conflict was detected by other line
// the displacement has to be applied to
the edge
// and not to a single point
this.dispVecPtEgLSOtherPolyList.add(dispVector.clone());
// look if conflict is already saved
double oldValuedx1 =
dxConflictMatrix.get(j,i);
double oldValuedy1 =
dyConflictMatrix.get(j,i);
double oldValuedx2 =
dxConflictMatrix.get(j+1,i);
double oldValuedy2 =
dyConflictMatrix.get(j+1,i);
//- save for first edge point
if ((oldValuedx1 != 0) || (oldValuedy1 !=
0)){
double dx = (dxMove + oldValuedx1)/2.0;
double dy = (dyMove + oldValuedy1)/2.0;
dxConflictMatrix.set(j,i,dx);
dyConflictMatrix.set(j,i,dy);
}
else{// no previous values saved on this
position
dxConflictMatrix.set(j,i,dxMove);
dyConflictMatrix.set(j,i,dyMove);
}
//- save for second edge point
if ((oldValuedx2 != 0) || (oldValuedy2 !=
0)){
double dx = (dxMove + oldValuedx2)/2.0;
double dy = (dyMove + oldValuedy2)/2.0;
dxConflictMatrix.set(j,i,dx);
dyConflictMatrix.set(j,i,dy);
}
else{// no previous values saved on this
position
dxConflictMatrix.set(j+1,i,dxMove);
dyConflictMatrix.set(j+1,i,dyMove);
}
}
}
else{//pt-pt conflict
if(originalPolygon == 1){
this.dispVecPtPtLSthisPolyList.add(dispVector.clone());
dxConflictMatrix.set(i,j,dxMove);
dyConflictMatrix.set(i,j,dyMove);
}
else{
this.dispVecPtPtLSOtherPolyList.add(dispVector.clone());
// displacement for point into right
direction
// turned back since detected by other line
dxMove = -1*dxMove;
dyMove = -1*dyMove;
double oldValuedx1 =
dxConflictMatrix.get(j,i);
double oldValuedy1 =
dyConflictMatrix.get(j,i);
double oldValuedx2 =
dxConflictMatrix.get(j+1,i);
double oldValuedy2 =
dyConflictMatrix.get(j+1,i);
//- save for first edge point
if ((oldValuedx1 != 0) || (oldValuedy1 !=
0)){
double dx = (dxMove + oldValuedx1)/2.0;
double dy = (dyMove + oldValuedy1)/2.0;
dxConflictMatrix.set(j,i,dx);
dyConflictMatrix.set(j,i,dy);
}
else{// no previous values saved on this
position
dxConflictMatrix.set(j,i,dxMove);
dyConflictMatrix.set(j,i,dyMove);
}
//- save for second edge point
if ((oldValuedx2 != 0) || (oldValuedy2 !=
0)){
double dx = (dxMove + oldValuedx2)/2.0;
double dy = (dyMove + oldValuedy2)/2.0;
dxConflictMatrix.set(j,i,dx);
dyConflictMatrix.set(j,i,dy);
}
else{// no previous values saved on this
position
dxConflictMatrix.set(j+1,i,dxMove);
dyConflictMatrix.set(j+1,i,dyMove);
}
}
}
} // end if
} // end for edges
} // end for test point
}
private void calcMeanDisplacement(){
// uses point-edge conlficts only
int total=0;
double sumdx=0, sumdy=0;
double angle, distance, deast, dnorth;
for(int i = 0; i < this.dispVecPtEgLSthisPolyList.size(); i++){
LineString myDispV =
(LineString)this.dispVecPtEgLSthisPolyList.get(i);
angle =
SecondGeodeticTask2d.calcAngle2Points(myDispV.getStartPoint(),
myDispV.getEndPoint());
distance = myDispV.getLength();
deast = distance * Math.cos(angle);
dnorth = distance * Math.sin(angle);
sumdx = sumdx + deast;
sumdy = sumdy + dnorth;
total= total +1;
}
for(int i = 0; i < this.dispVecPtEgLSOtherPolyList.size(); i++){
LineString myDispV =
(LineString)this.dispVecPtEgLSOtherPolyList.get(i);
angle =
SecondGeodeticTask2d.calcAngle2Points(myDispV.getStartPoint(),
myDispV.getEndPoint());
// turn displacement direction if conflict was reported from
// other polygon than from base poly
angle = angle+ Math.PI;
distance = myDispV.getLength();
deast = distance * Math.cos(angle);
dnorth = distance * Math.sin(angle);
sumdx = sumdx + deast;
sumdy = sumdy + dnorth;
total= total +1;
}
/*** this is evantuall not wished -
* polygon contacts should be kept
* but not using point-point conflicts may lead to non displacement
*/
// also use point-poin conflicts for case of the identic points
for(int i = 0; i < this.dispVecPtPtLSthisPolyList.size(); i++){
LineString myDispV =
(LineString)this.dispVecPtPtLSthisPolyList.get(i);
angle =
SecondGeodeticTask2d.calcAngle2Points(myDispV.getStartPoint(),
myDispV.getEndPoint());
// turn displacement direction if conflict was reported from
// other polygon than from base poly
angle = angle+ Math.PI;
distance = myDispV.getLength();
deast = distance * Math.cos(angle);
dnorth = distance * Math.sin(angle);
sumdx = sumdx + deast;
sumdy = sumdy + dnorth;
total= total +1;
}
//****/
if(total== 0){total=1;} //to avoid division by zero
double dx = sumdx/(double)total;
double dy = sumdy/(double)total;
//-- get dispComponents
this.dispVectorComponents[0]=dx;
this.dispVectorComponents[1]=dy;
Point centerp1 = p1.getCentroid();
Coordinate[] coord = new Coordinate[]{
new Coordinate(centerp1.getX(), centerp1.getY()),
new Coordinate(centerp1.getX()+dx, centerp1.getY()+dy)
};
GeometryFactory myGF = new GeometryFactory();
this.dispVectorPolyIntersection = myGF.createLineString(coord);
}
private void calcDispVectorForIntersection(Polygon p1, Polygon p2){
//-- calc the intersection geomtery
Geometry intersection = p1.intersection(p2);
//-- get Centroids of p1 and p2
JtsCentroid c1 = new JtsCentroid(p1);
Point center1 = c1.getGravityCentroid();
this.geometryList.add(center1.clone());
JtsCentroid c2 = new JtsCentroid(p2);
Point center2 = c2.getGravityCentroid();
this.geometryList.add(center2.clone());
//-- get Vector as LineString
GeometryFactory myGF = new GeometryFactory();
Coordinate[] vectorCoord = new Coordinate[2];
vectorCoord[0] = center1.getCoordinate();
vectorCoord[1] = center2.getCoordinate();
LineString centroidVector = myGF.createLineString(vectorCoord);
this.geometryList.add(centroidVector.clone());
//-- get horizintal angle of vector between the centroids
// from other poly to actual poly
// to get the direction for translation vector
double angle = SecondGeodeticTask2d.calcAngle2Points(center1,
center2);
//-- rotate intersection geometry by (negative) angle
JtsCentroid c3 = new JtsCentroid(intersection);
Point intersectionCentroid = c3.getGravityCentroid();
this.geometryList.add(intersectionCentroid.clone());
Geometry rotGeometry =
Rotate.rotate(intersectionCentroid,-1*angle,(Polygon)intersection);
this.geometryList.add(rotGeometry.clone());
//-- calculate Bounding Rectangle
Geometry envelope = rotGeometry.getEnvelope();
this.geometryList.add(envelope.clone());
//-- rotate envelope back
Geometry newEnvelope =
Rotate.rotate(intersectionCentroid,angle,(Polygon)envelope);
this.geometryList.add(newEnvelope.clone());
//-- intersect centroidvector with Envelope
double distToMove = 0;
Geometry intersectVector =
newEnvelope.intersection(centroidVector);
try{
LineString distvector = (LineString)intersectVector;
this.geometryList.add(distvector.clone());
distToMove = distvector.getLength() + this.threshold;
}
catch(Exception e){
System.out.println("PolygonDistance.calcDispVectorForIntersection: error in
calculation of intersection vector, length set to zero");
}
//-- get Point to displace to
Point toPoint = FirstGeodeticTask2d.getPoint(center1, angle +
Math.PI, distToMove);
this.geometryList.add(toPoint.clone());
//-- get dispComponents
double dx = toPoint.getX()-center1.getX();
double dy = toPoint.getY()-center1.getY();
this.dispVectorComponents[0]=dx;
this.dispVectorComponents[1]=dy;
//-- get disp vector as LineString
Coordinate[] dispVectorCoord = new Coordinate[2];
dispVectorCoord[0] = center1.getCoordinate();
dispVectorCoord[1] = toPoint.getCoordinate();
LineString dispVector = myGF.createLineString(dispVectorCoord);
this.geometryList.add(dispVector.clone());
//-- set return values
this.dispVectorPolyIntersection = dispVector;
this.polygonIntersection = intersection;
this.angle = angle*180/Math.PI;
this.shortestDistance = -1*distToMove;
}
/******************** getters and setter **********************/
public double getThreshold() {
return threshold;
}
/**
* @return list with displacement vectors among
* point and edge node for Base-Polygon
* saved as LineString
*/
public List getDispVecListPtPtLSThisPoly() {
return dispVecPtPtLSthisPolyList;
}
/**
* @return list with displacement vectors among
* point and perpendicular point on edge
* for Base-Polygon
* saved as LineString
*/
public List getDispVecListPtEgLSThisPoly() {
return dispVecPtEgLSthisPolyList;
}
/**
* @return list with displacement vectors among
* point and edge node for other Polygon
* saved as LineString
*/
public List getDispVecListPtPtLSOtherPoly() {
return this.dispVecPtPtLSOtherPolyList;
}
/**
* @return list with displacement vectors among
* point and perpendicular point on edge
* for other Polygon
* saved as LineString
*/
public List getDispVecListPtEgLSOtherPoly() {
return this.dispVecPtEgLSOtherPolyList;
}
/**
*
* @return widths/distances under threshold as double array
*/
/**
public double[] getMininmalDistances(){
double[] width = new double[this.minWidthDoubleList.size()];
int i=0;
Double value;
for (Iterator iter = minWidthDoubleList.iterator(); iter.hasNext();) {
value = (Double) iter.next();
width[i] = value.doubleValue();
i = i+1;
}
return width;
}
**/
/**
*
* @return the shortest distance between two objects
* measured from the polygon outlines (not the centroids);
* returns -1 if distance > 999999.99m
*/
public double getShortestDistance(){
if (this.shortestDistance == 999999.99){this.shortestDistance=-1;}
return this.shortestDistance;
}
/**
* Do geometries cross each other?
* one might be inside an other one,
* @return true for line cross
*/
public boolean haveLinesCross() {
return linesCross;
}
/**
* get Displacementvector for first polygon
* (on centroid) if polygons do intersect
* Use calcDisplacementVectors# first before using this method
* to obtain the displacement components.
* @return LineString (second point is toPoint)
*/
public LineString getDispVectorPolyIntersection() {
return dispVectorPolyIntersection;
}
/**
*
* @return true if a conflict between the polygons exits, means
* if to narrow or overlap. Attention: but is false if polygons
* have a common edge
*/
public boolean haveConflict() {
return hasConflict;
}
public Geometry getPolygonIntersection() {
return polygonIntersection;
}
/**
* only usefull for intersecting polygons
* @return (angle in rad) of the connection vector
* between the both polygon centroid
*/
public double getAngle() {
return angle;
}
/**
*
* @return the geometry of the buffered first polygon
* which characterizes the minimum distance to stay away
* from each other
*/
public Geometry getBufferGeom() {
return bufferGeom;
}
/**
*
* @return true if polygons have a common edge.
* This might be important if objects should be
* aggregated instead displaced
*/
public boolean haveCommonEdge() {
return commonEdge;
}
/**
*
* @return true if poly 2 is within buffer distance of poly1
*/
public boolean haveToShortDistance() {
return this.areToClose;
}
/**
* @return a Matrix containing the
* displacement vector element dx
*/
public Matrix getDxConflictMatrix() {
return this.dxConflictMatrix;
}
/**
* @return a Matrix containing the
* displacement vector element dy
*/
public Matrix getDyConflictMatrix() {
return this.dyConflictMatrix;
}
/**
*
* @param crucialDistance distance thereshold in metres there
* it is complicate to give a corrct displacement direction.
*/
public double getCrucialDistance() {
return crucialDistance;
}
/**
*
* @param crucialDistance distance thereshold in metres there
* it is complicate to give a corrct displacement direction.
*
*/
public void setCrucialDistance(double crucialDistance) {
this.crucialDistance = crucialDistance;
}
/**
*
* @return a special List type of the conflicts as
* MinWidthConflict type
*/
public MWConflictList getMwclist() {
return mwclist;
}
/**
* Use calcDisplacementVectors# first before using this method
* to obtain the displacement components.
* @return necessary [dx,dy] translations for centroid
* of first polygon to solve conflict.
*/
public double[] getDispVectorComponents() {
return dispVectorComponents;
}
}
_______________________________________________
jts-devel mailing list
[email protected]
http://lists.refractions.net/mailman/listinfo/jts-devel