Advertisement
Blade83

poligon.class.php

Nov 27th, 2013
300
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 37.68 KB | None | 0 0
  1. <?php
  2. /*------------------------------------------------------------------------------
  3. ** File:        polygon.class.php
  4. ** Description:     PHP class for a polygon.
  5. ** Version:     1.6
  6. ** Author:      Blade83
  7. ** Email:       johannes_kraemer@gmx.de
  8. **------------------------------------------------------------------------------
  9. ** COPYRIGHT (c) 2008-2013 JOHANNES KRÄMER
  10. **
  11. ** The source code included in this package is free software; you can
  12. ** redistribute it and/or modify it under the terms of the GNU General Public
  13. ** License as published by the Free Software Foundation. This license can be
  14. ** read at:
  15. **
  16. ** http://www.opensource.org/licenses/gpl-license.php
  17. **
  18. **------------------------------------------------------------------------------
  19. */
  20. define ("infinity", 100000000);
  21. require('vertex.class.php');
  22.  
  23. class polygon
  24. {
  25.     public
  26.         $first,
  27.         $cnt;
  28.     /*
  29.     ** Construct a new shiny polygon
  30.     */
  31.     function polygon ($first = NULL){
  32.         $this->first = $first;
  33.         $this->cnt = 0;}
  34.     /*
  35.     ** Get the first vertex
  36.     */
  37.     function &getFirst (){
  38.         return $this->first;}
  39.     /*
  40.     ** Return the next polygon
  41.     */
  42.     function &NextPoly() {
  43.         return $this->first->NextPoly(); }
  44.     /*
  45.     ** Print out main variables of the polygon for debugging
  46.     */
  47.     function print_poly()
  48.     {
  49.         print("Polygon:<br>");
  50.         $c =& $this->first;
  51.         do
  52.         {
  53.             $c->print_vertex();
  54.             $c =& $c->Next();
  55.         }
  56.         while ($c->id() != $this->first->id());
  57.         if ($this->first->nextPoly)
  58.         {
  59.             print("Next Polygon:<br>");
  60.             $this->first->nextPoly->print_poly();
  61.         }
  62.     }
  63.     /*
  64.     ** Add a vertex object to the polygon (vertex is added at the "end" of the list)
  65.     ** Which because polygons are closed lists means it is added just before the first
  66.     ** vertex.
  67.     */
  68.     function add (&$nv)
  69.     {
  70.         if ($this->cnt == 0)                // If this is the first vertex in the polygon
  71.         {
  72.             $this->first =& $nv;            // Save a reference to it in the polygon
  73.             $this->first->setNext($nv);     // Set its pointer to point to itself
  74.             $this->first->setPrev($nv);     // because it is the only vertex in the list
  75.             $ps =& $this->first->Nseg();    // Get ref to the Next segment object
  76.             $this->first->setPseg($ps);     // and save it as Prev segment as well
  77.         }
  78.         else                                // At least one other vertex already exists
  79.         {
  80.             // $p <-> $nv <-> $n
  81.             //    $ps     $ns
  82.             $n =& $this->first;             // Get a ref to the first vertex in the list
  83.             $p =& $n->Prev();               // Get ref to previous vertex
  84.             $n->setPrev($nv);               // Add at end of list (just before first)
  85.             $nv->setNext($n);               // link the new vertex to it
  86.             $nv->setPrev($p);               // link to the pervious EOL vertex
  87.             $p->setNext($nv);               // And finally link the previous EOL vertex
  88.             // Segments
  89.             $ns =& $nv->Nseg();             // Get ref to the new next segment
  90.             $ps =& $p->Nseg();              // Get ref to the previous segment
  91.             $n->setPseg($ns);               // Set new previous seg for $this->first
  92.             $nv->setPseg($ps);              // Set previous seg of the new vertex
  93.         }
  94.         $this->cnt++;                       // Increment the count of vertices
  95.     }
  96.     /*
  97.     ** Create a vertex and then add it to the polygon
  98.     */
  99.     function addv ($x, $y, $xc=0, $yc=0, $d=0)
  100.     {
  101.         $nv =& new vertex($x, $y, $xc, $yc, $d);
  102.         $this->add($nv);
  103.     }
  104.     /*
  105.     ** Delete a vertex object from the polygon. This is not used by the main algorithm
  106.     ** but instead is used to clean-up a polygon so that a second boolean operation can
  107.     ** be performed.
  108.     */
  109.     function &del (&$v)
  110.     {
  111.         // $p <-> $v <-> $n                Will delete $v and $ns
  112.         //    $ps    $ns
  113.         $p =& $v->Prev();               // Get ref to previous vertex
  114.         $n =& $v->Next();               // Get ref to next vertex
  115.         $p->setNext($n);                // Link previous forward to next
  116.         $n->setPrev($p);                // Link next back to previous
  117.         // Segments
  118.         $ps =& $p->Nseg();              // Get ref to previous segment
  119.         $ns =& $v->Nseg();              // Get ref to next segment
  120.         $n->setPseg($ps);               // Link next back to previous segment
  121.         $ns = NULL; $v = NULL;          // Free the memory
  122.         $this->cnt--;                   // One less vertex
  123.         return $n;                      // Return a ref to the next valid vertex
  124.     }
  125.     /*
  126.     ** Reset Polygon - Deletes all intersection vertices. This is used to
  127.     ** restore a polygon that has been processed by the boolean method
  128.     ** so that it can be processed again.
  129.     */
  130.     function res ()
  131.     {
  132.         $v =& $this->getFirst();        // Get the first vertex
  133.         do
  134.         {
  135.             $v =& $v->Next();       // Get the next vertex in the polygon
  136.             while ($v->isIntersect())   // Delete all intersection vertices
  137.                 $v =& $this->del($v);
  138.         }
  139.         while ($v->id() != $this->first->id());
  140.     }
  141.     /*
  142.     ** Copy Polygon - Returns a reference to a new copy of the poly object
  143.     ** including all its vertices & their segments
  144.     */
  145.     function &copy_poly ()
  146.     {
  147.         $this_class = get_class($this);         // Findout the class I'm in
  148.         $n =& new $this_class;;     // Create a new instance of this class
  149.         $v =& $this->getFirst();
  150.         do
  151.         {
  152.             $n->addv($v->X(),$v->Y(),$v->Xc(),$v->Yc(),$v->d());
  153.             $v =& $v->Next();
  154.         }
  155.         while ($v->id() != $this->first->id());
  156.         return $n;
  157.     }
  158.  
  159.     /*
  160.     ** Insert and Sort a vertex between a specified pair of vertices (start and end)
  161.     **
  162.     ** This function inserts a vertex (most likely an intersection point) between two
  163.     ** other vertices. These other vertices cannot be intersections (that is they must
  164.     ** be actual vertices of the original polygon). If there are multiple intersection
  165.     ** points between the two vertices then the new vertex is inserted based on its
  166.     ** alpha value.
  167.     */
  168.     function insertSort (&$nv, &$s, &$e)
  169.     {
  170.         $c =& $s;                       // Set current to the sarting vertex
  171.         while ($c->id() != $e->id()  && $c->Alpha() < $nv->Alpha())
  172.             $c =& $c->Next();       // Move current past any intersections
  173.                                         // whose alpha is lower but don't go past
  174.                                         // the end vertex
  175.         // $p <-> $nv <-> $c
  176.         $nv->setNext($c);               // Link new vertex forward to curent one
  177.         $p =& $c->Prev();               // Get a link to the previous vertex
  178.         $nv->setPrev($p);               // Link the new vertex back to the previous one
  179.         $p->setNext($nv);               // Link previous vertex forward to new vertex
  180.         $c->setPrev($nv);               // Link current vertex back to the new vertex
  181.         // Segments
  182.         $ps =& $p->Nseg();
  183.         $nv->setPseg($ps);
  184.         $ns =& $nv->Nseg();
  185.         $c->setPseg($ns);
  186.         $this->cnt++;                   // Just added a new vertex
  187.     }
  188.     /*
  189.     ** return the next non intersecting vertex after the one specified
  190.     */
  191.     function &nxt (&$v)
  192.     {
  193.         $c =& $v;                       // Initialize current vertex
  194.         while ($c && $c->isIntersect()) // Move until a non-intersection
  195.             $c =& $c->Next();       // vertex if found     
  196.         return $c;                      // return that vertex
  197.     }
  198.     /*
  199.     ** Check if any unchecked intersections remain in the polygon. The boolean
  200.     ** method is complete when all intersections have been checked.
  201.     */
  202.     function unckd_remain ()
  203.     {
  204.         $remain = FALSE;
  205.         $v =& $this->first;
  206.         do
  207.         {
  208.             if ($v->isIntersect() && !$v->isChecked())
  209.                 $remain = TRUE;     // Set if an unchecked intersection is found
  210.             $v =& $v->Next();
  211.         }
  212.         while ($v->id() != $this->first->id());
  213.         return $remain;
  214.     }
  215.     /*
  216.     ** Return a ref to the first unchecked intersection point in the polygon.
  217.     ** If none are found then just the first vertex is returned.
  218.     */
  219.     function &first_unckd_intersect ()
  220.     {
  221.         $v =& $this->first;
  222.         do                                  // Do-While
  223.         {                                   // Not yet reached end of the polygon
  224.             $v =& $v->Next();           // AND the vertex if NOT an intersection
  225.         }                                   // OR it IS an intersection, but has been checked already
  226.         while($v->id() != $this->first->id() && ( !$v->isIntersect() || ( $v->isIntersect() && $v->isChecked() ) ) );
  227.         return $v;
  228.     }
  229.     /*
  230.     ** Return the distance between two points
  231.     */
  232.     function dist ($x1, $y1, $x2, $y2){
  233.         return sqrt(($x1-$x2)*($x1-$x2) + ($y1-$y2)*($y1-$y2));}
  234.     /*
  235.     ** Calculate the angle between 2 points, where Xc,Yc is the center of a circle
  236.     ** and x,y is a point on its circumference. All angles are relative to
  237.     ** the 3 O'Clock position. Result returned in radians
  238.     */
  239.     function angle ($xc, $yc, $x1, $y1)
  240.     {
  241.         $d = $this->dist($xc, $yc, $x1, $y1); // calc distance between two points
  242.         if ($d != 0)
  243.             if ( asin( ($y1-$yc)/$d ) >= 0 )
  244.                 $a1 = acos( ($x1-$xc)/$d );
  245.             else
  246.                 $a1 = 2*pi() - acos( ($x1-$xc)/$d );
  247.         else
  248.             $a1 = 0;
  249.         return $a1;
  250.     }
  251.     /*
  252.     ** Return Alpha value for an Arc
  253.     **
  254.     ** X1/Y1 & X2/Y2 are the end points of the arc, Xc/Yc is the center & Xi/Yi
  255.     ** the intersection point on the arc. $d is the direction of the arc
  256.     */
  257.     function aAlpha ($x1, $y1, $x2, $y2, $xc, $yc, $xi, $yi, $d)
  258.     {
  259.         $sa = $this->angle($xc, $yc, $x1, $y1); // Start Angle
  260.         $ea = $this->angle($xc, $yc, $x2, $y2); // End Angle
  261.         $ia = $this->angle($xc, $yc, $xi, $yi); // Intersection Angle
  262.         if ($d == 1)    // Anti-Clockwise
  263.         {
  264.             $arc = $ea - $sa;
  265.             $int = $ia - $sa;
  266.         }
  267.         else            // Clockwise
  268.         {
  269.             $arc = $sa - $ea;
  270.             $int = $sa - $ia;
  271.         }
  272.         if ($arc < 0) $arc += 2*pi();
  273.         if ($int < 0) $int += 2*pi();
  274.         $a = $int/$arc;
  275.         return  $a;
  276.     }
  277.     /*
  278.     ** This function handles the degenerate case where a vertex of one
  279.     ** polygon lies directly on an edge of the other. This case can
  280.     ** also occur during the isInside() function, where the search
  281.     ** line exactly intersects with a vertex. The function works
  282.     ** by shortening the line by a tiny amount.
  283.     **
  284.     ** Revision 1.4 Completely new perturb function. The old version was
  285.     ** simply wrong, I'm amazed it took so long to show up as a problem.
  286.     */
  287.     function perturb (&$p1, &$p2, &$q1, &$q2, $aP, $aQ)
  288.     {
  289.         $PT = 0.00001;      // Perturbation factor
  290.         if ($aP == 0)       // q1,q2 intersects p1 exactly, move vertex p1 closer to p2
  291.         {
  292.             $h = $this->dist($p1->X(),$p1->Y(),$p2->X(),$p2->Y());
  293.             $a = ($PT * $this->dist($p1->X(),$p1->Y(),$p2->X(),$p1->Y()))/$h;
  294.             $b = ($PT * $this->dist($p2->X(),$p2->Y(),$p2->X(),$p1->Y()))/$h;
  295.             $p1->setX($p1->X() + $a);
  296.             $p1->setY($p1->Y() + $b);
  297.         }
  298.         elseif ($aP == 1)   // q1,q2 intersects p2 exactly, move vertex p2 closer to p1
  299.         {
  300.             $h = $this->dist($p1->X(),$p1->Y(),$p2->X(),$p2->Y());
  301.             $a = ($PT * $this->dist($p1->X(),$p1->Y(),$p2->X(),$p1->Y()))/$h;
  302.             $b = ($PT * $this->dist($p2->X(),$p2->Y(),$p2->X(),$p1->Y()))/$h;
  303.             $p2->setX($p2->X() - $a);
  304.             $p2->setY($p2->Y() - $b);
  305.         }
  306.         elseif ($aQ == 0)   // p1,p2 intersects q1 exactly, move vertex q1 closer to q2
  307.         {
  308.             $h = $this->dist($q1->X(),$q1->Y(),$q2->X(),$q2->Y());
  309.             $a = ($PT * $this->dist($q1->X(),$q1->Y(),$q2->X(),$q1->Y()))/$h;
  310.             $b = ($PT * $this->dist($q2->X(),$q2->Y(),$q2->X(),$q1->Y()))/$h;
  311.             $q1->setX($q1->X() + $a);
  312.             $q1->setY($q1->Y() + $b);
  313.         }
  314.         elseif ($aQ == 1)   // p1,p2 intersects q2 exactly, move vertex q2 closer to q1
  315.         {
  316.             $h = $this->dist($q1->X(),$q1->Y(),$q2->X(),$q2->Y());
  317.             $a = ($PT * $this->dist($q1->X(),$q1->Y(),$q2->X(),$q1->Y()))/$h;
  318.             $b = ($PT * $this->dist($q2->X(),$q2->Y(),$q2->X(),$q1->Y()))/$h;
  319.             $q2->setX($q2->X() - $a);
  320.             $q2->setY($q2->Y() - $b);
  321.         }
  322.     }
  323.     /*
  324.     ** Determine the intersection between two pairs of vertices p1/p2, q1/q2
  325.     **
  326.     ** Either or both of the segments passed to this function could be arcs.
  327.     ** Thus we must first determine if the intersection is line/line, arc/line
  328.     ** or arc/arc. Then apply the correct math to calculate the intersection(s).
  329.     **
  330.     ** Line/Line can have 0 (no intersection) or 1 intersection
  331.     ** Line/Arc and Arc/Arc can have 0, 1 or 2 intersections
  332.     **
  333.     ** The function returns TRUE is any intersections are found
  334.     ** The number found is returned in $n
  335.     ** The arrays $ix[], $iy[], $alphaP[] & $alphaQ[] return the intersection points
  336.     ** and their associated alpha values.
  337.     */
  338.     function ints (&$p1, &$p2, &$q1, &$q2, &$n, &$ix, &$iy, &$alphaP, &$alphaQ)
  339.     {
  340.  
  341.         $found = FALSE; $n = 0;                         // No intersections found yet
  342.         $pt = $p1->d(); $qt = $q1->d(); // Do we have Arcs or Lines?
  343.  
  344.         if ($pt == 0 && $qt == 0) // Is it line/Line ?
  345.         {
  346.         /* LINE/LINE
  347.         ** Algorithm from: http://astronomy.swin.edu.au/~pbourke/geometry/lineline2d/
  348.         */
  349.             $x1 = $p1->X(); $y1 = $p1->Y();
  350.             $x2 = $p2->X(); $y2 = $p2->Y();
  351.             $x3 = $q1->X(); $y3 = $q1->Y();
  352.             $x4 = $q2->X(); $y4 = $q2->Y();
  353.             $d = (($y4-$y3)*($x2-$x1)-($x4-$x3)*($y2-$y1));
  354.             if ($d != 0)
  355.             { // The lines intersect at a point somewhere
  356.                 $ua = (($x4-$x3)*($y1-$y3)-($y4-$y3)*($x1-$x3))/$d;
  357.                 $ub = (($x2-$x1)*($y1-$y3)-($y2-$y1)*($x1-$x3))/$d;
  358.         // The values of $ua and $ub tell us where the intersection occurred.
  359.         // A value between 0 and 1 means the intersection occurred within the
  360.         // line segment.
  361.         // A value less tha 0 or greater than 1 means the intersection occurred
  362.         // outside the line segment
  363.         // A value of exactly 0 or 1 means the intersection occurred right at the
  364.         // start or end of the line segment. For our purposes we will consider this
  365.         // NOT to be an intersection and we will move the vertex a tiny distance
  366.         // away from the intersecting line.
  367.                 if ( (($ua==0 || $ua==1 )&&($ub>=0 && $ub<=1)) || (($ub==0 || $ub==1)&&($ua>=0 && $ua<=1)))
  368.                 { // Degenerate case - vertex exactly touches a line
  369. //                  print("Perturb: P(".$p1->X().",".$p1->Y().")(".$p2->X().",".$p2->Y().") Q(".$q1->X().",".$q1->Y().")(".$q2->X().",".$q2->Y().") UA(".$ua.") UB(".$ub.")<br>");
  370.                     $this->perturb($p1, $p2, $q1, $q2, $ua, $ub);
  371.                     $found = FALSE;
  372.                 }
  373.                 elseif (($ua > 0 && $ua < 1) && ($ub > 0 && $ub < 1))
  374.                 { // Intersection occurs on both line segments
  375.                     $x = $x1 + $ua*($x2-$x1);
  376.                     $y = $y1 + $ua*($y2-$y1);
  377.                     $iy[0] = $y; $ix[0] = $x;
  378.                     $alphaP[0] = $ua; $alphaQ[0] = $ub;
  379.                     $n = 1; $found = TRUE;
  380.                 }
  381.                 else
  382.                 { // The lines do not intersect within the line segments
  383.                     $found = FALSE;
  384.                 }
  385.             }
  386.             else
  387.             { // The lines do not intersect
  388.                 $found = FALSE;
  389.             }
  390.         }   // End of find Line/Line intersection
  391.         elseif ($pt != 0 && $qt != 0)   // Is  it Arc/Arc?
  392.         {
  393.         /* ARC/ARC
  394.         ** Algorithm from: http://astronomy.swin.edu.au/~pbourke/geometry/2circle/
  395.         */
  396.             $x0 = $p1->Xc(); $y0 = $p1->Yc(); // Center of first Arc
  397.             $r0 = $this->dist($x0,$y0,$p1->X(),$p1->Y());   // Calc the radius
  398.             $x1 = $q1->Xc(); $y1 = $q1->Yc(); // Center of second Arc
  399.             $r1 = $this->dist($x1,$y1,$q1->X(),$q1->Y());   // Calc the radius
  400.  
  401.             $dx = $x1 - $x0;    // dx and dy are the vertical and horizontal
  402.             $dy = $y1 - $y0;    // distances between the circle centers.
  403.             $d = sqrt(($dy*$dy) + ($dx*$dx)); // Distance between the centers.
  404.  
  405.             if ($d == 0)        // Don't try an find intersection if centers are the same.
  406.             {                   // Added in Rev 1.2
  407.                 $found = FALSE;
  408.             }
  409.             elseif ($d > ($r0 + $r1))       // Check for solvability.
  410.             {                               // no solution. circles do not intersect.
  411.                 $found = FALSE;
  412.             }
  413.             elseif ($d < abs($r0 - $r1))
  414.             {                           // no solution. one circle inside the other
  415.                 $found = FALSE;
  416.             }
  417.             else
  418.             {
  419.                 /*
  420.                 ** 'xy2' is the point where the line through the circle intersection
  421.                 ** points crosses the line between the circle centers.  
  422.                 */
  423.                 $a = (($r0*$r0)-($r1*$r1)+($d*$d))/(2.0*$d); // Calc the distance from xy0 to xy2.
  424.                 $x2 = $x0 + ($dx * $a/$d);      // Determine the coordinates of xy2.
  425.                 $y2 = $y0 + ($dy * $a/$d);
  426.                 if ($d == ($r0 + $r1)) // Arcs touch at xy2 exactly (unlikely)
  427.                 {
  428.                     $alphaP[0] = $this->aAlpha($p1->X(), $p1->Y(), $p2->X(), $p2->Y(), $x0, $y0, $x2, $y2, $pt);
  429.                     $alphaQ[0] = $this->aAlpha($q1->X(), $q1->Y(), $q2->X(), $q2->Y(), $x1, $y1, $x2, $y2, $qt);
  430.                     if (($alphaP[0] >0 && $alphaP[0] < 1) && ($alphaQ[0] >0 && $alphaQ[0] < 1))
  431.                     {
  432.                         $ix[0] = $x2;
  433.                         $iy[0] = $y2;
  434.                         $n = 1; $found = TRUE;
  435.                     }
  436.                 }
  437.                 else                    // Arcs intersect at two points
  438.                 {
  439.                     $h = sqrt(($r0*$r0) - ($a*$a)); // Calc the distance from xy2 to either
  440.                                                     // of the intersection points.
  441.                     $rx = -$dy * ($h/$d);   // Now determine the offsets of the
  442.                     $ry =  $dx * ($h/$d);   // intersection points from xy2
  443.                     $x[0] = $x2 + $rx; $x[1] = $x2 - $rx;       // Calc the absolute intersection points.
  444.                     $y[0] = $y2 + $ry; $y[1] = $y2 - $ry;
  445.                     $alP[0] = $this->aAlpha($p1->X(), $p1->Y(), $p2->X(), $p2->Y(), $x0, $y0, $x[0], $y[0], $pt);
  446.                     $alQ[0] = $this->aAlpha($q1->X(), $q1->Y(), $q2->X(), $q2->Y(), $x1, $y1, $x[0], $y[0], $qt);
  447.                     $alP[1] = $this->aAlpha($p1->X(), $p1->Y(), $p2->X(), $p2->Y(), $x0, $y0, $x[1], $y[1], $pt);
  448.                     $alQ[1] = $this->aAlpha($q1->X(), $q1->Y(), $q2->X(), $q2->Y(), $x1, $y1, $x[1], $y[1], $qt);
  449.                     for ($i=0; $i<=1; $i++)
  450.                         if (($alP[$i] >0 && $alP[$i] < 1) && ($alQ[$i] >0 && $alQ[$i] < 1))
  451.                         {
  452.                             $ix[$n] = $x[$i]; $iy[$n] = $y[$i];
  453.                             $alphaP[$n] = $alP[$i]; $alphaQ[$n] = $alQ[$i];
  454.                             $n++; $found = TRUE;
  455.                         }
  456.                 }
  457.             }
  458.         }   // End of find Arc/Arc intersection
  459.         else    // It must be Arc/Line
  460.         {
  461.         /* ARC/LINE
  462.         ** Algorithm from: http://astronomy.swin.edu.au/~pbourke/geometry/sphereline/
  463.         */
  464.             if ($pt == 0)   // Segment p1,p2 is the line
  465.             {               // Segment q1,q2 is the arc
  466.                 $x1 = $p1->X(); $y1 = $p1->Y();
  467.                 $x2 = $p2->X(); $y2 = $p2->Y();
  468.                 $xc = $q1->Xc(); $yc = $q1->Yc();
  469.                 $xs = $q1->X(); $ys = $q1->Y();
  470.                 $xe = $q2->X(); $ye = $q2->Y();
  471.                 $d = $qt;
  472.             }
  473.             else            // Segment q1,q2 is the line
  474.             {               // Segment p1,p2 is the arc
  475.                 $x1 = $q1->X(); $y1 = $q1->Y();
  476.                 $x2 = $q2->X(); $y2 = $q2->Y();
  477.                 $xc = $p1->Xc(); $yc = $p1->Yc();
  478.                 $xs = $p1->X(); $ys = $p1->Y();
  479.                 $xe = $p2->X(); $ye = $p2->Y();
  480.                 $d = $pt;
  481.             }
  482.             $r = $this->dist($xc,$yc,$xs,$ys);
  483.             $a = pow(($x2 - $x1),2)+pow(($y2 - $y1),2);
  484.             $b = 2* ( ($x2 - $x1)*($x1 - $xc)
  485.                     + ($y2 - $y1)*($y1 - $yc) );
  486.             $c = pow($xc,2) + pow($yc,2) +
  487.                  pow($x1,2) + pow($y1,2) -
  488.                 2* ( $xc*$x1 + $yc*$y1) - pow($r,2);
  489.             $i =   $b * $b - 4 * $a * $c;
  490.             if ( $i < 0.0 ) // no intersection
  491.             {
  492.                 $found = FALSE;
  493.             }
  494.             elseif ( $i == 0.0 )    // one intersection
  495.             {
  496.                 if ($a != 0)
  497.                    $mu = -$b/(2*$a);
  498.                 $x = $x1 + $mu*($x2-$x1);
  499.                 $y = $y1 + $mu*($y2-$y1);
  500.                 $al = $mu; // Line Alpha
  501.                 $aa = $this->aAlpha($xs, $ys, $xe, $ye, $xc, $yc, $x, $y, $d); // Arc Alpha
  502.                 if (($al >0 && $al <1)&&($aa >0 && $aa <1))
  503.                 {
  504.                     $ix[0] = $x; $iy[0] = $y;
  505.                     $n = 1; $found = TRUE;
  506.                     if ($pt == 0)
  507.                     {
  508.                         $alphaP[0] = $al; $alphaQ[0] = $aa;
  509.                     }
  510.                     else
  511.                     {
  512.                         $alphaP[0] = $aa; $alphaQ[0] = $al;
  513.                     }
  514.                 }
  515.             }
  516.             elseif ( $i > 0.0 )     // two intersections
  517.             {
  518.                 if ($a != 0)
  519.                    $mu[0] = (-$b + sqrt( pow($b,2) - 4*$a*$c )) / (2*$a);   // first intersection
  520.                 $x[0] = $x1 + $mu[0]*($x2-$x1);
  521.                 $y[0] = $y1 + $mu[0]*($y2-$y1);
  522.                 if ($a != 0)
  523.                    $mu[1] = (-$b - sqrt(pow($b,2) - 4*$a*$c )) / (2*$a); // second intersection
  524.                 $x[1] = $x1 + $mu[1]*($x2-$x1);
  525.                 $y[1] = $y1 + $mu[1]*($y2-$y1);
  526.                 $al[0] = $mu[0];
  527.                 $aa[0] = $this->aAlpha($xs, $ys, $xe, $ye, $xc, $yc, $x[0], $y[0], $d);
  528.                 $al[1] = $mu[1];
  529.                 $aa[1] = $this->aAlpha($xs, $ys, $xe, $ye, $xc, $yc, $x[1], $y[1], $d);
  530.                 for ($i=0; $i<=1; $i++)
  531.                     if (($al[$i] >0 && $al[$i] < 1) && ($aa[$i] >0 && $aa[$i] < 1))
  532.                     {
  533.                         $ix[$n] = $x[$i]; $iy[$n] = $y[$i];
  534.                         if ($pt == 0)
  535.                         {
  536.                             $alphaP[$n] = $al[$i]; $alphaQ[$n] = $aa[$i];
  537.                         }
  538.                         else
  539.                         {
  540.                             $alphaP[$n] = $aa[$i]; $alphaQ[$n] = $al[$i];
  541.                         }
  542.                         $n++; $found = TRUE;
  543.                     }
  544.             }
  545.         }   // End of find Arc/Line intersection
  546.         return $found;
  547.     } // end of intersect function
  548.     /*
  549.     ** Test if a vertex lies inside the polygon
  550.     **
  551.     ** This function calculates the "winding" number for the point. This number
  552.     ** represents the number of times a ray emitted from the point to infinity
  553.     ** intersects any edge of the polygon. An even winding number means the point
  554.     ** lies OUTSIDE the polygon, an odd number means it lies INSIDE it.
  555.     **
  556.     ** Right now infinity is set to -10000000, some people might argue that infinity
  557.     ** actually is a bit bigger. Those people have no lives.
  558.     */
  559.     function isInside (&$v)
  560.     {
  561.         $winding_number = 0;
  562.         $point_at_infinity =& new vertex(-10000000,$v->Y());    // Create point at infinity
  563.         $q =& $this->first;     // End vertex of a line segment in polygon
  564.         do
  565.         {
  566.             if (!$q->isIntersect())
  567.             {
  568.                 if ($this->ints($point_at_infinity, $v, $q, $this->nxt($q->Next()), $n, $x, $y, $aP, $aQ))
  569.                     $winding_number += $n;      // Add number of intersections found
  570.             }
  571.             $q =& $q->Next();
  572.         }
  573.         while ($q->id() != $this->first->id());
  574.         $point_at_infinity = NULL;      // Free the memory for neatness
  575.         if ($winding_number % 2 == 0)   // Check even or odd
  576.             return FALSE;               // even == outside
  577.         else
  578.             return TRUE;                // odd == inside
  579.     }
  580.     /*
  581.     **  Execute a Boolean operation on a polygon
  582.     **
  583.     ** This is the key method. It allows you to AND/OR this polygon with another one
  584.     ** (equvalent to a UNION or INTERSECT operation. You may also subtract one from
  585.     ** the other (same as DIFFERENCE). Given two polygons A, B the following operations
  586.     ** may be performed:
  587.     **
  588.     ** A|B ... A OR  B (Union of A and B)
  589.     ** A&B ... A AND B (Intersection of A and B)
  590.     ** A\B ... A - B
  591.     ** B\A ... B - A
  592.     **
  593.     ** A is the object and B is the polygon passed to the method.
  594.     */
  595.     function &boolean (&$polyB, $oper)
  596.     {
  597.         $last = NULL;
  598.         $s =& $this->first;         // First vertex of the subject polygon
  599.         $c =& $polyB->getFirst();   // First vertex of the "clip" polygon
  600.         /*
  601.         ** Phase 1 of the algoritm is to find all intersection points between the two
  602.         ** polygons. A new vertex is created for each intersection and it is added to
  603.         ** the linked lists for both polygons. The "neighbor" reference in each vertex
  604.         ** stores the link between the same intersection point in each polygon.
  605.         */
  606.         do
  607.         {
  608.             if (!$s->isIntersect())
  609.             {
  610.                 do
  611.                 {
  612.                     if (!$c->isIntersect())
  613.                     {
  614.                         if ($this->ints($s, $this->nxt($s->Next()),$c, $polyB->nxt($c->Next()), $n, $ix, $iy, $alphaS, $alphaC))
  615.                         {
  616.                             for ($i=0; $i<$n; $i++)
  617.                             {
  618.                                 $is =& new vertex($ix[$i], $iy[$i], $s->Xc(), $s->Yc(), $s->d(), NULL, NULL, NULL, TRUE, NULL, $alphaS[$i], FALSE, FALSE);
  619.                                 $ic =& new vertex($ix[$i], $iy[$i], $c->Xc(), $c->Yc(), $c->d(), NULL, NULL, NULL, TRUE, NULL, $alphaC[$i], FALSE, FALSE);
  620.                                 $is->setNeighbor($ic);
  621.                                 $ic->setNeighbor($is);
  622.                                 $this->insertSort($is, $s, $this->nxt($s->Next()));
  623.                                 $polyB->insertSort($ic, $c, $polyB->nxt($c->Next()));
  624.                             }
  625.                         }
  626.                     } // end if $c is not an intersect point
  627.                     $c =& $c->Next();
  628.                 }
  629.                 while ($c->id() != $polyB->first->id());
  630.             } // end if $s not an intersect point
  631.             $s =& $s->Next();
  632.         }
  633.         while ($s->id() != $this->first->id());
  634.         /*
  635.         ** Phase 2 of the algorithm is to identify every intersection point as an
  636.         ** entry or exit point to the other polygon. This will set the entry bits
  637.         ** in each vertex object.
  638.         **
  639.         ** What is really stored in the entry record for each intersection is the
  640.         ** direction the algorithm should take when it arrives at that entry point.
  641.         ** Depending in the operation requested (A&B, A|B, A/B, B/A) the direction is
  642.         ** set as follows for entry points (f=foreward, b=Back), exit poits are always set
  643.         ** to the opposite:
  644.         **       Enter       Exit
  645.         **       A    B     A    B
  646.         ** A|B   b    b     f    f
  647.         ** A&B   f    f     b    b
  648.         ** A\B   b    f     f    b
  649.         ** B\A   f    b     b    f
  650.         **
  651.         ** f = TRUE, b = FALSE when stored in the entry record
  652.         */
  653.         switch ($oper)
  654.         {
  655.             case "A|B": $A = FALSE; $B = FALSE; break;
  656.             case "A&B": $A = TRUE;  $B = TRUE;  break;
  657.             case "A\B": $A = FALSE; $B = TRUE;  break;
  658.             case "B\A": $A = TRUE;  $B = FALSE; break;
  659.             default:    $A = TRUE;  $B = TRUE;  break;
  660.         }
  661.         $s =& $this->first;
  662.         if ($polyB->isInside($s)) // if we are already inside
  663.             $entry = !$A;       // next intersection must be an exit
  664.         else                    // otherwise
  665.             $entry = $A;        // next intersection must be an entry
  666.         do
  667.         {
  668.             if ($s->isIntersect())
  669.             {
  670.                 $s->setEntry($entry);
  671.                 $entry = !$entry;
  672.             }
  673.             $s =& $s->Next();
  674.         }
  675.         while ($s->id() != $this->first->id());
  676.         /*
  677.         ** Repeat for other polygon
  678.         */
  679.         $c =& $polyB->first;
  680.         if ($this->isInside($c)) // if we are already inside
  681.             $entry = !$B;   // next intersection must be an exit
  682.         else                // otherwise
  683.             $entry = $B;    // next intersection must be an entry
  684.         do
  685.         {
  686.             if ($c->isIntersect())
  687.             {
  688.                 $c->setEntry($entry);
  689.                 $entry = !$entry;
  690.             }
  691.             $c =& $c->Next();
  692.         }
  693.         while ($c->id() != $polyB->first->id());
  694.         /*
  695.         ** Phase 3 of the algorithm is to scan the linked lists of the
  696.         ** two input polygons an construct a linked list of result
  697.         ** polygons. We start at the first intersection then depending
  698.         ** on whether it is an entry or exit point we continue building
  699.         ** our result polygon by following the source or clip polygon
  700.         ** either forwards or backwards.
  701.         */
  702.         while ($this->unckd_remain())               // Loop while unchecked intersections remain
  703.         {
  704.             $v =& $this->first_unckd_intersect();   // Get the first unchecked intersect point
  705.             $this_class = get_class($this);         // Findout the class I'm in
  706.             $r =& new $this_class;                  // Create a new instance of that class
  707.             do
  708.             {
  709.                 $v->setChecked();                   // Set checked flag true for this intersection
  710.                 if ($v->isEntry())
  711.                 {
  712.                     do
  713.                     {
  714.                         $v =& $v->Next();
  715.                         $nv =& new vertex($v->X(),$v->Y(),$v->Xc(),$v->Yc(),$v->d());
  716.                         $r->add($nv);
  717.                     }
  718.                     while (!$v->isIntersect());
  719.                 }
  720.                 else
  721.                 {
  722.                     do
  723.                     {
  724.                         $v =& $v->Prev();
  725.                         $nv =& new vertex($v->X(),$v->Y(),$v->Xc(FALSE),$v->Yc(FALSE),$v->d(FALSE));
  726.                         $r->add($nv);
  727.                     }
  728.                     while (!$v->isIntersect());
  729.                 }
  730.                 $v =& $v->Neighbor();
  731.             }
  732.             while (!$v->isChecked()); // until polygon closed
  733.             if ($last)                          // Check in case first time thru the loop
  734.                 $r->first->setNextPoly($last);  // Save ref to the last poly in the first vertex
  735.                                                 // of this poly
  736.             $last =& $r;                        // Save this polygon
  737.         } // end of while there is another intersection to check
  738.     /*
  739.     ** Clean up the input polygons by deleting the intersection points
  740.     */
  741.         $this->res();
  742.         $polyB->res();
  743.     /*
  744.     ** It is possible that no intersection between the polygons was found and
  745.     ** there is no result to return. In this case we make function fail
  746.     ** gracefully as follows (depending on the requested operation):
  747.     **
  748.     ** A|B : Return $this with $polyB in $this->first->nextPoly
  749.     ** A&B : Return $this
  750.     ** A\B : Return $this
  751.     ** B\A : return $polyB
  752.     */
  753.         if (!$last)
  754.         {
  755.             switch ($oper)
  756.             {
  757.                 case "A|B": $last =& $this->copy_poly();
  758.                             $p    =& $polyB->copy_poly();
  759.                             $last->first->setNextPoly($p);
  760.                             break;
  761.                 case "A&B": $last =&  $this->copy_poly();   break;
  762.                 case "A\B": $last =&  $this->copy_poly();   break;
  763.                 case "B\A": $last =&  $polyB->copy_poly();  break;
  764.                 default:    $last =&  $this->copy_poly();   break;
  765.             }
  766.         }
  767.         elseif ($this->first->nextPoly)
  768.         {
  769.             $last->first->nextPoly =& $this->first->NextPoly();
  770.         }
  771.         return $last;
  772.     } // end of boolean function
  773.     /*
  774.     ** Test if a polygon lies entirly inside this polygon
  775.     **
  776.     ** First every point in the polygon is tested to determine if it is
  777.     ** inside this polygon. If all points are inside, then the second
  778.     ** test is performed that looks for any intersections between the
  779.     ** two polygons. If no intersections are found then the polygon
  780.     ** must be completely enclosed by this polygon.
  781.     */
  782.     function isPolyInside (&$p)
  783.     {
  784.         $inside = TRUE;
  785.         $c =& $p->getFirst();   // Get the first vertex in polygon $p
  786.         do
  787.         {
  788.             if (!$this->isInside($c))   // If vertex is NOT inside this polygon
  789.                 $inside = FALSE;        // then set flag to false
  790.             $c =& $c->Next();           // Get the next vertex in polygon $p
  791.         }
  792.         while ($c->id() != $p->first->id());
  793.         if ($inside)
  794.         {
  795.             $c =& $p->getFirst();       // Get the first vertex in polygon $p
  796.             $s =& $this->getFirst();    // Get the first vertex in this polygon
  797.             do
  798.             {
  799.                 do
  800.                 {
  801.                     if ($this->ints($s, $s->Next(),$c, $c->Next(), $n, $x, $y, $aS, $aC))
  802.                         $inside = FALSE;
  803.                     $c =& $c->Next();
  804.                 }
  805.                 while ($c->id() != $p->first->id());
  806.                 $s =& $s->Next();
  807.             }
  808.             while ($s->id() != $this->first->id());
  809.         }
  810.         return $inside;
  811.     } // end of isPolyInside
  812.     /*
  813.     ** Test if a polygon lies completely outside this polygon
  814.     **
  815.     ** First every point in the polygon is tested to determine if it is
  816.     ** outside this polygon. If all points are outside, then the second
  817.     ** test is performed that looks for any intersections between the
  818.     ** two polygons. If no intersections are found then the polygon
  819.     ** must be completely outside this polygon.
  820.     */
  821.     function isPolyOutside (&$p)
  822.     {
  823.         $outside = TRUE;
  824.         $c =& $p->getFirst();   // Get the first vertex in polygon $p
  825.         do
  826.         {
  827.             if ($this->isInside($c))    // If vertex is inside this polygon
  828.                 $outside = FALSE;       // then set flag to false
  829.             $c =& $c->Next();           // Get the next vertex in polygon $p
  830.         }
  831.         while ($c->id() != $p->first->id());
  832.         if ($outside)
  833.         {
  834.             $c =& $p->getFirst();       // Get the first vertex in polygon $p
  835.             $s =& $this->getFirst();    // Get the first vertex in this polygon
  836.             do
  837.             {
  838.                 do
  839.                 {
  840.                     if ($this->ints($s, $s->Next(),$c, $c->Next(), $n, $x, $y, $aS, $aC))
  841.                         $outside = FALSE;
  842.                     $c =& $c->Next();
  843.                 }
  844.                 while ($c->id() != $p->first->id());
  845.                 $s =& $s->Next();
  846.             }
  847.             while ($s->id() != $this->first->id());
  848.         }
  849.         return $outside;
  850.     } // end of isPolyOutside
  851.     /*
  852.     ** Test if a polygon intersects anywhere with this polygon
  853.     ** looks for any intersections between the two polygons.
  854.     ** If no intersections between any segments are found then
  855.     ** the polygons do not intersect. However, one could be
  856.     ** completely inside the other.
  857.     */
  858.     function isPolyIntersect (&$p)
  859.     {
  860.         $intersect = FALSE;
  861.             $c =& $p->getFirst();        // Get the first vertex in polygon $p
  862.             $s =& $this->getFirst();    // Get the first vertex in this polygon
  863.             do
  864.             {
  865.                 do
  866.                 {
  867.                     if ($this->ints($s, $s->Next(),$c, $c->Next(), $n, $x, $y, $aS, $aC))
  868.                         $intersect = TRUE;
  869.                     $c =& $c->Next();
  870.                 }
  871.                 while ($c->id() != $p->first->id());
  872.                 $s =& $s->Next();
  873.             }
  874.             while ($s->id() != $this->first->id());
  875.         return $intersect;
  876.     } // end of isPolyIntersect
  877.     /*
  878.     ** Test if this polygon intersects anywhere with itself
  879.     ** looks for any self intersections within the polygon.
  880.     ** If no intersections between any segments are found then
  881.     ** the polygon does not self intersect.
  882.     */
  883.     function isPolySelfIntersect ()
  884.     {
  885.         $intersect = FALSE;
  886.             $s =& $this->getFirst();    // Get the first vertex in this polygon
  887.             $c =& $s->Next();            // Get the next vertex
  888.             do
  889.             {
  890.                 do
  891.                 {
  892.                     if ($this->ints($s, $s->Next(),$c, $c->Next(), $n, $x, $y, $aS, $aC)) // If the segments intersect
  893.                         for ($i=0; $i<=$n; $i++) // then for each intersection point
  894.                             if (($aS[$i] <> 0) || ($aC[$i] <> 0)) // check that it NOT at the end of the segment
  895.                                 $intersect = TRUE; // Because sequential segments always intersect at their ends
  896.                     $c =& $c->Next();
  897.                 }
  898.                 while ($c->id() != $this->first->id());
  899.                 $s =& $s->Next();
  900.             }
  901.             while ($s->id() != $this->first->id());
  902.         return $intersect;
  903.     } // end of isPolySelfIntersect
  904.     /*
  905.     ** Move Polygon
  906.     **
  907.     ** Translates polygon by delta X and delta Y
  908.     */
  909.     function move ($dx, $dy)
  910.     {
  911.         $p =& $this;
  912.         if ($p) // For a valid polygon
  913.         do
  914.         {
  915.             $v =& $p->getFirst();
  916.             do
  917.             {
  918.                 $v->setX($v->X() + $dx);
  919.                 $v->setY($v->Y() + $dy);
  920.                 if ($v->d() != 0)
  921.                 {
  922.                     $v->setXc($v->Xc() + $dx);
  923.                     $v->setYc($v->Yc() + $dy);
  924.                 }
  925.                 $v =& $v->Next();
  926.             }
  927.             while($v->id() != $p->first->id());
  928.             $p =& $p->NextPoly();   // Get the next polygon in the list
  929.         }
  930.         while ($p);     // Keep checking polygons as long as they exist
  931.     } // end of move polygon   
  932.     /*
  933.     ** Rotate Polygon
  934.     **
  935.     ** Rotates a polgon about point $xr/$yr by $a radians
  936.     */
  937.     function rotate ($xr, $yr, $a)
  938.     {
  939.         $this->move(-$xr,-$yr);     // Move the polygon so that the point of
  940.                                     // rotation is at the origin (0,0)
  941.         if ($a < 0)                 // We might be passed a negitive angle
  942.             $a += 2*pi();           // make it positive
  943.  
  944.         $p =& $this;
  945.         if ($p) // For a valid polygon
  946.         do
  947.         {
  948.             $v =& $p->first;
  949.             do
  950.             {
  951.                 $x=$v->X(); $y=$v->Y();
  952.                 $v->setX($x*cos($a) - $y*sin($a));  // x' = xCos(a)-ySin(a)
  953.                 $v->setY($x*sin($a) + $y*cos($a));  // y' = xSin(a)+yCos(a)
  954.                 if ($v->d() != 0)
  955.                 {
  956.                     $x=$v->Xc(); $y=$v->Yc();
  957.                     $v->setXc($x*cos($a) - $y*sin($a));
  958.                     $v->setYc($x*sin($a) + $y*cos($a));
  959.                 }
  960.                 $v =& $v->Next();
  961.             }
  962.             while($v->id() != $p->first->id());
  963.             $p =& $p->NextPoly();   // Get the next polygon in the list
  964.         }
  965.         while ($p);     // Keep checking polygons as long as they exist
  966.         $this->move($xr,$yr);       // Move the rotated polygon back
  967.     } // end of rotate polygon
  968.     /*
  969.     ** Return Bounding Rectangle for a Polygon
  970.     **
  971.     ** returns a polygon object that represents the bounding rectangle
  972.     ** for this polygon. Arc segments are correctly handled.
  973.     **
  974.     ** Remember the polygon object allows for a linked list of polygons.
  975.     ** If more than one polygon is linked through the NextPoly list
  976.     ** then the bounding rectangle will be for ALL polygons in the
  977.     ** list.
  978.     */
  979.     function &bRect ()
  980.     {
  981.         $minX = INF; $minY = INF; $maxX = -INF; $maxY = -INF;
  982.         $p =& $this;
  983.         if ($p) // For a valid polygon
  984.         do
  985.         {
  986.             $v =& $p->first;    // Get the first vertex
  987.             do
  988.             {
  989.                 if ($v->d() != 0)   // Is it an arc segment
  990.                 {
  991.                     $vn =& $v->Next();                  // end vertex of the arc segment
  992.                     $v1 =& new vertex($v->Xc(), -infinity); // bottom point of vertical line thru arc center
  993.                     $v2 =& new vertex($v->Xc(), +infinity); // top point of vertical line thru arc center
  994.                     if ($p->ints($v, $vn, $v1, $v2, $n, $x, $y, $aS, $aC))  // Does line intersect the arc ?
  995.                     {
  996.                         for ($i=0; $i<$n; $i++)         // check y portion of all intersections
  997.                         {
  998.                             $minY = min($minY, $y[$i], $v->Y());
  999.                             $maxY = max($maxY, $y[$i], $v->Y());
  1000.                         }
  1001.                     }
  1002.                     else    // There was no intersection so bounding rect is determined
  1003.                     {       // by the start point only, not the edge of the arc
  1004.                         $minY = min($minY, $v->Y());
  1005.                         $maxY = max($maxY, $v->Y());
  1006.                     }
  1007.                     $v1 = NULL; $v2 = NULL; // Free the memory used
  1008.                     $h1 =& new vertex(-infinity, $v->Yc()); // left point of horozontal line thru arc center
  1009.                     $h2 =& new vertex(+infinity, $v->Yc()); // right point of horozontal line thru arc center
  1010.                     if ($p->ints($v, $vn, $h1, $h2, $n, $x, $y, $aS, $aC))  // Does line intersect the arc ?
  1011.                     {
  1012.                         for ($i=0; $i<$n; $i++)         // check x portion of all intersections
  1013.                         {
  1014.                             $minX = min($minX, $x[$i], $v->X());
  1015.                             $maxX = max($maxX, $x[$i], $v->X());
  1016.                         }
  1017.                     }
  1018.                     else
  1019.                     {
  1020.                         $minX = min($minX, $v->X());
  1021.                         $maxX = max($maxX, $v->X());
  1022.                     }
  1023.                     $h1 = NULL; $h2 = NULL;
  1024.                 }
  1025.                 else    // Straight segment so just check the vertex
  1026.                 {
  1027.                     $minX = min($minX, $v->X());
  1028.                     $minY = min($minY, $v->Y());
  1029.                     $maxX = max($maxX, $v->X());
  1030.                     $maxY = max($maxY, $v->Y());
  1031.                 }
  1032.                 $v =& $v->Next();
  1033.             }
  1034.             while($v->id() != $p->first->id());
  1035.             $p =& $p->NextPoly();                   // Get the next polygon in the list
  1036.         }
  1037.         while ($p);     // Keep checking polygons as long as they exist
  1038.         //
  1039.         // Now create an return a polygon with the bounding rectangle
  1040.         //
  1041.         $this_class = get_class($this);         // Findout the class I'm in (might be an extension of polygon)
  1042.         $p =& new $this_class;                  // Create a new instance of that class
  1043.         $p->addv($minX,$minY);
  1044.         $p->addv($minX,$maxY);
  1045.         $p->addv($maxX,$maxY);
  1046.         $p->addv($maxX,$minY);
  1047.         return $p;
  1048.     } // end of bounding rectangle
  1049.     /*
  1050.     ** Scale a Polygon
  1051.     **
  1052.     ** Resize a polygon by scale X & scale Y
  1053.     */
  1054.     function scale ($sx, $sy)
  1055.     {
  1056.         $p =& $this;
  1057.         if ($p) // For a valid polygon
  1058.         do
  1059.         {
  1060.             $v =& $p->getFirst();
  1061.             do
  1062.             {
  1063.                 $v->setX($v->X() * $sx);
  1064.                 $v->setY($v->Y() * $sy);
  1065.                 if ($v->d() != 0)
  1066.                 {
  1067.                     $v->setXc($v->Xc() * $sx);
  1068.                     $v->setYc($v->Yc() * $sy);
  1069.                 }
  1070.                 $v =& $v->Next();
  1071.             }
  1072.             while($v->id() != $p->first->id());
  1073.             $p =& $p->NextPoly();                   // Get the next polygon in the list
  1074.         }
  1075.         while ($p);     // Keep checking polygons as long as they exist
  1076.     } // end of scale polygon  
  1077.     /*
  1078.     ** translate a Polygon
  1079.     **
  1080.     ** Resize & move a polygon so that its bounding rectangle becomes
  1081.     ** the rectangle defined by the two points (xmin,ymin) and
  1082.     ** (xmax,ymax).
  1083.     */
  1084.     function translate ($xmin, $ymin, $xmax, $ymax)
  1085.     {
  1086.         $nXsize = $xmax - $xmin;
  1087.         $nYsize = $ymax - $ymin;
  1088.  
  1089.         $o_br =& $this->bRect(); // Get the min/max corners of the original polygon bounding rect
  1090.         $v =& $o_br->getFirst(); // First vertex of bRect is xmin & ymin of the polygon
  1091.         $o_xmin = $v->X(); $o_ymin = $v->Y();
  1092.         $v =& $v->Next(); // Next vertex has ymax
  1093.         $o_ymax = $v->Y();
  1094.         $v =& $v->Next(); // Next vertex has xmax
  1095.         $o_xmax = $v->X();
  1096.  
  1097.         $oXsize = $o_xmax - $o_xmin;
  1098.         $oYsize = $o_ymax - $o_ymin;
  1099.  
  1100.         $xScale = $nXsize / $oXsize; // Calculate the X axis scale factor
  1101.         $yScale = $nYsize / $oYsize; // Calculate the X axis scale factor
  1102.  
  1103.         $xMove = $xmin - ($o_xmin * $xScale);
  1104.         $yMove = $ymin - ($o_ymin * $yScale);
  1105.  
  1106.         $this->scale($xScale, $yScale);
  1107.         $this->move($xMove, $yMove);
  1108.     } // end of translate polygon
  1109. } //end of class polygon
  1110. ?>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement