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 FontConverter() {
super(null);
}
@Override
public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) {
Font f = (Font) object;
+47 -45
View File
@@ -13,18 +13,20 @@ import java.util.Queue;
import java.util.Set;
/**
* Implementation of an arbitrary-dimension RTree. Based on R-Trees: A Dynamic
* Index Structure for Spatial Searching (Antonn Guttmann, 1984)
* Implementation of an arbitrary-dimension RTree. Based on R-Trees: A Dynamic Index Structure for
* Spatial Searching (Antonn Guttmann, 1984)
* <p>
* This class is not thread-safe.
* <p>
* Copyright 2010 Russ Weeks rweeks@newbrightidea.com Licensed under the GNU
* LGPL License details here: http://www.gnu.org/licenses/lgpl-3.0.txt
* Copyright 2010 Russ Weeks rweeks@newbrightidea.com Licensed under the GNU LGPL License details
* here: http://www.gnu.org/licenses/lgpl-3.0.txt
*
* @param <T> the type of entry to store in this RTree.
*/
public class RTree<T> {
public enum SeedPicker {LINEAR, QUADRATIC}
public enum SeedPicker {
LINEAR, QUADRATIC
}
private final int maxEntries;
private final int minEntries;
@@ -70,8 +72,8 @@ public class RTree<T> {
}
/**
* Builds a new RTree using default parameters: maximum 50 entries per node
* minimum 2 entries per node 2 dimensions
* Builds a new RTree using default parameters: maximum 50 entries per node minimum 2 entries per
* node 2 dimensions
*/
public RTree() {
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
* root.
* @return the minimum number of entries per node for all nodes except the root.
*/
public int getMinEntries() {
return minEntries;
@@ -109,11 +110,10 @@ public class RTree<T> {
/**
* Searches the RTree for objects overlapping with the given rectangle.
*
* @param coords the corner of the rectangle that is the lower bound of every
* dimension (eg. the top-left corner)
* @param coords the corner of the rectangle that is the lower bound of every dimension (eg. the
* top-left corner)
* @param dimensions the dimensions of the rectangle.
* @return a list of objects whose rectangles overlap with the given
* rectangle.
* @return a list of objects whose rectangles overlap with the given rectangle.
*/
public List<T> search(float[] coords, float[] dimensions) {
assert (coords.length == numDims);
@@ -125,16 +125,17 @@ public class RTree<T> {
public List<T> search(Area area) {
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) {
return search(new float[] { (float) (point.getX() - t / 2), (float) (point.getY() - t / 2) },
new float[] { (float) t, (float) t });
return search(new float[] {(float) (point.getX() - t / 2), (float) (point.getY() - t / 2)},
new float[] {(float) t, (float) t});
}
private void search(float[] coords, float[] dimensions, Node n,
LinkedList<T> results) {
@SuppressWarnings("unchecked")
private void search(float[] coords, float[] dimensions, Node n, LinkedList<T> results) {
if (n.leaf) {
for (Node e : n.children) {
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
*
* @param coords the corner of the rectangle that is the lower bound in every
* dimension
* @param coords the corner of the rectangle that is the lower bound in every dimension
* @param dimensions the dimensions of the rectangle
* @param entry the entry to delete
* @return true iff the entry was deleted from the RTree.
@@ -194,6 +194,7 @@ public class RTree<T> {
return delete(coords, pointDims, entry);
}
@SuppressWarnings("unchecked")
private Node findLeaf(Node n, float[] coords, float[] dimensions, T entry) {
if (n.leaf) {
for (Node c : n.children) {
@@ -263,11 +264,9 @@ public class RTree<T> {
}
/**
* Inserts the given entry into the RTree, associated with the given
* rectangle.
* Inserts the given entry into the RTree, associated with the given rectangle.
*
* @param coords the corner of the rectangle that is the lower bound in every
* dimension
* @param coords the corner of the rectangle that is the lower bound in every dimension
* @param dimensions the dimensions of the rectangle
* @param entry the entry to insert
*/
@@ -294,8 +293,8 @@ public class RTree<T> {
}
public void insert(Point2D p, double t, T entry) {
insert(new float[] {(float) (p.getX() - t / 2), (float) (p.getY() - t /2) },
new float[] {(float) t, (float) t }, entry);
insert(new float[] {(float) (p.getX() - t / 2), (float) (p.getY() - t / 2)},
new float[] {(float) t, (float) t}, entry);
}
/**
@@ -308,11 +307,12 @@ public class RTree<T> {
insert(coords, pointDims, entry);
}
@SuppressWarnings("unchecked")
public void visit(NodeVisitor<T> nv) {
float[] coordBuf = new float[numDims];
float[] dimBuf = new float[numDims];
Queue<Node> toVisit = new LinkedList<>();
Map<Node,Integer> nodeDepths = new HashMap<>();
Map<Node, Integer> nodeDepths = new HashMap<>();
nodeDepths.put(root, 0);
toVisit.add(root);
while (!toVisit.isEmpty()) {
@@ -323,7 +323,7 @@ public class RTree<T> {
System.arraycopy(currentNode.coords, 0, coordBuf, 0, numDims);
System.arraycopy(currentNode.dimensions, 0, dimBuf, 0, numDims);
if (currentNode instanceof RTree.Entry) {
nv.visit(nodeDepths.get(currentNode), coordBuf, dimBuf, ((Entry)currentNode).entry);
nv.visit(nodeDepths.get(currentNode), coordBuf, dimBuf, ((Entry) currentNode).entry);
} else {
nv.visit(nodeDepths.get(currentNode), coordBuf, dimBuf, null);
}
@@ -367,8 +367,7 @@ public class RTree<T> {
// could be modified and inlined because it's only adjusting for the addition
// of a single node. Left as-is for now for readability.
@SuppressWarnings("unchecked")
Node[] nn = new RTree.Node[]
{n, new Node(n.coords, n.dimensions, n.leaf)};
Node[] nn = new RTree.Node[] {n, new Node(n.coords, n.dimensions, n.leaf)};
nn[1].parent = n.parent;
if (nn[1].parent != null) {
nn[1].parent.children.add(nn[1]);
@@ -431,7 +430,8 @@ public class RTree<T> {
float maxWaste = -1.0f * Float.MAX_VALUE;
for (Node n1 : nn) {
for (Node n2 : nn) {
if (n1 == n2) continue;
if (n1 == n2)
continue;
float n1a = getArea(n1.dimensions);
float n2a = getArea(n2.dimensions);
float ja = 1.0f;
@@ -456,7 +456,8 @@ public class RTree<T> {
/**
* 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.
*/
private Node qPickNext(LinkedList<Node> cc, Node[] nn) {
@@ -477,8 +478,8 @@ public class RTree<T> {
}
// Implementation of LinearPickSeeds
private RTree<T>.Node[] lPickSeeds(LinkedList<Node> nn) {
@SuppressWarnings("unchecked")
private RTree<T>.Node[] lPickSeeds(LinkedList<Node> nn) {
RTree<T>.Node[] bestPair = new RTree.Node[2];
boolean foundBestPair = false;
float bestSep = 0.0f;
@@ -502,8 +503,7 @@ public class RTree<T> {
nMinUb = n;
}
}
float sep = (nMaxLb == nMinUb) ? -1.0f :
Math.abs((dimMinUb - dimMaxLb) / (dimUb - dimLb));
float sep = (nMaxLb == nMinUb) ? -1.0f : Math.abs((dimMinUb - dimMaxLb) / (dimUb - dimLb));
if (sep >= bestSep) {
bestPair[0] = nMaxLb;
bestPair[1] = nMinUb;
@@ -515,7 +515,7 @@ public class RTree<T> {
// algorithm does not find a best pair. Just pick the first 2
// children.
if (!foundBestPair) {
bestPair = new RTree.Node[]{nn.get(0), nn.get(1)};
bestPair = new RTree.Node[] {nn.get(0), nn.get(1)};
}
nn.remove(bestPair[0]);
nn.remove(bestPair[1]);
@@ -525,15 +525,19 @@ public class RTree<T> {
/**
* 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) {
return cc.pop();
}
private void tighten(Node... nodes) {
assert (nodes.length >= 1) : "Pass some nodes to tighten!";
for (Node n : nodes) {
private void tighten(Node[] nn) {
for (Node n : nn)
tighten(n);
}
private void tighten(Node n) {
assert (n.children.size() > 0) : "tighten() called on empty node!";
float[] minCoords = 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(maxCoords, 0, n.dimensions, 0, numDims);
}
}
private RTree<T>.Node chooseLeaf(RTree<T>.Node n, RTree<T>.Entry e) {
if (n.leaf) {
@@ -590,8 +593,7 @@ public class RTree<T> {
}
/**
* Returns the increase in area necessary for the given rectangle to cover the
* given entry.
* Returns the increase in area necessary for the given rectangle to cover the given entry.
*/
private float getRequiredExpansion(float[] coords, float[] dimensions, Node e) {
float area = getArea(dimensions);
@@ -618,8 +620,8 @@ public class RTree<T> {
return area;
}
private boolean isOverlap(float[] scoords, float[] sdimensions,
float[] coords, float[] dimensions) {
private boolean isOverlap(float[] scoords, float[] sdimensions, float[] coords,
float[] dimensions) {
final float FUDGE_FACTOR = 1.001f;
for (int i = 0; i < scoords.length; i++) {
boolean overlapInThisDimension = false;