function &boolean(&$polyB, $oper) { $last = NULL; $s = $this->first; // First vertex of the subject polygon $c = $polyB->getFirst(); // First vertex of the "clip" polygon /* * * Phase 1 of the algoritm is to find all intersection points between the two * * polygons. A new Vertex is created for each intersection and it is added to * * the linked lists for both polygons. The "neighbor" reference in each vertex * * stores the link between the same intersection point in each polygon. */ do { if (!$s->isIntersect()) { do { if (!$c->isIntersect()) { if ($this->ints($s, $this->nxt($s->Next()), $c, $polyB->nxt($c->Next()), $n, $ix, $iy, $alphaS, $alphaC)) { for ($i = 0; $i < $n; $i++) { $is = new Vertex($ix[$i], $iy[$i], $s->Xc(), $s->Yc(), $s->d(), NULL, NULL, NULL, TRUE, NULL, $alphaS[$i], FALSE, FALSE); $ic = new Vertex($ix[$i], $iy[$i], $c->Xc(), $c->Yc(), $c->d(), NULL, NULL, NULL, TRUE, NULL, $alphaC[$i], FALSE, FALSE); $is->setNeighbor($ic); $ic->setNeighbor($is); $this->insertSort($is, $s, $this->nxt($s->Next())); $polyB->insertSort($ic, $c, $polyB->nxt($c->Next())); } } } // end if $c is not an intersect point $c = $c->Next(); } while ($c->id() != $polyB->first->id()); } // end if $s not an intersect point $s = $s->Next(); } while ($s->id() != $this->first->id()); /* * * Phase 2 of the algorithm is to identify every intersection point as an * * entry or exit point to the other polygon. This will set the entry bits * * in each vertex object. * * * * What is really stored in the entry record for each intersection is the * * direction the algorithm should take when it arrives at that entry point. * * Depending in the operation requested (A&B, A|B, A/B, B/A) the direction is * * set as follows for entry points (f=foreward, b=Back), exit poits are always set * * to the opposite: * * Enter Exit * * A B A B * * A|B b b f f * * A&B f f b b * * A\B b f f b * * B\A f b b f * * * * f = TRUE, b = FALSE when stored in the entry record */ switch ($oper) { case "A|B": $A = FALSE; $B = FALSE; break; case "A&B": $A = TRUE; $B = TRUE; break; case "A\\B": $A = FALSE; $B = TRUE; break; case "B\\A": $A = TRUE; $B = FALSE; break; default: $A = TRUE; $B = TRUE; break; } $s = $this->first; if ($polyB->isInside($s)) { // if we are already inside $entry = !$A; } else { // otherwise $entry = $A; } // next intersection must be an entry do { if ($s->isIntersect()) { $s->setEntry($entry); $entry = !$entry; } $s = $s->Next(); } while ($s->id() != $this->first->id()); /* * * Repeat for other polygon */ $c = $polyB->first; if ($this->isInside($c)) { // if we are already inside $entry = !$B; } else { // otherwise $entry = $B; } // next intersection must be an entry do { if ($c->isIntersect()) { $c->setEntry($entry); $entry = !$entry; } $c = $c->Next(); } while ($c->id() != $polyB->first->id()); /* * * Phase 3 of the algorithm is to scan the linked lists of the * * two input polygons an construct a linked list of result * * polygons. We start at the first intersection then depending * * on whether it is an entry or exit point we continue building * * our result polygon by following the source or clip polygon * * either forwards or backwards. */ while ($this->unckd_remain()) { $v = $this->first_unckd_intersect(); // Get the first unchecked intersect point $this_class = get_class($this); // Findout the class I'm in $r = new $this_class(); // Create a new instance of that class do { $v->setChecked(); // Set checked flag true for this intersection if ($v->isEntry()) { do { $v = $v->Next(); $nv = new Vertex($v->X(), $v->Y(), $v->Xc(), $v->Yc(), $v->d()); $r->add($nv); } while (!$v->isIntersect()); } else { do { $v = $v->Prev(); $nv = new Vertex($v->X(), $v->Y(), $v->Xc(FALSE), $v->Yc(FALSE), $v->d(FALSE)); $r->add($nv); } while (!$v->isIntersect()); } $v = $v->Neighbor(); } while (!$v->isChecked()); // until polygon closed if ($last) { // Check in case first time thru the loop $r->first->setNextPoly($last); } // Save ref to the last poly in the first vertex // of this poly $last = $r; // Save this polygon } // end of while there is another intersection to check /* * * Clean up the input polygons by deleting the intersection points */ $this->res(); $polyB->res(); /* * * It is possible that no intersection between the polygons was found and * * there is no result to return. In this case we make function fail * * gracefully as follows (depending on the requested operation): * * * * A|B : Return $this with $polyB in $this->first->nextPoly * * A&B : Return $this * * A\B : Return $this * * B\A : return $polyB */ if (!$last) { switch ($oper) { case "A|B": $last = $this->copy_poly(); $p = $polyB->copy_poly(); $last->first->setNextPoly($p); break; case "A&B": $last = $this->copy_poly(); break; case "A\\B": $last = $this->copy_poly(); break; case "B\\A": $last = $polyB->copy_poly(); break; default: $last = $this->copy_poly(); break; } } elseif ($this->first->nextPoly) { $last->first->nextPoly = $this->first->NextPoly(); } return $last; }