/*
 * This license does NOT supersede the original license of GPC.  Please see:
 * http://www.cs.man.ac.uk/~toby/alan/software/#Licensing
 *
 * The SEI Software Open Source License, Version 1.0
 *
 * Copyright (c) 2004, Solution Engineering, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer. 
 *
 * 2. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Solution Engineering, Inc. (http://www.seisw.com/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 3. The name "Solution Engineering" must not be used to endorse or
 *    promote products derived from this software without prior
 *    written permission. For written permission, please contact
 *    admin@seisw.com.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL SOLUTION ENGINEERING, INC. OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 */

package com.seisw.util.geom;

import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;

/**
 * PolyDefault is a default Poly implementation.  
 * It provides support for both complex and simple polygons.  A complex polygon 
 * is a polygon that consists of more than one polygon.  A simple polygon is a 
 * more traditional polygon that contains of one inner polygon and is just a 
 * collection of points.
 * 

* Implementation Note: If a point is added to an empty PolyDefault * object, it will create an inner polygon of type PolySimple. * * @see PolySimple * * @author Dan Bridenbecker, Solution Engineering, Inc. */ public class PolyDefault implements Poly { // ----------------- // --- Constants --- // ----------------- // ------------------------ // --- Member Variables --- // ------------------------ /** * Only applies to the first poly and can only be used with a poly that contains one poly */ private boolean m_IsHole = false ; protected List m_List = new ArrayList(); // -------------------- // --- Constructors --- // -------------------- /** Creates a new instance of PolyDefault */ public PolyDefault() { this( false ); } public PolyDefault( boolean isHole ) { m_IsHole = isHole ; } public PolyDefault(Rectangle rect) { add(rect.x, rect.y); add(rect.x + rect.width, rect.y); add(rect.x + rect.width, rect.y + rect.height); add(rect.x, rect.y + rect.height); } // ---------------------- // --- Object Methods --- // ---------------------- /** * Return true if the given object is equal to this one. */ public boolean equals( Object obj ) { if( !(obj instanceof PolyDefault) ) { return false; } PolyDefault that = (PolyDefault)obj; if( this.m_IsHole != that.m_IsHole ) return false ; if( !this.m_List.equals( that.m_List ) ) return false ; return true ; } /** * Return the hashCode of the object. * * @return an integer value that is the same for two objects * whenever their internal representation is the same (equals() is true) **/ public int hashCode() { int result = 17 ; result = 37*result + m_List.hashCode(); return result; } /** * */ public String toString() { return super.toString(); } // ---------------------- // --- Public Methods --- // ---------------------- /** * Remove all of the points. Creates an empty polygon. */ public void clear() { m_List.clear(); } /** * Add a point to the first inner polygon. *

* Implementation Note: If a point is added to an empty PolyDefault object, * it will create an inner polygon of type PolySimple. */ public void add(double x, double y) { add( new Point2D.Double( x, y ) ); } /** * Add a point to the first inner polygon. *

* Implementation Note: If a point is added to an empty PolyDefault object, * it will create an inner polygon of type PolySimple. */ public void add( Point2D p ) { if( m_List.size() == 0 ) { m_List.add( new PolySimple() ); } ((Poly)m_List.get(0)).add( p ); } /** * Add an inner polygon to this polygon - assumes that adding polygon does not * have any inner polygons. * * @throws IllegalStateException if the number of inner polygons is greater than * zero and this polygon was designated a hole. This would break the assumption * that only simple polygons can be holes. */ public void add( Poly p ) { if( (m_List.size() > 0) && m_IsHole ) { throw new IllegalStateException("Cannot add polys to something designated as a hole."); } m_List.add( p ); } /** * Return true if the polygon is empty */ public boolean isEmpty() { return m_List.isEmpty(); } /** * Returns the bounding rectangle of this polygon. * WARNING Not supported on complex polygons. */ public Rectangle2D getBounds() { if( m_List.size() == 0 ) { return new Rectangle2D.Double(); } else if( m_List.size() == 1 ) { Poly ip = getInnerPoly(0); return ip.getBounds(); } else { throw new UnsupportedOperationException("getBounds not supported on complex poly."); } } /** * Returns the polygon at this index. */ public Poly getInnerPoly(int polyIndex) { return (Poly)m_List.get(polyIndex); } /** * Returns the number of inner polygons - inner polygons are assumed to return one here. */ public int getNumInnerPoly() { return m_List.size(); } /** * Return the number points of the first inner polygon */ public int getNumPoints() { return ((Poly)m_List.get(0)).getNumPoints() ; } /** * Return the X value of the point at the index in the first inner polygon */ public double getX(int index) { return ((Poly)m_List.get(0)).getX(index) ; } /** * Return the Y value of the point at the index in the first inner polygon */ public double getY(int index) { return ((Poly)m_List.get(0)).getY(index) ; } /** * Return true if this polygon is a hole. Holes are assumed to be inner polygons of * a more complex polygon. * * @throws IllegalStateException if called on a complex polygon. */ public boolean isHole() { if( m_List.size() > 1 ) { throw new IllegalStateException( "Cannot call on a poly made up of more than one poly." ); } return m_IsHole ; } /** * Set whether or not this polygon is a hole. Cannot be called on a complex polygon. * * @throws IllegalStateException if called on a complex polygon. */ public void setIsHole( boolean isHole ) { if( m_List.size() > 1 ) { throw new IllegalStateException( "Cannot call on a poly made up of more than one poly." ); } m_IsHole = isHole ; } /** * Return true if the given inner polygon is contributing to the set operation. * This method should NOT be used outside the Clip algorithm. */ public boolean isContributing( int polyIndex) { return ((Poly)m_List.get(polyIndex)).isContributing(0); } /** * Set whether or not this inner polygon is constributing to the set operation. * This method should NOT be used outside the Clip algorithm. * * @throws IllegalStateException if called on a complex polygon */ public void setContributing( int polyIndex, boolean contributes) { if( m_List.size() != 1 ) { throw new IllegalStateException( "Only applies to polys of size 1" ); } ((Poly)m_List.get(polyIndex)).setContributing( 0, contributes ); } /** * Return a Poly that is the intersection of this polygon with the given polygon. * The returned polygon could be complex. * * @return the returned Poly will be an instance of PolyDefault. */ public Poly intersection(Poly p) { return Clip.intersection( p, this, this.getClass() ); } /** * Subtracts Poly p and returns a new Poly. * @param p The Poly to subtract. * @return The difference of this and p. */ public Poly subtract(Poly p) { return Clip.diff(this, p); } /** * Return a Poly that is the union of this polygon with the given polygon. * The returned polygon could be complex. * * @return the returned Poly will be an instance of PolyDefault. */ public Poly union(Poly p) { return Clip.union( p, this, this.getClass() ); } /** * Return a Poly that is the exclusive-or of this polygon with the given polygon. * The returned polygon could be complex. * * @return the returned Poly will be an instance of PolyDefault. */ public Poly xor(Poly p) { return Clip.xor( p, this, this.getClass() ); } /** * Return the area of the polygon in square units. */ public double getArea() { double area = 0.0 ; for( int i = 0 ; i < getNumInnerPoly() ; i++ ) { Poly p = getInnerPoly(i); double tarea = p.getArea() * (p.isHole() ? -1.0 : 1.0); area += tarea ; } return area ; } // ----------------------- // --- Package Methods --- // ----------------------- void print() { for( int i = 0 ; i < m_List.size() ; i++ ) { Poly p = getInnerPoly(i); System.out.println("InnerPoly("+i+").hole="+p.isHole()); for( int j = 0 ; j < p.getNumPoints() ; j++ ) { System.out.println(p.getX(j)+" "+p.getY(j)); } } } public Polygon getPolygon() { Polygon jp = new Polygon(); for( int i = 0 ; i < getNumPoints(); i++ ) { jp.addPoint( (int)getX(i), (int)getY(i) ); } return jp; } }

Ads help maintain this website.