/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2002-2008, Open Source Geospatial Foundation (OSGeo) * * 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.geotools.graph.structure.opt; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.geotools.graph.structure.Edge; import org.geotools.graph.structure.Node; /** * Optimized implementation of Node. The following optimizations reduce space * and improve performance.<BR> * <UL> * <LI>Edge adjacency list stored as array of predetermined size.</LI> * <LI>Removing support for removing edges from the nodes ajdacency list.</LI> * <LI>The related component iterator iterates over the underlying edge * array of the node instread of a newly created collection. * </UL> * Using an optimized node requires that the degree of the node be known before * the node is built. * * @author Justin Deoliveira, Refractions Research Inc, jdeolive@refractions.net * @see Node * * @source $URL$ */ public class OptNode extends OptGraphable implements Node { /** edge adjacency list **/ private Edge[] m_edges; /** * Constructs a new OptimizedNode. This constructor does not build the * adjacency array for the node. */ public OptNode() { this(0); } /** * Constructs a new Optimized Node with a known degree. * * @param degree The degree of the node. */ public OptNode(int degree) { super(); m_edges = new Edge[degree]; } /** * @see Node#add(Edge) */ public void add(Edge e) { for (int i = 0; i < m_edges.length; i++) { if (m_edges[i] == null) { m_edges[i] = e; return; } } } /** * Not supported. * * @throws UnsupportedOperationException * * @see Node#remove(Edge) */ public void remove(Edge e) { throw new UnsupportedOperationException( getClass().getName() + "#remove(Edge)" ); } /** * @see Node#getEdge(Node) */ public Edge getEdge(Node other) { for (int i = 0; i < m_edges.length; i++) { if ( m_edges[i].getNodeA().equals(this) && m_edges[i].getNodeB().equals(other) || m_edges[i].getNodeB().equals(this) && m_edges[i].getNodeA().equals(other) ) return(m_edges[i]); } return(null); } /** * @see Node#getEdges(Node) */ public List getEdges(Node other) { ArrayList edges = new ArrayList(); for (int i = 0; i < m_edges.length; i++) { if ( m_edges[i].getNodeA().equals(this) && m_edges[i].getNodeB().equals(other) || m_edges[i].getNodeB().equals(this) && m_edges[i].getNodeA().equals(other) ) edges.add(m_edges[i]); } return(edges); } /** * Returns the edge adjacency list of the node as an array. * * @return An array containing edges adjacent to the node. */ public Edge[] getEdgeArray() { return(m_edges); } /** * @see Node#getEdges() */ public List getEdges() { ArrayList edges = new ArrayList(); for (int i = 0; i < m_edges.length; i++) { edges.add(m_edges[i]); } return(edges); } /** * Sets the degree of the node. This method build the edge adjacency array * for the node. * * @param degree The degree of the node / size of edge adjacency array. */ public void setDegree(int degree) { m_edges = new Edge[degree]; } /** * @see Node#getDegree() */ public int getDegree() { return(m_edges.length); } /** * This iterator iterates over the underlying edge array of the node. * * @see org.geotools.graph.structure.Graphable#getRelated() */ public Iterator getRelated() { return(new RelatedIterator(this)); } /** * Overrides the default deserialization operation. Since edge adjacency * lists of Nodes are not written out upon serialization, they must be * recreated upon deserialization. * * @param in Object input stream containing serialized objects. * * @throws IOException * @throws ClassNotFoundException */ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); //read degree from object stream and recreate edge list setDegree(in.readInt()); } /** * Overrides the default serialization operation. Since edge adjacency * lists of Nodes are not written out upon serialization, all the information * needed to recreate them must be written to the object stream as well. Since * the edge list is not written out, and the node does not store its degree * explicitly, it must be written to the output stream. * * @param in Object output stream containing serialized objects. * * @throws IOException * @throws ClassNotFoundException */ private void writeObject(ObjectOutputStream out) throws IOException { out.defaultWriteObject(); //store degree in object stream out.writeInt(getDegree()); } /** * An iterator used to iterate over related nodes. * * @author Justin Deoliveira, Refractions Research Inc, jdeolive@refractions.net * */ public class RelatedIterator implements Iterator { /** index of iterator **/ private byte m_index = 0; private OptNode m_node; public RelatedIterator(OptNode node) { m_node = node; } /** * Not supported. * * @throws UnsupportedOperationException */ public void remove() { throw new UnsupportedOperationException( getClass().getName() + "#remove()" ); } /** * Determines if there are any more related nodes to return. * * @see Iterator#hasNext() */ public boolean hasNext() { return(m_index < m_edges.length); } /** * Returns the next related node. * * @see Iterator#next() */ public Object next() { Edge e = m_edges[m_index++]; return(e.getNodeA().equals(m_node) ? e.getNodeB() : e.getNodeA()); } } }