チェンジセット 91
- コミット日時:
- 2007/10/15 09:02:14 (6 年前)
- ファイル:
凡例:
- 変更無し
- 追加
- 削除
- 更新
- コピー
- 移動
nitoyon/as3/src/com/nitoyon/potras/Curve.as
r85 r91 8 8 { 9 9 import flash.geom.Point; 10 import mx.utils.StringUtil;11 10 12 11 public class Curve … … 39 38 public function toString():String 40 39 { 41 return StringUtil.substitute( 42 "alpha0: {0}\n" 43 + "alpha: {1}\n" 44 + "beta: {2}\n" 45 + "corner: {3}\n" 46 + "bezier: {4},{5}{6}", 47 alpha0, alpha, beta, tag == ProcessPath.POTRACE_CORNER, c[0], c[1], c[2]); 40 return "alpha0: " + alpha0 + "\n" 41 + "alpha: " + alpha + "\n" 42 + "beta: " + beta + "\n" 43 + "corner: " + (tag == ProcessPath.POTRACE_CORNER) + "\n" 44 + "bezier: " + c[0] + "," + c[1] + "," + c[2]; 48 45 } 49 46 } nitoyon/as3/src/com/nitoyon/potras/PathList.as
r85 r91 32 32 var param:Object = {turdSize : 3}; 33 33 34 var point:Point; 35 while(point = findNext(bmdCopy, y)) 34 // XOR 35 var filter:ColorMatrixFilter = new ColorMatrixFilter([ 36 -1, 0, 0, 0, 255, 37 -1, 0, 0, 0, 255, 38 -1, 0, 0, 0, 255, 39 0, 0, 0, 1, 0 40 ]); 41 42 var point:Point = new Point(); 43 while(findNext(bmdCopy, point)) 36 44 { 37 45 // calculate the sign by looking at the original … … 42 50 if(!p) 43 51 { 44 bitmapData.dispose();45 return null;52 pathList = null; 53 break; 46 54 } 47 55 48 56 // update buffered image 49 xorPath(bmdCopy, p );57 xorPath(bmdCopy, p, filter); 50 58 51 59 // if it's a turd, eliminate it, else append it to the list … … 67 75 * <p>If found, return Point object. Else return null.</p> 68 76 */ 69 private static function findNext(bmd:BitmapData, startY:int):Point70 { 71 for(var y:int = startY; y < bmd.height; y++)77 private static function findNext(bmd:BitmapData, pt:Point):Boolean 78 { 79 for(var y:int = pt.y; y < bmd.height; y++) 72 80 { 73 81 for(var x:int = 0; x < bmd.width; x++) … … 75 83 if(bmd.getPixel(x, y) == 0x000000) 76 84 { 77 return new Point(x, y); 85 pt.x = x; 86 pt.y = y; 87 return true; 78 88 } 79 89 } 80 90 } 81 91 82 return null;92 return false; 83 93 } 84 94 … … 160 170 * Note: the path must be within the dimensions of the pixmap. 161 171 */ 162 private static function xorPath(bm:BitmapData, p:Object):void 163 { 164 if(p.priv.length <= 0) // a path of length 0 is silly, but legal 165 { 166 return; 167 } 168 169 var y1:int = p.priv[p.priv.length - 1].y; 170 171 var xa:int = p.priv[0].x; 172 for(var k:int = 0; k < p.priv.length; k++) 173 { 174 var x:int = p.priv[k].x; 175 var y:int = p.priv[k].y; 172 private static function xorPath(bm:BitmapData, p:Object, filter:ColorMatrixFilter):void 173 { 174 var priv:Array = p.priv as Array; 175 var len:int = priv.length; 176 177 // get minimum x 178 var minX:int = 99999; 179 for(var i:int = 0; i < len; i++) 180 { 181 minX = Math.min(minX, priv[i].x); 182 } 183 184 var y1:int = priv[len - 1].y; 185 var pt:Point = new Point(); 186 var rect:Rectangle = new Rectangle; 187 for(i = 0; i < len; i++) 188 { 189 var x:int = priv[i].x; 190 var y:int = priv[i].y; 176 191 177 192 if(y != y1) 178 193 { 179 // efficiently invert the rectangle [x,xa] x [y,y1] 180 xorToRef(bm, x, Math.max(y, y1), xa); 194 // efficiently invert the rectangle [minX, x] x [y,y1] 195 var y2:int = Math.max(y, y1); 196 pt.x = minX; pt.y = y2; 197 rect.x = minX; rect.y = y2; rect.width = x - minX; rect.height = 1; 198 bm.applyFilter(bm, rect, pt, filter); 181 199 y1 = y; 182 200 } 183 201 } 184 }185 186 /**187 * decompose image into paths efficiently invert bits [x,infty) and [xa,infty) in line y.188 *189 * Here xa must be a multiple of BM_WORDBITS.190 */191 private static function xorToRef(bm:BitmapData, x:int, y:int, xa:int):void192 {193 // XOR194 var filter:ColorMatrixFilter = new ColorMatrixFilter([195 -1, 0, 0, 0, 255,196 -1, 0, 0, 0, 255,197 -1, 0, 0, 0, 255,198 0, 0, 0, 1, 0199 ]);200 201 bm.applyFilter(bm, new Rectangle(0, y, x, 1), new Point(0, y), filter);202 202 } 203 203 } nitoyon/as3/src/com/nitoyon/potras/ProcessPath.as
r85 r91 115 115 var ct:Array; 116 116 var dir:int; 117 var constraint:Array = [];118 117 var k1:int; 118 var constraint0:Point = new Point(); 119 var constraint1:Point = new Point(); 120 var cur:Point = new Point(); 121 var off:Point = new Point(); 122 var dk:Point = new Point(); 119 123 for(i = n - 1; i >= 0; i--) 120 124 { 121 //trace("==========");122 125 ct = [0, 0, 0, 0]; 123 126 … … 125 128 dir = (3 + 3 * (pt[mod(i + 1, n)].x - pt[i].x) + (pt[mod(i + 1, n)].y - pt[i].y)) / 2; 126 129 ct[dir]++; 127 constraint[0] = new Point(0, 0); 128 constraint[1] = new Point(0, 0); 130 constraint0.x = constraint0.y = constraint1.x = constraint1.y = 0; 129 131 130 132 // find the next k such that no straight line from i to k … … 137 139 ct[dir]++; 138 140 139 //trace("dir: ", dir, ", ct: ", ct);140 141 141 // if all four "directions" have occurred, cut this path 142 142 if(ct[0] && ct[1] && ct[2] && ct[3]) … … 147 147 } 148 148 149 var cur:Point = new Point(pt[k].x - pt[i].x, pt[k].y - pt[i].y);150 //trace("cur: ", cur);149 cur.x = pt[k].x - pt[i].x; 150 cur.y = pt[k].y - pt[i].y; 151 151 152 152 // see if current constraint is violated 153 if(xprod(constraint [0], cur) > 0 || xprod(constraint[1], cur) < 0)153 if(xprod(constraint0, cur) > 0 || xprod(constraint1, cur) < 0) 154 154 { 155 155 break; … … 163 163 else 164 164 { 165 var off:Point = new Point( 166 cur.x + ((-cur.y >= 0 && (-cur.y > 0 || cur.x < 0)) ? 1 : -1), 167 cur.y + ((-cur.x <= 0 && (-cur.x < 0 || cur.y < 0)) ? 1 : -1)); 168 //trace("off1 = ", off); 169 if(xprod(constraint[0], off) <= 0) 165 off.x = cur.x + ((-cur.y >= 0 && (-cur.y > 0 || cur.x < 0)) ? 1 : -1); 166 off.y = cur.y + ((-cur.x <= 0 && (-cur.x < 0 || cur.y < 0)) ? 1 : -1); 167 if(xprod(constraint0, off) <= 0) 170 168 { 171 constraint[0] = off; 169 constraint0.x = off.x; 170 constraint0.y = off.y; 172 171 } 173 172 174 off = new Point( 175 cur.x + ((-cur.y <= 0 && (-cur.y < 0 || cur.x < 0)) ? 1 : -1), 176 cur.y + ((-cur.x >= 0 && (-cur.x > 0 || cur.y < 0)) ? 1 : -1)) 177 //trace("off2 = ", off); 178 if(xprod(constraint[1], off) >= 0) 173 off.x = cur.x + ((-cur.y <= 0 && (-cur.y < 0 || cur.x < 0)) ? 1 : -1); 174 off.y = cur.y + ((-cur.x >= 0 && (-cur.x > 0 || cur.y < 0)) ? 1 : -1); 175 if(xprod(constraint1, off) >= 0) 179 176 { 180 constraint[1] = off; 177 constraint1.x = off.x; 178 constraint1.y = off.y; 181 179 } 182 183 //trace("constraint: ", constraint[0], constraint[1]);184 180 } 185 181 186 182 k1 = k; 187 183 k = nc[k1]; 188 //trace("k, k1 = ", k, k1);189 184 if(!cyclic(k, i, k1)) 190 185 { 191 186 break; 192 187 } 193 194 //trace("---"); 195 } 196 197 //trace("-"); 188 } 198 189 199 190 // constraint 200 191 if(!foundk) 201 192 { 202 var dk:Point = new Point(sign(pt[k].x-pt[k1].x), sign(pt[k].y-pt[k1].y)); 203 cur = new Point(pt[k1].x - pt[i].x, pt[k1].y - pt[i].y); 204 205 // find largest integer j such that xprod(constraint[0], cur+j*dk) >= 0 206 // and xprod(constraint[1], cur+j*dk) <= 0. Use bilinearity of xprod. 207 var a:int = xprod(constraint[0], cur); 208 var b:int = xprod(constraint[0], dk); 209 var c:int = xprod(constraint[1], cur); 210 var d:int = xprod(constraint[1], dk); 193 dk.x = sign(pt[k].x-pt[k1].x); 194 dk.y = sign(pt[k].y-pt[k1].y); 195 cur.x = pt[k1].x - pt[i].x; 196 cur.y = pt[k1].y - pt[i].y; 197 198 // find largest integer j such that xprod(constraint0, cur+j*dk) >= 0 199 // and xprod(constraint1, cur+j*dk) <= 0. Use bilinearity of xprod. 200 var a:int = xprod(constraint0, cur); 201 var b:int = xprod(constraint0, dk); 202 var c:int = xprod(constraint1, cur); 203 var d:int = xprod(constraint1, dk); 211 204 212 205 // find largest integer j such that a+j*b>=0 and c+j*d<=0. … … 219 212 if(d < 0) 220 213 { 221 //trace("j : ", j);222 214 j = Math.min(j, floordiv(c, -d)); 223 //trace("j : ", j);224 215 } 225 216 pivk[i] = mod(k1 + j, n); 226 227 //trace("dk = ", dk); 228 //trace("cur = ", cur); 229 //trace("a,b,c,d = ", a, b, c, d); 230 //trace("k1, j, n= ", k1, j, n, floordiv(c, -d)); 231 //trace("pivk[i] = ", pivk[i]); 232 } 233 234 //trace("----------------"); 217 } 235 218 236 219 // foundk … … 239 222 // clean up: for each i, let lon[i] be the largest k such that for 240 223 // all i' with i<=i'<k, i'<k<=pivk[i']. 241 j = pivk[n -1];224 j = pivk[n - 1]; 242 225 lon[n - 1] = j; 243 226 for(i = n - 2; i >= 0; i--) … … 248 231 } 249 232 lon[i] = j; 250 251 //trace("pivk[" + i + "]:", pivk[i] + ", lon[" + i + "]:", lon[i]);252 233 } 253 234 … … 349 330 } 350 331 pen[i] = best; 351 //trace(i, best);352 332 } 353 333 } … … 357 337 for(i = n, j = m - 1; i > 0; j--) 358 338 { 359 i = prev[i]; 360 po[j] = i; 339 po[j] = i = prev[i]; 361 340 } 362 341 … … 415 394 var n:int = pt.length; 416 395 417 var p0:Point = pt[0].clone();418 419 396 var i:int, j:int, k:int, l:int; 420 421 var vertex:Array = [];422 423 // calculate "optimal" point-slope representation for each line segment424 var ctr:Array = [];425 var dir:Array = [];426 for(i = 0; i < m; i++)427 {428 j = po[mod(i + 1, m)];429 j = mod(j - po[i], n) + po[i];430 431 ctr[i] = new Point();432 dir[i] = new Point();433 434 pointslope(pt, sums, po[i], j, ctr[i], dir[i]);435 }436 397 437 398 // represent each line segment as a singular quadratic form; the … … 440 401 var q:Array = []; 441 402 var v:Point3D = new Point3D(); 403 var ctr:Point = new Point(); 404 var dir:Point = new Point(); 442 405 for(i = 0; i < m; i++) 443 406 { 407 // calculate "optimal" point-slope representation for each line segment 408 j = po[(i + 1) % m]; 409 j = mod(j - po[i], n) + po[i]; 410 ctr.x = ctr.y = dir.x = dir.y = 0; 411 pointslope(pt, sums, po[i], j, ctr, dir); 412 444 413 q[i] = new QuadraticForm(); 445 446 var d1:Number = Math.pow(dir[i].x, 2) + Math.pow(dir[i].y, 2); 447 if(d1 == 0.0) 448 { 449 q[i] = new QuadraticForm(); 450 } 451 else 452 { 453 v = new Point3D(dir[i].y, -dir[i].x, 0); 454 v[2] = -v[1] * ctr[i].y - v[0] * ctr[i].x 455 q[i] = v.multiplyTranspose().scalar(1 / d1); 414 var d1:Number = dir.x * dir.x + dir.y * dir.y; 415 if(d1 != 0.0) 416 { 417 v[0] = dir.y; 418 v[1] = -dir.x; 419 v[2] = -v[1] * ctr.y - v[0] * ctr.x 420 q[i].fromVectorMultiply(v).scalar(1 / d1); 456 421 } 457 422 } … … 461 426 // within a given unit square which minimizes the square distance to 462 427 // the two lines. 428 var vertex:Array = []; 429 var p0:Point = pt[0].clone(); 430 var s:Point = new Point(); 431 var w:Point = new Point(); 432 var _q:QuadraticForm = new QuadraticForm(); 433 var minCoord:Point = new Point; 463 434 for(i = 0; i < m; i++) 464 435 { 465 var Q:QuadraticForm = new QuadraticForm();466 436 var z:int; 437 vertex[i] = new Point(); 467 438 468 439 // let s be the vertex, in coordinates relative to x0/y0 469 var s:Point = pt[po[i]].subtract(p0); 440 s.x = pt[po[i]].x - p0.x; 441 s.y = pt[po[i]].y - p0.y; 470 442 471 443 // intersect segments i-1 and i … … 473 445 474 446 // add quadratic forms 475 Q = q[j].add(q[i]); 476 477 var w:Point = new Point(); 447 var Q:QuadraticForm = q[j].clone().add(q[i]); 448 478 449 while(1) 479 450 { 480 451 // minimize the quadratic form Q on the unit square 481 452 // find intersection 482 483 453 var det:Number = Q[0][0] * Q[1][1] - Q[0][1] * Q[1][0]; 484 454 if(det != 0.0) … … 509 479 var d:Number = v[0] * v[0] + v[1] * v[1]; 510 480 v[2] = - v[1] * s.y - v[0] * s.x; 511 Q = Q.add(v.multiplyTranspose().scalar(1 / d));481 Q.add(_q.fromVectorMultiply(v)).scalar(1 / d); 512 482 } 513 483 … … 516 486 if(dx <= .5 && dy <= .5) 517 487 { 518 vertex[i] = w.add(p0); 488 vertex[i].x = w.x + p0.x; 489 vertex[i].y = w.y + p0.y; 519 490 continue; 520 491 } … … 523 494 // on boundary of square 524 495 var min:Number, cand:Number; // minimum and candidate for minimum of quad. form 525 var minCoord:Point = new Point();// coordinates of minimum496 minCoord.x = s.x; minCoord.y = s.y; // coordinates of minimum 526 497 min = Q.apply(s); 527 minCoord = s.clone();528 498 529 499 if(Q[0][0] != 0.0) … … 533 503 w.y = s.y - 0.5 + z; 534 504 w.x = - (Q[0][1] * w.y + Q[0][2]) / Q[0][0]; 535 dx = Math.abs(w.x - s.x);505 dx = (w.x - s.x > 0 ? w.x - s.x : s.x - w.x); 536 506 cand = Q.apply(w); 537 507 if(dx <= .5 && cand < min) 538 508 { 539 509 min = cand; 540 minCoord = w.clone();510 minCoord.x = w.x; minCoord.y = w.y; 541 511 } 542 512 } … … 549 519 w.x = s.x - 0.5 + z; 550 520 w.y = - (Q[1][0] * w.x + Q[1][2]) / Q[1][1]; 551 dy = Math.abs(w.y - s.y);521 dy = (w.y - s.y > 0 ? w.y - s.y : s.y - w.y); 552 522 cand = Q.apply(w); 553 523 if(dy <= .5 && cand < min) 554 524 { 555 525 min = cand; 556 minCoord = w.clone();526 minCoord.x = w.x; minCoord.y = w.y; 557 527 } 558 528 } … … 564 534 for(k = 0; k < 2; k++) 565 535 { 566 w = new Point(s.x - 0.5 + l, s.y - 0.5 + k); 536 w.x = s.x - 0.5 + l; 537 w.y = s.y - 0.5 + k; 567 538 cand = Q.apply(w); 568 539 if(cand < min) 569 540 { 570 541 min = cand; 571 minCoord = w.clone();542 minCoord.x = w.x; minCoord.y = w.y; 572 543 } 573 544 } 574 545 } 575 546 576 vertex[i] = minCoord.add(p0); 547 vertex[i].x = minCoord.x + p0.x; 548 vertex[i].y = minCoord.y + p0.y; 577 549 continue; 578 550 } … … 596 568 { 597 569 // reverse orientation of negative paths 570 var tmp:Point; 598 571 for(i = 0, j = m - 1; i < j; i++, j--) 599 572 { 600 var tmp:Point = vertex[i].clone();573 tmp = vertex[i]; 601 574 vertex[i] = vertex[j]; 602 575 vertex[j] = tmp; … … 605 578 606 579 // examine each vertex and find its best fit 580 var p2:Point = new Point(); 581 var p3:Point = new Point(); 582 var p4:Point = new Point(); 607 583 for(i = 0; i < m; i++) 608 584 { 609 var j:int = mod(i + 1, m);610 var k:int = mod(i + 2, m);611 var p4:Point = interval(1 / 2.0, vertex[k], vertex[j]);585 var j:int = (i + 1) % m; 586 var k:int = (i + 2) % m; 587 interval(1 / 2.0, vertex[k], vertex[j], p4); 612 588 613 589 var curve:Curve = new Curve(); 614 curve.vertex = vertex[j].clone(); 590 curve.vertex.x =vertex[j].x; 591 curve.vertex.y =vertex[j].y; 615 592 616 593 var denom:Number = ddenom(vertex[i], vertex[k]); 594 var alpha:Number; 617 595 if(denom != 0.0) 618 596 { 619 597 var dd:Number = dpara(vertex[i], vertex[j], vertex[k]) / denom; 620 dd = Math.abs(dd); 621 var alpha:Number = dd > 1 ? (1 - 1.0 / dd) : 0; 622 alpha = alpha / 0.75; 598 dd = dd < 0 ? -dd : dd; 599 alpha = dd > 1 ? (1 - 1.0 / dd) / 0.75 : 0; 623 600 } 624 601 else … … 631 608 { 632 609 curve.tag = POTRACE_CORNER; 633 curve.c[0] = new Point();634 curve.c[1] = vertex[j];635 curve.c[2] = p4;610 curve.c[0].x = 0; curve.c[0].y = 0; 611 curve.c[1].x = vertex[j].x; curve.c[1].y = vertex[j].y; 612 curve.c[2].x = p4.x; curve.c[2].y = p4.y; 636 613 } 637 614 else … … 645 622 alpha = 1; 646 623 } 647 var p2:Point = interval(.5 + .5 * alpha, vertex[i], vertex[j]);648 var p3:Point = interval(.5 + .5 * alpha, vertex[k], vertex[j]);624 interval(.5 + .5 * alpha, vertex[i], vertex[j], p2); 625 interval(.5 + .5 * alpha, vertex[k], vertex[j], p3); 649 626 curve.tag = POTRACE_CURVETO; 650 curve.c[0] = p2;651 curve.c[1] = p3;652 curve.c[2] = p4;627 curve.c[0].x = p2.x; curve.c[0].y = p2.y; 628 curve.c[1].x = p3.x; curve.c[1].y = p3.y; 629 curve.c[2].x = p4.x; curve.c[2].y = p4.y; 653 630 } 654 631 curve.alpha = alpha; // store the "cropped" value of alpha … … 745 722 * range over the straight line segment [a,b] when lambda ranges over [0,1] 746 723 */ 747 public static function interval(lambda:Number, a:Point, b:Point):Point 748 { 749 return new Point( 750 a.x + lambda * (b.x - a.x), 751 a.y + lambda * (b.y - a.y) 752 ); 724 public static function interval(lambda:Number, a:Point, b:Point, ret:Point):void 725 { 726 ret.x = a.x + lambda * (b.x - a.x); 727 ret.y = a.y + lambda * (b.y - a.y); 753 728 } 754 729 … … 854 829 import flash.utils.flash_proxy; 855 830 import flash.errors.IllegalOperationError; 856 import mx.utils.StringUtil;857 831 858 832 internal class Point3D extends Proxy … … 886 860 } 887 861 888 public function multiplyTranspose():QuadraticForm889 {890 var matrix:QuadraticForm = new QuadraticForm();891 892 for(var i:int = 0; i < 3; i++)893 {894 for(var j:int = 0; j < 3; j++)895 {896 matrix[i][j] = $v[i] * $v[j];897 }898 }899 return matrix;900 }901 902 862 public function toString():String 903 863 { 904 return StringUtil.substitute( 905 "({0},{1},{2})", 906 $v[0], $v[1], $v[2]); 864 return "(" + $v[0] + "," + $v[1] + "," + $v[2] + ")"; 907 865 } 908 866 } … … 961 919 } 962 920 921 public function clone():QuadraticForm 922 { 923 var ret:QuadraticForm = new QuadraticForm(); 924 for(var i:int = 0; i < 3; i++) 925 { 926 for(var j:int = 0; j < 3; j++) 927 { 928 ret[i][j] = $m[i][j]; 929 } 930 } 931 return ret; 932 } 933 963 934 public function add(m2:QuadraticForm):QuadraticForm 964 935 { 965 var ret:QuadraticForm = new QuadraticForm();966 967 936 for(var i:int = 0; i < 3; i++) 968 937 { 969 938 for(var j:int = 0; j < 3; j++) 970 939 { 971 ret[i][j] = $m[i][j] +m2[i][j];972 } 973 } 974 return ret;940 $m[i][j] += m2[i][j]; 941 } 942 } 943 return this; 975 944 } 976 945 977 946 public function scalar(s:Number):QuadraticForm 978 947 { 979 var ret:QuadraticForm = new QuadraticForm();980 981 948 for(var i:int = 0; i < 3; i++) 982 949 { 983 950 for(var j:int = 0; j < 3; j++) 984 951 { 985 ret[i][j] = $m[i][j] * s; 986 } 987 } 988 return ret; 952 $m[i][j] *= s; 953 } 954 } 955 return this; 956 } 957 958 public function fromVectorMultiply(v:Point3D):QuadraticForm 959 { 960 for(var i:int = 0; i < 3; i++) 961 { 962 for(var j:int = 0; j < 3; j++) 963 { 964 $m[i][j] = v[i] * v[j]; 965 } 966 } 967 return this; 989 968 } 990 969 991 970 public function toString():String 992 971 { 993 return StringUtil.substitute( 994 "[({0},{1},{2}), ({3},{4},{5}), ({6},{7},{8})]", 995 $m[0][0], $m[0][1], $m[0][2], 996 $m[1][0], $m[1][1], $m[1][2], 997 $m[2][0], $m[2][1], $m[2][2]); 972 return "[" + 973 $m[0][0] + "," + $m[0][1] + "," + $m[0][2] + "," + 974 $m[1][0] + "," + $m[1][1] + "," + $m[1][2] + "," + 975 $m[2][0] + "," + $m[2][1] + "," + $m[2][2] + "]"; 998 976 } 999 977 }

