Advertisement
greg1996

phhp

Apr 22nd, 2012
79
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 31.26 KB | None | 0 0
  1. private function xor_path(bitmapDataMatrix:Vector-><Vector-><uint>>, path:Path) {
  2.         if (count(path->monotonIntervals) == 0) {
  3.             return;
  4.         }
  5.        
  6.         $i = 0;
  7.         $n = count(path->pt);
  8.             $mis:Vector-><MonotonInterval> = path->monotonIntervals;
  9.         $mi:MonotonInterval = mis[0];
  10.         mi->resetCurrentId(n);
  11.        
  12.         $y = path->pt[mi->currentId]->y;
  13.         $currentIntervals:Vector-><MonotonInterval> = new Vector-><MonotonInterval>();
  14.         currentIntervals[] = mi;
  15.        
  16.         mi->currentId = mi->min();
  17.        
  18.         while ((count(mis) > i + 1) && (mis[i + 1]->minY(path->pt) == y)) {
  19.             mi = mis[i + 1];
  20.             mi->resetCurrentId(n);
  21.             currentIntervals[] = mi;
  22.             i++;
  23.         }
  24.        
  25.         while (count(currentIntervals) > 0) {
  26.             $j;
  27.            
  28.             for ($k = 0; k < count(currentIntervals) - 1; k++) {
  29.                 $x1 = path->pt[currentIntervals[k]->currentId]->x + 1;
  30.                 $x2 = path->pt[currentIntervals[k + 1]->currentId]->x;
  31.                 for ($x = x1; x <= x2; x++) {
  32.                     // Invert pixel
  33.                     bitmapDataMatrix[y][x] ^= 0xffffff;
  34.                 }
  35.                 k++;
  36.             }
  37.            
  38.             y++;
  39.             for (j = count(currentIntervals) - 1; j >= 0; j--) {
  40.                 $m:MonotonInterval = currentIntervals[j];
  41.                 if (y > m->maxY(path->pt)) {
  42.                     currentIntervals->splice(j, 1);
  43.                     continue;
  44.                 }
  45.                 $cid = m->currentId;
  46.                 while (path->pt[cid]->y < y) {
  47.                     cid = m->increasing ? mod(cid + 1, n) : mod(cid - 1, n);
  48.                 }
  49.                 m->currentId = cid;
  50.             }
  51.            
  52.             // Add Items of MonotonIntervals with Down->y==y
  53.             while ((count(mis) > i + 1) && (mis[i + 1]->minY(path->pt) == y)) {
  54.                 $newInt:MonotonInterval = mis[i + 1];
  55.                 // Search the correct x position
  56.                 j = 0;
  57.                 $_x = path->pt[newInt->min()]->x;
  58.                 while ((count(currentIntervals) > j) && (_x > path->pt[currentIntervals[j]->currentId]->x)) {
  59.                     j++;
  60.                 }
  61.                 currentIntervals->splice(j, 0, newInt);
  62.                 newInt->resetCurrentId(n);
  63.                 i++;
  64.             }
  65.         }
  66.     }
  67.    
  68.     private function get_monoton_intervals(pt:Vector-><PointInt>):Vector-><MonotonInterval> {
  69.         $result:Vector-><MonotonInterval> = new Vector-><MonotonInterval>();
  70.         $n = count(pt);
  71.         if (n == 0) {
  72.             return result;
  73.         }
  74.        
  75.         $intervals:Vector-><MonotonInterval> = new Vector-><MonotonInterval>();
  76.        
  77.         // Start with Strong Monoton (Pts[i]->y < Pts[i+1]->y) or (Pts[i]->y > Pts[i+1]->y)
  78.         $firstStrongMonoton = 0;
  79.         while (pt[firstStrongMonoton]->y == pt[firstStrongMonoton + 1]->y) {
  80.             firstStrongMonoton++;
  81.         }
  82.        
  83.         $i = firstStrongMonoton;
  84.         $up = (pt[firstStrongMonoton]->y < pt[firstStrongMonoton + 1]->y);
  85.         $interval:MonotonInterval = new MonotonInterval(up, firstStrongMonoton, firstStrongMonoton);
  86.         intervals[] = interval;
  87.        
  88.         while (i != firstStrongMonoton) {
  89.             $i1n = mod(i + 1, n);
  90.             if ((pt[i]->y == pt[i1n]->y) || (up == (pt[i]->y < pt[i1n]->y))) {
  91.                 interval->to = i;
  92.             } else {
  93.                 up = (pt[i]->y < pt[i1n]->y);
  94.                 interval = new MonotonInterval(up, i, i);
  95.                 intervals[] = interval;
  96.             }
  97.             i = i1n;
  98.         }
  99.        
  100.         if ((count(intervals) & 1) == 1) {
  101.             $last:MonotonInterval = intervals->pop();
  102.             intervals[0]->from = last->from;
  103.         }
  104.        
  105.         while (count(intervals) > 0) {
  106.             i = 0;
  107.             $m:MonotonInterval = intervals->shift();
  108.             while ((i < count(result)) && (pt[m->min()]->y > pt[result[i]->min()]->y)) {
  109.                 i++;
  110.             }
  111.             while ((i < count(result)) && (pt[m->min()]->y == pt[result[i]->min()]->y) && (pt[m->min()]->x > pt[result[i]->min()]->x)) {
  112.                 i++;
  113.             }
  114.             result->splice(i, 0, m);
  115.         }
  116.        
  117.         return result;
  118.     }
  119.    
  120.     private function find_next_trace(bitmapDataMatrix:Vector-><Vector-><uint>>, pInt, dir) {
  121.         switch(dir) {
  122.             case Direction->WEST:
  123.                 if (bitmapDataMatrix[p->y + 1][p->x + 1] == 0) {
  124.                     dir = Direction->NORTH;
  125.                     p->y++;
  126.                 } else {
  127.                     if (bitmapDataMatrix[p->y][p->x + 1] == 0) {
  128.                         dir = Direction->WEST;
  129.                         p->x++;
  130.                     } else {
  131.                         dir = Direction->SOUTH;
  132.                         p->y--;
  133.                     }
  134.                 }
  135.                 break;
  136.                
  137.             case Direction->SOUTH:
  138.                 if (bitmapDataMatrix[p->y][p->x + 1] == 0) {
  139.                     dir = Direction->WEST;
  140.                     p->x++;
  141.                 } else {
  142.                     if (bitmapDataMatrix[p->y][p->x] == 0) {
  143.                         dir = Direction->SOUTH;
  144.                         p->y--;
  145.                     } else {
  146.                         dir = Direction->EAST;
  147.                         p->x--;
  148.                     }
  149.                 }
  150.                 break;
  151.                
  152.             case Direction->EAST:
  153.                 if (bitmapDataMatrix[p->y][p->x] == 0) {
  154.                     dir = Direction->SOUTH;
  155.                     p->y--;
  156.                 } else {
  157.                     if (bitmapDataMatrix[p->y + 1][p->x] == 0) {
  158.                         dir = Direction->EAST;
  159.                         p->x--;
  160.                     } else {
  161.                         dir = Direction->NORTH;
  162.                         p->y++;
  163.                     }
  164.                 }
  165.                 break;
  166.                
  167.             case Direction->NORTH:
  168.                 if (bitmapDataMatrix[p->y + 1][p->x] == 0) {
  169.                     dir = Direction->EAST;
  170.                     p->x--;
  171.                 } else {
  172.                     if (bitmapDataMatrix[p->y + 1][p->x + 1] == 0) {
  173.                         dir = Direction->NORTH;
  174.                         p->y++;
  175.                     } else {
  176.                         dir = Direction->WEST;
  177.                         p->x++;
  178.                     }
  179.                 }
  180.                 break;
  181.         }
  182.         return dir;
  183.     }
  184.    
  185.     private function process_path(plists) {
  186.         // call downstream function with each path
  187.         for ($j = 0; j < count(plists); j++) {
  188.             $plist = plists[j] as Array;
  189.             for ($i = 0; i < count(plist); i++) {
  190.                 $path:Path = plist[i] as Path;
  191.                 calc_sums(path);
  192.                 calc_lon(path);
  193.                 bestpolygon(path);
  194.                 adjust_vertices(path);
  195.                 smooth(path->curves, 1, params->alphaMax);
  196.                 if (params->curveOptimizing) {
  197.                     opticurve(path, params->optTolerance);
  198.                     path->fCurves = path->optimizedCurves;
  199.                 } else {
  200.                     path->fCurves = path->curves;
  201.                 }
  202.                 path->curves = path->fCurves;
  203.             }
  204.         }
  205.     }
  206.    
  207.     /////////////////////////////////////////////////////////////////////////
  208.     // PREPARATION
  209.     /////////////////////////////////////////////////////////////////////////
  210.    
  211.     /*
  212.      * Fill in the sum* fields of a path (used for later rapid summing)
  213.      */
  214.     private function calc_sums(path:Path) {
  215.         $n = count(path->pt);
  216.        
  217.         // Origin
  218.         $x0 = path->pt[0]->x;
  219.         $y0 = path->pt[0]->y;
  220.        
  221.         path->sums = new Vector-><SumStruct>(n + 1);
  222.            
  223.         $ss:SumStruct = new SumStruct();
  224.         ss->x2 = ss->xy = ss->y2 = ss->x = ss->y = 0;
  225.         path->sums[0] = ss;
  226.        
  227.         for ($i = 0; i < n; i++) {
  228.             $x = path->pt[i]->x - x0;
  229.             $y = path->pt[i]->y - y0;
  230.             ss = new SumStruct();
  231.             ss->x = path->sums[i]->x + x;
  232.             ss->y = path->sums[i]->y + y;
  233.             ss->x2 = path->sums[i]->x2 + x * x;
  234.             ss->xy = path->sums[i]->xy + x * y;
  235.             ss->y2 = path->sums[i]->y2 + y * y;
  236.             path->sums[i + 1] = ss;
  237.         }
  238.     }
  239.    
  240.     /////////////////////////////////////////////////////////////////////////
  241.     // STAGE 1
  242.     // determine the straight subpaths (Sec-> 2->2->1)->
  243.     /////////////////////////////////////////////////////////////////////////
  244.    
  245.     /*
  246.      * Fill in the "lon" component of a path object (based on pt/len)->
  247.      * For each i, lon[i] is the furthest index such that a straight line
  248.      * can be drawn from i to lon[i]->
  249.      *
  250.      * This algorithm depends on the fact that the existence of straight
  251.      * subpaths is a triplewise property-> I->e->, there exists a straight
  252.      * line through squares i0,->->->,in if there exists a straight line
  253.      * through i,j,k, for all i0 <= i < j < k <= in-> (Proof?)
  254.      */
  255.     private function calc_lon(path:Path) {
  256.         $i;
  257.         $j;
  258.         $k;
  259.         $k1;
  260.         $a;
  261.         $b;
  262.         $c;
  263.         $d;
  264.         $dir;
  265.         $ct:Vector-><int> = new Vector-><int>(4);
  266.         $constraint:Vector-><PointInt> = new Vector-><PointInt>(2);
  267.         constraint[0] = new PointInt();
  268.         constraint[1] = new PointInt();
  269.         $curInt = new PointInt();
  270.         $offInt = new PointInt();
  271.         $dkInt = new PointInt(); // direction of k - k1
  272.         $pt:Vector-><PointInt> = path->pt;
  273.        
  274.         $n = count(pt);
  275.         $pivot:Vector-><int> = new Vector-><int>(n);
  276.         $nc:Vector-><int> = new Vector-><int>(n);
  277.        
  278.         // Initialize the nc data structure-> Point from each point to the
  279.         // furthest future point to which it is connected by a vertical or
  280.         // horizontal segment-> We take advantage of the fact that there is
  281.         // always a direction change at 0 (due to the path decomposition
  282.         // algorithm)-> But even if this were not so, there is no harm, as
  283.         // in practice, correctness does not depend on the word "furthest"
  284.         // above->
  285.        
  286.         k = 0;
  287.         for (i = n - 1; i >= 0; i--) {
  288.             if (pt[i]->x != pt[k]->x && pt[i]->y != pt[k]->y) {
  289.                 k = i + 1; // necessarily i < n-1 in this case
  290.             }
  291.             nc[i] = k;
  292.         }
  293.        
  294.         path->lon = new Vector-><int>(n);
  295.        
  296.         // Determine pivot points:
  297.         // for each i, let pivot[i] be the furthest k such that
  298.         // all j with i < j < k lie on a line connecting i,k
  299.        
  300.         for (i = n - 1; i >= 0; i--) {
  301.             ct[0] = ct[1] = ct[2] = ct[3] = 0;
  302.            
  303.             // Keep track of "directions" that have occurred
  304.             dir = (3 + 3 * (pt[mod(i + 1, n)]->x - pt[i]->x) + (pt[mod(i + 1, n)]->y - pt[i]->y)) / 2;
  305.             ct[dir % 4]++;
  306.            
  307.             constraint[0]->x = 0;
  308.             constraint[0]->y = 0;
  309.             constraint[1]->x = 0;
  310.             constraint[1]->y = 0;
  311.            
  312.             // Find the next k such that no straight line from i to k
  313.             k = nc[i];
  314.             k1 = i;
  315.        
  316.             $foundk = false;
  317.             while (true) {
  318.                 dir = (3 + 3 * sign(pt[k]->x - pt[k1]->x) + sign(pt[k]->y - pt[k1]->y)) / 2;
  319.                 ct[dir]++;
  320.                
  321.                 // If all four "directions" have occurred, cut this path
  322.                 if ((ct[0] >= 1) && (ct[1] >= 1) && (ct[2] >= 1) && (ct[3] >= 1)) {
  323.                     pivot[i] = k1;
  324.                     foundk = true;
  325.                     break;
  326.                 }
  327.                
  328.                 cur->x = pt[k]->x - pt[i]->x;
  329.                 cur->y = pt[k]->y - pt[i]->y;
  330.                
  331.                 // See if current constraint is violated
  332.                 if (xprod(constraint[0], cur) < 0 || xprod(constraint[1], cur) > 0) {
  333.                     break;
  334.                 }
  335.                
  336.                 if (abs(cur->x) <= 1 && abs(cur->y) <= 1) {
  337.                     // no constraint
  338.                 } else {
  339.                     off->x = cur->x + ((cur->y >= 0 && (cur->y > 0 || cur->x < 0)) ? 1 : -1);
  340.                     off->y = cur->y + ((cur->x <= 0 && (cur->x < 0 || cur->y < 0)) ? 1 : -1);
  341.                     if (xprod(constraint[0], off) >= 0) {
  342.                         constraint[0] = off->_clone();
  343.                     }
  344.                     off->x = cur->x + ((cur->y <= 0 && (cur->y < 0 || cur->x < 0)) ? 1 : -1);
  345.                     off->y = cur->y + ((cur->x >= 0 && (cur->x > 0 || cur->y < 0)) ? 1 : -1);
  346.                     if (xprod(constraint[1], off) <= 0) {
  347.                         constraint[1] = off->_clone();
  348.                     }
  349.                 }
  350.                
  351.                 k1 = k;
  352.                 k = nc[k1];
  353.                 if (!cyclic(k, i, k1)) {
  354.                     break;
  355.                 }
  356.             }
  357.            
  358.             if(foundk) {
  359.                 continue;
  360.             }
  361.            
  362.             // k1 was the last "corner" satisfying the current constraint, and
  363.             // k is the first one violating it-> We now need to find the last
  364.             // point along k1->->k which satisfied the constraint->
  365.             dk->x = sign(pt[k]->x - pt[k1]->x);
  366.             dk->y = sign(pt[k]->y - pt[k1]->y);
  367.             cur->x = pt[k1]->x - pt[i]->x;
  368.             cur->y = pt[k1]->y - pt[i]->y;
  369.            
  370.             // find largest integer j such that xprod(constraint[0], cur+j*dk)
  371.             // >= 0 and xprod(constraint[1], cur+j*dk) <= 0-> Use bilinearity
  372.             // of xprod->
  373.             a = xprod(constraint[0], cur);
  374.             b = xprod(constraint[0], dk);
  375.             c = xprod(constraint[1], cur);
  376.             d = xprod(constraint[1], dk);
  377.            
  378.             // find largest integer j such that a+j*b >= 0 and c+j*d <= 0-> This
  379.             // can be solved with integer arithmetic->
  380.             j = int->MAX_VALUE;
  381.             if (b < 0) {
  382.                 j = floordiv(a, -b);
  383.             }
  384.             if (d > 0) {
  385.                 j = min(j, floordiv(-c, d));
  386.             }
  387.             pivot[i] = mod(k1 + j, n);
  388.         }
  389.        
  390.         // Clean up:
  391.         // for each i, let lon[i] be the largest k such that
  392.         // for all i' with i <= i' < k, i' < k <= pivk[i']-> */
  393.        
  394.         j = pivot[n - 1];
  395.         path->lon[n - 1] = j;
  396.        
  397.         for (i = n - 2; i >= 0; i--) {
  398.             if (cyclic(i + 1, pivot[i], j)) {
  399.                 j = pivot[i];
  400.             }
  401.             path->lon[i] = j;
  402.         }
  403.        
  404.         for (i = n - 1; cyclic(mod(i + 1, n), j, path->lon[i]); i--) {
  405.             path->lon[i] = j;
  406.         }
  407.     }
  408.    
  409.     /////////////////////////////////////////////////////////////////////////
  410.     // STAGE 2
  411.     // Calculate the optimal polygon (Sec-> 2->2->2 - 2->2->4)->
  412.     /////////////////////////////////////////////////////////////////////////
  413.    
  414.     /*
  415.      * Auxiliary function: calculate the penalty of an edge from i to j in
  416.      * the given path-> This needs the "lon" and "sum*" data->
  417.      */
  418.     private function penalty3(path:Path, i, j) {
  419.         $n = count(path->pt);
  420.        
  421.         // assume 0 <= i < j <= n
  422.         $sums:Vector-><SumStruct> = path->sums;
  423.         $pt:Vector-><PointInt> = path->pt;
  424.        
  425.         $r = 0; // rotations from i to j
  426.         if (j >= n) {
  427.             j -= n;
  428.             r++;
  429.         }
  430.        
  431.         $x = sums[j + 1]->x - sums[i]->x + r * sums[n]->x;
  432.         $y = sums[j + 1]->y - sums[i]->y + r * sums[n]->y;
  433.         $x2 = sums[j + 1]->x2 - sums[i]->x2 + r * sums[n]->x2;
  434.         $xy = sums[j + 1]->xy - sums[i]->xy + r * sums[n]->xy;
  435.         $y2 = sums[j + 1]->y2 - sums[i]->y2 + r * sums[n]->y2;
  436.         $k = j + 1 - i + r * n;
  437.        
  438.         $px = (pt[i]->x + pt[j]->x) / 2->0 - pt[0]->x;
  439.         $py = (pt[i]->y + pt[j]->y) / 2->0 - pt[0]->y;
  440.         $ey = (pt[j]->x - pt[i]->x);
  441.         $ex = -(pt[j]->y - pt[i]->y);
  442.        
  443.         $a = ((x2 - 2 * x * px) / k + px * px);
  444.         $b = ((xy - x * py - y * px) / k + px * py);
  445.         $c = ((y2 - 2 * y * py) / k + py * py);
  446.        
  447.         return sqrt(ex * ex * a + 2 * ex * ey * b + ey * ey * c);
  448.     }
  449.  
  450.     /*
  451.      * Find the optimal polygon->
  452.      */
  453.     private function bestpolygon(path:Path) {
  454.         $i;
  455.         $j;
  456.         $m;
  457.         $k;
  458.         $n = count(path->pt);
  459.         $pen:Vector-><Number> = new Vector-><Number>(n + 1); // penalty vector
  460.         $prev:Vector-><int> = new Vector-><int>(n + 1); // best path pointer vector
  461.         $clip0:Vector-><int> = new Vector-><int>(n); // longest segment pointer, non-cyclic
  462.         $clip1:Vector-><int> = new Vector-><int>(n + 1); // backwards segment pointer, non-cyclic
  463.         $seg0:Vector-><int> = new Vector-><int>(n + 1); // forward segment bounds, m <= n
  464.         $seg1:Vector-><int> = new Vector-><int>(n + 1); // backward segment bounds, m <= n
  465.        
  466.         $thispen;
  467.         $best;
  468.         $c;
  469.        
  470.         // Calculate clipped paths
  471.         for (i = 0; i < n; i++) {
  472.             c = mod(path->lon[mod(i - 1, n)] - 1, n);
  473.             if (c == i) {
  474.                 c = mod(i + 1, n);
  475.             }
  476.             clip0[i] = (c < i) ? n : c;
  477.         }
  478.        
  479.         // calculate backwards path clipping, non-cyclic->
  480.         // j <= clip0[i] iff clip1[j] <= i, for i,j = 0->->n
  481.         j = 1;
  482.         for (i = 0; i < n; i++) {
  483.             while (j <= clip0[i]) {
  484.                 clip1[j] = i;
  485.                 j++;
  486.             }
  487.         }
  488.        
  489.         // calculate seg0[j] = longest path from 0 with j segments
  490.         i = 0;
  491.         for (j = 0; i < n; j++) {
  492.             seg0[j] = i;
  493.             i = clip0[i];
  494.         }
  495.         seg0[j] = n;
  496.        
  497.         // calculate seg1[j] = longest path to n with m-j segments
  498.         i = n;
  499.         m = j;
  500.         for (j = m; j > 0; j--) {
  501.             seg1[j] = i;
  502.             i = clip1[i];
  503.         }
  504.         seg1[0] = 0;
  505.        
  506.         // Now find the shortest path with m segments, based on penalty3
  507.         // Note: the outer 2 loops jointly have at most n interations, thus
  508.         // the worst-case behavior here is quadratic-> In practice, it is
  509.         // close to linear since the inner loop tends to be short->
  510.         pen[0] = 0;
  511.         for (j = 1; j <= m; j++) {
  512.             for (i = seg1[j]; i <= seg0[j]; i++) {
  513.                 best = -1;
  514.                 for (k = seg0[j - 1]; k >= clip1[i]; k--) {
  515.                     thispen = penalty3(path, k, i) + pen[k];
  516.                     if (best < 0 || thispen < best) {
  517.                         prev[i] = k;
  518.                         best = thispen;
  519.                     }
  520.                 }
  521.                 pen[i] = best;
  522.             }
  523.         }
  524.        
  525.         // read off shortest path
  526.         path->po = new Vector-><int>(m);
  527.         for (i = n, j = m - 1; i > 0; j--) {
  528.             i = prev[i];
  529.             path->po[j] = i;
  530.         }
  531.     }
  532.    
  533.     /////////////////////////////////////////////////////////////////////////
  534.     // STAGE 3
  535.     // Vertex adjustment (Sec-> 2->3->1)->
  536.     /////////////////////////////////////////////////////////////////////////
  537.    
  538.     /*
  539.      * Adjust vertices of optimal polygon: calculate the intersection of
  540.      * the two "optimal" line segments, then move it into the unit square
  541.      * if it lies outside->
  542.      */
  543.     private function adjust_vertices(path:Path) {
  544.         $pt:Vector-><PointInt> = path->pt;
  545.         $po:Vector-><int> = path->po;
  546.        
  547.         $n = count(pt);
  548.         $m = count(po);
  549.        
  550.         $x0 = pt[0]->x;
  551.         $y0 = pt[0]->y;
  552.        
  553.         $i;
  554.         $j;
  555.         $k;
  556.         $l;
  557.        
  558.         $d;
  559.         $v:Vector-><Number> = new Vector-><Number>(3);
  560.         $q:Vector-><Vector-><Vector-><Number>>> = new Vector-><Vector-><Vector-><Number>>>(m);
  561.        
  562.         $ctr:Vector-><Point> = new Vector-><Point>(m);
  563.         $dir:Vector-><Point> = new Vector-><Point>(m);
  564.        
  565.         for (i = 0; i < m; i++) {
  566.             q[i] = new Vector-><Vector-><Number>>(3);
  567.             for (j = 0; j < 3; j++) {
  568.                 q[i][j] = new Vector-><Number>(3);
  569.             }
  570.             ctr[i] = new Point();
  571.             dir[i] = new Point();
  572.         }
  573.        
  574.         $s = new Point();
  575.        
  576.         path->curves = new PrivCurve(m);
  577.        
  578.         // calculate "optimal" point-slope representation for each line segment
  579.         for (i = 0; i < m; i++) {
  580.             j = po[mod(i + 1, m)];
  581.             j = mod(j - po[i], n) + po[i];
  582.             pointslope(path, po[i], j, ctr[i], dir[i]);
  583.         }
  584.        
  585.         // represent each line segment as a singular quadratic form;
  586.         // the distance of a point (x,y) from the line segment will be
  587.         // (x,y,1)Q(x,y,1)^t, where Q=q[i]
  588.         for (i = 0; i < m; i++) {
  589.             d = dir[i]->x * dir[i]->x + dir[i]->y * dir[i]->y;
  590.             if (d == 0) {
  591.                 for (j = 0; j < 3; j++) {
  592.                     for (k = 0; k < 3; k++) {
  593.                         q[i][j][k] = 0;
  594.                     }
  595.                 }
  596.             } else {
  597.                 v[0] = dir[i]->y;
  598.                 v[1] = -dir[i]->x;
  599.                 v[2] = -v[1] * ctr[i]->y - v[0] * ctr[i]->x;
  600.                 for (l = 0; l < 3; l++) {
  601.                     for (k = 0; k < 3; k++) {
  602.                         q[i][l][k] = v[l] * v[k] / d;
  603.                     }
  604.                 }
  605.             }
  606.         }
  607.        
  608.         // now calculate the "intersections" of consecutive segments->
  609.         // Instead of using the actual intersection, we find the point
  610.         // within a given unit square which minimizes the square distance to
  611.         // the two lines->
  612.         for (i = 0; i < m; i++) {
  613.             $Q:Vector-><Vector-><Number>> = new Vector-><Vector-><Number>>(3);
  614.             $w = new Point();
  615.             $dx;
  616.             $dy;
  617.             $det;
  618.             $min; // minimum for minimum of quad-> form
  619.             $cand; // candidate for minimum of quad-> form
  620.             $xmin; // coordinate of minimum
  621.             $ymin; // coordinate of minimum
  622.             $z;
  623.            
  624.             for (j = 0; j < 3; j++) {
  625.                 Q[j] = new Vector-><Number>(3);
  626.             }
  627.            
  628.             // let s be the vertex, in coordinates relative to x0/y0
  629.             s->x = pt[po[i]]->x - x0;
  630.             s->y = pt[po[i]]->y - y0;
  631.            
  632.             // intersect segments i-1 and i
  633.             j = mod(i - 1, m);
  634.            
  635.             // add quadratic forms
  636.             for (l = 0; l < 3; l++) {
  637.                 for (k = 0; k < 3; k++) {
  638.                     Q[l][k] = q[j][l][k] + q[i][l][k];
  639.                 }
  640.             }
  641.            
  642.             while (true) {
  643.                 /* minimize the quadratic form Q on the unit square */
  644.                 /* find intersection */
  645.                 det = Q[0][0] * Q[1][1] - Q[0][1] * Q[1][0];
  646.                 if (det != 0) {
  647.                     w->x = (-Q[0][2] * Q[1][1] + Q[1][2] * Q[0][1]) / det;
  648.                     w->y = (Q[0][2] * Q[1][0] - Q[1][2] * Q[0][0]) / det;
  649.                     break;
  650.                 }
  651.                
  652.                 // matrix is singular - lines are parallel-> Add another,
  653.                 // orthogonal axis, through the center of the unit square
  654.                 if (Q[0][0] > Q[1][1]) {
  655.                     v[0] = -Q[0][1];
  656.                     v[1] = Q[0][0];
  657.                 } else if (Q[1][1] != 0) {
  658.                     v[0] = -Q[1][1];
  659.                     v[1] = Q[1][0];
  660.                 } else {
  661.                     v[0] = 1;
  662.                     v[1] = 0;
  663.                 }
  664.                
  665.                 d = v[0] * v[0] + v[1] * v[1];
  666.                 v[2] = -v[1] * s->y - v[0] * s->x;
  667.                 for (l = 0; l < 3; l++) {
  668.                     for (k = 0; k < 3; k++) {
  669.                         Q[l][k] += v[l] * v[k] / d;
  670.                     }
  671.                 }
  672.             }
  673.            
  674.             dx = abs(w->x - s->x);
  675.             dy = abs(w->y - s->y);
  676.             if (dx <= 0->5 && dy <= 0->5) {
  677.                 // - 1 because we have a additional border set to the bitmap
  678.                 path->curves->vertex[i] = new Point(w->x + x0, w->y + y0);
  679.                 continue;
  680.             }
  681.            
  682.             // the minimum was not in the unit square;
  683.             // now minimize quadratic on boundary of square
  684.             min = quadform(Q, s);
  685.             xmin = s->x;
  686.             ymin = s->y;
  687.            
  688.             if (Q[0][0] != 0) {
  689.                 for (z = 0; z < 2; z++) {
  690.                     // value of the y-coordinate
  691.                     w->y = s->y - 0->5 + z;
  692.                     w->x = -(Q[0][1] * w->y + Q[0][2]) / Q[0][0];
  693.                     dx = abs(w->x - s->x);
  694.                     cand = quadform(Q, w);
  695.                     if (dx <= 0->5 && cand < min) {
  696.                         min = cand;
  697.                         xmin = w->x;
  698.                         ymin = w->y;
  699.                     }
  700.                 }
  701.             }
  702.            
  703.             if (Q[1][1] != 0) {
  704.                 for (z = 0; z < 2; z++) {
  705.                     // value of the x-coordinate
  706.                     w->x = s->x - 0->5 + z;
  707.                     w->y = -(Q[1][0] * w->x + Q[1][2]) / Q[1][1];
  708.                     dy = abs(w->y - s->y);
  709.                     cand = quadform(Q, w);
  710.                     if (dy <= 0->5 && cand < min) {
  711.                         min = cand;
  712.                         xmin = w->x;
  713.                         ymin = w->y;
  714.                     }
  715.                 }
  716.             }
  717.            
  718.             // check four corners
  719.             for (l = 0; l < 2; l++) {
  720.                 for (k = 0; k < 2; k++) {
  721.                     w->x = s->x - 0->5 + l;
  722.                     w->y = s->y - 0->5 + k;
  723.                     cand = quadform(Q, w);
  724.                     if (cand < min) {
  725.                         min = cand;
  726.                         xmin = w->x;
  727.                         ymin = w->y;
  728.                     }
  729.                 }
  730.             }
  731.            
  732.             // - 1 because we have a additional border set to the bitmap
  733.             path->curves->vertex[i] = new Point(xmin + x0 - 1, ymin + y0 - 1);
  734.             continue;
  735.         }
  736.     }
  737.    
  738.     /////////////////////////////////////////////////////////////////////////
  739.     // STAGE 4
  740.     // Smoothing and corner analysis (Sec-> 2->3->3)->
  741.     /////////////////////////////////////////////////////////////////////////
  742.    
  743.     private function smooth(curve:PrivCurve, sign, alphaMax) {
  744.         $m = curve->n;
  745.        
  746.         $i;
  747.         $j;
  748.         $k;
  749.         $dd;
  750.         $denom;
  751.         $alpha;
  752.        
  753.         $p2;
  754.         $p3;
  755.         $p4;
  756.        
  757.         if (sign < 0) {
  758.             /* reverse orientation of negative paths */
  759.             for (i = 0, j = m - 1; i < j; i++, j--) {
  760.                 $tmp = curve->vertex[i];
  761.                 curve->vertex[i] = curve->vertex[j];
  762.                 curve->vertex[j] = tmp;
  763.             }
  764.         }
  765.        
  766.         /* examine each vertex and find its best fit */
  767.         for (i = 0; i < m; i++) {
  768.             j = mod(i + 1, m);
  769.             k = mod(i + 2, m);
  770.             p4 = interval(1 / 2->0, curve->vertex[k], curve->vertex[j]);
  771.            
  772.             denom = ddenom(curve->vertex[i], curve->vertex[k]);
  773.             if (denom != 0) {
  774.                 dd = dpara(curve->vertex[i], curve->vertex[j], curve->vertex[k]) / denom;
  775.                 dd = abs(dd);
  776.                 alpha = (dd > 1) ? (1 - 1->0 / dd) : 0;
  777.                 alpha = alpha / 0->75;
  778.             } else {
  779.                 alpha = 4 / 3;
  780.             }
  781.            
  782.             // remember "original" value of alpha */
  783.             curve->alpha0[j] = alpha;
  784.              
  785.             if (alpha > alphaMax) {
  786.                 // pointed corner
  787.                 curve->tag[j] = POTRACE_CORNER;
  788.                 curve->controlPoints[j][1] = curve->vertex[j];
  789.                 curve->controlPoints[j][2] = p4;
  790.             } else {
  791.                 if (alpha < 0->55) {
  792.                     alpha = 0->55;
  793.                 } else if (alpha > 1) {
  794.                     alpha = 1;
  795.                 }
  796.                 p2 = interval(->5 + ->5 * alpha, curve->vertex[i], curve->vertex[j]);
  797.                 p3 = interval(->5 + ->5 * alpha, curve->vertex[k], curve->vertex[j]);
  798.                 curve->tag[j] = POTRACE_CURVETO;
  799.                 curve->controlPoints[j][0] = p2;
  800.                 curve->controlPoints[j][1] = p3;
  801.                 curve->controlPoints[j][2] = p4;
  802.             }
  803.             // store the "cropped" value of alpha
  804.             curve->alpha[j] = alpha;
  805.             curve->beta[j] = 0->5;
  806.         }
  807.     }
  808.    
  809.     /////////////////////////////////////////////////////////////////////////
  810.     // STAGE 5
  811.     // Curve optimization (Sec-> 2->4)->
  812.     /////////////////////////////////////////////////////////////////////////
  813.    
  814.     /*
  815.      * Optimize the path p, replacing sequences of Bezier segments by a
  816.      * single segment when possible->
  817.      */
  818.     private function opticurve(path:Path, optTolerance) {
  819.         $m = path->curves->n;
  820.         $pt:Vector-><int> = new Vector-><int>(m);
  821.         $pen:Vector-><Number> = new Vector-><Number>(m + 1);
  822.         $len:Vector-><int> = new Vector-><int>(m + 1);
  823.         $opt:Vector-><Opti> = new Vector-><Opti>(m + 1);
  824.         $convc:Vector-><int> = new Vector-><int>(m);
  825.         $areac:Vector-><Number> = new Vector-><Number>(m + 1);
  826.        
  827.         $i;
  828.         $j;
  829.         $area;
  830.         $alpha;
  831.         $p0;
  832.         $i1;
  833.         $o:Opti = new Opti();
  834.         $r;
  835.    
  836.         // Pre-calculate convexity: +1 = right turn, -1 = left turn, 0 = corner
  837.         for (i = 0; i < m; i++) {
  838.             if(path->curves->tag[i] == POTRACE_CURVETO) {
  839.                 convc[i] = sign(dpara(path->curves->vertex[mod(i - 1, m)], path->curves->vertex[i], path->curves->vertex[mod(i + 1, m)]));
  840.             } else {
  841.                 convc[i] = 0;
  842.             }
  843.         }
  844.        
  845.         // Pre-calculate areas
  846.         area = 0;
  847.         areac[0] = 0;
  848.         p0 = path->curves->vertex[0];
  849.         for (i = 0; i < m; i++) {
  850.             i1 = mod(i + 1, m);
  851.             if (path->curves->tag[i1] == POTRACE_CURVETO) {
  852.                 alpha = path->curves->alpha[i1];
  853.                 area += 0->3 * alpha * (4 - alpha) * dpara(path->curves->controlPoints[i][2], path->curves->vertex[i1], path->curves->controlPoints[i1][2]) / 2;
  854.                 area += dpara(p0, path->curves->controlPoints[i][2], path->curves->controlPoints[i1][2]) / 2;
  855.             }
  856.             areac[i + 1] = area;
  857.         }
  858.        
  859.         pt[0] = -1;
  860.         pen[0] = 0;
  861.         len[0] = 0;
  862.        
  863.         // Fixme:
  864.         // We always start from a fixed point -- should find the best curve cyclically ###
  865.        
  866.         for (j = 1; j <= m; j++) {
  867.             // Calculate best path from 0 to j
  868.             pt[j] = j - 1;
  869.             pen[j] = pen[j - 1];
  870.             len[j] = len[j - 1] + 1;
  871.            
  872.             for (i = j - 2; i >= 0; i--) {
  873.                 r = opti_penalty(path, i, mod(j, m), o, optTolerance, convc, areac);
  874.                 if (r) {
  875.                     break;
  876.                 }
  877.                 if (len[j] > len[i] + 1 || (len[j] == len[i] + 1 && pen[j] > pen[i] + o->pen)) {
  878.                     pt[j] = i;
  879.                     pen[j] = pen[i] + o->pen;
  880.                     len[j] = len[i] + 1;
  881.                     opt[j] = o->_clone();
  882.                 }
  883.             }
  884.         }
  885.    
  886.         $om = len[m];
  887.        
  888.         path->optimizedCurves = new PrivCurve(om);
  889.        
  890.         $s:Vector-><Number> = new Vector-><Number>(om);
  891.         $t:Vector-><Number> = new Vector-><Number>(om);
  892.        
  893.         j = m;
  894.         for (i = om - 1; i >= 0; i--) {
  895.             $jm = mod(j, m);
  896.             if (pt[j] == j - 1) {
  897.                 path->optimizedCurves->tag[i] = path->curves->tag[jm];
  898.                 path->optimizedCurves->controlPoints[i][0] = path->curves->controlPoints[jm][0];
  899.                 path->optimizedCurves->controlPoints[i][1] = path->curves->controlPoints[jm][1];
  900.                 path->optimizedCurves->controlPoints[i][2] = path->curves->controlPoints[jm][2];
  901.                 path->optimizedCurves->vertex[i] = path->curves->vertex[jm];
  902.                 path->optimizedCurves->alpha[i] = path->curves->alpha[jm];
  903.                 path->optimizedCurves->alpha0[i] = path->curves->alpha0[jm];
  904.                 path->optimizedCurves->beta[i] = path->curves->beta[jm];
  905.                 s[i] = t[i] = 1;
  906.             } else {
  907.                 path->optimizedCurves->tag[i] = POTRACE_CURVETO;
  908.                 path->optimizedCurves->controlPoints[i][0] = opt[j]->c[0];
  909.                 path->optimizedCurves->controlPoints[i][1] = opt[j]->c[1];
  910.                 path->optimizedCurves->controlPoints[i][2] = path->curves->controlPoints[jm][2];
  911.                 path->optimizedCurves->vertex[i] = interval(opt[j]->s, path->curves->controlPoints[jm][2], path->curves->vertex[jm]);
  912.                 path->optimizedCurves->alpha[i] = opt[j]->alpha;
  913.                 path->optimizedCurves->alpha0[i] = opt[j]->alpha;
  914.                 s[i] = opt[j]->s;
  915.                 t[i] = opt[j]->t;
  916.             }
  917.             j = pt[j];
  918.         }
  919.        
  920.         /* Calculate beta parameters */
  921.         for (i = 0; i < om; i++) {
  922.             i1 = mod(i + 1, om);
  923.             path->optimizedCurves->beta[i] = s[i] / (s[i] + t[i1]);
  924.         }
  925.     }
  926.    
  927.     /*
  928.      * Calculate best fit from i+->5 to j+->5->  Assume i<j (cyclically)->
  929.      * Return 0 and set badness and parameters (alpha, beta), if
  930.      * possible-> Return 1 if impossible->
  931.      */
  932.     private function opti_penalty(path:Path, i, j, res:Opti, optTolerance, convc:Vector-><int>, areac:Vector-><Number>) {
  933.         $m = path->curves->n;
  934.         $k;
  935.         $k1;
  936.         $k2;
  937.         $conv;
  938.         $i1;
  939.         $area;
  940.         $d;
  941.         $d1;
  942.         $d2;
  943.         $pt;
  944.        
  945.         if(i == j) {
  946.             // sanity - a full loop can never be an opticurve
  947.             return true;
  948.         }
  949.        
  950.         k = i;
  951.         i1 = mod(i + 1, m);
  952.         k1 = mod(k + 1, m);
  953.         conv = convc[k1];
  954.         if (conv == 0) {
  955.             return true;
  956.         }
  957.         d = ddist(path->curves->vertex[i], path->curves->vertex[i1]);
  958.         for (k = k1; k != j; k = k1) {
  959.             k1 = mod(k + 1, m);
  960.             k2 = mod(k + 2, m);
  961.             if (convc[k1] != conv) {
  962.                 return true;
  963.             }
  964.             if (sign(cprod(path->curves->vertex[i], path->curves->vertex[i1], path->curves->vertex[k1], path->curves->vertex[k2])) != conv) {
  965.                 return true;
  966.             }
  967.             if (iprod1(path->curves->vertex[i], path->curves->vertex[i1], path->curves->vertex[k1], path->curves->vertex[k2]) < d * ddist(path->curves->vertex[k1], path->curves->vertex[k2]) * COS179) {
  968.                 return true;
  969.             }
  970.         }
  971.        
  972.         // the curve we're working in:
  973.         $p0 = path->curves->controlPoints[mod(i, m)][2];
  974.         $p1 = path->curves->vertex[mod(i + 1, m)];
  975.         $p2 = path->curves->vertex[mod(j, m)];
  976.         $p3 = path->curves->controlPoints[mod(j, m)][2];
  977.        
  978.         // determine its area
  979.         area = areac[j] - areac[i];
  980.         area -= dpara(path->curves->vertex[0], path->curves->controlPoints[i][2], path->curves->controlPoints[j][2]) / 2;
  981.         if (i >= j) {
  982.             area += areac[m];
  983.         }
  984.        
  985.         // find intersection o of p0p1 and p2p3->
  986.         // Let t,s such that o = interval(t, p0, p1) = interval(s, p3, p2)->
  987.         // Let A be the area of the triangle (p0, o, p3)->
  988.            
  989.         $A1 = dpara(p0, p1, p2);
  990.         $A2 = dpara(p0, p1, p3);
  991.         $A3 = dpara(p0, p2, p3);
  992.         $A4 = A1 + A3 - A2;
  993.        
  994.         if (A2 == A1) {
  995.             // this should never happen
  996.             return true;
  997.         }
  998.    
  999.         $t = A3 / (A3 - A4);
  1000.         $s = A2 / (A2 - A1);
  1001.         $A = A2 * t / 2->0;
  1002.        
  1003.         if (A == 0) {
  1004.             // this should never happen
  1005.             return true;
  1006.         }
  1007.    
  1008.         $R = area / A; // relative area
  1009.         $alpha = 2 - sqrt(4 - R / 0->3); // overall alpha for p0-o-p3 curve
  1010.        
  1011.         res->c = new Vector-><Point>(2);
  1012.         res->c[0] = interval(t * alpha, p0, p1);
  1013.         res->c[1] = interval(s * alpha, p3, p2);
  1014.         res->alpha = alpha;
  1015.         res->t = t;
  1016.         res->s = s;
  1017.        
  1018.         p1 = res->c[0];
  1019.         p2 = res->c[1];  // the proposed curve is now (p0,p1,p2,p3)
  1020.        
  1021.         res->pen = 0;
  1022.        
  1023.         // Calculate penalty
  1024.         // Check tangency with edges
  1025.         for (k = mod(i + 1, m); k != j; k = k1) {
  1026.             k1 = mod(k + 1, m);
  1027.             t = tangent(p0, p1, p2, p3, path->curves->vertex[k], path->curves->vertex[k1]);
  1028.             if (t < -0->5) {
  1029.                 return true;
  1030.             }
  1031.             pt = bezier(t, p0, p1, p2, p3);
  1032.             d = ddist(path->curves->vertex[k], path->curves->vertex[k1]);
  1033.             if (d == 0) {
  1034.                 // this should never happen
  1035.                 return true;
  1036.             }
  1037.             d1 = dpara(path->curves->vertex[k], path->curves->vertex[k1], pt) / d;
  1038.             if (abs(d1) > optTolerance) {
  1039.                 return true;
  1040.             }
  1041.             if (iprod(path->curves->vertex[k], path->curves->vertex[k1], pt) < 0 || iprod(path->curves->vertex[k1], path->curves->vertex[k], pt) < 0) {
  1042.                 return true;
  1043.             }
  1044.             res->pen += d1 * d1;
  1045.         }
  1046.         // Check corners
  1047.         for (k = i; k != j; k = k1) {
  1048.             k1 = mod(k + 1, m);
  1049.             t = tangent(p0, p1, p2, p3, path->curves->controlPoints[k][2], path->curves->controlPoints[k1][2]);
  1050.             if (t < -0->5) {
  1051.                 return true;
  1052.             }
  1053.             pt = bezier(t, p0, p1, p2, p3);
  1054.             d = ddist(path->curves->controlPoints[k][2], path->curves->controlPoints[k1][2]);
  1055.             if (d == 0) {
  1056.                 // this should never happen
  1057.                 return true;
  1058.             }
  1059.             d1 = dpara(path->curves->controlPoints[k][2], path->curves->controlPoints[k1][2], pt) / d;
  1060.             d2 = dpara(path->curves->controlPoints[k][2], path->curves->controlPoints[k1][2], path->curves->vertex[k1]) / d;
  1061.             d2 *= 0->75 * path->curves->alpha[k1];
  1062.             if (d2 < 0) {
  1063.                 d1 = -d1;
  1064.                 d2 = -d2;
  1065.             }
  1066.             if (d1 < d2 - optTolerance) {
  1067.                 return true;
  1068.             }
  1069.             if (d1 < d2) {
  1070.                 res->pen += (d1 - d2) * (d1 - d2);
  1071.             }
  1072.         }
  1073.        
  1074.         return false;
  1075.     }
  1076.    
  1077.     private function pathlist_to_curvearrayslist(plists) {
  1078.         $res = [];
  1079.        
  1080.         /* call downstream function with each path */
  1081.         for ($j = 0; j < count(plists); j++) {
  1082.             $plist = plists[j] as Array;
  1083.             $clist = [];
  1084.             res[] = clist;
  1085.            
  1086.             for ($i = 0; i < count(plist); i++) {
  1087.                 $p:Path = plist[i] as Path;
  1088.                 $A = p->curves->controlPoints[p->curves->n - 1][2];
  1089.                 $curves = [];
  1090.                 for ($k = 0; k < p->curves->n; k++) {
  1091.                     $C = p->curves->controlPoints[k][0];
  1092.                     $D = p->curves->controlPoints[k][1];
  1093.                     $E = p->curves->controlPoints[k][2];
  1094.                     if (p->curves->tag[k] == POTRACE_CORNER) {
  1095.                         add_curve(curves, A, A, D, D);
  1096.                         add_curve(curves, D, D, E, E);
  1097.                     } else {
  1098.                         add_curve(curves, A, C, D, E);
  1099.                     }
  1100.                     A = E;
  1101.                 }
  1102.                 if (count(curves) > 0) {
  1103.                     $cl:Curve = curves[count(curves) - 1] as Curve;
  1104.                     $cf:Curve = curves[0] as Curve;
  1105.                     if ((cl->kind == $CurveKind->LINE) && (cf->kind == $CurveKind->LINE)
  1106.                         && iprod(cl->b, cl->a, cf->b) < 0
  1107.                         && (abs(xprodf(
  1108.                             new Point(cf->b->x - cf->a->x, cf->b->y - cf->a->y),
  1109.                             new Point(cl->a->x - cl->a->x, cl->b->y - cl->a->y))) < 0->01))
  1110.                     {
  1111.                         curves[0] = new Curve($CurveKind->LINE, cl->a, cl->a, cl->a, cf->b);
  1112.                         curves->pop();
  1113.                     }
  1114.                     $curveList = [];
  1115.                     for ($ci = 0; ci < count(curves); ci++) {
  1116.                         curveList[] = curves[ci];
  1117.                     }
  1118.                     clist[] = curveList;
  1119.                 }
  1120.             }
  1121.         }
  1122.         return res;
  1123.     }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement