[Geom4j-developer] SF.net SVN: geom4j:[25] trunk
Status: Pre-Alpha
Brought to you by:
skhenkin
|
From: <skh...@us...> - 2010-01-09 21:20:29
|
Revision: 25
http://geom4j.svn.sourceforge.net/geom4j/?rev=25&view=rev
Author: skhenkin
Date: 2010-01-09 21:20:22 +0000 (Sat, 09 Jan 2010)
Log Message:
-----------
Bentley-Ottmman algorithm enhanced to work with points of intersection of more than 2 segments. Minor changes.
Modified Paths:
--------------
trunk/build.xml
trunk/src/net/sourceforge/geom4j/PolygonTriangulationAlgorithmTest.java
trunk/src/net/sourceforge/geom4j/SegmentIntersectionAlgorithm.java
trunk/src/net/sourceforge/geom4j/SegmentIntersectionAlgorithmTest.java
trunk/src/net/sourceforge/geom4j/Triangulation.java
trunk/src/net/sourceforge/geom4j/util/BinarySearchTree.java
trunk/src/net/sourceforge/geom4j/util/BinaryTreeBasedSmartQueue.java
trunk/src/net/sourceforge/geom4j/util/ListBasedSmartQueue.java
trunk/src/net/sourceforge/geom4j/util/ListBasedSmartQueueTest.java
trunk/src/net/sourceforge/geom4j/util/SmartQueue.java
Modified: trunk/build.xml
===================================================================
--- trunk/build.xml 2009-12-25 22:05:23 UTC (rev 24)
+++ trunk/build.xml 2010-01-09 21:20:22 UTC (rev 25)
@@ -19,6 +19,7 @@
<property name="app.bin.tgz" value="${build.dir}/${ant.project.name}-${app.version}-bin.tar.gz"/>
<property name="app.src.zip" value="${build.dir}/${ant.project.name}-${app.version}-src.zip"/>
<property name="app.src.tgz" value="${build.dir}/${ant.project.name}-${app.version}-src.tar.gz"/>
+ <property name="javadoc.dir" value="${build.dir}/javadoc"/>
<path id="junit.classpath">
<fileset dir="${junit.dir}" includes="**/*.jar"/>
@@ -108,7 +109,7 @@
</target>
<target name="all" depends="package-application, package-binaries,
- package-sources, package-tests, unit-test, run-demo" />
+ package-sources, package-tests, unit-test, run-demo, javadoc" />
<target name="compile-debug">
<mkdir dir="${debug.classes.dir}"/>
@@ -159,4 +160,20 @@
</target>
<target name="coverage" depends="coverage-report" />
+
+ <target name="javadoc">
+ <javadoc
+ destdir="${javadoc.dir}"
+ author="true"
+ version="true"
+ use="true"
+ windowtitle="Geom4J ${app.version}"
+ classpathref="junit.classpath">
+
+ <fileset dir="${src.dir}" defaultexcludes="yes" />
+
+ <doctitle><![CDATA[<h1>Geom4J - A Pure Java Computational Geometry Library</h1>]]></doctitle>
+ <bottom><![CDATA[<i>Copyright © 2009 Sergey Khenkin. All Rights Reserved.</i>]]></bottom>
+ </javadoc>
+ </target>
</project>
Modified: trunk/src/net/sourceforge/geom4j/PolygonTriangulationAlgorithmTest.java
===================================================================
--- trunk/src/net/sourceforge/geom4j/PolygonTriangulationAlgorithmTest.java 2009-12-25 22:05:23 UTC (rev 24)
+++ trunk/src/net/sourceforge/geom4j/PolygonTriangulationAlgorithmTest.java 2010-01-09 21:20:22 UTC (rev 25)
@@ -28,11 +28,26 @@
public class PolygonTriangulationAlgorithmTest {
@Test
- public void testNaive() {
+ public void testConvex() {
Polygon polygon = new Polygon(new Point(0, 0), new Point(100, 0),
new Point(100, 100), new Point(0, 100));
- Triangulation triangulation = polygon.triangulate();
+ Triangulation triangulation = polygon.triangulate(PolygonTriangulationAlgorithm.CONVEX);
assertTrue(triangulation.fits(polygon));
}
+ @Test
+ public void testX() {
+ Polygon polygon = new Polygon(
+ new Point(1, 1),
+ new Point(3, 2),
+ new Point(2, 0),
+ new Point(8, 3),
+ new Point(7, 5),
+ new Point(4, 2),
+ new Point(3, 3),
+ new Point(3, 4));
+ Triangulation triangulation = polygon.triangulate(PolygonTriangulationAlgorithm.CONVEX);
+ assertTrue(triangulation.fits(polygon));
+ }
+
}
Modified: trunk/src/net/sourceforge/geom4j/SegmentIntersectionAlgorithm.java
===================================================================
--- trunk/src/net/sourceforge/geom4j/SegmentIntersectionAlgorithm.java 2009-12-25 22:05:23 UTC (rev 24)
+++ trunk/src/net/sourceforge/geom4j/SegmentIntersectionAlgorithm.java 2010-01-09 21:20:22 UTC (rev 25)
@@ -15,7 +15,11 @@
package net.sourceforge.geom4j;
+import java.util.Collection;
+import java.util.Collections;
import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Set;
import net.sourceforge.geom4j.util.BinaryTreeBasedSmartQueue;
import net.sourceforge.geom4j.util.SmartQueue;
@@ -77,10 +81,9 @@
public PointSet run(SegmentSet segments) {
// initialization
SmartQueue<Event> eventQueue = initializeEventQueue(segments);
- //SmartQueue<SweepLineSegment> sweepLine
- // = new ListBasedSmartQueue<Segment>(sweepLineComparator);
- SmartQueue<Segment> sweepLine =
- new BinaryTreeBasedSmartQueue<Segment>(sweepLineComparator);
+ SmartQueue<Segment> sweepLine
+ //= new ListBasedSmartQueue<Segment>(sweepLineComparator);
+ = new BinaryTreeBasedSmartQueue<Segment>(sweepLineComparator);
PointSet intersections = new PointSet();
// process all events in the queue
while (!eventQueue.isEmpty()) {
@@ -147,7 +150,16 @@
if (seg1 != null && seg2 != null) {
for (Point p : seg1.intersects(seg2).getPoints()) {
if (p.getX() >= curPoint.getX()) {
- eventQueue.insert(new IntersectionEvent(p, seg1, seg2, sweepLineComparator));
+ IntersectionEvent templateEvent = new IntersectionEvent(p, seg1, seg2, sweepLineComparator);
+ Event existingEvent = eventQueue.find(templateEvent);
+ if (existingEvent != null && existingEvent instanceof IntersectionEvent) {
+ // found a point where more than 2 segments intersect
+ ((IntersectionEvent) existingEvent).addSegment(seg1);
+ ((IntersectionEvent) existingEvent).addSegment(seg2);
+ } else {
+ // it's just a point of intersection of 2 segments
+ eventQueue.insert(templateEvent);
+ }
}
}
}
@@ -267,16 +279,23 @@
*/
class IntersectionEvent extends Event {
private Point p;
- private Segment sAbove;
- private Segment sBelow;
+ private Set<Segment> segments;
public IntersectionEvent(Point p, Segment sAbove, Segment sBelow,
SweepLineComparator sweepLineComparator) {
super(sweepLineComparator);
this.p = p;
- this.sAbove = sAbove;
- this.sBelow = sBelow;
+ this.segments = new HashSet<Segment>();
+ this.segments.add(sBelow);
+ this.segments.add(sAbove);
}
+
+ public IntersectionEvent(Point p, Collection<Segment> segments,
+ SweepLineComparator sweepLineComparator) {
+ super(sweepLineComparator);
+ this.p = p;
+ this.segments = new HashSet<Segment>(segments);
+ }
/**
* On reaching intersection point of two segments on the sweep line add
@@ -289,12 +308,24 @@
SmartQueue<Segment> sweepLine, PointSet intersectionSet) {
intersectionSet.add(p);
sweepLineComparator.setBefore(true);
- sweepLine.swap(sAbove, sBelow);
+ Segment sAbove = getLastSegment();
+ Segment sBelow = getFirstSegment();
+ sweepLine.revert(sBelow, sAbove);
sweepLineComparator.setBefore(false);
addIntersectionEvent(eventQueue, sAbove, sweepLine.previous(sAbove), p);
addIntersectionEvent(eventQueue, sweepLine.next(sBelow), sBelow, p);
}
+ private Segment getLastSegment() {
+ //return segments.get(segments.size()-1);
+ return Collections.max(segments, sweepLineComparator);
+ }
+
+ private Segment getFirstSegment() {
+ //return segments.get(0);
+ return Collections.min(segments, sweepLineComparator);
+ }
+
@Override
public Point getPoint() {
return p;
@@ -306,19 +337,36 @@
}
public String toString() {
- return "<" + getType() + ", " + getPoint() + ", " + sAbove + ", "
- + sBelow + ">";
+ return "<" + getType() + ", " + getPoint() + ", [" + segments + "]>";
}
@Override
public boolean equals(Object obj) {
if (obj instanceof IntersectionEvent) {
IntersectionEvent ie = (IntersectionEvent) obj;
- return p.equals(ie.p) && sAbove.equals(ie.sAbove)
- && sBelow.equals(ie.sBelow);
+ return p.equals(ie.p) /* sAbove.equals(ie.sAbove)
+ && sBelow.equals(ie.sBelow) */;
}
return false;
}
+
+ private void addSegment(Segment s) {
+/* Iterator<Segment> i = segments.iterator();
+ int j = 0;
+ while (i.hasNext()) {
+ Segment intersectingSegment = i.next();
+ if (sweepLineComparator.compare(intersectingSegment, s) < 0) {
+ //if (sweepLineComparator.compare(intersectingSegment, s) < 0) {
+ break;
+ }
+ if (intersectingSegment.equals(s)) {
+ return;
+ }
+ j++;
+ }
+ segments.add(j, s);*/
+ segments.add(s);
+ }
}
/** Comparator for events in the event queue */
Modified: trunk/src/net/sourceforge/geom4j/SegmentIntersectionAlgorithmTest.java
===================================================================
--- trunk/src/net/sourceforge/geom4j/SegmentIntersectionAlgorithmTest.java 2009-12-25 22:05:23 UTC (rev 24)
+++ trunk/src/net/sourceforge/geom4j/SegmentIntersectionAlgorithmTest.java 2010-01-09 21:20:22 UTC (rev 25)
@@ -170,4 +170,42 @@
//System.out.println(naiveSet.size());
assertEquals(naiveSet, boSet);
}
+
+ @Test
+ public void testBentleyOttmanSpecialCase3SegmentsIntersection() {
+ double[][] coords = new double[][] {
+ //{5, 2, 1, 1},
+ {3, 3, 1, 1},
+ {2, 0, 1, 1},
+ {1, 1, 8, 3},
+ //{1, 1, 7, 5}
+ };
+ SegmentSet ss = new SegmentSet();
+ for (int i = 0; i < coords.length; i++) {
+ ss.add(new Segment(new Point(coords[i][0], coords[i][1]),
+ new Point(coords[i][2], coords[i][3])));
+ }
+ PointSet naiveSet = ss.getAllIntersectionPoints(SegmentIntersectionAlgorithm.NAIVE);
+ PointSet boSet = ss.getAllIntersectionPoints(SegmentIntersectionAlgorithm.BENTLEY_OTTMANN);
+ assertEquals(naiveSet, boSet);
+ }
+
+ @Test
+ public void testBentleyOttmanSpecialCase4SegmentsIntersection() {
+ double[][] coords = new double[][] {
+ {5, 2, 1, 1},
+ {3, 3, 1, 1},
+ {2, 0, 1, 1},
+ {1, 1, 8, 3},
+ //{1, 1, 7, 5}
+ };
+ SegmentSet ss = new SegmentSet();
+ for (int i = 0; i < coords.length; i++) {
+ ss.add(new Segment(new Point(coords[i][0], coords[i][1]),
+ new Point(coords[i][2], coords[i][3])));
+ }
+ PointSet naiveSet = ss.getAllIntersectionPoints(SegmentIntersectionAlgorithm.NAIVE);
+ PointSet boSet = ss.getAllIntersectionPoints(SegmentIntersectionAlgorithm.BENTLEY_OTTMANN);
+ assertEquals(naiveSet, boSet);
+ }
}
Modified: trunk/src/net/sourceforge/geom4j/Triangulation.java
===================================================================
--- trunk/src/net/sourceforge/geom4j/Triangulation.java 2009-12-25 22:05:23 UTC (rev 24)
+++ trunk/src/net/sourceforge/geom4j/Triangulation.java 2010-01-09 21:20:22 UTC (rev 25)
@@ -16,7 +16,7 @@
package net.sourceforge.geom4j;
/**
- * A polygon triangulation, actually a set of triangles.
+ * Polygon triangulation, actually a set of triangles.
*
* @author Sergey Khenkin
* @since 1.0.0
@@ -64,9 +64,10 @@
return false;
}
// 5
- if (!getPoints().contains(doubles.getAllIntersectionPoints())) {
+ if (!new PointSet(polygon.getVertices()).contains(doubles.getAllIntersectionPoints())) {
return false;
}
+ // everything is fine
return true;
}
Modified: trunk/src/net/sourceforge/geom4j/util/BinarySearchTree.java
===================================================================
--- trunk/src/net/sourceforge/geom4j/util/BinarySearchTree.java 2009-12-25 22:05:23 UTC (rev 24)
+++ trunk/src/net/sourceforge/geom4j/util/BinarySearchTree.java 2010-01-09 21:20:22 UTC (rev 25)
@@ -84,7 +84,11 @@
public void setParent(Node parent) {
this.parent = parent;
}
-
+
+ @Override
+ public String toString() {
+ return value.toString();
+ }
}
/** Root of the tree */
@@ -249,7 +253,7 @@
}
@SuppressWarnings("unchecked")
- private int compare(E e1, E e2) {
+ protected int compare(E e1, E e2) {
if (comparator == null)
return ((Comparable<? super E>) e1).compareTo(e2);
else
Modified: trunk/src/net/sourceforge/geom4j/util/BinaryTreeBasedSmartQueue.java
===================================================================
--- trunk/src/net/sourceforge/geom4j/util/BinaryTreeBasedSmartQueue.java 2009-12-25 22:05:23 UTC (rev 24)
+++ trunk/src/net/sourceforge/geom4j/util/BinaryTreeBasedSmartQueue.java 2010-01-09 21:20:22 UTC (rev 25)
@@ -16,6 +16,8 @@
package net.sourceforge.geom4j.util;
import java.util.Comparator;
+import java.util.LinkedList;
+import java.util.List;
/**
* "Smarter" implementation of SmartQueue based on a self-balancing
@@ -56,6 +58,31 @@
n2.value = e1;
}
}
+
+ @Override
+ public void revert(E e1, E e2) {
+ List<Node> nodes = new LinkedList<Node>();
+ Node n = findNode(e1);
+ nodes.add(n);
+ do {
+ n = nextNode(n);
+ nodes.add(n);
+ } while (!n.value.equals(e2));
+ int s = nodes.size();
+ for (int i = 0; i < s/2; i++) {
+ Node n1 = nodes.get(i);
+ Node n2 = nodes.get(s-i-1);
+ E t = n1.value;
+ n1.value = n2.value;
+ n2.value = t;
+ }
+ }
+
+ @Override
+ public E find(E e) {
+ Node n = findNode(e);
+ return n == null ? null : n.value;
+ }
}
Modified: trunk/src/net/sourceforge/geom4j/util/ListBasedSmartQueue.java
===================================================================
--- trunk/src/net/sourceforge/geom4j/util/ListBasedSmartQueue.java 2009-12-25 22:05:23 UTC (rev 24)
+++ trunk/src/net/sourceforge/geom4j/util/ListBasedSmartQueue.java 2010-01-09 21:20:22 UTC (rev 25)
@@ -125,6 +125,36 @@
return comparator.compare(e1, e2);
}
}
+
+ @Override
+ public void revert(E e1, E e2) {
+ // TODO change: to real implementation
+ int i1 = list.indexOf(e1);
+ int i2 = list.indexOf(e2);
+ if (i1 != -1 && i2 != -1 && i1 != i2) {
+ for (int i = 0; i < (i2-i1-1)/2+1; i++) {
+ swap(list.get(i1+i), list.get(i2-i));
+ }
+ }
+ }
+
+ @Override
+ public E find(E e) {
+ int i = 0;
+ while (i < list.size()) {
+ if (compare(list.get(i), e) > 0) {
+ break;
+ } else if (compare(list.get(i), e) == 0) {
+ if (list.get(i).equals(e)) {
+ return list.get(i);
+ } else {
+ break;
+ }
+ }
+ i++;
+ }
+ return null;
+ }
}
Modified: trunk/src/net/sourceforge/geom4j/util/ListBasedSmartQueueTest.java
===================================================================
--- trunk/src/net/sourceforge/geom4j/util/ListBasedSmartQueueTest.java 2009-12-25 22:05:23 UTC (rev 24)
+++ trunk/src/net/sourceforge/geom4j/util/ListBasedSmartQueueTest.java 2010-01-09 21:20:22 UTC (rev 25)
@@ -16,6 +16,7 @@
package net.sourceforge.geom4j.util;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
@@ -54,4 +55,20 @@
assertTrue(q.isEmpty());
}
+ @Test
+ public void testRevert() {
+ SmartQueue<String> q = createQueue();
+ q.revert("New York", "Toronto");
+ assertFalse(q.isEmpty());
+ assertEquals("Brussels", q.poll());
+ assertEquals("London", q.poll());
+ assertEquals("Toronto", q.poll());
+ assertEquals("Tel Aviv", q.poll());
+ assertEquals("Sydney", q.poll());
+ assertEquals("San Francisco", q.poll());
+ assertEquals("Paris", q.poll());
+ assertEquals("New York", q.poll());
+ assertEquals("Zurich", q.poll());
+ assertTrue(q.isEmpty());
+ }
}
Modified: trunk/src/net/sourceforge/geom4j/util/SmartQueue.java
===================================================================
--- trunk/src/net/sourceforge/geom4j/util/SmartQueue.java 2009-12-25 22:05:23 UTC (rev 24)
+++ trunk/src/net/sourceforge/geom4j/util/SmartQueue.java 2010-01-09 21:20:22 UTC (rev 25)
@@ -20,11 +20,13 @@
* <ul>
* <li>only unique elements are stored;</li>
* <li>elements are kept sorted according to some order;</li>
- * <li>elements can be inserted and removed efficiently;</li>
+ * <li>elements can be searched, inserted and removed efficiently;</li>
* <li>first element (smallest) can be extracted from the queue;</li>
* <li>for any element immediately previous and immediately next
* elements can be obtained;</li>
- * <li>any pair of elements can be swapped.</li>
+ * <li>any pair of elements can be swapped;</li>
+ * <li>an order of a set of elements between the given pair of elements
+ * can be inverted.</li>
* </ul>
* All these actions should be performed efficiently.
*
@@ -46,5 +48,9 @@
boolean isEmpty();
/** Swap 2 elements */
void swap(E e1, E e2);
+ /** Invert the order of elements between e1 and e2 */
+ void revert(E e1, E e2);
+ /** Find an element and return it */
+ E find(E e);
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|