/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2005-2008, Open Source Geospatial Foundation (OSGeo) * (C) 2010, Geomatys * * This library 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; * version 2.1 of the License. * * This library 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. */ package org.geotoolkit.index.quadtree; import com.vividsolutions.jts.geom.Envelope; import java.util.logging.Level; /** * Represent a tyle in the fake quad tree. * * @author Tommaso Nolli * @author Johann Sorel (Geomatys) * @module */ public abstract class AbstractNode { private static final int[] EMPTY_ARRAY = new int[0]; public static final int NONE = 0; public static final int INTERSECT = 1; public static final int CONTAINED = 2; /** * [MinX,MinY,MaxX,MaxY] */ private double minx; private double miny; private double maxx; private double maxy; private int[] shapesId; /** * @param env the node envelope */ public AbstractNode(final Envelope env) { this(env.getMinX(),env.getMinY(),env.getMaxX(),env.getMaxY()); } /** * @param envelope the node bounds [MinX,MinY,MaxX,MaxY] */ public AbstractNode(final double minx, final double miny, final double maxx, final double maxy) { this.minx = minx; this.miny = miny; this.maxx = maxx; this.maxy = maxy; this.shapesId = EMPTY_ARRAY; } public abstract void setSubNodes(AbstractNode ... nodes); /** * @return Returns the bounds. [MinX,MinY,MaxX,MaxY] */ public double[] getEnvelope() { return new double[]{minx,miny,maxx,maxy}; } public void setEnvelope(final double minx, final double miny, final double maxx, final double maxy) { this.minx = minx; this.miny = miny; this.maxx = maxx; this.maxy = maxy; } public void setEnvelope(final double[] env) { this.minx = env[0]; this.miny = env[1]; this.maxx = env[2]; this.maxy = env[3]; } public Envelope getBounds(final Envelope buffer){ buffer.init(minx, maxx, miny, maxy); return buffer; } /** * @return Number of sub nodes */ public abstract int getNumSubNodes(); /** * DOCUMENT ME! * * @return Returns the number of records stored. */ public int getNumShapeIds() { return this.shapesId.length; } /** * Gets the Node at the requested position * * @param pos The position * @return A Node * @throws StoreException DOCUMENT ME! */ public abstract AbstractNode getSubNode(int pos) throws StoreException; /** * Add a shape id * * @param id */ public void addShapeId(final int id) { final int[] old = shapesId; final int size = shapesId.length; shapesId = new int[size+1]; System.arraycopy(old, 0, shapesId, 0, size); shapesId[size] = id; } /** * Gets a shape id * * @param pos The position * @return The shape id (or recno) at the requested position * @throws ArrayIndexOutOfBoundsException DOCUMENT ME! */ public int getShapeId(final int pos) { return this.shapesId[pos]; } /** * Sets the shape ids * @param ids */ public void setShapesId(final int[] ids) { if (ids == null) { this.shapesId = EMPTY_ARRAY; } else { this.shapesId = ids; } } /** * DOCUMENT ME! * @return Returns the shapesId. */ public int[] getShapesId() { return this.shapesId; } @Override public String toString() { return toString(null); } /** * Special toString, that will add "<>" before each node that intersect the * given envelope. * @param env * @return */ public String toString(final Envelope env) { final StringBuilder sb = new StringBuilder(); if(env != null && env.intersects(getBounds(new Envelope()))){ sb.append("<> "); } sb.append("Node : envelope["); sb.append(minx).append(',').append(miny).append(','); sb.append(maxx).append(',').append(maxy).append(']'); sb.append(" ids(nb=").append(getNumShapeIds()); sb.append(")["); for(int i=0,n=getNumShapeIds();i<n;i++){ sb.append(shapesId[i]); if(i<n-1){ sb.append(','); } } sb.append("]"); for(int i=0,n=getNumSubNodes();i<n;i++){ sb.append('\n'); try{ String subIterator; //move text to the right if(i<n-1){ subIterator = "\u251C\u2500\u2500" + getSubNode(i).toString(env); subIterator = subIterator.replaceAll("\n", "\n\u2502\u00A0\u00A0"); }else{ subIterator = "\u2514\u2500\u2500" + getSubNode(i).toString(env); subIterator = subIterator.replaceAll("\n", "\n\u00A0\u00A0\u00A0"); } sb.append(subIterator); }catch(StoreException ex){ QuadTree.LOGGER.log(Level.WARNING, ex.getLocalizedMessage(), ex); } } return sb.toString(); } public boolean intersects(final Envelope other){ return !(other.getMinX() > maxx || other.getMaxX() < minx || other.getMinY() > maxy || other.getMaxY() < miny); } public int relation(final Envelope other){ final double envMinx = other.getMinX(); final double envMaxx = other.getMaxX(); final double envMiny = other.getMinY(); final double envMaxy = other.getMaxY(); if(minx >= envMinx && maxx <= envMaxx && miny >= envMiny && maxy <= envMaxy){ //we are contained by the given envelope return CONTAINED; }else if(!(envMinx > maxx || envMaxx < minx || envMiny > maxy || envMaxy < miny)){ //we intersect return INTERSECT; }else{ return NONE; } } /** * Returns true if the node is larger or heigher then the given resolution. */ public boolean isBigger(final double[] res){ if(res != null){ return (res[0] <= maxx-minx) || (res[1] <= maxy-miny); } return true; } }