📄 geopolygon.java
字号:
{
reply.addElement(new GeoPoint(xpoints[i],ypoints[i]));
}
return reply;
}
}
public boolean equals(Object o){
if(! (o instanceof GeoPolygon)){return false;}
GeoPolygon b = (GeoPolygon)o;
if(b.getID()!=this.getID()){return false;}
return equalsIgnoreID(b);
}
public boolean equalsIgnoreID(GeoPolygon b){
int iCount = 0;
Object gpp1,gpp2;
Vector vP1,vP2;
vP1 = this.getPoints();
vP2 = b.getPoints();
if(vP1.size()!=vP2.size()){
return false;
}
for(int i=0;i<vP1.size();i++){
gpp1 = vP1.elementAt(i);
for(int j=0;j<vP2.size();j++){
gpp2 = vP2.elementAt(j);
if(gpp1.equals(gpp2)){
iCount++;
break;
}
}
}
if(iCount == vP1.size()){
return true;
}
return false;
}
/**
* Tests to see if the polygon is Clockwise<br>
* anti-clockwise polygons often represent holes<br>
* this is computed on the fly so might be expensive.<br>
* Addapted from C function writen by Paul Bourke.
* @return boolean true if polygon is clockwise.
*/
public boolean isClockwise(){
if (npoints < 3) return false;
int j,k,count=0;
double z;
for (int i=0;i<npoints;i++){
j = (i + 1) % npoints;
k = (i + 2) % npoints;
z = (ypoints[j] - xpoints[i]) * (ypoints[k] - ypoints[j]);
z -= (ypoints[j] - ypoints[i]) * (xpoints[k] - xpoints[j]);
if (z < 0)
count--;
else if (z > 0)
count++;
}
if (count > 0) return false;
else if (count < 0) return true;
else return false;//coliniar points?
}
/**
* Calculates the area of the polygon
* the result is stored in the private member variable area<br>
* Must be called during construction and after any changes to the polygons point set.
* N.B. Polygons with anti-clockwise point storage will result in a negative area
* @author James Macgill
* @since 0.7.7.1 08/May/00
*/
private void calculateArea(){
//move polygon to origin to remove negative y values and reduce coordinate sizes
GeoRectangle box = getBounds();
double xShift = 0-box.x;
double yShift = 0-box.y;
double area;
double total =0;
//Calculate area of each tapezoid formed by droping lines from each pair of point to the x-axis.
//x[i]<x[i-1] will contribute a negative area
for(int i=0;i<npoints-1;i++){
area = ((xpoints[i+1]+xShift)-(xpoints[i]+xShift))*(((ypoints[i+1]+yShift)+(ypoints[i]+yShift))/2d);
total+=area;
}
this.area = total;
//System.out.println("Area calculated");
areaDone=true;
}
/**
* Calculates a waighted centroid location for this polygon.<br>
* the result is stored in the private member variables xcent and ycent
* overwriting any values that may already be stored their.<br>
* area must be set before calling this method, e.g. a call to calculateArea should have been made
* during construction.<br>
* Polygons must have clockwise point encoding in order to have a centroid, holes (encoded
* with anti-clockwise points) have undefined behavior at this point.
* N.B. the centroid will be the 'center of mass' but this is not guaranteed to be inside the
* polygon.
* @author James Macgill JM
* @since 0.7.7.1 08/May/2000
* @see #calculateArea
*/
protected void calculateCentroidLocation(){
GeoRectangle box = getBounds();
double xShift = 0-box.x;
double yShift = 0-box.y;
if(!areaDone)calculateArea();
if(area == 0){
//test and approx fix for polygons that are effectively lines or points.
xcent = (box.x+(box.width/2d));
ycent = (box.y+(box.height/2d));
}
else
{
double total =0;
double x=0,y=0,x1,x2,y1,y2;
for(int i=0;i<npoints-1;i++){
x1 = xpoints[i]+xShift;
x2 = xpoints[i+1]+xShift;
y1 = ypoints[i]+yShift;
y2 = ypoints[i+1]+yShift;
x+= ((y1-y2)*(Math.pow(x1,2)+(x1*x2)+Math.pow(x2,2))/(6*area));
y+= ((x2-x1)*(Math.pow(y1,2)+(y1*y2)+Math.pow(y2,2))/(6*area));
}
xcent = x-xShift;
ycent = y-yShift;
}
}
/**
* Will test the given polygon to see if it is adjacent to this polygon.
* <br>This code is somewhat experimental and has not been fully tested.
* @param gp The GeoPolygon to test for contiguity
* @return boolean, true if this polygon and gp share two or more verteces that are consecetive in both polygons
*/
public boolean isContiguous(GeoPolygon gp){
GeoRectangle bBox = getBounds();
GeoRectangle safe = new GeoRectangle(bBox.x-1,bBox.y-1,bBox.width+2,bBox.height+2);
if(!gp.getBounds().intersects(safe))return false;
Vector a = getPoints();
Vector b = gp.getPoints();
int aLast = a.size()-2; // one for 0 counting one for duplicate final point.
int bLast = b.size()-2;
for(int i=0;i<=aLast;i++){
if(b.contains(a.elementAt(i))){
int indexB = b.indexOf(a.elementAt(i));
int nextA = (i+1)%(a.size()-1);
if(b.contains(a.elementAt(nextA))){
int nextB = b.indexOf(a.elementAt(nextA));
if((indexB == 0 && nextB == bLast) || (indexB == bLast && nextB==0)) return true;//wrap round end.
if(Math.abs(indexB-nextB)==1)return true;//no break in chain
//keep trying.
}
}
}
if(subParts!=null){
for(int i=0;i<subParts.size();i++){
if(((GeoPolygon)subParts.elementAt(i)).isContiguous(gp))return true;
}
}
return false;
}
/**
* Calculates the length of all arcs that are common both to this polygon and to the polygon pased in.
* @param gp The polygon to measure shared lengths with
* <br>This code is somewhat experimental and has not been fully tested.
* @return double the total length of all shared arcs between the two polygons, returns as 0 if there are no shared arcs/
*/
public double getContiguousLength(GeoPolygon gp){
double dist = 0;
//int start = 0;
Vector a = getPoints();
Vector b = gp.getPoints();
int last = a.size()-1;//0 count
GeoPoint start = (GeoPoint)a.elementAt(0);
GeoPoint end;
for(int i=0;i<last;i++){
end = (GeoPoint)a.elementAt((i+1)%last);
if(gp.areConsecutive(start,end)){
dist+=Math.sqrt((start.x-end.x)*(start.x-end.x)+(start.y-end.y)*(start.y-end.y));
}
start = end;
}
if(subParts!=null){
for(int i=0;i<subParts.size();i++){
dist+=(((GeoPolygon)subParts.elementAt(i)).getContiguousLength(gp));
}
}
return dist;
}
/**
* Tests the two provied points to see if they apeare next to each other in any of this
* polygons arcs. The test is regardless of order.
*
* <br>This code is somewhat experimental and has not been fully tested.
* @param p1 the first point to test
* @param p2 the second point to test
* @return boolean true if p1 follows p2 or p2 follows p1, false in any other case, including p1 and/or p2 being absent from the polygon
*
*/
public final boolean areConsecutive(GeoPoint p1,GeoPoint p2){
int i1 = storedPoints.indexOf(p1);
if(i1== -1) return false;
int i2 = storedPoints.indexOf(p2);
if( i2 == -1)return false;
if(Math.abs(i2-i1)==1){return true;}
if(i1 == storedPoints.size()-2 && i2 ==0) return true;
if(i2 == storedPoints.size()-2 && i1 ==0) return true;
if(subParts!=null){
for(int i=0;i<subParts.size();i++){
if(((GeoPolygon)subParts.elementAt(i)).areConsecutive(p1,p1))return true;
}
}
return false;
}
/**
* Provides a list of all of the polygons from the provided list that are adjacent to this one
*
* <br>This code is somewhat experimental and has not been fully tested.
* @param polys a Vector of GeoPolgyons to test against for contiguity.
* @return Vector a sub set of polys that contains only the polygons that are adjacent to this one.
*/
public Vector getContiguityList(Vector polys){
//build contiguity list
Vector list = new Vector();
for(int i=0;i<polys.size();i++){
if(this.isContiguous((GeoPolygon)polys.elementAt(i))){
list.addElement(polys.elementAt(i));
}
}
list.removeElement(this);
if(subParts!=null){
Vector subList;
for(int i=0;i<subParts.size();i++){
subList = (((GeoPolygon)subParts.elementAt(i)).getContiguityList(polys));
subList.removeElement(this);
for(int j=0;j<subList.size();j++){
if(!list.contains(subList.elementAt(j))){list.addElement(subList.elementAt(j));}
}
if(DEBUG)System.out.println("Fixed multipart contiguity by adding "+subList.size());
}
}
return list;
}
/**
* Given the line described by the two points, this method tests to see if it is internal or external with regards to the set
* of polygons listed in the vector.
* <br>p1 and p2 SHOULD be points that are in this polygon.
* <br>This code is somewhat experimental and has not been fully tested.
* @param p1 GeoPoint the first endpoint of the line to test
* @param p2 GeoPoint the second endpoint of the line to test
* @param polys A Vector of polygons to test the line agains for inside/outside ness.
*/
public boolean isOnOutside(GeoPoint p1,GeoPoint p2,Vector polys){
boolean outside = true;
for(int j=0;j<polys.size();j++){
GeoPolygon testPolygon = ((GeoPolygon)polys.elementAt(j));
if(testPolygon == this){continue;}
if(testPolygon.areConsecutive(p1,p2)){
outside = false;
j=polys.size();
}
}
return outside;
}
/**
* Tests this polygon to see if contains at least one edge that is on the outside of the set of polygons
* described in the provided set.
*
* <br>This code is somewhat experimental and has not been fully tested.
* @param polys A Vector of polygons to test against
* @param boolean true if any edge of this polygon is not contiguous with any of the polgyons listed in polys
*/
public boolean isOnOutside(Vector polys){
Vector points = getPoints();
boolean done = false;
for(int i=0;i<points.size()-1 ;i++){
GeoPoint p1 = (GeoPoint)points.elementAt(i);
GeoPoint p2 = (GeoPoint)points.elementAt(i+1);
if(isOnOutside(p1,p2,polys)){return true;}
}
return false;
}
public static GeoPolygon dissolve(Vector polys){
return dissolve(0,polys);
}
/**
* A static method that will disolve all internal borders within the provided set to create a single polygon
* which describes the outline of all the given polygons combined.
*
* <br>This code is somewhat experimental and has not been fully tested.
* in particular, if the polygons do not define a single clump then it will not work as expected.
* @param polys A Vector of GeoPolgyons to disolve.
* @param an id for this new polygon.
* @return GeoPolygon the disolved version of the polys set.
*/
public static GeoPolygon dissolve(int id,Vector polys){
Vector outList = (Vector)polys.clone();
Vector holes = new Vector();Vector fills = new Vector();
int count = outList.size();
GeoPolygon multiPartTest;
for(int i=0;i<count;i++){
if(DEBUG)System.out.println("Element "+i+" of "+count);
//multiPartTest = (GeoPolygon)outList.elementAt(i);
multiPartTest = (GeoPolygon)polys.elementAt(i);
if(multiPartTest.isMultiPart() && 2==3){
if(DEBUG)System.out.println("Scary dissolve involving a multipart polygon!");
for(int j=1;j<=multiPartTest.getNumParts()-1;j++){
if(DEBUG)System.out.println("Area of part"+((GeoPolygon)multiPartTest.getPart(j)).getArea());
if(((GeoPolygon)multiPartTest.getPart(j)).getArea()>=0){
if(multiPartTest.getPart(j).getPoints().size()<3)
{
if(DEBUG)System.err.println("Multipart polygon only had 2 points.");
}
outList.addElement(multiPartTest.getPart(j));
}
else{
if(DEBUG)System.out.println("Hole");
/* TODO JM: sort out holes properly by implementing cases 2 and 3, although a change in the represenation of
* polygon toplogy may come first.
* this part represents a hole.
* There are three states that this hole could be in for this zone.
* 1) Empty, with no polygons at all inside it.
* 2) Filled, with polygons that belong to this zone.
* 3) Semi-filled, with some or all of the polygons inside it not belonging to this zone.
* 3 is a hard case that will need to be planed out carefully and proably requires
* more constructive geometry methods than exist at the moment
*/
//Is the hole empty?
GeoPolygon hole = (GeoPolygon)multiPartTest.getPart(j);
Vector fillers = hole.getContiguityList(polys);
if(fillers.size()==0){
//case 1 from above.
//hole is only contiguous with the polygon to which it is a hole
//therefore keep it!
holes.addElement(hole);
}
else{
//case 2 or 3 from above.
//There is something attached to this hole, other than the polygon to which it is attached.
//for now we will assume a simple case 2 by removing all polygons attached to this hole
//this is the danger that a polygon will be attached to a polygon that is attached to this hole.
//TODO JM: implement case 2 properly and sort out case 3
holes.addElement(hole);
for(int k =0;k<fillers.size();k++){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -