/* * Copyright (c) 2016 Fraunhofer IGD * * All rights reserved. This program and the accompanying materials are made * available 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. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution. If not, see <http://www.gnu.org/licenses/>. * * Contributors: * Fraunhofer IGD <http://www.igd.fraunhofer.de/> */ package de.fhg.igd.geom.shape; import java.util.Arrays; import de.fhg.igd.geom.BoundingBox; import de.fhg.igd.geom.Point2D; import de.fhg.igd.geom.util.BlochHashCode; /** * This class is equal to the OGC simple feature spec's Surface class, that is, * it describes a 2D feature that has one exterior ring and n interior rings * (holes). Each ring is a Polygon. * * @author Thorsten Reitz */ public class Surface extends Shape { /** * The class' serial version UID */ private static final long serialVersionUID = 4468837090533482032L; /** * A Polygon which defines the outer boundary of this Surface. */ private Polygon exterior_boundary; /** * An Array of Polygons which defines the holes in this Surface. Hole * Polygons may neither intersect the outer boundary nor touch it. */ private Polygon[] interior_boundaries; /** * Def. Constructor. */ public Surface() { super(); } /** * Constructs a surface that has only a exterior boundary * * @param exterior_boundary the exterior boundary of the new surface */ public Surface(Polygon exterior_boundary) { super(); this.exterior_boundary = exterior_boundary; } /** * Full constructor. You are encouraged to use this one. * * @param exterior_boundary the exterior boundary polygon * @param interior_boundaries the interior polygons (holes) */ public Surface(Polygon exterior_boundary, Polygon... interior_boundaries) { super(); this.exterior_boundary = exterior_boundary; this.interior_boundaries = interior_boundaries; } // functional methods ...................................................... /** * This method will return this Surface as an array of java.AWT.Polygons, so * that they can be printed on images. * * @param scale_x the scale factor in x direction * @param scale_y the scale factor in y direction * @param offset the offset to add to the points * @return an AWT polygon */ public java.awt.Polygon[] toAWTPolygons(double scale_x, double scale_y, Point2D offset) { if (this.exterior_boundary != null) { int length = 1; if (this.interior_boundaries != null) { length += this.interior_boundaries.length; } java.awt.Polygon[] result = new java.awt.Polygon[length]; result[0] = this.exterior_boundary.toAWTPolygon(scale_x, scale_y, offset); if (this.interior_boundaries != null) { for (int n = 0; n < this.interior_boundaries.length; n++) { result[n + 1] = this.interior_boundaries[n].toAWTPolygon(scale_x, scale_y, offset); } } return result; } return null; } @Override public BoundingBox getBoundingBox() { return this.exterior_boundary.getBoundingBox(); } // canonical java methods .................................................. /** * @see Object#toString() super.toString() is included. */ @Override public String toString() { StringBuilder buffer = new StringBuilder(); buffer.append("Surface["); buffer.append(super.toString()); buffer.append("exterior_boundary = ").append(exterior_boundary); if (interior_boundaries == null) { buffer.append(" interior_boundaries = ").append("null"); } else { buffer.append(" interior_boundaries = ") .append(Arrays.asList(interior_boundaries).toString()); } buffer.append("]"); return buffer.toString(); } /** * This equals method will test the following cases to determine equality: * <ol> * <li>runtime environment equivalence</li> * <li>if IDs have been set, ID equivalence</li> * <li>if no IDs have been set, check if all Polygons are equal.</li> * </ol> * * @param o the object to check * @return true if the tests pass, false otherwise */ @Override public boolean equals(Object o) { if (!super.equals(o) || !(o instanceof Surface)) return false; Surface s = (Surface) o; // check exterior polygon if (this.exterior_boundary.equals(s.getExterior_boundary())) { if (this.interior_boundaries != null && s.getInterior_boundaries() != null) { // find an equal polygon for every interior polygon for (int ti = 0; ti < this.interior_boundaries.length; ti++) { boolean found = false; for (int si = 0; si < s.getInterior_boundaries().length; si++) { if (this.interior_boundaries[ti].equals(s.getInterior_boundaries()[si])) { found = true; break; } } if (!found) { // there was no matching polygon for the // current interior polygon return false; } } } return true; } return false; } @Override public int hashCode() { int hash = BlochHashCode.HASH_CONSTANT; hash = BlochHashCode.addFieldToHash(hash, this.exterior_boundary); if (this.interior_boundaries != null) { for (Polygon i : this.interior_boundaries) { hash = BlochHashCode.addFieldToHash(hash, i); } } return hash; } // getter / setter methods ................................................. /** * @return Returns the exterior_boundary. */ public Polygon getExterior_boundary() { return exterior_boundary; } /** * @param exterior_boundary The exterior_boundary to set. */ public void setExterior_boundary(Polygon exterior_boundary) { this.exterior_boundary = exterior_boundary; } /** * @return Returns the interior_boundaries. */ public Polygon[] getInterior_boundaries() { return interior_boundaries; } /** * @param interior_boundaries The interior_boundaries to set. */ public void setInterior_boundaries(Polygon[] interior_boundaries) { this.interior_boundaries = interior_boundaries; } }