Example #1
0
 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;
 }