This commit is contained in:
Bane Stojkovic
2022-12-08 23:11:50 +01:00
parent 82d4b9ebfc
commit 3dc0f0d01b
2 changed files with 626 additions and 620 deletions
@@ -34,6 +34,10 @@ import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
*/ */
public class FontConverter extends com.thoughtworks.xstream.converters.extended.FontConverter { public class FontConverter extends com.thoughtworks.xstream.converters.extended.FontConverter {
public FontConverter() {
super(null);
}
@Override @Override
public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) { public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) {
Font f = (Font) object; Font f = (Font) object;
+40 -38
View File
@@ -13,18 +13,20 @@ import java.util.Queue;
import java.util.Set; import java.util.Set;
/** /**
* Implementation of an arbitrary-dimension RTree. Based on R-Trees: A Dynamic * Implementation of an arbitrary-dimension RTree. Based on R-Trees: A Dynamic Index Structure for
* Index Structure for Spatial Searching (Antonn Guttmann, 1984) * Spatial Searching (Antonn Guttmann, 1984)
* <p> * <p>
* This class is not thread-safe. * This class is not thread-safe.
* <p> * <p>
* Copyright 2010 Russ Weeks rweeks@newbrightidea.com Licensed under the GNU * Copyright 2010 Russ Weeks rweeks@newbrightidea.com Licensed under the GNU LGPL License details
* LGPL License details here: http://www.gnu.org/licenses/lgpl-3.0.txt * here: http://www.gnu.org/licenses/lgpl-3.0.txt
* *
* @param <T> the type of entry to store in this RTree. * @param <T> the type of entry to store in this RTree.
*/ */
public class RTree<T> { public class RTree<T> {
public enum SeedPicker {LINEAR, QUADRATIC} public enum SeedPicker {
LINEAR, QUADRATIC
}
private final int maxEntries; private final int maxEntries;
private final int minEntries; private final int minEntries;
@@ -70,8 +72,8 @@ public class RTree<T> {
} }
/** /**
* Builds a new RTree using default parameters: maximum 50 entries per node * Builds a new RTree using default parameters: maximum 50 entries per node minimum 2 entries per
* minimum 2 entries per node 2 dimensions * node 2 dimensions
*/ */
public RTree() { public RTree() {
this(50, 2, 2, SeedPicker.LINEAR); this(50, 2, 2, SeedPicker.LINEAR);
@@ -85,8 +87,7 @@ public class RTree<T> {
} }
/** /**
* @return the minimum number of entries per node for all nodes except the * @return the minimum number of entries per node for all nodes except the root.
* root.
*/ */
public int getMinEntries() { public int getMinEntries() {
return minEntries; return minEntries;
@@ -109,11 +110,10 @@ public class RTree<T> {
/** /**
* Searches the RTree for objects overlapping with the given rectangle. * Searches the RTree for objects overlapping with the given rectangle.
* *
* @param coords the corner of the rectangle that is the lower bound of every * @param coords the corner of the rectangle that is the lower bound of every dimension (eg. the
* dimension (eg. the top-left corner) * top-left corner)
* @param dimensions the dimensions of the rectangle. * @param dimensions the dimensions of the rectangle.
* @return a list of objects whose rectangles overlap with the given * @return a list of objects whose rectangles overlap with the given rectangle.
* rectangle.
*/ */
public List<T> search(float[] coords, float[] dimensions) { public List<T> search(float[] coords, float[] dimensions) {
assert (coords.length == numDims); assert (coords.length == numDims);
@@ -125,7 +125,8 @@ public class RTree<T> {
public List<T> search(Area area) { public List<T> search(Area area) {
Rectangle2D bounds2D = area.getBounds2D(); Rectangle2D bounds2D = area.getBounds2D();
return search(new float[] { (float) bounds2D.getMinX(), (float) bounds2D.getMinY() } , new float[] { (float) bounds2D.getWidth(), (float) bounds2D.getHeight() }); return search(new float[] {(float) bounds2D.getMinX(), (float) bounds2D.getMinY()},
new float[] {(float) bounds2D.getWidth(), (float) bounds2D.getHeight()});
} }
public List<T> search(Point2D point, double t) { public List<T> search(Point2D point, double t) {
@@ -133,8 +134,8 @@ public class RTree<T> {
new float[] {(float) t, (float) t}); new float[] {(float) t, (float) t});
} }
private void search(float[] coords, float[] dimensions, Node n, @SuppressWarnings("unchecked")
LinkedList<T> results) { private void search(float[] coords, float[] dimensions, Node n, LinkedList<T> results) {
if (n.leaf) { if (n.leaf) {
for (Node e : n.children) { for (Node e : n.children) {
if (isOverlap(coords, dimensions, e.coords, e.dimensions)) { if (isOverlap(coords, dimensions, e.coords, e.dimensions)) {
@@ -153,8 +154,7 @@ public class RTree<T> {
/** /**
* Deletes the entry associated with the given rectangle from the RTree * Deletes the entry associated with the given rectangle from the RTree
* *
* @param coords the corner of the rectangle that is the lower bound in every * @param coords the corner of the rectangle that is the lower bound in every dimension
* dimension
* @param dimensions the dimensions of the rectangle * @param dimensions the dimensions of the rectangle
* @param entry the entry to delete * @param entry the entry to delete
* @return true iff the entry was deleted from the RTree. * @return true iff the entry was deleted from the RTree.
@@ -194,6 +194,7 @@ public class RTree<T> {
return delete(coords, pointDims, entry); return delete(coords, pointDims, entry);
} }
@SuppressWarnings("unchecked")
private Node findLeaf(Node n, float[] coords, float[] dimensions, T entry) { private Node findLeaf(Node n, float[] coords, float[] dimensions, T entry) {
if (n.leaf) { if (n.leaf) {
for (Node c : n.children) { for (Node c : n.children) {
@@ -263,11 +264,9 @@ public class RTree<T> {
} }
/** /**
* Inserts the given entry into the RTree, associated with the given * Inserts the given entry into the RTree, associated with the given rectangle.
* rectangle.
* *
* @param coords the corner of the rectangle that is the lower bound in every * @param coords the corner of the rectangle that is the lower bound in every dimension
* dimension
* @param dimensions the dimensions of the rectangle * @param dimensions the dimensions of the rectangle
* @param entry the entry to insert * @param entry the entry to insert
*/ */
@@ -308,6 +307,7 @@ public class RTree<T> {
insert(coords, pointDims, entry); insert(coords, pointDims, entry);
} }
@SuppressWarnings("unchecked")
public void visit(NodeVisitor<T> nv) { public void visit(NodeVisitor<T> nv) {
float[] coordBuf = new float[numDims]; float[] coordBuf = new float[numDims];
float[] dimBuf = new float[numDims]; float[] dimBuf = new float[numDims];
@@ -367,8 +367,7 @@ public class RTree<T> {
// could be modified and inlined because it's only adjusting for the addition // could be modified and inlined because it's only adjusting for the addition
// of a single node. Left as-is for now for readability. // of a single node. Left as-is for now for readability.
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Node[] nn = new RTree.Node[] Node[] nn = new RTree.Node[] {n, new Node(n.coords, n.dimensions, n.leaf)};
{n, new Node(n.coords, n.dimensions, n.leaf)};
nn[1].parent = n.parent; nn[1].parent = n.parent;
if (nn[1].parent != null) { if (nn[1].parent != null) {
nn[1].parent.children.add(nn[1]); nn[1].parent.children.add(nn[1]);
@@ -431,7 +430,8 @@ public class RTree<T> {
float maxWaste = -1.0f * Float.MAX_VALUE; float maxWaste = -1.0f * Float.MAX_VALUE;
for (Node n1 : nn) { for (Node n1 : nn) {
for (Node n2 : nn) { for (Node n2 : nn) {
if (n1 == n2) continue; if (n1 == n2)
continue;
float n1a = getArea(n1.dimensions); float n1a = getArea(n1.dimensions);
float n2a = getArea(n2.dimensions); float n2a = getArea(n2.dimensions);
float ja = 1.0f; float ja = 1.0f;
@@ -456,7 +456,8 @@ public class RTree<T> {
/** /**
* Implementation of QuadraticPickNext * Implementation of QuadraticPickNext
* *
* @param cc the children to be divided between the new nodes, one item will be removed from this list. * @param cc the children to be divided between the new nodes, one item will be removed from this
* list.
* @param nn the candidate nodes for the children to be added to. * @param nn the candidate nodes for the children to be added to.
*/ */
private Node qPickNext(LinkedList<Node> cc, Node[] nn) { private Node qPickNext(LinkedList<Node> cc, Node[] nn) {
@@ -477,8 +478,8 @@ public class RTree<T> {
} }
// Implementation of LinearPickSeeds // Implementation of LinearPickSeeds
private RTree<T>.Node[] lPickSeeds(LinkedList<Node> nn) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private RTree<T>.Node[] lPickSeeds(LinkedList<Node> nn) {
RTree<T>.Node[] bestPair = new RTree.Node[2]; RTree<T>.Node[] bestPair = new RTree.Node[2];
boolean foundBestPair = false; boolean foundBestPair = false;
float bestSep = 0.0f; float bestSep = 0.0f;
@@ -502,8 +503,7 @@ public class RTree<T> {
nMinUb = n; nMinUb = n;
} }
} }
float sep = (nMaxLb == nMinUb) ? -1.0f : float sep = (nMaxLb == nMinUb) ? -1.0f : Math.abs((dimMinUb - dimMaxLb) / (dimUb - dimLb));
Math.abs((dimMinUb - dimMaxLb) / (dimUb - dimLb));
if (sep >= bestSep) { if (sep >= bestSep) {
bestPair[0] = nMaxLb; bestPair[0] = nMaxLb;
bestPair[1] = nMinUb; bestPair[1] = nMinUb;
@@ -525,15 +525,19 @@ public class RTree<T> {
/** /**
* Implementation of LinearPickNext * Implementation of LinearPickNext
* *
* @param cc the children to be divided between the new nodes, one item will be removed from this list. * @param cc the children to be divided between the new nodes, one item will be removed from this
* list.
*/ */
private Node lPickNext(LinkedList<Node> cc) { private Node lPickNext(LinkedList<Node> cc) {
return cc.pop(); return cc.pop();
} }
private void tighten(Node... nodes) { private void tighten(Node[] nn) {
assert (nodes.length >= 1) : "Pass some nodes to tighten!"; for (Node n : nn)
for (Node n : nodes) { tighten(n);
}
private void tighten(Node n) {
assert (n.children.size() > 0) : "tighten() called on empty node!"; assert (n.children.size() > 0) : "tighten() called on empty node!";
float[] minCoords = new float[numDims]; float[] minCoords = new float[numDims];
float[] maxCoords = new float[numDims]; float[] maxCoords = new float[numDims];
@@ -561,7 +565,6 @@ public class RTree<T> {
System.arraycopy(minCoords, 0, n.coords, 0, numDims); System.arraycopy(minCoords, 0, n.coords, 0, numDims);
System.arraycopy(maxCoords, 0, n.dimensions, 0, numDims); System.arraycopy(maxCoords, 0, n.dimensions, 0, numDims);
} }
}
private RTree<T>.Node chooseLeaf(RTree<T>.Node n, RTree<T>.Entry e) { private RTree<T>.Node chooseLeaf(RTree<T>.Node n, RTree<T>.Entry e) {
if (n.leaf) { if (n.leaf) {
@@ -590,8 +593,7 @@ public class RTree<T> {
} }
/** /**
* Returns the increase in area necessary for the given rectangle to cover the * Returns the increase in area necessary for the given rectangle to cover the given entry.
* given entry.
*/ */
private float getRequiredExpansion(float[] coords, float[] dimensions, Node e) { private float getRequiredExpansion(float[] coords, float[] dimensions, Node e) {
float area = getArea(dimensions); float area = getArea(dimensions);
@@ -618,8 +620,8 @@ public class RTree<T> {
return area; return area;
} }
private boolean isOverlap(float[] scoords, float[] sdimensions, private boolean isOverlap(float[] scoords, float[] sdimensions, float[] coords,
float[] coords, float[] dimensions) { float[] dimensions) {
final float FUDGE_FACTOR = 1.001f; final float FUDGE_FACTOR = 1.001f;
for (int i = 0; i < scoords.length; i++) { for (int i = 0; i < scoords.length; i++) {
boolean overlapInThisDimension = false; boolean overlapInThisDimension = false;