001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2003-2006, GeoTools Project Managment Committee (PMC)
005: * (C) 2002, Centre for Computational Geography
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation;
010: * version 2.1 of the License.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: */
017: package org.geotools.index.rtree;
018:
019: import com.vividsolutions.jts.geom.Envelope;
020: import org.geotools.index.TreeException;
021: import java.util.ArrayList;
022: import java.util.Arrays;
023: import java.util.Collection;
024:
025: /**
026: * DOCUMENT ME!
027: *
028: * @author Tommaso Nolli
029: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/plugin/shapefile/src/main/java/org/geotools/index/rtree/Node.java $
030: */
031: public abstract class Node implements EntryBoundsChangeListener {
032: private boolean leaf;
033: protected int entriesCount = 0;
034: protected int maxNodeEntries;
035: protected Envelope bounds;
036: protected Entry[] entries;
037: protected boolean isChanged;
038:
039: public Node(int maxNodeEntries) {
040: this .maxNodeEntries = maxNodeEntries;
041: this .entries = new Entry[maxNodeEntries + 1];
042: this .bounds = null;
043: }
044:
045: /**
046: * Adds an <code>Entry</code> to this <code>Node</code>
047: *
048: * @param entry
049: */
050: public final void addEntry(Entry entry) {
051: this .entries[this .entriesCount++] = entry;
052: entry.setListener(this );
053:
054: if (this .bounds == null) {
055: this .bounds = new Envelope(entry.getBounds());
056: } else {
057: this .bounds.expandToInclude(entry.getBounds());
058: }
059:
060: this .isChanged = true;
061: }
062:
063: /**
064: * Removes an <code>Entry</code> from this <code>Node</code>
065: *
066: * @param entry The <code>Entry</code> to remove
067: */
068: public final void removeEntry(Entry entry) {
069: Entry[] newEntries = new Entry[this .entries.length];
070: Envelope newBounds = null;
071: int newSize = 0;
072:
073: for (int i = 0; i < this .entriesCount; i++) {
074: if (!this .entries[i].equals(entry)) {
075: newEntries[newSize++] = this .entries[i];
076:
077: if (newBounds == null) {
078: newBounds = new Envelope(this .entries[i]
079: .getBounds());
080: } else {
081: newBounds.expandToInclude(this .entries[i]
082: .getBounds());
083: }
084: }
085: }
086:
087: this .entries = newEntries;
088: this .entriesCount = newSize;
089: this .bounds = newBounds;
090: this .isChanged = true;
091: }
092:
093: /**
094: * Removes all <code>Entry</code>s from this <code>Node</code>
095: */
096: public void clear() {
097: Arrays.fill(this .entries, null);
098: this .entriesCount = 0;
099: this .bounds = null;
100: this .isChanged = true;
101: }
102:
103: /**
104: * DOCUMENT ME!
105: *
106: */
107: public boolean isLeaf() {
108: return leaf;
109: }
110:
111: /**
112: * DOCUMENT ME!
113: *
114: * @param b
115: */
116: public void setLeaf(boolean b) {
117: leaf = b;
118: }
119:
120: /**
121: * DOCUMENT ME!
122: *
123: */
124: public int getEntriesCount() {
125: return this .entriesCount;
126: }
127:
128: /**
129: * Gets the n<i>th</i> Element
130: *
131: * @param n
132: *
133: */
134: public Entry getEntry(int n) {
135: return (Entry) this .entries[n];
136: }
137:
138: public Collection getEntries() {
139: ArrayList ret = new ArrayList(this .entriesCount);
140:
141: for (int i = 0; i < this .entriesCount; i++) {
142: ret.add(this .entries[i].clone());
143: }
144:
145: return ret;
146: }
147:
148: /**
149: * DOCUMENT ME!
150: *
151: * @return The bounds
152: */
153: public Envelope getBounds() {
154: return bounds;
155: }
156:
157: /**
158: * @see org.geotools.index.rtree.EntryBoundsChangeListener#boundsChanged(org.geotools.index.rtree.Entry)
159: */
160: public void boundsChanged(Entry e) {
161: this .bounds = new Envelope(this .entries[0].getBounds());
162:
163: for (int i = 1; i < this .entriesCount; i++) {
164: this .bounds.expandToInclude(this .entries[i].getBounds());
165: }
166: }
167:
168: /**
169: * Saves this <code>Node</code>; this method calls doSave()
170: *
171: * @throws TreeException
172: */
173: public final void save() throws TreeException {
174: this .doSave();
175: this .isChanged = false;
176: }
177:
178: /**
179: * DOCUMENT ME!
180: *
181: *
182: * @throws TreeException DOCUMENT ME!
183: */
184: public abstract Node getParent() throws TreeException;
185:
186: /**
187: * Sets the parent of this <code>Node</code>
188: *
189: * @param node The parent <code>Node</code>
190: */
191: public abstract void setParent(Node node);
192:
193: /**
194: * Returns the Entry pointing the specified <code>Node</code>
195: *
196: * @param node The <code>Node</code>
197: *
198: * @return The <code>Entry</code>
199: */
200: protected abstract Entry getEntry(Node node);
201:
202: /**
203: * Saves this <code>Node</code>; called from save()
204: *
205: * @throws TreeException
206: */
207: protected abstract void doSave() throws TreeException;
208: }
|