/* * Copyright (c) 2003-2012 Fred Hutchinson Cancer Research Center * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.fhcrc.cpl.toolbox.datastructure; import java.util.*; /** * User: mbellew * Date: Sep 16, 2004 * Time: 2:03:20 PM * <p/> * Dumb implementation of 2D tree, find good open source implementation, or get back to this * <p/> * Not thead safe */ public class Tree2D { ArrayList entries = new ArrayList(); Entry2D[] xArray = null; Entry2D[] yArray = null; TreeSet xTree = new TreeSet(Entry2D.compareX); TreeSet yTree = new TreeSet(Entry2D.compareY); static class Entry2D { float x; float y; int i; Entry2D(float x, float y, int i) { this.x = x; this.y = y; this.i = i; } static Comparator compareX = new Comparator() { public int compare(Object o1, Object o2) { Entry2D e1 = (Entry2D)o1; Entry2D e2 = (Entry2D)o2; return e1.x > e2.x ? 1 : e1.x < e2.x ? -1 : e1.i > e2.i ? 1 : e1.i < e2.i ? -1 : 0; } }; static Comparator compareY = new Comparator() { public int compare(Object o1, Object o2) { Entry2D e1 = (Entry2D)o1; Entry2D e2 = (Entry2D)o2; return e1.y > e2.y ? 1 : e1.y < e2.y ? -1 : e1.i > e2.i ? 1 : e1.i < e2.i ? -1 : 0; } }; } static class IndexRange { int start, end; } public Tree2D() { } public void add(float x, float y, Object o) { int i = entries.size(); entries.add(o); Entry2D entry = new Entry2D(x, y, i); xTree.add(entry); yTree.add(entry); // bitSet = null; xArray = null; yArray = null; } public ArrayList getPoints(float xMin, float yMin, float xMax, float yMax) { return getPoints(xMin, yMin, xMax, yMax, new ArrayList()); } /** min inclusive, max exclusive */ public ArrayList getPoints(float xMin, float yMin, float xMax, float yMax, ArrayList list) { list.clear(); Entry2D[] xEntries = getXEntries(); Entry2D[] yEntries = getYEntries(); IndexRange xRange = find(xEntries, xMin, xMax, Entry2D.compareX); IndexRange yRange = find(yEntries, yMin, yMax, Entry2D.compareY); if (xRange.end - xRange.start < yRange.end - yRange.start) { for (int x = xRange.start; x < xRange.end; x++) { Entry2D e = xEntries[x]; if (e.y >= yMin && e.y <= yMax) list.add(entries.get(e.i)); } } else { for (int y = yRange.start; y < yRange.end; y++) { Entry2D e = yEntries[y]; if (e.x >= xMin && e.x <= xMax) list.add(entries.get(e.i)); } } return list; } private IndexRange find(Entry2D[] entries, float min, float max, Comparator c) { IndexRange range = new IndexRange(); // it's irritating, but need to provide matching object class here Entry2D finder = new Entry2D(min, min, 0); range.start = Arrays.binarySearch(entries, finder, c); if (range.start < 0) range.start = -(range.start+1); finder.x = max; finder.y = max; range.end = Arrays.binarySearch(entries, finder, c); if (range.end < 0) range.end = -(range.end+1); return range; } public boolean containsPoints(float xMin, float yMin, float xMax, float yMax) { // optimize ArrayList list = getPoints(xMin, yMin, xMax, yMax); return !list.isEmpty(); } private Entry2D[] getXEntries() { if (null == xArray) xArray = (Entry2D[])xTree.toArray(new Entry2D[xTree.size()]); return xArray; } private Entry2D[] getYEntries() { if (null == yArray) yArray = (Entry2D[])yTree.toArray(new Entry2D[yTree.size()]); return yArray; } // private BitSet getBitSet() // { // if (null == bitSet) // bitSet = new BitSet(entries.size()); // else // bitSet.clear(); // return bitSet; // } }