/*
* Copyright (c) 2016 Vivid Solutions.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
*
* http://www.eclipse.org/org/documents/edl-v10.php.
*/
package test.jts.perf.operation.buffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.locationtech.jts.geom.LineSegment;
import test.jts.perf.PerformanceTestCase;
import test.jts.perf.PerformanceTestRunner;
/**
* Stress tests {@link DepthSegment} to determine if the compare contract is maintained.
*
* @author Martin Davis
*
*/
public class DepthSegmentStressTest
extends PerformanceTestCase
{
public static void main(String args[]) {
PerformanceTestRunner.run(DepthSegmentStressTest.class);
}
public DepthSegmentStressTest(String name)
{
super(name);
setRunSize(new int[] {20});
setRunIterations(100);
}
public void startRun(int size)
{
System.out.println("Running with size " + size);
iter = 0;
}
private int iter = 0;
public void XXrunSort()
{
System.out.println("Iter # " + iter++);
// do test work here
List segs = createRandomDepthSegments(100);
Collections.sort(segs);
}
public void runMin()
{
System.out.println("Iter # " + iter++);
// do test work here
List segs = createRandomDepthSegments(100);
Collections.min(segs);
}
public void runCompare()
{
System.out.println("Iter # " + iter++);
DepthSegment seg1 = createRandomDepthSegment();
DepthSegment seg2 = createRandomDepthSegment();
DepthSegment seg3 = createRandomDepthSegment();
// do test work here
boolean fails = false;
if (! isSymmetric(seg1, seg2))
fails = true;
if (! isTransitive(seg1, seg2, seg3))
fails = true;
if (fails ){
System.out.println("FAILS!");
throw new RuntimeException("FAILS!");
}
}
public boolean isSymmetric(DepthSegment seg1, DepthSegment seg2) {
int cmp12 = seg1.compareTo(seg2);
int cmp21 = seg2.compareTo(seg1);
return cmp12 == -cmp21;
}
public boolean isTransitive(DepthSegment seg1, DepthSegment seg2, DepthSegment seg3) {
int cmp12 = seg1.compareTo(seg2);
int cmp23 = seg2.compareTo(seg3);
int cmp13 = seg1.compareTo(seg3);
if (cmp12 > 0 && cmp23 > 0) {
if (cmp13 <= 0) {
System.out.println(seg1 + " " + seg2 + " " + seg3);
return false;
}
}
return true;
}
public List createRandomDepthSegments(int n)
{
List segs = new ArrayList();
for (int i = 0; i < n; i++) {
segs.add(createRandomDepthSegment());
}
return segs;
}
int randint(int max) {
return (int) (max * Math.random());
}
private DepthSegment createRandomDepthSegment() {
double scale = 10;
int max = 10;
double x0 = randint(max);
double y0 = randint(max);
double ang = 2 * Math.PI * Math.random();
double x1 = Math.rint(x0 + max * Math.cos(ang));
double y1 = Math.rint(y0 + max * Math.sin(ang));
LineSegment seg = new LineSegment(x0,y0,x1,y1);
seg.normalize();
return new DepthSegment(seg, 0);
}
double round(double x, double scale)
{
return Math.round(x * scale) / scale;
}
/**
* A segment from a directed edge which has been assigned a depth value
* for its sides.
*/
private class DepthSegment
implements Comparable
{
private LineSegment upwardSeg;
private int leftDepth;
public DepthSegment(LineSegment seg, int depth)
{
// input seg is assumed to be normalized
upwardSeg = new LineSegment(seg);
//upwardSeg.normalize();
this.leftDepth = depth;
}
/**
* Defines a comparison operation on DepthSegments
* which orders them left to right
*
* <pre>
* DS1 < DS2 if DS1.seg is left of DS2.seg
* DS1 > DS2 if DS1.seg is right of DS2.seg
* </pre>
*
* @param obj
* @return the comparison value
*/
public int compareTo(Object obj)
{
DepthSegment other = (DepthSegment) obj;
if (! envelopesOverlap(upwardSeg, other.upwardSeg))
return upwardSeg.compareTo(other.upwardSeg);
// check orientations
int orientIndex = upwardSeg.orientationIndex(other.upwardSeg);
if (orientIndex != 0) return orientIndex;
orientIndex = - other.upwardSeg.orientationIndex(upwardSeg);
if (orientIndex != 0) return orientIndex;
// segments cross or are collinear. Use segment ordering
return upwardSeg.compareTo(other.upwardSeg);
}
public int XcompareTo(Object obj)
{
DepthSegment other = (DepthSegment) obj;
// if segments are collinear and vertical compare endpoints
if (isVertical() && other.isVertical()
&& upwardSeg.p0.x == other.upwardSeg.p0.x)
return compareX(this.upwardSeg, other.upwardSeg);
// check if segments are trivially ordered along X
if (upwardSeg.maxX() <= other.upwardSeg.minX()) return -1;
if (upwardSeg.minX() >= other.upwardSeg.maxX()) return 1;
/**
* try and compute a determinate orientation for the segments.
* Test returns 1 if other is left of this (i.e. this > other)
*/
int orientIndex = upwardSeg.orientationIndex(other.upwardSeg);
// if orientation is determinate, return it
if (orientIndex != 0)
return orientIndex;
/**
* If comparison between this and other is indeterminate,
* try the opposite call order.
* orientationIndex value is 1 if this is left of other,
* so have to flip sign to get proper comparison value of
* -1 if this is leftmost
*/
if (orientIndex == 0)
orientIndex = -1 * other.upwardSeg.orientationIndex(upwardSeg);
// if orientation is determinate, return it
if (orientIndex != 0)
return orientIndex;
// otherwise, segs must be collinear - sort based on minimum X value
return compareX(this.upwardSeg, other.upwardSeg);
}
public boolean isVertical() {
return upwardSeg.p0.x == upwardSeg.p1.x;
}
public boolean envelopesOverlap(LineSegment seg1, LineSegment seg2) {
if (seg1.maxX() <= seg2.minX()) return false;
if (seg2.maxX() <= seg1.minX()) return false;
if (seg1.maxY() <= seg2.minY()) return false;
if (seg2.maxY() <= seg1.minY()) return false;
return true;
}
/**
* Compare two collinear segments for left-most ordering.
* If segs are vertical, use vertical ordering for comparison.
* If segs are equal, return 0.
* Segments are assumed to be directed so that the second coordinate is >= to the first
* (e.g. up and to the right).
*
* @param seg0 a segment to compare
* @param seg1 a segment to compare
* @return
*/
private int compareX(LineSegment seg0, LineSegment seg1)
{
int compare0 = seg0.p0.compareTo(seg1.p0);
if (compare0 != 0)
return compare0;
return seg0.p1.compareTo(seg1.p1);
}
public String toString()
{
return upwardSeg.toString();
}
}
}