/* XXL: The eXtensible and fleXible Library for data processing Copyright (C) 2000-2011 Prof. Dr. Bernhard Seeger Head of the Database Research Group Department of Mathematics and Computer Science University of Marburg Germany 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; either version 3 of the License, or (at your option) any later version. 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. You should have received a copy of the GNU Lesser General Public License along with this library; If not, see <http://www.gnu.org/licenses/>. http://code.google.com/p/xxl/ */ package xxl.connectivity.jts.applications; import java.awt.Color; import java.awt.geom.Line2D; import java.util.Comparator; import java.util.Iterator; import xxl.connectivity.jts.visual.VisualOutput; import xxl.connectivity.jts.visual.VisualOutputCursor; import xxl.core.collections.containers.Container; import xxl.core.collections.containers.MapContainer; import xxl.core.collections.queues.DynamicHeap; import xxl.core.cursors.AbstractCursor; import xxl.core.cursors.Cursor; import xxl.core.cursors.filters.Taker; import xxl.core.cursors.identities.DelayCursor; import xxl.core.cursors.mappers.Mapper; import xxl.core.cursors.sources.EmptyCursor; import xxl.core.functions.AbstractFunction; import xxl.core.functions.Function; import xxl.core.indexStructures.Descriptor; import xxl.core.indexStructures.RTree; import xxl.core.indexStructures.Tree.Query.Candidate; import xxl.core.spatial.KPE; import xxl.core.spatial.points.DoublePoint; import xxl.core.spatial.points.Point; import xxl.core.spatial.rectangles.DoublePointRectangle; import xxl.core.spatial.rectangles.Rectangle; public class KNNJoin extends AbstractCursor<KPE[]>{ Iterator<KPE> R; Iterator<Candidate> tmp; int k; RTree S; KPE[] next = null; KPE rNext; public KNNJoin(Iterator<KPE> r, RTree s, int k) { super(); R = r; S = s; this.k = k; tmp = new EmptyCursor<Candidate>(); } @Override protected boolean hasNextObject() { next = null; while(! tmp.hasNext() && R.hasNext()){ rNext = R.next(); tmp = new Taker( S.query(new DynamicHeap( new Comparator<Candidate>(){ public int compare(Candidate c1, Candidate c2) { double d1 = ((Rectangle) c1.descriptor()).minDistance((Point) rNext.getData(), 2); double d2 = ((Rectangle) c2.descriptor()).minDistance((Point) rNext.getData(), 2); return Double.compare(d1,d2); } })), k); } if( tmp.hasNext() ){ next = new KPE[]{rNext, (KPE)tmp.next().entry()}; return true; } return false; } @Override protected KPE[] nextObject() { return next; } @Override public void remove() { throw new UnsupportedOperationException(); } public static Iterator<Point> getRandomPoints(final Rectangle universe, final int numPoints){ return new AbstractCursor<Point>(){ int num; Point next; @Override public void open(){ super.open(); num = numPoints; } @Override protected boolean hasNextObject() { next = new DoublePoint( new double[]{ universe.getCorner(false).getValue(0) + universe.deltas()[0] * Math.random(), universe.getCorner(false).getValue(1) + universe.deltas()[1] * Math.random() }); return num-- > 0; } @Override protected Point nextObject() { return next; } }; } public static void main(String[] args){ RTree S = new RTree(); Container container = new MapContainer(); int m=5, M= 12; Rectangle universe = new DoublePointRectangle(new double[]{0,0}, new double[]{100,100}); Function<KPE, Descriptor> getDescriptor = new AbstractFunction<KPE, Descriptor>(){ @Override public Descriptor invoke(KPE k){ DoublePoint p = (DoublePoint) k.getData(); return new DoublePointRectangle(p,p); } }; final VisualOutput out = new VisualOutput("", universe, 500); out.setRepaintImmediately(true); Iterator<KPE> R= new Mapper<Point, KPE>( new AbstractFunction<Point, KPE>(){ @Override public KPE invoke(Point p){ return new KPE(p); } }, getRandomPoints(universe, 20) ); S.initialize(getDescriptor, container, m, M); Iterator<Point> itS = getRandomPoints(universe, 500); while(itS.hasNext()){ Point p = itS.next(); out.transformAndDraw(VisualOutputCursor.pointToShape.invoke(p), Color.RED); S.insert(new KPE(p)); } Cursor<KPE[]> knnJoin = new DelayCursor(new KNNJoin(R, S, 15), 50, false); while(knnJoin.hasNext()){ KPE[] k = knnJoin.next(); Point p0 = (Point) k[0].getData(); Point p1 = (Point) k[1].getData(); Line2D line = new Line2D.Double(p0.getValue(0), p0.getValue(1), p1.getValue(0), p1.getValue(1)); out.transformAndDraw(line, Color.BLUE); out.transformAndDraw(VisualOutputCursor.pointToShape.invoke(p0), Color.GREEN); } } }