home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************
- * "Irit" - the 3d polygonal solid modeller. *
- * *
- * Written by: Gershon Elber Ver 0.2, Mar. 1990 *
- ******************************************************************************
- * Module to handle the low level boolean operations. The routines in this *
- * module should be accessed from "bool-hi.c" module only. *
- * Note the polygons of the two given objects may not be convex, and must *
- * be subdivided into convex ones in the boolean upper level routines (module *
- * bool-hi.c). All the routines of this module expects objects with convex *
- * polygons only although they might return objects with non convex polygons, *
- * but marked as so (via polygons CONVEX tags - see Irit.h)! *
- * Because Bool-low.c module was too big, it was subdivided to two: *
- * Bool1Low.c - mainly handles the intersection polyline between the oper. *
- * Bool2Low.c - mainly handles the polygon extraction from operands given the *
- * polyline of intersection and the adjacencies (see ADJACNCY.C) *
- * Note we said mainly has routines CAN call one another! *
- *****************************************************************************/
-
- /* #define DEBUG2 If defined, defines some printing routines. */
- /* #define DEBUG3 Print messages to entry/exit from routines. */
-
- #ifdef __MSDOS__
- #include <alloc.h>
- #include <dos.h>
- #endif /* __MSDOS__ */
-
- #include <stdio.h>
- #include <ctype.h>
- #include <math.h>
- #include <string.h>
- #include "program.h"
- #include "allocatg.h"
- #include "adjcncyg.h"
- #include "objects.h"
- #include "geomat3d.h"
- #include "booleang.h"
- #include "booleanl.h"
-
- static int ObjectsIntersect;
-
- static ObjectStruct *BooleanLowGenInOut(ObjectStruct *PObj1, int InOut);
- static void BooleanLowInterAll(ObjectStruct *PObj1, ObjectStruct *PObj2);
- static void BooleanLowInterOne(PolygonStruct *Pl1, PolygonStruct *Pl2);
- static InterSegmentStruct *InterSegmentPoly(PolygonStruct *Pl,
- PolygonStruct *SegPl, PointType Segment[2]);
- static void SwapPointInterList(InterSegmentStruct *PSeg);
- static void DeleteSegInterList(InterSegmentStruct *PSeg,
- InterSegmentStruct **PSegList);
- static InterSegmentStruct *FindMatchInterList(PointType Pt,
- InterSegmentStruct **PSegList);
- static void SortOpenReverseLoop(SortOpenStruct *PSHead);
- static RealType SortOpenInsertOne(SortOpenStruct **PSHead,
- SortOpenStruct *PSTemp, PointType Pt, VertexStruct *V, PolygonStruct *Pl);
- static ObjectStruct *PolylineFromInterSeg(ObjectStruct *PObj);
-
- #ifdef DEBUG2
- static void PrintVrtxList(VertexStruct *V);
- static void PrintInterList(InterSegmentStruct *PInt);
- #endif /* DEBUG2 */
-
- /*****************************************************************************
- * Routine to find the part of PObj1 which is out of PObj2: *
- *****************************************************************************/
- ObjectStruct *BooleanLow1Out2(ObjectStruct *PObj1, ObjectStruct *PObj2)
- {
- #ifdef DEBUG3
- printf("Enter BooleanLow1Out2\n");
- #endif /* DEBUG3 */
-
- GenAdjacencies(PObj1);
-
- /* Find all intersections of PObj1 polygons with PObj2 polygons. */
- ObjectsIntersect = FALSE;
- BooleanLowInterAll(PObj1, PObj2);
-
- /* Generate all the polygons in PObj1 which are out of PObj2. */
- if (!ObjectsIntersect) {
- FatalBooleanError(FTL_BOOL_NO_INTER);
- }
- return BooleanLowGenInOut(PObj1, FALSE);
- }
-
- /*****************************************************************************
- * Routine to find the part of PObj1 which is in PObj2: *
- *****************************************************************************/
- ObjectStruct *BooleanLow1In2(ObjectStruct *PObj1, ObjectStruct *PObj2)
- {
- #ifdef DEBUG3
- printf("Enter BooleanLow1In2\n");
- #endif /* DEBUG3 */
-
- GenAdjacencies(PObj1);
-
- /* Find all intersections of PObj1 polygons with PObj2 polygons. */
- ObjectsIntersect = FALSE;
- BooleanLowInterAll(PObj1, PObj2);
-
- /* Generate all the polygons in PObj1 which are in PObj2. */
- if (!ObjectsIntersect) {
- FatalBooleanError(FTL_BOOL_NO_INTER);
- }
- return BooleanLowGenInOut(PObj1, TRUE);
- }
-
- /*****************************************************************************
- * Scan the InterSegmentList of each polygon and decide using Intersection *
- * list, if it is IN relative to the other object. Note that for polygons *
- * that does not intersect at all, we use the polygon adjacencies to decide *
- * if they are IN or not. *
- *****************************************************************************/
- static ObjectStruct *BooleanLowGenInOut(ObjectStruct *PObj, int InOut)
- {
- if (BooleanOutputInterCurve) {
- /* Return a polyline object - extract the InterSegment list of each */
- /* polygon into open/closed polyline loops object. */
- return PolylineFromInterSeg(PObj);
- }
- else
- return ExtractPolygons(PObj, InOut);
- }
-
- /*****************************************************************************
- * Create a polyline object out of the intersection list of the polygons. *
- *****************************************************************************/
- static ObjectStruct *PolylineFromInterSeg(ObjectStruct *PObj)
- {
- struct ObjectStruct *PObjRet;
- struct PolygonStruct *PlTemp, *PlHead = NULL, *PlObj;
- struct InterSegmentStruct *PInter, *PInterNext;
- struct InterSegListStruct *PClosed, *POpen, *PClosedNext, *POpenNext;
- struct VertexStruct *V;
-
- PlObj = PObj -> U.Pl;
- while (PlObj != NULL) {
- LoopsFromInterList(PlObj, &PClosed, &POpen);
- while (POpen != NULL) {
- /* Make one polyline from each loop in list: */
- PInter = POpen -> PISeg;
- POpenNext = POpen -> Pnext;
-
- PlTemp = AllocPolygon(0, 0, NULL, NULL);
- PlTemp -> V = V = AllocVertex(0, 0, NULL, NULL);
- PT_COPY(V -> Pt, PInter -> PtSeg[0]);
- while (PInter) {
- PInterNext = PInter -> Pnext;
-
- V -> Pnext = AllocVertex(0, 0, NULL, NULL); V = V -> Pnext;
- PT_COPY(V -> Pt, PInter -> PtSeg[1]);
-
- MyFree((char *) PInter, OTHER_TYPE);
- PInter = PInterNext;
- }
- PlTemp -> Pnext = PlHead;
- PlHead = PlTemp;
-
- MyFree((char *) POpen, OTHER_TYPE);
- POpen = POpenNext;
- }
- while (PClosed != NULL) {
- /* Make one polyline from each loop in list: */
- PInter = PClosed -> PISeg;
- PClosedNext = PClosed -> Pnext;
-
- PlTemp = AllocPolygon(0, 0, NULL, NULL);
- PlTemp -> V = V = AllocVertex(0, 0, NULL, NULL);
- PT_COPY(V -> Pt, PInter -> PtSeg[0]);
- while (PInter) {
- V -> Pnext = AllocVertex(0, 0, NULL, NULL); V = V -> Pnext;
- PT_COPY(V -> Pt, PInter -> PtSeg[1]);
- PInter = PInter -> Pnext;
- }
- PlTemp -> Pnext = PlHead;
- PlHead = PlTemp;
-
- MyFree((char *) PClosed, OTHER_TYPE);
- PClosed = PClosedNext;
- }
- PlObj = PlObj -> Pnext;
- }
-
- PObjRet = GenGeomObject("", PlHead, NULL);
- SET_POLYLINE_GEOM_OBJ(PObjRet); /* Mark it as polyline object. */
- return PObjRet;
- }
-
- /*****************************************************************************
- * Routine to find all the intersections between all PObj1 polygons with *
- * PObj2 polygons. The intersections are saved as a list of segments (struct *
- * InterSegmentStruct) in each of PObj1 polygons using the PAux pointer (see *
- * PolygonStruct). Note PObj2 is not modified at all, and in PObj1, only PAux *
- * of each polygon is set to the segment list, or NULL if none *
- *****************************************************************************/
- static void BooleanLowInterAll(ObjectStruct *PObj1, ObjectStruct *PObj2)
- {
- struct PolygonStruct *Pl1, *Pl2;
-
- #ifdef DEBUG3
- printf("Enter BooleanLowInterAll\n");
- #endif /* DEBUG3 */
-
- Pl1 = PObj1 -> U.Pl;
- while (Pl1 != NULL) {
- Pl1 -> PAux = NULL; /* Empty InterSegment list to start with: */
-
- Pl2 = PObj2 -> U.Pl;
- while (Pl2 != NULL) {
- BooleanLowInterOne(Pl1, Pl2);
- Pl2 = Pl2 -> Pnext;
- }
- ObjectsIntersect |= (Pl1 -> PAux != NULL); /* If any intersection. */
-
- Pl1 = Pl1 -> Pnext;
- }
-
- #ifdef DEBUG3
- printf("Exit BooleanLowInterAll\n");
- #endif /* DEBUG3 */
- }
-
- /*****************************************************************************
- * Routine to intersect polygon Pl1, with polygon Pl2. If found common *
- * intersection, that segment will be added to the InterSegmentStruct list *
- * saved in Pl1 PAux list. *
- * Note that as the two polygons convex, only one segment can result from *
- * such intersection. *
- * Algorithm: intersect all Pl2 edges with Pl1 plane. If found that *
- * (exactly) two vertices (one segment) of Pl2 do intersect Pl1 plane then: *
- * Perform clipping of the segment against Pl1. If result is not empty, add *
- * the result segment to Pl1 InterSegmentStruct list (saved at PAux of *
- * polygon - see PolygonStruct). *
- *****************************************************************************/
- static void BooleanLowInterOne(PolygonStruct *Pl1, PolygonStruct *Pl2)
- {
- int NumOfInter = 0;
- RealType TInter[2],
- *Plane = Pl1 -> Plane; /* For faster access. */
- PointType Inter[2], Dir;
- VertexStruct *Vnext, *V = Pl2 -> V;
- InterSegmentStruct *PSeg, *PLSeg;
-
- #ifdef DEBUG3
- printf("Enter BooleanLowInterOne\n");
- #endif /* DEBUG3 */
-
- TestBooleanCtrlBrk();
-
- do {
- Vnext = V -> Pnext;
- PT_SUB(Dir, Vnext -> Pt, V -> Pt);
- if (CGPointFromLinePlane01(V -> Pt, Dir, Plane, Inter[NumOfInter],
- &TInter[NumOfInter]) &&
- ((NumOfInter == 0) || (NumOfInter == 1 &&
- !PT_EQ(Inter[0], Inter[1]))))
- NumOfInter++;
- if (NumOfInter == 2) break; /* Cannt have more intersections. */
-
- V = Vnext;
- }
- while (V != NULL && V != Pl2 -> V);
-
- switch (NumOfInter) {
- case 0:
- break;
- case 1:
- /* One intersection is possible if only one vertex of Pl2 is in */
- /* the plane of Pl1, all other vertices are on one side of plane.*/
- break;
- case 2:
- /* Clip the segment against the polygon and insert if not empty: */
- if ((PSeg = InterSegmentPoly(Pl1, Pl2, Inter)) != NULL) {
- /* insert that segment to list of Pl1. Note however that the */
- /* intersection may be exactly on 2 other polygons boundary, */
- /* And therefore creates the same intersection edge TWICE! */
- /* Another possiblity is on same case, the other polygon */
- /* will have that inter. edge on its edge, and its ignored. */
- /* We therefore test for duplicates and ignore edge if so */
- if (PSeg -> V[0] != NULL && PSeg -> V[0] == PSeg -> V[1]) {
- MyFree((char *) PSeg, OTHER_TYPE); /* Ignore it! */
- return;
- }
- PLSeg = (InterSegmentStruct *) Pl1 -> PAux;
- while (PLSeg != NULL) {
- if ((PT_EQ(PSeg -> PtSeg[0], PLSeg -> PtSeg[0]) &&
- PT_EQ(PSeg -> PtSeg[1], PLSeg -> PtSeg[1])) ||
- (PT_EQ(PSeg -> PtSeg[0], PLSeg -> PtSeg[1]) &&
- PT_EQ(PSeg -> PtSeg[1], PLSeg -> PtSeg[0]))) {
- MyFree((char *) PSeg, OTHER_TYPE); /* Ignore it! */
- return;
- }
- PLSeg = PLSeg -> Pnext;
- }
-
- PSeg -> Pnext = (InterSegmentStruct *) Pl1 -> PAux;
- Pl1 -> PAux = (VoidPtr) PSeg;
- }
- break;
- }
-
- #ifdef DEBUG3
- printf("Exit BooleanLowInterOne\n");
- #endif /* DEBUG3 */
- }
-
- /*****************************************************************************
- * Intersects the given segment (given as two end points), with the given *
- * polygon (which must be convex). Upto two intersections are possible, as *
- * again, the polygon is convex. Note Segment polygon is given as SegPl. *
- *****************************************************************************/
- static InterSegmentStruct *InterSegmentPoly(PolygonStruct *Pl,
- PolygonStruct *SegPl, PointType Segment[2])
- {
- int i, NumOfInter = 0, Reverse, Res;
- RealType TInter[2], temp, Min, Max, *PtSeg0, *PtSeg1;
- PointType Dir, Inter[2], SegDir, Pt1, Pt2;
- VertexStruct *VInter[2], *V = Pl -> V, *Vnext;
- InterSegmentStruct *PSeg;
-
- /* Find the segment direction vector: */
- PT_SUB(SegDir, Segment[1], Segment[0]);
-
- #ifdef DEBUG3
- printf("Enter InterSegmentPoly\n");
- #endif /* DEBUG3 */
-
- do {
- Vnext = V -> Pnext;
- PT_SUB(Dir, Vnext -> Pt, V -> Pt);
- /* Find the intersection of the segment with all the polygon edges: */
- /* Note the t parameter value of the edge (temp) must be in [0..1]. */
- if ((Res = CG2PointsFromLineLine(Segment[0], SegDir,
- V -> Pt, Dir, Pt1, &TInter[NumOfInter], Pt2, &temp)) != 0 &&
- (temp > 0.0 || APX_EQ(temp, 0.0)) &&
- (temp < 1.0 || APX_EQ(temp, 1.0)) && PT_EQ(Pt1, Pt2) &&
- (NumOfInter == 0 ||
- (NumOfInter == 1 && !APX_EQ(TInter[0], TInter[1])))) {
- PT_COPY(Inter[NumOfInter], Pt1);
- VInter[NumOfInter++] = V; /* Save pointer to intersected edge. */
- }
- else {
- /* If Res == 0 its parallel to edge. If distance is zero then */
- /* line is on the edge line itself - quit from this one! */
- if (!Res && CGDistPointPoint(Pt1, Pt2) < EPSILON) {
- /* Wipe out adjacency of this vertex as we dont want to */
- /* propagate through this one nothing - its on in/out border.*/
- VertexStruct *Vtemp;
-
- if (V -> PAdj == NULL) return NULL;
-
- Vtemp = V -> PAdj -> V;
- do {/* Find the edge on the other polygon to wipe out first. */
- if (Vtemp -> PAdj == Pl) {
- Vtemp -> PAdj = NULL;
- break;
- }
- Vtemp = Vtemp -> Pnext;
- }
- while (Vtemp != NULL && Vtemp != V -> PAdj -> V);
- V -> PAdj = NULL; /* And wipe out ours also... */
- return NULL;
- }
- }
-
- V = Vnext;
- }
- while (V != NULL && V != Pl -> V);
-
- switch (NumOfInter) {
- case 0:
- return NULL;
- case 1:
- /* One intersection is possible if segment intersects one vertex */
- /* of polygon and all other vertices are on same side of segment.*/
- return NULL;
- case 2:
- /* In order the segment to really intersect the polygon, it must */
- /* at list part of t in [0..1] in the polygon. Test it: */
- Min = MIN(TInter[0], TInter[1]);
- Max = MAX(TInter[0], TInter[1]);
- Reverse = TInter[0] > TInter[1];
- if (Min >= 1.0 || APX_EQ(Min, 1.0) ||
- Max <= 0.0 || APX_EQ(Max, 0.0)) return NULL;
-
- PSeg = (InterSegmentStruct *) MyMalloc(sizeof(InterSegmentStruct),
- OTHER_TYPE);
- PSeg -> Pl = SegPl; /* Pointer to other (intersect) polygon. */
-
- /* Handle the Min end point: */
- if (APX_EQ(Min, 0.0)) {
- PtSeg0 = Segment[0];
- PSeg -> V[0] = (Reverse ? VInter[1] : VInter[0]);
- }
- else if (Min < 0.0) {
- PtSeg0 = Segment[0];
- PSeg -> V[0] = NULL; /* End is internal. */
- }
- else { /* Min > 0.0 */
- PtSeg0 = (Reverse ? Inter[1] : Inter[0]);
- PSeg -> V[0] = (Reverse ? VInter[1] : VInter[0]);
- }
-
- /* Handle the Max end point: */
- if (APX_EQ(Max, 1.0)) {
- PtSeg1 = Segment[1];
- PSeg -> V[1] = (Reverse ? VInter[0] : VInter[1]);
- }
- else if (Max > 1.0) {
- PtSeg1 = Segment[1];
- PSeg -> V[1] = NULL; /* End is internal. */
- }
- else { /* Max < 1.0 */
- PtSeg1 = (Reverse ? Inter[0] : Inter[1]);
- PSeg -> V[1] = (Reverse ? VInter[0] : VInter[1]);
- }
-
- PT_COPY(PSeg -> PtSeg[0], PtSeg0); /* The two segment end point. */
- PT_COPY(PSeg -> PtSeg[1], PtSeg1);
-
- for (i=0; i<3; i++) { /* Make zeros look nicer... */
- if (ABS(PSeg -> PtSeg[0][i]) < EPSILON)
- PSeg -> PtSeg[0][i] = 0.0;
- if (ABS(PSeg -> PtSeg[1][i]) < EPSILON)
- PSeg -> PtSeg[1][i] = 0.0;
- }
- if (PT_EQ(PSeg -> PtSeg[0], PSeg -> PtSeg[1])) {
- MyFree((char *) PSeg, OTHER_TYPE);
- return NULL;
- }
- return PSeg;
- }
- return NULL; /* Makes warning silent. */
- }
-
- /*****************************************************************************
- * Given a polygon with the intersection list, create the polylines loop(s) *
- * out of it, which can be one of the two: *
- * 1. Closed loop - all the intersection create a loop in one polygon. *
- * 2. Open polyline - if the intersection crosses the polygon boundary. In *
- * this case the two end point of the polyline, must lay on polygon *
- * boundary. *
- * In both cases, the polyline will be as follows: *
- * First point at first list element at PtSeg[0] (see InterSegmentStruct). *
- * Second point at first list element at PtSeg[1] (see InterSegmentStruct). *
- * Point i at list element (i-1) at PtSeg[0] (PtSeg[1] is not used!). *
- * In the closed loop case the last point is equal to first. *
- * Both cases returns NULL terminated list. *
- *****************************************************************************/
- void LoopsFromInterList(PolygonStruct *Pl,
- InterSegListStruct **PClosed, InterSegListStruct **POpen)
- {
- InterSegmentStruct *PSeg, *PSegHead, *PSegTemp, *PSegNewTemp;
- InterSegListStruct *PSLTemp;
-
- #ifdef DEBUG3
- printf("Enter LoopsFromInterList\n");
- #endif /* DEBUG3 */
-
- *PClosed = (*POpen) = NULL;
-
- if ((PSeg = (InterSegmentStruct *) Pl -> PAux) == NULL) {
- return;
- }
- else {
- /* Do intersect - find if there are closed loops and/or open ones: */
- Pl -> PAux = NULL;
- while (TRUE) {
- /* First, we look for open loops - scans linearly (maybe should */
- /* be done more efficiently) for segment on boundary and start */
- /* build chain from it (up to the other end, on the boundary). */
- PSegHead = PSeg;
- while (PSegHead) {
- if (PSegHead -> V[0] != NULL || PSegHead -> V[1] != NULL) {
- /* Found one - make it in correct order, del. from list: */
- if (PSegHead -> V[0] == NULL) SwapPointInterList(PSegHead);
- DeleteSegInterList(PSegHead, &PSeg);
- break;
- }
- else PSegHead = PSegHead -> Pnext;
- }
- if (PSegHead == NULL) break; /* No more open segments here... */
-
- PSegTemp = PSegHead;
- while (PSegTemp -> V[1] == NULL) {
- /* Search for matching to the second boundary end: */
- PSegNewTemp = FindMatchInterList(PSegTemp -> PtSeg[1], &PSeg);
- PSegTemp -> Pnext = PSegNewTemp;
- PSegTemp = PSegNewTemp;
- }
- PSegTemp -> Pnext = NULL;
- PSLTemp = (InterSegListStruct *)
- MyMalloc(sizeof(InterSegListStruct), OTHER_TYPE);
- PSLTemp -> PISeg = PSegHead;
- PSLTemp -> Pnext = (*POpen);
- *POpen = PSLTemp;
- }
-
- while (TRUE) {
- /* Now, we look for closed loops - pick one segment and search */
- /* for matching until you close the loop. */
- PSegHead = PSeg;
- if (PSegHead == NULL) break; /* No more closed segments here... */
- DeleteSegInterList(PSegHead, &PSeg);
-
- PSegTemp = PSegHead;
- while (!PT_EQ(PSegTemp -> PtSeg[1], PSegHead -> PtSeg[0])) {
- /* Search for matching until we back at first point: */
- PSegNewTemp = FindMatchInterList(PSegTemp -> PtSeg[1], &PSeg);
- PSegTemp -> Pnext = PSegNewTemp;
- PSegTemp = PSegNewTemp;
- }
- PSegTemp -> Pnext = NULL;
- PSLTemp = (InterSegListStruct *)
- MyMalloc(sizeof(InterSegListStruct), OTHER_TYPE);
- PSLTemp -> PISeg = PSegHead;
- PSLTemp -> Pnext = (*PClosed);
- *PClosed = PSLTemp;
- }
- }
-
- #ifdef DEBUG3
- printf("Exit LoopsFromInterList\n");
- #endif /* DEBUG3 */
- }
-
- /*****************************************************************************
- * Swap the two points in the InterSegmentStruct (modifies PtSeg & V entries) *
- *****************************************************************************/
- static void SwapPointInterList(InterSegmentStruct *PSeg)
- {
- PointType Pt;
- VertexStruct *V;
-
- PT_COPY(Pt, PSeg -> PtSeg[0]);
- PT_COPY(PSeg -> PtSeg[0], PSeg -> PtSeg[1]);
- PT_COPY(PSeg -> PtSeg[1], Pt);
-
- V = PSeg -> V[0];
- PSeg -> V[0] = PSeg -> V[1];
- PSeg -> V[1] = V;
- }
-
- /*****************************************************************************
- * Delete one InterSegment PSeg, from InterSegmentList PSegList: *
- *****************************************************************************/
- static void DeleteSegInterList(InterSegmentStruct *PSeg,
- InterSegmentStruct **PSegList)
- {
- InterSegmentStruct *PSegTemp;
-
- if (*PSegList == PSeg) { /* Its the first one - simply advance list ptr: */
- *PSegList = (*PSegList) -> Pnext;
- }
- else {
- PSegTemp = (*PSegList);
- while (PSegTemp -> Pnext != NULL && PSegTemp -> Pnext != PSeg)
- PSegTemp = PSegTemp -> Pnext;
- if (PSegTemp -> Pnext == PSeg)
- PSegTemp -> Pnext = PSegTemp -> Pnext -> Pnext;
- else FatalError("DeleteSegInterList: element to delete not found\n");
- }
- }
-
- /*****************************************************************************
- * Search for matching point, in the given inter segment list. Returns the *
- * pointer to that element after swapping its points if needed (the match *
- * must be with point 0 of new segment returned), and deleting it from list *
- *****************************************************************************/
- static InterSegmentStruct *FindMatchInterList(PointType Pt,
- InterSegmentStruct **PSegList)
- {
- InterSegmentStruct *PSegTemp = (*PSegList);
-
- #ifdef DEBUG3
- printf("Enter FindMatchInterList\n");
- #endif /* DEBUG3 */
-
- while (PSegTemp != NULL) {
- if (PT_EQ(Pt, PSegTemp -> PtSeg[0])) {
- DeleteSegInterList(PSegTemp, PSegList);
- return PSegTemp;
- }
- if (PT_EQ(Pt, PSegTemp -> PtSeg[1])) {
- DeleteSegInterList(PSegTemp, PSegList);
- SwapPointInterList(PSegTemp);
- return PSegTemp;
- }
- PSegTemp = PSegTemp -> Pnext;
- }
-
- FatalError("FindMatchInterList: No match found - Empty Object Result\n");
- return NULL;
- }
-
- /*****************************************************************************
- * Sort the open loops of the given polygon to an order that can be used in *
- * subdividing the polygons later (see comments for ExtractPolygons). *
- * This order is such that each loops will have no other loop between its *
- * end points, if we walk along the polygon in the (linked list direction) *
- * perimeter from one end to the other, before it. For example: *
- * -----------------------------L3 *
- * | ---------------L1 -----L2 | --------L4 --L5 *
- * | | | | | | | | | | *
- * P0 ------ P1 ------- P2 ----- P3 -------- P4 ------ P5 -------- P0 *
- * In this case, any order such that L1, L2 are before L3 will do. Obviously *
- * this is not a total order, and they are few correct ways to sort it. *
- * Algorithm: *
- * For each open loop, for each of its two end, evaluate a RealType key for *
- * the end point P between segment P(i) .. P(i+1) to be i + t, where: *
- * t is the ratio (P - P(i)) / (P(i+1) - P(i)) . This maps the all perimeter *
- * of the polygon onto 0..N-1, where N is number of vertices of that polygon. *
- * Sort the keys, and while they are keys in data sturcture, search and *
- * remove a consecutive pair of keys assosiated with same loop, and output it *
- * Note that each open loop point sequence is tested to be such that it *
- * starts on the first point (first and second along vertex list) on polygon *
- * perimeter, and the sequence end is on the second point, and the sequence *
- * is reversed if not so. This order will make the replacement of the *
- * perimeter from first to second points by the open loop much easier. *
- * This may be real problem if there are two intersection points almost *
- * identical - floating point errors may cause it to loop forever. We use *
- * some reordering heuristics in this case, and return fatal error if fail! *
- *****************************************************************************/
- void SortOpenInterList(PolygonStruct *Pl, InterSegListStruct **POpen)
- {
- int Found = TRUE, ReOrderFirst = FALSE, NumOfReOrders = 0;
- RealType Key1, Key2;
- InterSegmentStruct *PSeg;
- InterSegListStruct *PResHead = NULL, *PResTemp, *PLSeg, *PLNext;
- SortOpenStruct *PSHead = NULL, *PSTemp, *PSTemp1, *PSTemp2;
-
- #ifdef DEBUG3
- printf("Enter SortOpenInterList\n");
- #endif /* DEBUG3 */
-
- PLSeg = (*POpen);
- while (PLSeg != NULL) { /* Evaluate the two end keys and insert them: */
- PSeg = PLSeg -> PISeg;
- PLNext = PLSeg -> Pnext;
- PLSeg -> Pnext = NULL;
-
- PSTemp1 = (SortOpenStruct *) MyMalloc(sizeof(SortOpenStruct),
- OTHER_TYPE);
- PSTemp1 -> PLSeg = PLSeg;
- /* Insert PSTemp1 into PLHead list according to position of Pt in Pl.*/
- Key1 = SortOpenInsertOne(&PSHead, PSTemp1, PSeg -> PtSeg[0],
- PSeg -> V[0], Pl);
-
- while (PSeg -> Pnext != NULL) PSeg = PSeg -> Pnext; /* Go other end. */
- PSTemp2 = (SortOpenStruct *) MyMalloc(sizeof(SortOpenStruct),
- OTHER_TYPE);
- PSTemp2 -> PLSeg = PLSeg;
- /* Insert PSTemp2 into PLHead list according to position of Pt in Pl.*/
- Key2 = SortOpenInsertOne(&PSHead, PSTemp2, PSeg -> PtSeg[1],
- PSeg -> V[1], Pl);
-
- if (Key1 > Key2) /* Reverse the open loop points order: */
- SortOpenReverseLoop(PSTemp1);
-
- PLSeg = PLNext;
- }
-
- while (PSHead != NULL) { /* Search for consecutive pair of same loop. */
- if (NumOfReOrders++ > 10)
- FatalError("SortOpenInterList: fail to sort intersection list\n");
- if (Found) NumOfReOrders = 0;
-
- Found = FALSE;
- PSTemp = PSHead;
- if (PSTemp -> PLSeg == PSTemp -> Pnext -> PLSeg) { /* First is pair! */
- if (PResHead == NULL) PResHead = PResTemp = PSTemp -> PLSeg;
- else {
- PResTemp -> Pnext = PSTemp -> PLSeg;
- PResTemp = PSTemp -> PLSeg;
- }
- PSHead = PSHead -> Pnext -> Pnext; /* Skip the first pair. */
- MyFree((char *) PSTemp -> Pnext, OTHER_TYPE);
- MyFree((char *) PSTemp, OTHER_TYPE);
- Found = TRUE;
- continue;
- }
- /* If we are here, first pair is not of same loop - search on: */
- while (PSTemp -> Pnext -> Pnext != NULL) {
- if (PSTemp -> Pnext -> PLSeg == PSTemp -> Pnext -> Pnext -> PLSeg) {
- if (PResHead == NULL) PResHead = PResTemp =
- PSTemp -> Pnext -> PLSeg;
- else {
- PResTemp -> Pnext = PSTemp -> Pnext -> PLSeg;
- PResTemp = PSTemp -> Pnext -> PLSeg;
- }
- PSTemp2 = PSTemp -> Pnext;
- PSTemp -> Pnext = PSTemp -> Pnext -> Pnext -> Pnext;
- MyFree((char *) PSTemp2 -> Pnext, OTHER_TYPE);
- MyFree((char *) PSTemp2, OTHER_TYPE);
- Found = TRUE;
- break;
- }
- PSTemp = PSTemp -> Pnext;
- }
- /* The only way we might found nothing is in floating point round */
- /* off error - two curve ends has almost the same Key... */
- /* Note, obviously, that there are at list 4 entries in list. */
- if (!Found) {
- if (!ReOrderFirst &&
- APX_EQ(PSHead -> Pnext -> Key, PSHead -> Key)) {
- ReOrderFirst = TRUE;
- PSTemp1 = PSHead -> Pnext;
- PSHead -> Pnext = PSTemp1 -> Pnext;
- PSTemp1 -> Pnext = PSHead;
- PSHead = PSTemp1;
- continue;
- }
- else ReOrderFirst = FALSE;
- PSTemp = PSHead;
- while (PSTemp -> Pnext -> Pnext != NULL) {
- if (APX_EQ(PSTemp -> Pnext -> Key,
- PSTemp -> Pnext -> Pnext -> Key)) {
- PSTemp1 = PSTemp -> Pnext;
- PSTemp2 = PSTemp1 -> Pnext;
- PSTemp1 -> Pnext = PSTemp2 -> Pnext;
- PSTemp2 -> Pnext = PSTemp1;
- PSTemp -> Pnext = PSTemp2;
- break;
- }
- PSTemp = PSTemp -> Pnext;
- }
- }
- }
-
- *POpen = PResHead;
-
- #ifdef DEBUG3
- printf("Exit SortOpenInterList\n");
- #endif /* DEBUG3 */
- }
-
- /*****************************************************************************
- * Reverse the order of the open loop pointed by PSHead. *
- *****************************************************************************/
- static void SortOpenReverseLoop(SortOpenStruct *PSHead)
- {
- InterSegmentStruct *PINewHead = NULL, *PIHead, *PITemp;
-
- PIHead = PSHead -> PLSeg -> PISeg;
-
- while (PIHead != NULL) {
- PITemp = PIHead;
- PIHead = PIHead -> Pnext;
- SwapPointInterList(PITemp);
- PITemp -> Pnext = PINewHead;
- PINewHead = PITemp;
- }
-
- PSHead -> PLSeg -> PISeg = PINewHead;
- }
-
- /*****************************************************************************
- * Insert new loop PSTemp, defines key by Pt and V (V defines the vertex *
- * and P is the points on it), into (decreasing) ordered list PSHead. *
- *****************************************************************************/
- static RealType SortOpenInsertOne(SortOpenStruct **PSHead,
- SortOpenStruct *PSTemp, PointType Pt, VertexStruct *V, PolygonStruct *Pl)
- {
- int i = 0;
- RealType Key;
- PointType Pt1, Pt2;
- VertexStruct *VTemp = Pl -> V;
- SortOpenStruct *PSTail;
-
- PSTemp -> Pnext = NULL;
-
- while (VTemp != V && VTemp != NULL) {
- i++;
- VTemp = VTemp -> Pnext;
- }
- if (VTemp == NULL) FatalError("SortOpenInsertOne: fail to find vertex\n");
-
- PT_SUB(Pt1, V -> Pnext -> Pt, V -> Pt);
- PT_SUB(Pt2, Pt, V -> Pt);
- Key = PSTemp -> Key = i + PT_LENGTH(Pt2) / PT_LENGTH(Pt1);
-
- /* Now insert PSTemp into the ordered list: */
- if (*PSHead == NULL) {
- *PSHead = PSTemp;
- return Key;
- }
- if (PSTemp -> Key > (*PSHead) -> Key) { /* Insert as first? */
- PSTemp -> Pnext = (*PSHead);
- *PSHead = PSTemp;
- return Key;
- }
- PSTail = (*PSHead);
- while (PSTail -> Pnext != NULL && PSTemp -> Key < PSTail -> Pnext -> Key)
- PSTail = PSTail -> Pnext;
- PSTemp -> Pnext = PSTail -> Pnext;
- PSTail -> Pnext = PSTemp;
-
- return Key;
- }
-
- /*****************************************************************************
- * Create a new vertex list, in reverse order. The original is not modified.*
- *****************************************************************************/
- struct VertexStruct *GenReverseVrtxList(VertexStruct *VIn)
- {
- VertexStruct *VOutHead, *VOut;
-
- VOutHead = AllocVertex(0, 0, NULL, NULL);
-
- PT_COPY(VOutHead -> Pt, VIn -> Pt);
- VIn = VIn -> Pnext;
-
- while (VIn != NULL) {
- VOut = AllocVertex(0, 0, NULL, NULL);
- PT_COPY(VOut -> Pt, VIn -> Pt);
-
- VOut -> Pnext = VOutHead; /* Chain them in reverse order. */
- VOutHead = VOut;
-
- VIn = VIn -> Pnext;
- }
-
- return VOutHead;
- }
-
- #ifdef DEBUG2
-
- /*****************************************************************************
- * Print the content of the given polygon, to standard output. *
- *****************************************************************************/
- static void PrintVrtxList(VertexStruct *V)
- {
- struct VertexStruct *VHead = V;
-
- do {
- printf(" %12lf %12lf %12lf\n", V -> Pt[0], V -> Pt[1], V -> Pt[2]);
- V = V -> Pnext;
- }
- while (V!= NULL && V != VHead);
- }
-
- /*****************************************************************************
- * Print the content of the given InterSegment list, to standard output. *
- *****************************************************************************/
- static void PrintInterList(InterSegmentStruct *PInt)
- {
- printf("INTER SEGMENT LIST:\n");
-
- if (PInt) printf("Entry vertex pointer %p\n", PInt -> V[0]);
- while (PInt) {
- printf("%9lg %9lg %9lg (%04x), %9lg %9lg %9lg (%04x)\n",
- PInt->PtSeg[0][0], PInt->PtSeg[0][1], PInt->PtSeg[0][2],
- #ifdef __MSDOS__
- FP_SEG(PInt->V[0]),
- #else
- PInt->V[0],
- #endif /* __MSDOS__ */
- PInt->PtSeg[1][0], PInt->PtSeg[1][1], PInt->PtSeg[1][2],
- #ifdef __MSDOS__
- FP_SEG(PInt->V[1]));
- #else
- PInt->V[1]);
- #endif /* __MSDOS__ */
- if (PInt -> Pnext == NULL)
- printf("Exit vertex pointer %p\n", PInt -> V[1]);
-
- PInt = PInt -> Pnext;
- }
- }
-
- #endif /* DEBUG2 */
-