/* * SupportOps.java 2004-11-10 * * Dirk Ansorge, FernUniversitaet Hagen * */ package twodsack.operation.setoperation; import twodsack.io.*; import twodsack.operation.basictypeoperation.*; import twodsack.set.*; import twodsack.setelement.*; import twodsack.setelement.datatype.basicdatatype.*; import twodsack.setelement.datatype.compositetype.*; import twodsack.util.*; import twodsack.util.collection.*; import twodsack.util.collectiontype.*; import twodsack.util.comparator.*; import twodsack.util.graph.*; import twodsack.util.number.*; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Iterator; import java.util.LinkedList; import java.util.ListIterator; import java.io.BufferedReader; import java.io.InputStreamReader; /** * Placed in this class are some high level algebra operations which are needed to formulate * operations of a target algebra with the help of 2D-SACK. Though an algebra implementor * is not really forced to use these operations, they make the implementation much easier. If used, * a target algebra operation rarely consists of more than a few lines. *
Operations for the conversion ElemMultiSet <-> LinkedList can be found here, too.
*/
public class SupportOps {
/*
* fields
*/
private static BufferedReader inBR = new BufferedReader(new InputStreamReader(System.in));
final private static int INITIAL_CAPACITY = 499;
static final Class pointClass = (new Point()).getClass();
static final Class segClass = (new Segment()).getClass();
static final Class triClass = (new Triangle()).getClass();
static final Class ptOpsClass = (new PointTri_Ops()).getClass();
static final Class ssOpsClass = (new SegSeg_Ops()).getClass();
static final Class stOpsClass = (new SegTri_Ops()).getClass();
static final Class ttOpsClass = (new TriTri_Ops()).getClass();
static final Class emsClass = (new ElemMultiSet(new ElemComparator())).getClass();
final static Class[] paramListT = { triClass };
final static Class[] paramListPT = { pointClass, triClass };
final static Class[] paramListTT = { triClass, triClass };
final static Class[] paramListST = { segClass, triClass };
final static Class[] paramListSS = { segClass, segClass };
final static Class[] paramListEMS = { emsClass };
final static SegmentComparator SEGMENT_COMPARATOR = new SegmentComparator();
final static ElemComparator ELEM_COMPARATOR = new ElemComparator();
final static TriangleComparator TRIANGLE_COMPARATOR = new TriangleComparator();
/*
* constructors
*/
/**
* Don't use this constructor.
*/
private SupportOps(){}
/**
* For a set of segments, minimal tests this set for adjacent segments and concats them.
* This method is ment to be used for the border of a Polygons instance, but can be
* used for any SegMultiSet. This methods finds pairs of segments which are adjacent,
* i.e. they are linearly dependant and one of their endpoints is the same (in short: they
* are 'neighbours' without overlap). If such a pair is found, both segments are concatenated. As
* result, the number of segments is reduced by one for every such pair found.
*
* @param sl the set of segments
* @param overlap If false, the more robust but slow SetOps.reduce() is
* used to find pairs of adjacent segments. Otherwise, SetOps.overlapReduceSweep is used.
* @param bboxFilter if true, a bounding box filter is applied (may reduce the time spent for this operation)
* @param handleCycles if true, the set of segments is divided into cycles it may build. Then,
* minimal is invoked on every cycle.
* @return the new, reduced set of segments as SegMultiSet
*/
public static SegMultiSet minimal (SegMultiSet sl, boolean overlap, boolean bboxFilter, boolean handleCycles) {
SegMultiSet retList = new SegMultiSet(SEGMENT_COMPARATOR);
Class c = ssOpsClass;
try {
Method m1 = c.getMethod("adjacent",paramListSS);
Method m2 = c.getMethod("concat",paramListSS);
if (handleCycles) {
//compute the cycles of sl
Graph myGraph = new Graph(sl);
ElemMultiSetList emsl = myGraph.computeFaces();
//compute minimal for every single cycle of emsl
for (int i = 0; i < emsl.size(); i++)
if (!overlap)
retList.addAll(SegMultiSet.convert(SetOps.reduce((ElemMultiSet)emsl.get(i),m1,m2)));
else {
try {
boolean meet = true;
boolean earlyExit = false;
int setNumber = 0;
retList.addAll(SegMultiSet.convert(SetOps.overlapReduceSweep((ElemMultiSet)emsl.get(i),m1,m2,meet)));
} catch (Exception e) {
System.out.println("SupportOps.minimal: Caucht unexpected exception: "+e);
e.printStackTrace();
throw new RuntimeException("An error occurred in the 2DSACK package.");
}//catch
}//else
}//if handleCycles
else {
if (!overlap)
retList = SegMultiSet.convert(SetOps.reduce(sl,m1,m2));
else {
try {
boolean meet = true;
boolean earlyExit = false;
int setNumber = 0;
//this is the 'old' version of reduce that uses overlapReduce instead of overlapReduceSweep
//retList = SegMultiSet.convert(SetOps.overlapReduce(sl,m1,m2,meet,bboxFilter,earlyExit,setNumber));
retList = SegMultiSet.convert(SetOps.overlapReduceSweep(sl,m1,m2,meet));
} catch (Exception e) {
System.out.println("SupportOps.minimal: Caught unexpected exception: "+e);
e.printStackTrace();
throw new RuntimeException("An error occurred in the 2DSACK package.");
}//catch
}//else
}//else
}//try
catch (Exception e) {
System.out.println("Exception was thrown in SupportOps.minimal(SegMultiSet,boolean):");
System.out.println("Exception: "+e.getClass()+" --- "+e.getMessage());
e.printStackTrace();
throw new RuntimeException("An error occurred in the 2DSACK package.");
}//catch
return retList;
}//end method minimal
/**
* For a set of segments, unique finds pairs of overlapping pairs and removes the overlapping part.
* Generally, this method is used to compute the contour of a Polygons instance.
* In that case, the passed set of segments consists of all border segments of the triangles
* representing the Polygons instance. Nevertheless, this method can be applied on
* an arbitrary set of segments.
*
unique finds pairs of segments which overlap, computes that overlapping part
* and removes it from both segments. For two identical segments the result set would be
* empty.
*
* @param sl the set of segments
* @param overlap If false, the more robust but slow SetOps.reduce() is
* used to find pairs of overlapping segments. Otherwise, SetOps.overlapReduce is used.
* @param sweep If true, the fastest algorithm is used: SetOps.overlapReduceSweep2.
* @param bboxFilter if true, a bounding box filter is used (may help to reduce time spent)
* @return the new, reduced set of segments as SegMultiSet
*/
public static SegMultiSet unique (SegMultiSet sl, boolean overlap, boolean sweep, boolean bboxFilter) {
SegMultiSet retList = new SegMultiSet(SEGMENT_COMPARATOR);
Class c = ssOpsClass;
//remove duplicates with SetOps.rdup2
SetOps.rdup2(sl);
try {
Method m1 = c.getMethod("overlap",paramListSS);
Method m2 = c.getMethod("symDiff",paramListSS);
if (!overlap && !sweep)
retList = SegMultiSet.convert(SetOps.reduce(sl,m1,m2));
else {
try {
boolean meet = true;
boolean earlyExit = false;
int setNumber = 0;
if (!sweep)
retList = SegMultiSet.convert(SetOps.overlapReduce(sl,m1,m2,meet,bboxFilter,earlyExit,setNumber));
else
retList = SegMultiSet.convert(SetOps.overlapReduceSweep2(sl,m1,m2,meet));
} catch (Exception e) {
System.out.println("SupportOps.unique: Caught unexpected exception: "+e);
e.printStackTrace();
throw new RuntimeException("An error occurred in the 2DSACK package.");
}//catch
}//else
}//try
catch (Exception e) {
System.out.println("Exception was thrown in SupportOps.unique(SegMultiSet,boolean):");
System.out.println("Exception: "+e.getClass()+" --- "+e.getMessage());
System.out.println("Exception cause: "+e.getCause());
System.out.println("Exception string: "+e.toString());
System.out.println("stack trace: ");
e.printStackTrace();
throw new RuntimeException("An error occurred in the 2DSACK package.");
}//catch
return SegMultiSet.convert(SetOps.rdup2(retList));
}//end method unique
/**
* The contour of a triangle set (representing a polygon) is computed with this method.
* This is done in three steps: *
unique to remove all overlapping parts of segmentsminimal to concat adjacent segments
* The usage of SetOps.reduce or SetOps.overlapReduce is
* toggled via minOverlap and uniOverlap.
*
* @param tl the set of triangles
* @param minOverlap If false, the more robust but slow SetOps.reduce() is
* used in minimal. Otherwise, SetOps.overlapReduce is used.
* @param uniOverlap If false, the more robust but slow SetOps.reduce() is
* used in unique. Otherwise, SetOps.overlapReduce is used.
* @param uniSweep Iftrue, the fastest algorithm is used for unique.
* @param bboxFilter if true, a bounding box filter is used (may reduce time spent for this operation)
* @param computeMinimalSet if true, minimal is used to reduce the set of segments in the
* resulting set
* @param handleCycles this parameter is passed to {@link #minimal(SegMultiSet,boolean,boolean,boolean)}
* @return the contour as SegMultiSet
* @see #minimal(SegMultiSet,boolean,boolean,boolean)
* @see #unique(SegMultiSet,boolean,boolean,boolean)
*/
public static SegMultiSet contourGeneral (TriMultiSet tl,boolean minOverlap,boolean uniOverlap,boolean uniSweep,boolean bboxFilter, boolean computeMinimalSet, boolean handleCycles) {
Class c = triClass;
SegMultiSet retList = new SegMultiSet(SEGMENT_COMPARATOR);
try {
Method m = c.getMethod("segmentArray",null);
if (computeMinimalSet)
retList = minimal(unique(SegMultiSet.convert(SetOps.map(tl,m)),uniOverlap,uniSweep,bboxFilter),minOverlap,bboxFilter,handleCycles);
else
retList = unique(SegMultiSet.convert(SetOps.map(tl,m)),uniOverlap,uniSweep,bboxFilter);
}//try
catch (Exception e) {
System.out.println("Exception was thrown in SupportOps.contourGeneral(TriMultiSet,boolean,boolean):");
System.out.println("Exception: "+e.getClass()+" --- "+e.getMessage());
System.out.println("Exception cause: "+e.getCause());
System.out.println("Exception string: "+e.toString());
System.out.println("stack trace:"); e.printStackTrace();
throw new RuntimeException("An error occurred in the 2DSACK package.");
}//catch
return retList;
}//end method contourGeneral
/**
* The contour of a triangle set (representing a polygon) is computed with this method.
* When using this method instead of contourGeneral it is assumed, that the triangle set
* was computed using the methods of class {@link twodsack.setelement.datatype.compositetype.Polygons}. In that case, bounding segments of the
* triangle set don't overlap. This method doesn't work for triangles with overlapping (instead of identical) segments.
* {@link #minimal(SegMultiSet,boolean,boolean,boolean)} is executed on the resulting set to combine collinear and adjacent segments,
* if minimal parameter is set.
*
* @param ts the set of triangles
* @param minimal if true, minimal is invoked on the resulting segment set.
* @param handleCycles this parameter is passed to {@link #minimal(SegMultiSet,boolean,boolean,boolean)}
* @return the contour as SegMultiSet
* @see #contourGeneral(TriMultiSet,boolean,boolean,boolean,boolean,boolean,boolean)
*/
public static SegMultiSet contour (TriMultiSet ts, boolean minimal, boolean handleCycles) {
SegMultiSet retSet = new SegMultiSet(SEGMENT_COMPARATOR);
Triangle actTri;
Segment[] actSegs;
Iterator it = ts.iterator();
while (it.hasNext()) {
actTri = (Triangle)((MultiSetEntry)it.next()).value;
actSegs = actTri.segmentArray();
retSet.add(actSegs[0]);
retSet.add(actSegs[1]);
retSet.add(actSegs[2]);
}//while
if (minimal)
retSet = minimal(SegMultiSet.convert(SetOps.rdup2(retSet)),true,false,handleCycles);
else
retSet = SegMultiSet.convert(SetOps.rdup2(retSet));
return retSet;
}//end method contour
/**
* Removes from the set of segments all parts that are covered by triangles of the triangle set.
* For a set of segments that is completely covered by triangles, the returned set is empty. * This method works a follows: *
* Finally, the remainig parts of the segments are returned.
*
* @param sl the set of segments
* @param tl the set of triangles
* @param bboxFilter if true, a bounding box filter is applied (may help to reduce time spent)
* @param earlyExit if true, execution is stopped immediately, when no overlapping pair is found
* for an element of the set specified by setNumber
* @param setNumber specifies the setNumber
* @return the set of remaining segments
* @throws EarlyExit
*/
public static SegMultiSet minus (SegMultiSet sl, TriMultiSet tl, boolean bboxFilter,boolean earlyExit, int setNumber)
throws EarlyExit {
SegMultiSet retList = new SegMultiSet(SEGMENT_COMPARATOR);
Class c = stOpsClass;
Class c2 = (new SetOps()).getClass();
Class c3 = ssOpsClass;
Class[] paramList = new Class[4];
Iterator lit = null;
Method m1 = null;
Method m4 = null;
Method m7 = null;
LeftJoinPairMultiSet ljpl;
try {
paramList[0] = Class.forName("twodsack.set.ElemMultiSet");
paramList[1] = Class.forName("twodsack.set.ElemMultiSet");
m1 = c.getMethod("isCovered",paramListST);
paramList[2] = m1.getClass();
paramList[3] = m1.getClass();
ljpl = new LeftJoinPairMultiSet();
m4 = c.getMethod("intersection",paramListST);
m7 = segClass.getMethod("minus",paramListEMS);
lit = sl.iterator();
}//try
catch (Exception e) {
System.out.println("Exception was thrown in SupportOps.minus(SegMultiSet,TriMultiSet):");
System.out.println("Exception: "+e.getClass()+" --- "+e.getMessage());
e.printStackTrace();
throw new RuntimeException("An error occurred in the 2DSACK package.");
}//catch
//align all segments
while (lit.hasNext()) {
((Segment)((MultiSetEntry)lit.next()).value).align(); }
//compute pairlists: 1 segment n intersecting triangles
try {
boolean meet = true;
ljpl = SetOps.overlapLeftOuterJoin(sl,tl,m1,meet,bboxFilter,earlyExit,setNumber);
} catch (EarlyExit exit) {
throw exit;
}//catch
//compute from leftjoinlist a new leftjoinlist with
//Elem=actual segment and
//ElemList=segment parts which have to be subtracted from actual segment
ljpl = SetOps.subtractSets(ljpl,m4);
//sutract all segment parts from actual segments in leftjoinpairlist
ljpl = SetOps.map(ljpl,null,m7);
retList = SegMultiSet.convert(SetOps.collect(ljpl));
return retList;
}//end method minus
/**
* Returns true if the set of segments completely lies inside of the triangle set.
* Actually, this method implements a high level operation which would be a part of a possible
* target algebra. But since it is needed at some places inside of the 2D-SACK framework,
* an implementation is provided here.
*
* @param sl the set of segments
* @param tl the set of triangles
* @param bboxFilter if true, a bounding box filter is used (may reduce the time spent)
* @param earlyExit if true, execution is stopped immediately, when no overlapping pair is found for
* an element of the set specified by setNumber
* @param setNumber specifies the setNumber
* @return {true, false} depending on the mutual position of the objects
* @throws EarlyExit
*/
public static boolean lr_inside (SegMultiSet sl, TriMultiSet tl, boolean bboxFilter,boolean earlyExit, int setNumber)
throws EarlyExit {
SegMultiSet retList = minus(sl,tl,bboxFilter,earlyExit,setNumber);
if (retList.size() == 0) { return true; }
else { return false; }
}//end method lr_inside
/**
* Returns true if the set of points completely lies inside of the triangle set.
* Actually, this method implements a high level operation which would be a part of a possible
* target algebra. But since it is needed at some places inside of the 2D-SACK framework,
* an implementation is provided here.
*
* @param ps the set of points
* @param ts the set of triangles
* @param bboxFilter if true, a bounding box filter is used (may reduce the time spent for this operation
* @return {true, false} depending on the mutual position of the objects
*/
public static boolean pr_inside (PointMultiSet ps, TriMultiSet ts, boolean bboxFilter) {
PointMultiSet retList = null;
try {
Method m = ptOpsClass.getMethod("isCovered",paramListPT);
try {
boolean meet = true;
boolean earlyExit = true;
int setNumber = 1;
retList = PointMultiSet.convert(SetOps.rdup(SetOps.proj1(SetOps.overlapJoin(ps,ts,m,meet,bboxFilter,earlyExit,setNumber))));
} catch (EarlyExit exit) {
return false;
}//catch
} catch (Exception e) {
System.out.println("Exception was thrown in SupportOps.pr_inside(PointMultiSet,TriMultiSet):");
System.out.println("Exception: "+e.getClass()+" --- "+e.getMessage());
e.printStackTrace();
throw new RuntimeException("An error occurred in the 2DSACK package.");
}//catch
if (ps.size() == retList.size()) return true;
else return false;
}//end method pr_inside
/**
* Converts a set from ElemMultiSet to LinkedList representation.
* The resulting list is sorted by the comparator of the ElemMultiSet.
*
* @param inMS the passed ElemMultiSet
* @return the same set in LinkedList format
* @see #convert(LinkedList)
*/
public static LinkedList convert(ElemMultiSet inMS) {
LinkedList retList = new LinkedList();
Iterator it = inMS.iterator();
MultiSetEntry mse;
int number;
while (it.hasNext()) {
mse = (MultiSetEntry)it.next();
number = mse.number;
for (int i = 0; i < number; i++) {
retList.add((Element)mse.value);
}//for i
}//while it
return retList;
}//end method convert
/**
* Converts a list from LinkedList to ElemMultiSet representation.
*
* @param inLL the passed LinkedList
* @return the same list in ElemMultiSet format
* @see #convert(ElemMultiSet)
*/
public static ElemMultiSet convert(LinkedList inLL) {
ElemMultiSet retSet = new ElemMultiSet(ELEM_COMPARATOR);
ListIterator lit = inLL.listIterator(0);
while (lit.hasNext())
retSet.add(lit.next());
return retSet;
}//end method convert
/**
* Returns that part of the first set of triangles, which is not covered by the second set of triangles.
* This method works as follows: *
tl1 find all overlapping triangles of tl2.
* This set of pairs (triangle x set of triangles) is stored in a
* LeftJoinPairMultiSet.LeftJoinPairMultiSet subtract the covered area
* from the triangle.
* Afterwards, the uncovered parts of triangles are returned.
*
* @param tl1 the first (covered) set of triangles
* @param tl2 the second (covering) set of triangles
* @param bboxFilter if true, a bounding box filter is used (may reduce time spent for this operation)
* @return the uncovered set of (new) triangles
*/
public static TriMultiSet minus (TriMultiSet tl1, TriMultiSet tl2, boolean bboxFilter) {
TriMultiSet retSet = null;
Class c = (new Triangle()).getClass();
Class c3 = (new ElemMultiSet(ELEM_COMPARATOR)).getClass();
Class[] paramListT = { c };
Class[] paramListTMS = { c3 };
try {
Method m1 = c.getMethod("pintersects",paramListT);
Method m4 = c.getMethod("minus",paramListTMS);
boolean meet = false;
boolean earlyExit = false;
int setNumber = 0;
double mill1 = System.currentTimeMillis();
LeftJoinPairMultiSet ljpMS = SetOps.overlapLeftOuterJoin(tl1,tl2,m1,meet,bboxFilter,earlyExit,setNumber);
double mill2 = System.currentTimeMillis();
ljpMS = SetOps.map(ljpMS,null,m4);
double mill3 = System.currentTimeMillis();
SegMultiSet retSetS = SegMultiSet.convert(SetOps.rdup2(SetOps.collect(ljpMS)));
double mill4 = System.currentTimeMillis();
retSetS = minimal(retSetS,true,false,true);
double mill5 = System.currentTimeMillis();
retSet = Polygons.computeMesh(retSetS,true);
double mill6 = System.currentTimeMillis();
System.out.println("SupportOps.minus: ");
System.out.println("time for overlapLeftOuterJoin: "+((mill2-mill1)/1000)+" s");
System.out.println("time for map: "+((mill3-mill2)/1000)+" s");
System.out.println("time for convert/rdup2/collect: "+((mill4-mill3)/1000)+" s");
System.out.println("time for minimal: "+((mill5-mill3)/1000)+" s");
System.out.println("time for computMesh: "+((mill6-mill5)/1000)+" s");
}//try
catch (Exception e) {
System.out.println("Exception was thrown in ROSEAlgebra.minus(TriMultiSet,TriMultiSet):");
System.out.println("Exception: "+e.getClass()+" --- "+e.getMessage());
e.printStackTrace();
throw new RuntimeException("An error occurred in the 2DSACK package.");
}//catch
return retSet;
}//end method minus
/**
* Returns the set of (not overlapping) triangles that covers the intersection of the passed two triangle sets.
* This method works as follows: *
ts1 find all overlapping triangles of ts2.
* This set of pairs (triangle x set of triagles) is stored in a LeftJoinPairMultiSet.LeftJoinPairMultiSet compute the intersection.
* Afterwards, the set of triangles representing the intersection is returned.
*
* @param ts1 the first set of triangles
* @param ts2 the second set of triangles
* @param bboxFilter if true, a bounding box filter is used (may reduce the time spent for this operation)
* @return the intersection of ts1, ts2
*/
public static TriMultiSet intersection (TriMultiSet ts1, TriMultiSet ts2, boolean bboxFilter) {
TriMultiSet retSet = null;
Class c = (new Triangle()).getClass();
Class c2 = (new ElemMultiSet(ELEM_COMPARATOR)).getClass();
Class[] paramListT = { c };
Class[] paramListTMS = { c2 };
try {
Method pintersectsM = c.getMethod("pintersects",paramListT);
Method intersectionM = c.getMethod("intersection",paramListTMS);
boolean meet = false;
boolean earlyExit = false;
int setNumber = 0;
LeftJoinPairMultiSet ljpMS = SetOps.overlapLeftOuterJoin(ts1,ts2,pintersectsM,meet,bboxFilter,earlyExit,setNumber);
ljpMS = SetOps.map(ljpMS,null,intersectionM);
SegMultiSet retSetS = SegMultiSet.convert(SetOps.rdup2(SetOps.collect2nd(ljpMS)));
retSetS = minimal(retSetS,true,false,true);
retSet = Polygons.computeMesh(retSetS,true);
} catch (Exception e) {
System.out.println("SupportOps.intersection: Caught an unexpected exception: "+e);
e.printStackTrace();
throw new RuntimeException("An error occurred in the 2DSACK package.");
}//catch
return retSet;
}//end method intersection
/**
* Returns the set of (not overlapping) triangles building the union of the passed two triangle sets.
* This method works as follows:
*
* At the end, the set of triangles representing the union is returned. * Using the recomputeTriangleSet switch, the user may decide, whether for two polygons, which don't * overlap, but meet, the result is re-triangulated or not. The number um triangles is reduced in most cases, * when the result is re-triangulated.
* Note: When setting recomputeTriangleSet = false, the resulting triangle set cannot be used with
* {@link #contour(TriMultiSet,boolean,boolean)} no more. The more expensive {@link #contourGeneral(TriMultiSet,boolean,boolean,boolean,boolean,boolean,boolean)} has to be used to compute the contour
* of such a triangle set.
*
* @param ts1 the first set of triangles
* @param ts2 the second set of triangles
* @param bboxFilter if true, a bounding box filter is used (may reduce the time spent for this operation)
* @param recomputeTriangleSet if true the result of the plus operation is triangulated for two
* polygons which don't overlap but meet only
* @return the union of ts1, ts2
*/
public static TriMultiSet plus (TriMultiSet ts1, TriMultiSet ts2, boolean bboxFilter, boolean recomputeTriangleSet) {
/**
* The following implementation can be used to apply some kind of filtering mechanism on the triangle sets.
* If used, both sets are traversed first to find the faces of the regions. After having done that, these faces are
* checked for overlapping pairs (with one face element of first set and the other set element of the other set).
* Then, the PLUS operation is computed only for those pairs, while the triangulation of the other faces remains
* unchanged.
* This means a dramatic reduction of triangulation costs, when working properly. Unfortunately, the costs for
* computing the faces are very high. In fact, not the faces (i.e. their borders) have to be computed, but the
* triangle sets representing the faces. This is done via the GROUP operation using the ADJACENT predicate. For
* a huge triangle set this operation is extremely expensive due to the construction of the graph. The graph construction
* is very expensive, since for every triangle, 2 new() operations are called (once for an insertion in a hash table
* and another time for the construction of an adjacency list).
* These are the reasons, why this mechanism is NOT used. Instead, we use only a small part of this algorithm, namely
* the first filtering step:
* Instead of building triangle groups, we compute the faces (i.e. segment groups) of the regions. Then, we check
* for overlapping pairs of faces (just like explained above). If no faces (i.e. their bounding boxes) overlap, the triangle
* sets are simply unified. Otherwise, minus is computed for the whole triangle set.
*/
/* OLD CODE as described above
System.out.println("Entering SO.plus.");
Runtime rt = Runtime.getRuntime();
System.out.println("JAVA memory total: "+Double.toString(((int)(rt.totalMemory()/1048.567))/1000.0)+" mb");
System.out.println("JAVA memory free: "+Double.toString(((int)(rt.freeMemory()/1048.567))/1000.0)+" mb\n");
double x0 = System.currentTimeMillis();
PairSet ps = overlappingPairs(ts1,ts2,recomputeTriangleSet);
double x1 = System.currentTimeMillis();
System.out.println("time for ovPairs: "+(x1-x0)+" ms");
System.out.println("overlappingPairs found: "+ps.pairSet.size());
TriMultiSet retSet = new TriMultiSet(TRIANGLE_COMPARATOR);
//if number of pairs found == 0, then just sum up triangle sets and return
if (ps.pairSet.size() == 0) {
retSet.addAll(ts1);
retSet.addAll(ts2);
return retSet;
}//if
//...otherwise, compute plus for the pairs and add all regions which are not involved in pairs directly
//put in the retSet all unused triangles from tms1 (which are now in ps.firstSet and
//put in the set the results of the minus operation invoked on the pairs of ps.pairSet
retSet.addAll(ps.firstSet);
retSet.addAll(ps.secondSet);
//compute minus for all pairs in ps.pairSet
Iterator it = ps.pairSet.iterator();
Class c2 = (new ElemMultiSet(ELEM_COMPARATOR)).getClass();
Class[] paramListT = { triClass };
Class[] paramListTMS = { c2 };
SegMultiSet retSetS = new SegMultiSet(SEGMENT_COMPARATOR);
Method pintersectsM, minusM;
try {
pintersectsM = triClass.getMethod("pintersects",paramListT);
minusM = triClass.getMethod("minus",paramListTMS);
} catch (Exception e) {
System.out.println("Caught an exception in SupportOps.plus.");
e.printStackTrace();
System.out.println("Returning empty value.");
return new TriMultiSet(TRIANGLE_COMPARATOR);
}//catch
boolean meet = false;
boolean earlyExit = false;
int setNumber = 0;
LeftJoinPairMultiSet ljpMS;
ElemPair actPair;
int itno = 0;
while (it.hasNext()) {
System.out.println("\nexamine pair "+itno+" of "+(ps.pairSet.size()-1)); itno++;
actPair = (ElemPair)((MultiSetEntry)it.next()).value;
try {
//ljpMS = SetOps.overlapLeftOuterJoin(((EMSPointer)actPair.second).set,((EMSPointer)actPair.first).set,pintersectsM,meet,bboxFilter,earlyExit,setNumber);
//recompute sizes for sets
((EMSPointer)actPair.first).set.recomputeSize();
((EMSPointer)actPair.second).set.recomputeSize();
ljpMS = SetOps.overlapLeftOuterJoin(((EMSPointer)actPair.first).set,((EMSPointer)actPair.second).set,pintersectsM,meet,bboxFilter,earlyExit,setNumber);
} catch (Exception e) {
System.out.println("Caught unexpected exception. Returning empty value.");
e.printStackTrace();
return new TriMultiSet(TRIANGLE_COMPARATOR);
}//catch
//if the number of overlapping triangles is 0, re-retriangulate, if switch RECOMPUTETRIANGLESET=true
//if RECOMPUTETRIANGLESET=false, simply add triangle set to result set
System.out.println("\nnumber of overlapping pairs: "+ljpMS.size());
Iterator sit = ljpMS.iterator();
int cc = 0;
while (sit.hasNext()) {
LeftJoinPair pp = (LeftJoinPair)((MultiSetEntry)sit.next()).value;
if (pp.elemSet != null) cc++;
}
System.out.println("non-empty pairs: "+cc);
if (recomputeTriangleSet) {
ljpMS = SetOps.map(ljpMS,null,minusM);
retSetS.addAll(SegMultiSet.convert(SetOps.collect(ljpMS)));
//System.out.println("retSetS after adding ljpMS: "); retSetS.print();
} else {
System.out.println("simply adding sets");
retSet.addAll(((EMSPointer)actPair.second).set);
retSet.addAll(((EMSPointer)actPair.first).set);
}//else
}//while it
if (recomputeTriangleSet) {
//now, add to retSetS all second sets which are involved (add them one time only)
retSetS.addAll(contour(TriMultiSet.convert(ps.fourthSet),true,false));
retSetS = unique(retSetS,true,false);
retSetS = minimal(retSetS,true,false,true);
retSet.addAll(Polygons.computeMesh(retSetS,false));
}//if
OLD CODE as decribed above */
/* NEW CODE */
//test triangle sets for faces with overlapping bounding boxes
//System.out.println("SO.contour");
SegMultiSet contour1, contour2;
if (recomputeTriangleSet) {
contour1 = contour(ts1,true,true);
contour2 = contour(ts2,true,true);
} else {
contour1 = contourGeneral(ts1,true,true,true,false,true,true);
contour2 = contourGeneral(ts2,true,true,true,false,true,true);
}//else
//construct graphs from contours
//System.out.println("SO.graphs");
Graph graph1 = new Graph(contour1);
Graph graph2 = new Graph(contour2);
//compute cycles from graphs
//System.out.println("SO.computeFaces");
ElemMultiSetList groups1 = graph1.computeFaces();
ElemMultiSetList groups2 = graph2.computeFaces();
//wrap sets in EMSPointers and store them in ElemMultiSets
Iterator git = groups1.iterator();
int number = 0;
ElemMultiSet actSet;
ElemMultiSet groups1EMS = new ElemMultiSet(ELEM_COMPARATOR);
while (git.hasNext()) {
actSet = (ElemMultiSet)git.next();
groups1EMS.add(new EMSPointer(actSet,actSet.rect(),number));
number++;
}//while
git = groups2.iterator();
number = 0;
ElemMultiSet groups2EMS = new ElemMultiSet(ELEM_COMPARATOR);
while (git.hasNext()) {
actSet = (ElemMultiSet)git.next();
groups2EMS.add(new EMSPointer(actSet,actSet.rect(),number));
number++;
}//while git
//compute pairs of overlapping EMSPointers
PairMultiSet pairs = null;
try {
pairs = SetOps.overlappingPairs(groups1EMS,groups2EMS,false,true,false,false,-1);
} catch (Exception e) {
System.out.println("Caught an unexpected exception in SupportOps.overlappingPairs.");
e.printStackTrace();
throw new RuntimeException("An error occurred in the 2DSACK package.");
}//catch
TriMultiSet retSet = new TriMultiSet(TRIANGLE_COMPARATOR);
//if number of pairs found == 0, then just sum up triangle sets and return
if (pairs.size() == 0) {
retSet.addAll(ts1);
retSet.addAll(ts2);
return retSet;
}//if
//...otherwise, compute plus for complete triangle sets. This is done by computing
//retSet = (tms2 - tms1) + tms1
//compute (tms2 - tms1)
Method methodPINT = null;
Method methodMINUS = null;
LeftJoinPairMultiSet ljpMS = null;
try {
methodPINT = triClass.getMethod("pintersects",paramListT);
methodMINUS = triClass.getMethod("minus",paramListEMS);
ljpMS = SetOps.overlapLeftOuterJoin(ts2,ts1,methodPINT,false,bboxFilter,false,-1);
} catch (Exception e) {
System.out.println("Caught exception in SupportOps.plus.");
e.printStackTrace();
System.out.println("Returning empty value.");
return new TriMultiSet(TRIANGLE_COMPARATOR);
}//catch
ljpMS = SetOps.map(ljpMS,null,methodMINUS);
SegMultiSet retSetS = SegMultiSet.convert(SetOps.collect(ljpMS));
retSetS.addAll(contour(ts1,false,false));
retSetS = unique(retSetS,true,true,false);
retSetS = minimal(retSetS,true,false,true);
retSet = Polygons.computeMesh(retSetS,false);
/* END of NEW CODE */
return retSet;
}//end method plus
/**
* Computes pairs of polygons which have overlapping bounding boxes.
* This method first groups the triangles of every triangle in such a way, that every group builds a polygon which is not
* adjacent to any other group. After that, bounding boxes are computed for every polygon. Then, pairs of polygons are computed
* where the bounding boxes of the polygons overlap. These pairs are returned in the PairSets return type together
* with two sets of polygons (e.g. triangle sets) of both initial sets which are not involved in those pairs.
*
* @param tms1 the first set of triangles
* @param tms2 the second set of triangles
* @param simpleContour if true, the simpler (and cheaper) contour method is used instead of the more expensive
* contourGeneral
* @return the resulting sets stored in a PairSet
*/
public static PairSet overlappingPairs (TriMultiSet tms1, TriMultiSet tms2, boolean simpleContour) {
//compute groups for both triangle sets
double tt01 = System.currentTimeMillis();
ElemMultiSetList groups1, groups2;
PairMultiSet pairs = null;
/**
* This piece of code must be used instead of the code below marked with NEW CODE, if the special filtering mechanism
* described in PLUS method shall be used.
* OLD CODE using SetOps.group to find groups; this is very slow.
Method padjacent = null;
try {
padjacent = ttOpsClass.getMethod("adjacent",paramListTT);
} catch (Exception e) {
System.out.println("Error in SupportOps.overlappingPairs.");
e.printStackTrace();
System.exit(0);
}//catch
double tt02 = System.currentTimeMillis();
groups1 = SetOps.overlapGroup(tms1,padjacent,true);
groups2 = SetOps.overlapGroup(tms2,padjacent,true);
double tt03 = System.currentTimeMillis();
END of OLD CODE */
/* NEW CODE using Graph.computeCycles to find groups; this is faster (hopefully) */
//first, compute contours of both sets
SegMultiSet contour1,contour2;
if (simpleContour) {
contour1 = contour(tms1,true,true);
contour2 = contour(tms2,true,true);
} else {
contour1 = contourGeneral(tms1,true,true,true,false,true,true);
contour2 = contourGeneral(tms2,true,true,true,false,true,true);
}//else
double tt02 = System.currentTimeMillis();
//construct graphs from contours
Graph graph1 = new Graph(contour1);
Graph graph2 = new Graph(contour2);
double tt021 = System.currentTimeMillis();
//compute cycles from graphs
groups1 = graph1.computeFaces();
groups2 = graph2.computeFaces();
double tt03 = System.currentTimeMillis();
/* END of NEW CODE */
//wrap sets in EMSPointers and store them in ElemMultiSets
Iterator git = groups1.iterator();
int number = 0;
ElemMultiSet actSet;
ElemMultiSet groups1EMS = new ElemMultiSet(ELEM_COMPARATOR);
while (git.hasNext()) {
actSet = (ElemMultiSet)git.next();
groups1EMS.add(new EMSPointer(actSet,actSet.rect(),number));
number++;
}//while
double tt04 = System.currentTimeMillis();
git = groups2.iterator();
number = 0;
ElemMultiSet groups2EMS = new ElemMultiSet(ELEM_COMPARATOR);
while (git.hasNext()) {
actSet = (ElemMultiSet)git.next();
groups2EMS.add(new EMSPointer(actSet,actSet.rect(),number));
number++;
}//while git
double tt05 = System.currentTimeMillis();
//compute pairs of overlapping EMSPointers
try {
pairs = SetOps.overlappingPairs(groups1EMS,groups2EMS,false,true,false,false,-1);
} catch (Exception e) {
System.out.println("Caught an unexpected exception in SupportOps.overlappingPairs.");
e.printStackTrace();
throw new RuntimeException("An error occurred in the 2DSACK package.");
}//catch
double tt06 = System.currentTimeMillis();
//build return set
//construct boolean arrays for groups1EMS and groups1EMS, where TRUE stands for "is used in pairs"
boolean[] groups1Used = new boolean[groups1EMS.size()];
boolean[] groups2Used = new boolean[groups2EMS.size()];
//System.out.println("constructed arrays of size "+groups1Used.length+" and "+groups2Used.length);
double tt07 = System.currentTimeMillis();
//initialize boolean arrays
for (int i = 0; i < groups1Used.length; i++) groups1Used[i] = false;
for (int i = 0; i < groups2Used.length; i++) groups2Used[i] = false;
//traverse pairs and build new PairMultiSet, where the first element is a EMS of groups1EMS and
//the second set is the union of all EMS of groups2EMS which occur as pairs of the first element
//in PAIRS. e.g.:
//pairs: <1,12> <1,13> <2,14> <3,20> <3,21>
//pairSet: <1, (union of 12,13)> <2,14> <3, (union of 20,21)>
double tt08 = System.currentTimeMillis();
PairSet retSet = new PairSet();
Iterator it = pairs.iterator();
EMSPointer actGroup1,actGroup2;
ElemPair actPair = null;
int lastKey = -1;
MultiSetEntry mse;
while (it.hasNext()) {
mse = (MultiSetEntry)it.next();
actGroup1 = (EMSPointer)(((ElemPair)mse.value).first);
actGroup2 = (EMSPointer)(((ElemPair)mse.value).second);
//mark groups in boolean arrays
groups1Used[actGroup1.key] = true;
groups2Used[actGroup2.key] = true;
//a pair with a new group was found
if (lastKey != actGroup1.key) {
//construct new entry in retPair
ElemPair newPair = new ElemPair(actGroup1,actGroup2);
actPair = newPair;
retSet.pairSet.add(newPair);
lastKey = actGroup1.key;
} else {
//a pair with the actual key already exists
//add triangles of actGroup2 to actual pair
((EMSPointer)(actPair.second)).set.addAll(actGroup2.set);
}//else
}//while
double tt09 = System.currentTimeMillis();
//now traverse group sets and store all elements from unused sets in retSet.firstSet
//and retSet.secondSet; store used elements of retSet.firstSet in thirdSet and used
//elements of retSet.secondet in fourthSet
it = groups1EMS.iterator();
while (it.hasNext()) {
actGroup1 = (EMSPointer)((MultiSetEntry)it.next()).value;
if (!groups1Used[actGroup1.key])
retSet.firstSet.addAll(actGroup1.set);
else
retSet.thirdSet.addAll(actGroup1.set);
}//while
it = groups2EMS.iterator();
while (it.hasNext()) {
actGroup2 = (EMSPointer)((MultiSetEntry)it.next()).value;
if (!groups2Used[actGroup2.key])
retSet.secondSet.addAll(actGroup2.set);
else
retSet.fourthSet.addAll(actGroup2.set);
}//while
double tt10 = System.currentTimeMillis();
/*
System.out.println("retSet: "+retSet.firstSet.size()+" element(s) in firstSet; "+retSet.secondSet.size+" element(s) in secondSet; "+retSet.pairSet.size+" pairs in pairSet");
System.out.println("\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
System.out.println("time spent for: ");
System.out.println("contour: "+(tt021-tt01)+" ms");
System.out.println("construct graphs: "+(tt02-tt021)+" ms");
System.out.println("computeFaces: "+(tt03-tt02)+" ms");
System.out.println("wrap sets: "+(tt04-tt03)+" ms");
System.out.println("wrap sets2: "+(tt05-tt04)+" ms");
System.out.println("pairs of overlapping pointers: "+(tt06-tt05)+" ms");
System.out.println("construct arrays: "+(tt07-tt06)+" ms");
System.out.println("initialize: "+(tt08-tt07)+" ms");
System.out.println("sort pointers: "+(tt09-tt08)+" ms");
System.out.println("traverse group sets: "+(tt10-tt09)+" ms");
*/
return retSet;
}//end method overlappingPairs
/**
* This method evaluates the intersects and meets predicate for special cases.
* A special case occurs, if an endpoint of a segment S of SET1 lies on an endpoint of T of SET2. Another special
* case is an endpoint of S which lies on T, but not on its endpoint. Both of these cases are treated here.
*
* @param pms the set of pairs of segments that have common points
* @return a boolean array with two elements; the first value stands for the result of the intersects predicate and
* the second value represents the meets predicate
*/
static public Boolean[] evaluateIntersectionAndMeets (PairMultiSet pms) {
Method methodFormALine,methodSecondHasPointOnFirst;
try {
methodSecondHasPointOnFirst = ssOpsClass.getMethod("secondHasPointOnFirst",paramListSS);
ElemMultiSet set1 = new ElemMultiSet(ELEM_COMPARATOR);
ElemMultiSet set2 = new ElemMultiSet(ELEM_COMPARATOR);
SetOps.separateSets(pms,set1,set2);
Boolean[] retArr = SupportOps.checkForIntersectionAndMeetsSameEndpoints(SegMultiSet.convert(set1),
SegMultiSet.convert(set2));
if (retArr[0].booleanValue() == true) return retArr;
//Now we can still have a special case, where one (or more) segment(s) of S1 has(have) an endpoint somewhere on a
//segment of S2, but _not_ on its endpoint. To extract those cases, collect all elements from the pair set and
//construct two LeftJoinPairSets from them using an "endpoint_on_segment" predicate; one for each 'direction'. Then,
//if a segment has only one element in ist elemSet, meets=true and intersects=false. If there are more than one
//elements in elemSet, test for the sides on which their endpoints lie. If they are on different sides of the
//key element in a LeftJoinPair, then intersects=true and meets=false. If they are on the same side,
//intersects=false and meets=true.
LeftJoinPairMultiSet ljp1,ljp2;
ljp1 = SetOps.overlapLeftOuterJoin(set1,set2,methodSecondHasPointOnFirst,true,false,false,-1);
ljp2 = SetOps.overlapLeftOuterJoin(set2,set1,methodSecondHasPointOnFirst,true,false,false,-1);
Boolean[] retArr2 = SupportOps.checkForIntersectionAndMeets(ljp1,ljp2);
if (retArr[0].booleanValue() || retArr2[0].booleanValue()) retArr[0] = Boolean.TRUE;
if (retArr[1].booleanValue() || retArr2[1].booleanValue()) retArr[1] = Boolean.TRUE;
return retArr;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("An error occurred in SupportOps.evaluateIntersectionAndMeets.");
}//catch
}//end method evaluateIntersectionAndMeets
/**
* This methods checks two sets of segments for the intersects and meets predicate.
* It treats a special case, where pairs of segments have the same endpoints. This method works as follows:
* First, it constructs a graph for every segment set and gets a sorted version of the graphs' vertices.
* Then, these vertex arrays are traversed in parallel. For every pair of equal vertices, we have to
* examine, whether any of the both predicates holds. Consider the vertex we are currently examining as the
* middle point M. Then, all outgoing edges end up in other points V1 and V2, depending on the graph they
* belong to. We start now at an arbitrary point and define the degree D at this point as 0 degree. All other points Vx
* are sorted. Then, these vertices are traversed in ascending D-order. We count the number of changes
* from vertices of V1 to V2 and vice versa. If the number gets higher than 2, the intersects predicate holds.
* in all other cases, the meets predicate holds.
* If there are no equal vertices in both of the vertex arrays, none of the predicates holds. */ private static Boolean[] checkForIntersectionAndMeetsSameEndpoints(SegMultiSet sms1, SegMultiSet sms2) { Boolean[] retArr = { Boolean.FALSE, Boolean.FALSE }; //construct graphs from segsets Graph graph1 = new Graph(sms1); Graph graph2 = new Graph(sms2); Vertex[] g1vArr = graph1.getSortedVertexArray(); Vertex[] g2vArr = graph2.getSortedVertexArray(); //traverse both arrays in parallel int arrIdx1 = 0; int arrIdx2 = 0; boolean getNext1 = true; boolean getNext2 = true; Vertex actV1 = null; Vertex actV2 = null; Vertex[] neighbours1 = null; Vertex[] neighbours2 = null; while ((arrIdx1 < g1vArr.length || !getNext1) && (arrIdx2 < g2vArr.length || !getNext2)) { if (getNext1) { //arrIdx1++; actV1 = g1vArr[arrIdx1]; getNext1 = false; }//if if (getNext2) { //arrIdx2++; actV2 = g2vArr[arrIdx2]; getNext2 = false; }//if //if vertices are equal, get neighbours if (actV1.equal(actV2)) { neighbours1 = graph1.getNeighbours(actV1); neighbours2 = graph2.getNeighbours(actV2); //test lengthes of neighbour arrays if ((neighbours1.length == 1 && neighbours2.length == 1) || (neighbours1.length > 1 && neighbours2.length == 1) || (neighbours1.length == 1 && neighbours2.length > 1)) { retArr[1] = Boolean.TRUE; } else { //traverse both arrays in parallel using the angularly sorting double[] angle1 = new double[neighbours1.length]; double[] angle2 = new double[neighbours2.length]; //compute the angles of the other vertices compared to the 0 degree which is a //horizontally drawn segment from the center point to the right. Point midP = (Point)actV1.value; Point startP = new Point(midP.x.plus(RationalFactory.constRational(10)),midP.y); for (int i = 0; i < angle1.length; i++) if (Mathset.pointPosition(midP,startP,(Point)neighbours1[i].value) <= 0) angle1[i] = Mathset.angleD(Mathset.diff(midP,startP), Mathset.diff(midP,(Point)neighbours1[i].value)); else angle1[i] = 360 - Mathset.angleD(Mathset.diff(midP,startP), Mathset.diff(midP,(Point)neighbours1[i].value)); for (int i = 0; i < angle2.length; i++) if (Mathset.pointPosition(midP,startP,(Point)neighbours2[i].value) <= 0) angle2[i] = Mathset.angleD(Mathset.diff(midP,startP), Mathset.diff(midP,(Point)neighbours2[i].value)); else angle2[i] = 360 - Mathset.angleD(Mathset.diff(midP,startP), Mathset.diff(midP,(Point)neighbours2[i].value)); //sort arrays Arrays.sort(angle1); Arrays.sort(angle2); //traverse arrays in parallel and count the number of 'array changes' int changes = 0; boolean next1 = true; boolean next2 = true; int aIdx1 = 0; int aIdx2 = 0; //define start value double actD = 0.0; boolean lastTakenFrom = false; //false = angle1, true = angle2, if (angle1[0] < angle2[0]) { actD = angle1[0]; aIdx1++; next1 = false; lastTakenFrom = false; } else { actD = angle2[0]; aIdx2++; next2 = false; lastTakenFrom = true; }//else //start traversal while (((aIdx1 < angle1.length || !next1)) && ((aIdx2 < angle2.length) || !next2)) { if (next1) { //aIdx1++; next1 = false; }//if if (next2) { //aIdx2++; next2 = false; }//if //compare values and set variable changes if (angle1[aIdx1] < angle2[aIdx2]) { next1 = true; aIdx1++; if (lastTakenFrom) changes++; lastTakenFrom = false; } else { next2 = true; aIdx2++; if (!lastTakenFrom) changes++; lastTakenFrom = true; }//else }//while //check, whether there are still unvisited fields and modify the changes variable if ((aIdx1 < angle1.length+1) || (aIdx2 < angle2.length+1)) changes++; //check variable changes and set boolean array if (changes > 2) { retArr[0] = Boolean.TRUE; retArr[1] = Boolean.FALSE; return retArr; } else { retArr[0] = Boolean.FALSE; retArr[1] = Boolean.TRUE; }//if }//else lengthes were > 1 //now go one step forward in both arrays getNext1 = true; arrIdx1++; getNext2 = true; arrIdx2++; } else { //neighbours are not equal, proceed in one of the arrays int res = actV1.compare(actV2); if (res == -1) { arrIdx1++; getNext1 = true; } else { arrIdx2++; getNext2 = true; }//else }//else }//while return retArr; }//end method checkForIntersectionAndMeetSameEndpoints /** * This method computes the intersects and meets predicate for a special case. * That special case is, when a segment S1 (of SET1) has and endpoint on S2 (of SET2), but not on an endpoint of S2. Then, * we have meets==true, if there are no other segments of SET2 which also have endpoints on S1. In the latter case * it must be examined, whether those other segments end up in the same point or whether they lie on different sides * of S1. All this is done here.
* As a result, an array is returned which holds two boolean values. The first value represents the intersects predicate, * whereas the second one stands for the meets predicate. Obviously, not both can be true at the same time. * Valid configurations are [false,false], [true,false] and [false,true]. * * @param ljp1 a set with LeftJoinPairs, where for every element of such a pair the elemSet holds only segments, which * have an endpoint on that segment * @param ljp2 same as ljp1, but now the elements of each pair are of SET2 (in ljp1 of SET1) and the segments in elemSet * are of SET1 (in ljp1 of SET2); * @return the array that holds the result */ private static Boolean[] checkForIntersectionAndMeets(LeftJoinPairMultiSet ljp1, LeftJoinPairMultiSet ljp2) { //for both sets (ljp1,ljp2) do the following: //traverse set and look at elemSet of every setelement (S,ES): //if ES is empty: do nothing //if ES has 1 element: set meets = true //if ES has more elements: // - for every element E do: // * find the point P that lies on the S // * store P in a hashtable (use P as key for E), if key doesn't exist already in the hashtable // * if segments with P are already there, check all other linked segments (Es), on which side of the S they lie, // if any segment lies on the other side, set intersects=true, set meets=false and BREAK; // if all other segments lie on the same side, set intersects=false, set meets= true and CONTINUE; store P in the hashtable // // NOTE: We check only the first found element and not ALL elements, because, every time a segment is added to the // hashtable, it is checked for the correct side. // //after both sets were traversed: // - intersects must be false, otherwise this point would never have been reached; // if meets=true, return meets=true,intersects=false; // if meets=false, return meets=false,intersects=false Boolean[] retArr = { Boolean.FALSE, Boolean.FALSE }; Iterator it = ljp1.iterator(); LeftJoinPair actLjp; ProHashtable ht = new ProHashtable(INITIAL_CAPACITY); Iterator sit; Segment actSeg,htSeg,actLjpSeg; while (it.hasNext()) { actLjp = (LeftJoinPair)((MultiSetEntry)it.next()).value; actLjpSeg = (Segment)actLjp.element; if (actLjp.elemSet == null || actLjp.elemSet.isEmpty()) { //do nothing }//if else { if (actLjp.elemSet.size() == 1) { retArr[1] = Boolean.TRUE; }//if else { //ES has more elements ht.clear(); sit = actLjp.elemSet.iterator(); while (sit.hasNext()) { actSeg = (Segment)((MultiSetEntry)sit.next()).value; Point commPoint = actLjpSeg.intersection(actSeg); //store segment in hashtable if (ht.containsKey(commPoint)) { //get first segment from hashtable with the same key htSeg = (Segment)ht.getFirst(commPoint); //check, whether the other segment lies 'on the other side' //NOTE: it's not necessary to check _all_ elements, since every time, a new element is //added to the hashtable, it's checked for the correct side. Therefore, we check only //the first found segment. if (Mathset.pointPosition(actLjpSeg.getStartpoint(),actLjpSeg.getEndpoint(),actSeg.theOtherOne(commPoint)) != Mathset.pointPosition(actLjpSeg.getStartpoint(),actLjpSeg.getEndpoint(),htSeg.theOtherOne(commPoint))) { retArr[0] = Boolean.TRUE; retArr[1] = Boolean.FALSE; return retArr; }//if //store segment in the hashtable, otherwise ht.put(commPoint,actSeg); } else { //simply store segment ht.put(commPoint,actSeg); retArr[1] = Boolean.TRUE; }//else }//while sit }//else }//else }//while it //now do the same for the other LeftJoinPairMultiSet it = ljp2.iterator(); while (it.hasNext()) { actLjp = (LeftJoinPair)((MultiSetEntry)it.next()).value; actLjpSeg = (Segment)actLjp.element; if (actLjp.elemSet == null || actLjp.elemSet.isEmpty()) { //do nothing }//if else { if (actLjp.elemSet.size() == 1) { retArr[1] = Boolean.TRUE; }//if else { //ES has more elements ht.clear(); sit = actLjp.elemSet.iterator(); while (sit.hasNext()) { actSeg = (Segment)((MultiSetEntry)sit.next()).value; Point commPoint = actLjpSeg.intersection(actSeg); //store segment in hashtable if (ht.containsKey(commPoint)) { //get first segment from hashtable with the same key htSeg = (Segment)ht.getFirst(commPoint); //check, whether the other segment lies 'on the other side' //NOTE: it's not necessary to check _all_ elements, since every time, a new element is //added to the hashtable, it's checked for the correct side. Therefore, we check only //the first found segment. if (Mathset.pointPosition(actLjpSeg.getStartpoint(),actLjpSeg.getEndpoint(),actSeg.theOtherOne(commPoint)) != Mathset.pointPosition(actLjpSeg.getStartpoint(),actLjpSeg.getEndpoint(),htSeg.theOtherOne(commPoint))) { retArr[0] = Boolean.TRUE; retArr[1] = Boolean.FALSE; return retArr; }//if //store segment in the hashtable, otherwise ht.put(commPoint,actSeg); } else { //simply store segment ht.put(commPoint,actSeg); retArr[1] = Boolean.TRUE; }//else }//while sit }//else }//else }//while it return retArr; }//end method checkForIntersectionAndMeets }//end class SupportOps