※現在、「wonderfl build flash online」求人コンテンツ制作に関してのアンケートを実施中です!みなさまのお力添えを頂いて、続々とアンケート結果が集まっていますが、まだまだ募集しております。ご協力のほど、どうぞよろしくお願いいたします!

wonderfl運営事務局
→アンケートページ(※ログインしてからお答えいただけるようになっています。)

 notice: Flash editor updated! Join the development! Thanks to MiniBuilder


FORKED
  1. // forked from fumix's 超速ボロノイ図(Fortune's algorithm)
  2. /**
  3.  * 超速ボロノイアルゴリズム
  4.  * 元ネタ
  5.  * Fortune's algorithm - Wikipedia, the free encyclopedia
  6.  * http://en.wikipedia.org/wiki/Fortune's_algorithm
  7.  * Controul > Speedy Voronoi diagrams in as3/flash
  8.  * http://blog.controul.com/2009/05/speedy-voronoi-diagrams-in-as3flash/
  9.  * 上記blogのasそのままです(Fortuneクラス)。
  10.  * 全然ロジックわからないので誰か解説してほしいです。
  11.  *
  12.  * 母点を800程度にしてますがもう少し多くてもいけそう。
  13.  * fullscreenでもお楽しみいただけます(重いけど)
  14.  * 
  15.  * 日本語の資料(PDF)
  16.  * http://atom.is.ocha.ac.jp/~kanenko/KOUGI/CompGeo/cpgeob.pdf
  17.  * http://i-health.u-aizu.ac.jp/CompuGeo/2008/handouts/chapter4/Chapter4H.pdf
  18.  */
  19. package {
  20.     import flash.display.Bitmap;
  21.     import flash.display.BitmapData;
  22.     import flash.display.Graphics;
  23.     import flash.display.StageQuality;
  24.     import flash.events.Event;
  25.     import flash.display.Sprite;
  26.     import flash.display.StageAlign;
  27.     import flash.display.StageScaleMode;
  28.     import com.flashdynamix.utils.SWFProfiler;
  29.     [SWF(backgroundColor="#000000", frameRate="30", width="465", height="465")]    
  30.     public class Main extends Sprite {
  31.         //キャンパス
  32.         private var _canvas : Sprite;
  33.         //background
  34.         private var _background:BitmapData;
  35.         //voronoi母点数
  36.         private const Q : uint = 800;
  37.         //voronoi作図用のクラス
  38.         private var fortune : Fortune;
  39.         //voronoi母点(パーティクル的な?)
  40.         private var points : Vector.<Number2>;
  41.         private var _first : Number2;
  42.         private var stageWidth : int;
  43.         private var stageHeight : int;
  44.         public function Main() {
  45.             addEventListener(Event.ADDED_TO_STAGE, _initialize);
  46.         }
  47.         /**
  48.          * 初期化
  49.          */
  50.         private function _initialize(event : Event) : void {
  51.             var i : uint,old : Number2,point : Number2;
  52.             removeEventListener(Event.ADDED_TO_STAGE, _initialize);
  53.             SWFProfiler.init(this);
  54.             //ステージ設定
  55.             stage.scaleMode = StageScaleMode.NO_SCALE;
  56.             stage.align = StageAlign.TOP_LEFT;
  57.             stage.quality = StageQuality.LOW;
  58.             
  59.             stageWidth = stage.stageWidth;
  60.             stageHeight = stage.stageHeight;
  61.             //背景カラー
  62.             _background = new BitmapData(stageWidth , stageHeight, false, 0x0);
  63.             addChild(new Bitmap(_background));
  64.             //キャンパス設定
  65.             _canvas = new Sprite();
  66.             _canvas.x = 0;
  67.             _canvas.y = 0;
  68.             addChild(_canvas);
  69.             //voronoi母点生成
  70.             points = new Vector.<Number2>();
  71.             for(i = 0;i < Q;i++) {
  72.                 point = new Number2();
  73.                 point.x = stageWidth * Math.random();
  74.                 point.y = stageHeight * Math.random();
  75.                 //各母点の速度
  76.                 point.vx = Math.random() * 4 - 2;
  77.                 point.vy = Math.random() * 4 - 2;
  78.                 points.push(point);
  79.             }
  80.             //voronoi母点リンクリスト生成
  81.             for(i = 0;i < Q;i++) {
  82.                 point = points[i];
  83.                 if (_first == null) {
  84.                     old = _first = point;
  85.                 } else {
  86.                     old.next = point;
  87.                     old = point;
  88.                 }                
  89.             }
  90.             
  91.             //ボロノイ作図用クラス            
  92.             fortune = new Fortune();
  93.             
  94.             addEventListener(Event.ENTER_FRAME, _updateHandler);            
  95.         }
  96.         //アップデート
  97.         private function _updateHandler(event : Event) : void {
  98.             _interaction();
  99.             _draw();
  100.         }
  101.         //インタラクション
  102.         private function _interaction() : void {
  103.             var point : Number2 = _first;
  104.             do {
  105.                 //母点の位置を更新
  106.                 point.x += point.vx;
  107.                 point.y += point.vy;
  108.                 if(point.x > stageWidth) {
  109.                     point.x -= stageWidth;
  110.                 }else if(point.x < 0) {
  111.                     point.x += stageWidth;
  112.                 }
  113.                 if(point.y > stageHeight) {
  114.                     point.y -= stageHeight;
  115.                 }else if(point.y < 0) {
  116.                     point.y += stageHeight;
  117.                 }
  118.             } while (point = point.next);
  119.             
  120.             //更新した母点をvoronoi作図用クラスに入れる
  121.             fortune.points = points;
  122.         }
  123.         //描画
  124.         private function _draw() : void {
  125.             //ボロノイ頂点
  126.             var segments : Vector.<Number2> = fortune.compute(),
  127.                 i : uint,start : Number2,end : Number2,
  128.                 point : Number2 = _first,
  129.                 g : Graphics = _canvas.graphics;
  130.             //ボロノイ辺の描画
  131.             g.clear();
  132.             g.lineStyle(1, 0xFFFFFF, 0.25);
  133.             for(i = 0;i < segments.length;i += 2) {
  134.                 start = segments[i];
  135.                 end = segments[i + 1];                
  136.                 g.moveTo(start.x, start.y);
  137.                 g.lineTo(end.x, end.y);
  138.             }
  139.             //ボロノイ母点の描画
  140.             g.lineStyle(1, 0xFF0000, 0.5);
  141.             do {
  142.                 g.drawCircle(point.x, point.y, 1);
  143.             } while (point = point.next);
  144.         }
  145.     }
  146. }
  147. /*
  148.  * Fortune's algorithm
  149.  * http://blog.controul.com/2009/05/speedy-voronoi-diagrams-in-as3flash/
  150.  * オリジナルは上記blogからダウンロードして見てください!
  151.  * はっきりいって全然わからないのでなにやってるのかどなたか解説を!
  152.  */
  153. class Fortune {
  154.     //    voronoi図の母点となる点群
  155.     public var points : Vector.<Number2>;
  156.     //    Bounding box.
  157.     private var x0 : Number;
  158.     //    Root of the frontline and next arc to be removed.
  159.     private var root : Arc;
  160.     private var next : Arc;
  161.     //    Reusable objects and pools.
  162.     private var o : Number2 = new Number2;
  163.     private static var arcPoolD : Arc;
  164.     
  165.     
  166.     /**
  167.      * 与えられた母点からvoronoi頂点群を返します.
  168.      * @return A vector or vertices in pairs, describing segments ready for drawing.
  169.      */
  170.     public function compute() : Vector.<Number2> {
  171.         //    Clear the output.
  172.         var out : Vector.<Number2> = new Vector.<Number2>,
  173.                 len : int = 0;
  174.         //    Clear the state.
  175.         root = null;
  176.         next = null;
  177.         //    Read the pools.
  178.         var key : * ,
  179.                 arcPool : Arc = arcPoolD;
  180.         //    Vars:
  181.         var i : int,
  182.                 j : int,
  183.                 w : Number,
  184.                 x : Number,
  185.                 a : Arc,
  186.                 b : Arc,
  187.                 z : Number2,
  188.                 p : Number2 = points[ 0 ],
  189.                 points : Vector.<Number2> = points,
  190.                 n : int = points.length,
  191.             //    Circle events check inlined.
  192.                 circle : Boolean,
  193.                 eventX : Number,
  194.                 c : Arc,
  195.                 d : Arc,
  196.                 aa : Number2,
  197.                 bb : Number2,
  198.                 cc : Number2,
  199.                 A : Number,
  200.                 B : Number,
  201.                 C : Number,
  202.                 D : Number,
  203.                 E : Number,
  204.                 F : Number,
  205.                 G : Number;
  206.         //    与えられた母点をx軸でソート
  207.         /////    Currently insertion sort. Quicksort?
  208.         w = points[ 0 ].x;
  209.         for ( i = 1;i < n;i++ ) {
  210.             p = points[ i ];
  211.             //    Insertion sort.
  212.             x = p.x;
  213.             if ( x < w ) {
  214.                 j = i;
  215.                 while ( ( j > 0 ) && ( points[ int(j - 1) ].x > x ) ) {
  216.                     points[ j ] = points[ int(j - 1) ];
  217.                     j--;
  218.                 }
  219.                 points[ j ] = p;
  220.             }
  221.                 else
  222.                     w = x;
  223.         }
  224.         //    Get x bounds.
  225.         x0 = points[ 0 ].x;
  226.         //    Process.
  227.         i = 0;
  228.         p = points[ 0 ];
  229.         x = p.x;
  230.             
  231.         //多分母点群でループ
  232.         for ( ;; ) {
  233.             //    Check circle events. /////////////////////////
  234.             if ( a ) {
  235.                 //    Check for arc a.
  236.                 circle = false;
  237.                 if ( a.prev && a.next ) {
  238.                     aa = a.prev.p,
  239.                     bb = a.p,
  240.                     cc = a.next.p;
  241.                     //    Algorithm from O'Rourke 2ed p. 189.
  242.                     A = bb.x - aa.x,
  243.                     B = bb.y - aa.y,
  244.                     C = cc.x - aa.x,
  245.                     D = cc.y - aa.y;
  246.                     //    Check that bc is a "right turn" from ab.
  247.                     if ( A * D - C * B <= 0 ) {
  248.                         E = A * ( aa.x + bb.x ) + B * ( aa.y + bb.y ),
  249.                         F = C * ( aa.x + cc.x ) + D * ( aa.y + cc.y ),
  250.                         G = 2 * ( A * ( cc.y - bb.y ) - B * ( cc.x - bb.x ) );
  251.                         //    Check for colinearity.
  252.                         //    if ( G > 0.000000001 || G < -0.000000001 )
  253.                         if ( G ) {
  254.                             //    Point o is the center of the circle.
  255.                             o.x = ( D * E - B * F ) / G;
  256.                             o.y = ( A * F - C * E ) / G;
  257.                             //    o.x plus radius equals max x coordinate.
  258.                             A = aa.x - o.x;
  259.                             B = aa.y - o.y;
  260.                             eventX = o.x + Math.sqrt(A * A + B * B);
  261.                             if ( eventX >= w ) circle = true;
  262.                         }
  263.                     }
  264.                 }
  265.                 //    Remove from queue.
  266.                 if ( a.right )
  267.                         a.right.left = a.left;
  268.                 if ( a.left )
  269.                         a.left.right = a.right;
  270.                 if ( a == next )
  271.                         next = a.right;
  272.                 //    Record event.
  273.                 if ( circle ) {
  274.                     a.endX = eventX;
  275.                     if ( a.endP ) {
  276.                         a.endP.x = o.x;
  277.                         a.endP.y = o.y;
  278.                     } else {
  279.                         a.endP = o;
  280.                         o = new Number2;
  281.                     }
  282.                     d = next;
  283.                     if ( !d ) {
  284.                         next = a;
  285.                     }
  286.                         else for ( ;; ) {
  287.                         if ( d.endX >= eventX ) {
  288.                             a.left = d.left;
  289.                             if ( d.left ) d.left.right = a;
  290.                             if ( next == d ) next = a;
  291.                             a.right = d;
  292.                             d.left = a;
  293.                             break;
  294.                         }
  295.                         if ( !d.right ) {
  296.                             d.right = a;
  297.                             a.left = d;
  298.                             a.right = null;
  299.                             break;
  300.                         }
  301.                         d = d.right;
  302.                     }
  303.                 } else {
  304.                     a.endX = NaN;
  305.                     a.endP = null;
  306.                     a.left = null;
  307.                     a.right = null;
  308.                 }
  309.                 //    Push next arc to check.
  310.                 if ( b ) {
  311.                     a = b;
  312.                     b = null;
  313.                     continue;
  314.                 }
  315.                 if ( c ) {
  316.                     a = c;
  317.                     c = null;
  318.                     continue;
  319.                 }
  320.                 a = null;
  321.             }
  322.             //////////////////////////////////////////////////
  323.             //
  324.             if ( next && next.endX <= x ) {
  325.                 //
  326.                 //    Handle next circle event.
  327.                 //    Get the next event from the queue. ///////////
  328.                 a = next;
  329.                 next = a.right;
  330.                 if ( next )
  331.                         next.left = null;
  332.                 a.right = null;
  333.                 //    Remove the associated arc from the front.
  334.                 if ( a.prev ) {
  335.                     a.prev.next = a.next;
  336.                     a.prev.v1 = a.endP;
  337.                 }
  338.                 if ( a.next ) {
  339.                     a.next.prev = a.prev;
  340.                     a.next.v0 = a.endP;
  341.                 }
  342.                 if ( a.v0 ) {
  343.                     out[ len++ ] = a.v0;
  344.                     a.v0 = null;
  345.                     out[ len++ ] = a.endP;
  346.                 }
  347.                 if ( a.v1 ) {
  348.                     out[ len++ ] = a.v1;
  349.                     a.v1 = null;
  350.                     out[ len++ ] = a.endP;
  351.                 }
  352.                 //    Keep a ref for collection.
  353.                 d = a;
  354.                 //    Recheck circle events on either side of p:
  355.                 w = a.endX;
  356.                 if ( a.prev ) {
  357.                     b = a.prev;
  358.                     a = a.next;
  359.                 } else {
  360.                     a = a.next;
  361.                     b = null;
  362.                 }
  363.                 c = null;
  364.                 //    Collect.
  365.                 d.v0 = null;
  366.                 d.v1 = null;
  367.                 d.p = null;
  368.                 d.prev = null;
  369.                 d.endX = NaN;
  370.                 d.endP = null;
  371.                 d.next = arcPool;
  372.                 arcPool = d;
  373.                     //////////////////////////////////////////////////
  374.                     //
  375.             } else {
  376.                 if ( !p ) break;
  377.                 //
  378.                 //    Handle next site event. //////////////////////
  379.                 if ( !root ) {
  380.                     if ( arcPool ) {
  381.                         root = arcPool;
  382.                         arcPool = arcPool.next;
  383.                         root.next = null;
  384.                     }
  385.                         else
  386.                             root = new Arc;
  387.                     root.p = p;
  388.                 } else {
  389.                     z = new Number2;
  390.                     //    Find the first arc with a point below p,
  391.                     //    and start searching for the intersection around it.
  392.                     a = root.next;
  393.                     if ( a ) {
  394.                             while ( a.next ) {
  395.                                 a = a.next;
  396.                                 if ( a.p.y >= p.y ) break;
  397.                             }
  398.                             //    Find the intersecting curve.
  399.                             intersection(a.prev.p, a.p, p.x, z);
  400.                             if ( z.y <= p.y ) {
  401.                                 
  402.                                 //    Search for the intersection to the south of i.
  403.                                 while ( a.next ) {
  404.                                     a = a.next;
  405.                                     intersection(a.prev.p, a.p, p.x, z);
  406.                                     if ( z.y >= p.y ) {
  407.                                         a = a.prev;
  408.                                         break;
  409.                                     }
  410.                                 }
  411.                             } else {
  412.                                 //    Search for the intersection above i.
  413.                                 a = a.prev;
  414.                                 while ( a.prev ) {
  415.                                     a = a.prev;
  416.                                     intersection(a.p, a.next.p, p.x, z);
  417.                                     if ( z.y <= p.y ) {
  418.                                         a = a.next;
  419.                                         break;
  420.                                     }
  421.                                 }
  422.                             }
  423.                         }
  424.                         else
  425.                             a = root;
  426.                     //    New parabola will intersect arc a. Duplicate a.
  427.                     if ( a.next ) {
  428.                             if ( arcPool ) {
  429.                                 b = arcPool;
  430.                                 arcPool = arcPool.next;
  431.                                 b.next = null;
  432.                             }
  433.                             else
  434.                                 b = new Arc;
  435.                             b.p = a.p;
  436.                             b.prev = a;
  437.                             b.next = a.next;
  438.                             a.next.prev = b;
  439.                             a.next = b;
  440.                         } else {
  441.                             if ( arcPool ) {
  442.                                 b = arcPool;
  443.                                 arcPool = arcPool.next;
  444.                                 b.next = null;
  445.                             }
  446.                             else
  447.                                 b = new Arc;
  448.                             b.p = a.p;
  449.                             b.prev = a;
  450.                             a.next = b;
  451.                         }
  452.                     a.next.v1 = a.v1;
  453.                     //    Find the point of intersection.
  454.                     z.y = p.y;
  455.                     z.x = ( a.p.x * a.p.x + ( a.p.y - p.y ) * ( a.p.y - p.y ) - p.x * p.x ) / ( 2 * a.p.x - 2 * p.x );
  456.                     //    Add p between i and i->next.
  457.                     if ( arcPool ) {
  458.                             b = arcPool;
  459.                             arcPool = arcPool.next;
  460.                             b.next = null;
  461.                         }
  462.                         else
  463.                             b = new Arc;
  464.                     b.p = p;
  465.                     b.prev = a;
  466.                     b.next = a.next;
  467.                     a.next.prev = b;
  468.                     a.next = b;
  469.                     a = a.next;    //    Now a points to the new arc.
  470.                     a.prev.v1 = z;
  471.                         a.next.v0 = z;
  472.                         a.v0 = z;
  473.                         a.v1 = z;
  474.                         //    Check for new circle events around the new arc:
  475.                         b = a.next;
  476.                         a = a.prev;
  477.                         c = null;
  478.                         w = p.x;
  479.                 }
  480.                 //////////////////////////////////////////////////
  481.                 //
  482.                 i++;
  483.                 if ( i >= n ) {
  484.                         p = null;
  485.                         x = Number.MAX_VALUE;
  486.                     } else {
  487.                         p = points[ i ];
  488.                         x = p.x;
  489.                     }
  490.             }
  491.         }
  492.         //    Store the pools.
  493.         arcPoolD = arcPool;
  494.         //
  495.         //
  496.         //    Return the result ready for drawing.
  497.         return out;
  498.     }
  499.         
  500.         
  501.         /**
  502.          * Where do two parabolas intersect?
  503.          * @param    p0 A Number2 object describing the site for the first parabola.
  504.          * @param    p1 A Number2 object describing the site for the second parabola.
  505.          * @param    l The location of the sweep line.
  506.          * @param    res A Number2 object in which to store the intersection.
  507.          * @return The point of intersection.
  508.          */
  509.         public function intersection( p0 : Number2, p1 : Number2, l : Number, res : Number2 ) : Number2 {
  510.             var p : Number2 = p0,
  511.                 ll : Number = l * l;
  512.             if ( p0.x == p1.x )
  513.                 res.y = ( p0.y + p1.y ) / 2;
  514.             else if ( p1.x == l )
  515.                 res.y = p1.y;
  516.             else if ( p0.x == l ) {
  517.                 res.y = p0.y;
  518.                 p = p1;
  519.             } else {
  520.                 //    Use the quadratic formula.
  521.                 var z0 : Number = 0.5 / ( p0.x - l ); // 1 / ( 2*(p0.x - l) )
  522.                 var z1 : Number = 0.5 / ( p1.x - l ); // 1 / ( 2*(p1.x - l) )
  523.                 var a : Number = z0 - z1;
  524.                 var b : Number = -2 * ( p0.y * z0 - p1.y * z1 );
  525.                 var c : Number = ( p0.y * p0.y + p0.x * p0.x - ll ) * z0 - ( p1.y * p1.y + p1.x * p1.x - ll ) * z1;
  526.                 res.y = ( -b - Math.sqrt(b * b - 4 * a * c) ) / ( 2 * a );
  527.             }
  528.             
  529.             //    Plug back into one of the parabola equations.
  530.             res.x = ( p.x * p.x + ( p.y - res.y ) * ( p.y - res.y ) - ll ) / ( 2 * p.x - 2 * l );
  531.             return res;
  532.         }
  533. }
  534. class Arc {
  535.     public var p : Number2;
  536.     public var next : Arc;
  537.     public var prev : Arc;
  538.     public var v0 : Number2;
  539.     public var v1 : Number2;
  540.     //    Circle event data :
  541.     public var left : Arc;
  542.     public var right : Arc;
  543.     public var endX : Number;
  544.     public var endP : Number2;
  545. }
  546. class Number2 {
  547.     public var x : Number;
  548.     public var y : Number;
  549.     //速度
  550.     public var vx : Number;
  551.     public var vy : Number;
  552.     public var next : Number2;
  553. }
noswf
  1. // forked from fumix's 超速ボロノイ図(Fortune's algorithm)
  2. /**
  3.  * 超速ボロノイアルゴリズム
  4.  * 元ネタ
  5.  * Fortune's algorithm - Wikipedia, the free encyclopedia
  6.  * http://en.wikipedia.org/wiki/Fortune's_algorithm
  7.  * Controul > Speedy Voronoi diagrams in as3/flash
  8.  * http://blog.controul.com/2009/05/speedy-voronoi-diagrams-in-as3flash/
  9.  * 上記blogのasそのままです(Fortuneクラス)。
  10.  * 全然ロジックわからないので誰か解説してほしいです。
  11.  *
  12.  * 母点を800程度にしてますがもう少し多くてもいけそう。
  13.  * fullscreenでもお楽しみいただけます(重いけど)
  14.  * 
  15.  * 日本語の資料(PDF)
  16.  * http://atom.is.ocha.ac.jp/~kanenko/KOUGI/CompGeo/cpgeob.pdf
  17.  * http://i-health.u-aizu.ac.jp/CompuGeo/2008/handouts/chapter4/Chapter4H.pdf
  18.  */
  19. package {
  20.     import flash.display.Bitmap;
  21.     import flash.display.BitmapData;
  22.     import flash.display.Graphics;
  23.     import flash.display.StageQuality;
  24.     import flash.events.Event;
  25.     import flash.display.Sprite;
  26.     import flash.display.StageAlign;
  27.     import flash.display.StageScaleMode;
  28.     import com.flashdynamix.utils.SWFProfiler;
  29.     [SWF(backgroundColor="#000000", frameRate="30", width="465", height="465")]    
  30.     public class Main extends Sprite {
  31.         //キャンパス
  32.         private var _canvas : Sprite;
  33.         //background
  34.         private var _background:BitmapData;
  35.         //voronoi母点数
  36.         private const Q : uint = 60000;
  37.         //voronoi作図用のクラス
  38.         private var fortune : Fortune;
  39.         //voronoi母点(パーティクル的な?)
  40.         private var points : Vector.<Number2>;
  41.         private var _first : Number2;
  42.         private var stageWidth : int;
  43.         private var stageHeight : int;
  44.         public function Main() {
  45.             addEventListener(Event.ADDED_TO_STAGE, _initialize);
  46.         }
  47.         /**
  48.          * 初期化
  49.          */
  50.         private function _initialize(event : Event) : void {
  51.             var i : uint,old : Number2,point : Number2;
  52.             removeEventListener(Event.ADDED_TO_STAGE, _initialize);
  53.             SWFProfiler.init(this);
  54.             //ステージ設定
  55.             stage.scaleMode = StageScaleMode.NO_SCALE;
  56.             stage.align = StageAlign.TOP_LEFT;
  57.             stage.quality = StageQuality.LOW;
  58.             
  59.             stageWidth = stage.stageWidth;
  60.             stageHeight = stage.stageHeight;
  61.             //背景カラー
  62.             _background = new BitmapData(stageWidth , stageHeight, false, 0x0);
  63.             addChild(new Bitmap(_background));
  64.             //キャンパス設定
  65.             _canvas = new Sprite();
  66.             _canvas.x = 0;
  67.             _canvas.y = 0;
  68.             addChild(_canvas);
  69.             //voronoi母点生成
  70.             points = new Vector.<Number2>();
  71.             for(i = 0;i < Q;i++) {
  72.                 point = new Number2();
  73.                 point.x = stageWidth * Math.random();
  74.                 point.y = stageHeight * Math.random();
  75.                 //各母点の速度
  76.                 point.vx = Math.random() * 4 - 2;
  77.                 point.vy = Math.random() * 4 - 2;
  78.                 points.push(point);
  79.             }
  80.             //voronoi母点リンクリスト生成
  81.             for(i = 0;i < Q;i++) {
  82.                 point = points[i];
  83.                 if (_first == null) {
  84.                     old = _first = point;
  85.                 } else {
  86.                     old.next = point;
  87.                     old = point;
  88.                 }                
  89.             }
  90.             
  91.             //ボロノイ作図用クラス            
  92.             fortune = new Fortune();
  93.             
  94.             addEventListener(Event.ENTER_FRAME, _updateHandler);            
  95.         }
  96.         //アップデート
  97.         private function _updateHandler(event : Event) : void {
  98.             _interaction();
  99.             _draw();
  100.         }
  101.         //インタラクション
  102.         private function _interaction() : void {
  103.             var point : Number2 = _first;
  104.             do {
  105.                 //母点の位置を更新
  106.                 point.x += point.vx;
  107.                 point.y += point.vy;
  108.                 if(point.x > stageWidth) {
  109.                     point.x -= stageWidth;
  110.                 }else if(point.x < 0) {
  111.                     point.x += stageWidth;
  112.                 }
  113.                 if(point.y > stageHeight) {
  114.                     point.y -= stageHeight;
  115.                 }else if(point.y < 0) {
  116.                     point.y += stageHeight;
  117.                 }
  118.             } while (point = point.next);
  119.             
  120.             //更新した母点をvoronoi作図用クラスに入れる
  121.             fortune.points = points;
  122.         }
  123.         //描画
  124.         private function _draw() : void {
  125.             //ボロノイ頂点
  126.             var segments : Vector.<Number2> = fortune.compute(),
  127.                 i : uint,start : Number2,end : Number2,
  128.                 point : Number2 = _first,
  129.                 g : Graphics = _canvas.graphics;
  130.             //ボロノイ辺の描画
  131.             g.clear();
  132.             g.lineStyle(1, 0xFFffff, 1);
  133.             for(i = 0;i < segments.length;i += 2) {
  134.                 start = segments[i];
  135.                 end = segments[i + 1];                
  136.                 g.moveTo(start.x, start.y);
  137.                 g.lineTo(end.x, end.y);
  138.             }
  139.             //ボロノイ母点の描画
  140.             g.lineStyle(1, 0xFF0000, 0.5);
  141.             do {
  142.                 g.drawCircle(point.x, point.y, 1);
  143.             } while (point = point.next);
  144.         }
  145.     }
  146. }
  147. /*
  148.  * Fortune's algorithm
  149.  * http://blog.controul.com/2009/05/speedy-voronoi-diagrams-in-as3flash/
  150.  * オリジナルは上記blogからダウンロードして見てください!
  151.  * はっきりいって全然わからないのでなにやってるのかどなたか解説を!
  152.  */
  153. class Fortune {
  154.     //    voronoi図の母点となる点群
  155.     public var points : Vector.<Number2>;
  156.     //    Bounding box.
  157.     private var x0 : Number;
  158.     //    Root of the frontline and next arc to be removed.
  159.     private var root : Arc;
  160.     private var next : Arc;
  161.     //    Reusable objects and pools.
  162.     private var o : Number2 = new Number2;
  163.     private static var arcPoolD : Arc;
  164.     
  165.     
  166.     /**
  167.      * 与えられた母点からvoronoi頂点群を返します.
  168.      * @return A vector or vertices in pairs, describing segments ready for drawing.
  169.      */
  170.     public function compute() : Vector.<Number2> {
  171.         //    Clear the output.
  172.         var out : Vector.<Number2> = new Vector.<Number2>,
  173.                 len : int = 0;
  174.         //    Clear the state.
  175.         root = null;
  176.         next = null;
  177.         //    Read the pools.
  178.         var key : * ,
  179.                 arcPool : Arc = arcPoolD;
  180.         //    Vars:
  181.         var i : int,
  182.                 j : int,
  183.                 w : Number,
  184.                 x : Number,
  185.                 a : Arc,
  186.                 b : Arc,
  187.                 z : Number2,
  188.                 p : Number2 = points[ 0 ],
  189.                 points : Vector.<Number2> = points,
  190.                 n : int = points.length,
  191.             //    Circle events check inlined.
  192.                 circle : Boolean,
  193.                 eventX : Number,
  194.                 c : Arc,
  195.                 d : Arc,
  196.                 aa : Number2,
  197.                 bb : Number2,
  198.                 cc : Number2,
  199.                 A : Number,
  200.                 B : Number,
  201.                 C : Number,
  202.                 D : Number,
  203.                 E : Number,
  204.                 F : Number,
  205.                 G : Number;
  206.         //    与えられた母点をx軸でソート
  207.         /////    Currently insertion sort. Quicksort?
  208.         w = points[ 0 ].x;
  209.         for ( i = 1;i < n;i++ ) {
  210.             p = points[ i ];
  211.             //    Insertion sort.
  212.             x = p.x;
  213.             if ( x < w ) {
  214.                 j = i;
  215.                 while ( ( j > 0 ) && ( points[ int(j - 1) ].x > x ) ) {
  216.                     points[ j ] = points[ int(j - 1) ];
  217.                     j--;
  218.                 }
  219.                 points[ j ] = p;
  220.             }
  221.                 else
  222.                     w = x;
  223.         }
  224.         //    Get x bounds.
  225.         x0 = points[ 0 ].x;
  226.         //    Process.
  227.         i = 0;
  228.         p = points[ 0 ];
  229.         x = p.x;
  230.             
  231.         //多分母点群でループ
  232.         for ( ;; ) {
  233.             //    Check circle events. /////////////////////////
  234.             if ( a ) {
  235.                 //    Check for arc a.
  236.                 circle = false;
  237.                 if ( a.prev && a.next ) {
  238.                     aa = a.prev.p,
  239.                     bb = a.p,
  240.                     cc = a.next.p;
  241.                     //    Algorithm from O'Rourke 2ed p. 189.
  242.                     A = bb.x - aa.x,
  243.                     B = bb.y - aa.y,
  244.                     C = cc.x - aa.x,
  245.                     D = cc.y - aa.y;
  246.                     //    Check that bc is a "right turn" from ab.
  247.                     if ( A * D - C * B <= 0 ) {
  248.                         E = A * ( aa.x + bb.x ) + B * ( aa.y + bb.y ),
  249.                         F = C * ( aa.x + cc.x ) + D * ( aa.y + cc.y ),
  250.                         G = 2 * ( A * ( cc.y - bb.y ) - B * ( cc.x - bb.x ) );
  251.                         //    Check for colinearity.
  252.                         //    if ( G > 0.000000001 || G < -0.000000001 )
  253.                         if ( G ) {
  254.                             //    Point o is the center of the circle.
  255.                             o.x = ( D * E - B * F ) / G;
  256.                             o.y = ( A * F - C * E ) / G;
  257.                             //    o.x plus radius equals max x coordinate.
  258.                             A = aa.x - o.x;
  259.                             B = aa.y - o.y;
  260.                             eventX = o.x + Math.sqrt(A * A + B * B);
  261.                             if ( eventX >= w ) circle = true;
  262.                         }
  263.                     }
  264.                 }
  265.                 //    Remove from queue.
  266.                 if ( a.right )
  267.                         a.right.left = a.left;
  268.                 if ( a.left )
  269.                         a.left.right = a.right;
  270.                 if ( a == next )
  271.                         next = a.right;
  272.                 //    Record event.
  273.                 if ( circle ) {
  274.                     a.endX = eventX;
  275.                     if ( a.endP ) {
  276.                         a.endP.x = o.x;
  277.                         a.endP.y = o.y;
  278.                     } else {
  279.                         a.endP = o;
  280.                         o = new Number2;
  281.                     }
  282.                     d = next;
  283.                     if ( !d ) {
  284.                         next = a;
  285.                     }
  286.                         else for ( ;; ) {
  287.                         if ( d.endX >= eventX ) {
  288.                             a.left = d.left;
  289.                             if ( d.left ) d.left.right = a;
  290.                             if ( next == d ) next = a;
  291.                             a.right = d;
  292.                             d.left = a;
  293.                             break;
  294.                         }
  295.                         if ( !d.right ) {
  296.                             d.right = a;
  297.                             a.left = d;
  298.                             a.right = null;
  299.                             break;
  300.                         }
  301.                         d = d.right;
  302.                     }
  303.                 } else {
  304.                     a.endX = NaN;
  305.                     a.endP = null;
  306.                     a.left = null;
  307.                     a.right = null;
  308.                 }
  309.                 //    Push next arc to check.
  310.                 if ( b ) {
  311.                     a = b;
  312.                     b = null;
  313.                     continue;
  314.                 }
  315.                 if ( c ) {
  316.                     a = c;
  317.                     c = null;
  318.                     continue;
  319.                 }
  320.                 a = null;
  321.             }
  322.             //////////////////////////////////////////////////
  323.             //
  324.             if ( next && next.endX <= x ) {
  325.                 //
  326.                 //    Handle next circle event.
  327.                 //    Get the next event from the queue. ///////////
  328.                 a = next;
  329.                 next = a.right;
  330.                 if ( next )
  331.                         next.left = null;
  332.                 a.right = null;
  333.                 //    Remove the associated arc from the front.
  334.                 if ( a.prev ) {
  335.                     a.prev.next = a.next;
  336.                     a.prev.v1 = a.endP;
  337.                 }
  338.                 if ( a.next ) {
  339.                     a.next.prev = a.prev;
  340.                     a.next.v0 = a.endP;
  341.                 }
  342.                 if ( a.v0 ) {
  343.                     out[ len++ ] = a.v0;
  344.                     a.v0 = null;
  345.                     out[ len++ ] = a.endP;
  346.                 }
  347.                 if ( a.v1 ) {
  348.                     out[ len++ ] = a.v1;
  349.                     a.v1 = null;
  350.                     out[ len++ ] = a.endP;
  351.                 }
  352.                 //    Keep a ref for collection.
  353.                 d = a;
  354.                 //    Recheck circle events on either side of p:
  355.                 w = a.endX;
  356.                 if ( a.prev ) {
  357.                     b = a.prev;
  358.                     a = a.next;
  359.                 } else {
  360.                     a = a.next;
  361.                     b = null;
  362.                 }
  363.                 c = null;
  364.                 //    Collect.
  365.                 d.v0 = null;
  366.                 d.v1 = null;
  367.                 d.p = null;
  368.                 d.prev = null;
  369.                 d.endX = NaN;
  370.                 d.endP = null;
  371.                 d.next = arcPool;
  372.                 arcPool = d;
  373.                     //////////////////////////////////////////////////
  374.                     //
  375.             } else {
  376.                 if ( !p ) break;
  377.                 //
  378.                 //    Handle next site event. //////////////////////
  379.                 if ( !root ) {
  380.                     if ( arcPool ) {
  381.                         root = arcPool;
  382.                         arcPool = arcPool.next;
  383.                         root.next = null;
  384.                     }
  385.                         else
  386.                             root = new Arc;
  387.                     root.p = p;
  388.                 } else {
  389.                     z = new Number2;
  390.                     //    Find the first arc with a point below p,
  391.                     //    and start searching for the intersection around it.
  392.                     a = root.next;
  393.                     if ( a ) {
  394.                             while ( a.next ) {
  395.                                 a = a.next;
  396.                                 if ( a.p.y >= p.y ) break;
  397.                             }
  398.                             //    Find the intersecting curve.
  399.                             intersection(a.prev.p, a.p, p.x, z);
  400.                             if ( z.y <= p.y ) {
  401.                                 
  402.                                 //    Search for the intersection to the south of i.
  403.                                 while ( a.next ) {
  404.                                     a = a.next;
  405.                                     intersection(a.prev.p, a.p, p.x, z);
  406.                                     if ( z.y >= p.y ) {
  407.                                         a = a.prev;
  408.                                         break;
  409.                                     }
  410.                                 }
  411.                             } else {
  412.                                 //    Search for the intersection above i.
  413.                                 a = a.prev;
  414.                                 while ( a.prev ) {
  415.                                     a = a.prev;
  416.                                     intersection(a.p, a.next.p, p.x, z);
  417.                                     if ( z.y <= p.y ) {
  418.                                         a = a.next;
  419.                                         break;
  420.                                     }
  421.                                 }
  422.                             }
  423.                         }
  424.                         else
  425.                             a = root;
  426.                     //    New parabola will intersect arc a. Duplicate a.
  427.                     if ( a.next ) {
  428.                             if ( arcPool ) {
  429.                                 b = arcPool;
  430.                                 arcPool = arcPool.next;
  431.                                 b.next = null;
  432.                             }
  433.                             else
  434.                                 b = new Arc;
  435.                             b.p = a.p;
  436.                             b.prev = a;
  437.                             b.next = a.next;
  438.                             a.next.prev = b;
  439.                             a.next = b;
  440.                         } else {
  441.                             if ( arcPool ) {
  442.                                 b = arcPool;
  443.                                 arcPool = arcPool.next;
  444.                                 b.next = null;
  445.                             }
  446.                             else
  447.                                 b = new Arc;
  448.                             b.p = a.p;
  449.                             b.prev = a;
  450.                             a.next = b;
  451.                         }
  452.                     a.next.v1 = a.v1;
  453.                     //    Find the point of intersection.
  454.                     z.y = p.y;
  455.                     z.x = ( a.p.x * a.p.x + ( a.p.y - p.y ) * ( a.p.y - p.y ) - p.x * p.x ) / ( 2 * a.p.x - 2 * p.x );
  456.                     //    Add p between i and i->next.
  457.                     if ( arcPool ) {
  458.                             b = arcPool;
  459.                             arcPool = arcPool.next;
  460.                             b.next = null;
  461.                         }
  462.                         else
  463.                             b = new Arc;
  464.                     b.p = p;
  465.                     b.prev = a;
  466.                     b.next = a.next;
  467.                     a.next.prev = b;
  468.                     a.next = b;
  469.                     a = a.next;    //    Now a points to the new arc.
  470.                     a.prev.v1 = z;
  471.                         a.next.v0 = z;
  472.                         a.v0 = z;
  473.                         a.v1 = z;
  474.                         //    Check for new circle events around the new arc:
  475.                         b = a.next;
  476.                         a = a.prev;
  477.                         c = null;
  478.                         w = p.x;
  479.                 }
  480.                 //////////////////////////////////////////////////
  481.                 //
  482.                 i++;
  483.                 if ( i >= n ) {
  484.                         p = null;
  485.                         x = Number.MAX_VALUE;
  486.                     } else {
  487.                         p = points[ i ];
  488.                         x = p.x;
  489.                     }
  490.             }
  491.         }
  492.         //    Store the pools.
  493.         arcPoolD = arcPool;
  494.         //
  495.         //
  496.         //    Return the result ready for drawing.
  497.         return out;
  498.     }
  499.         
  500.         
  501.         /**
  502.          * Where do two parabolas intersect?
  503.          * @param    p0 A Number2 object describing the site for the first parabola.
  504.          * @param    p1 A Number2 object describing the site for the second parabola.
  505.          * @param    l The location of the sweep line.
  506.          * @param    res A Number2 object in which to store the intersection.
  507.          * @return The point of intersection.
  508.          */
  509.         public function intersection( p0 : Number2, p1 : Number2, l : Number, res : Number2 ) : Number2 {
  510.             var p : Number2 = p0,
  511.                 ll : Number = l * l;
  512.             if ( p0.x == p1.x )
  513.                 res.y = ( p0.y + p1.y ) / 2;
  514.             else if ( p1.x == l )
  515.                 res.y = p1.y;
  516.             else if ( p0.x == l ) {
  517.                 res.y = p0.y;
  518.                 p = p1;
  519.             } else {
  520.                 //    Use the quadratic formula.
  521.                 var z0 : Number = 0.5 / ( p0.x - l ); // 1 / ( 2*(p0.x - l) )
  522.                 var z1 : Number = 0.5 / ( p1.x - l ); // 1 / ( 2*(p1.x - l) )
  523.                 var a : Number = z0 - z1;
  524.                 var b : Number = -2 * ( p0.y * z0 - p1.y * z1 );
  525.                 var c : Number = ( p0.y * p0.y + p0.x * p0.x - ll ) * z0 - ( p1.y * p1.y + p1.x * p1.x - ll ) * z1;
  526.                 res.y = ( -b - Math.sqrt(b * b - 4 * a * c) ) / ( 2 * a );
  527.             }
  528.             
  529.             //    Plug back into one of the parabola equations.
  530.             res.x = ( p.x * p.x + ( p.y - res.y ) * ( p.y - res.y ) - ll ) / ( 2 * p.x - 2 * l );
  531.             return res;
  532.         }
  533. }
  534. class Arc {
  535.     public var p : Number2;
  536.     public var next : Arc;
  537.     public var prev : Arc;
  538.     public var v0 : Number2;
  539.     public var v1 : Number2;
  540.     //    Circle event data :
  541.     public var left : Arc;
  542.     public var right : Arc;
  543.     public var endX : Number;
  544.     public var endP : Number2;
  545. }
  546. class Number2 {
  547.     public var x : Number;
  548.     public var y : Number;
  549.     //速度
  550.     public var vx : Number;
  551.     public var vy : Number;
  552.     public var next : Number2;
  553. }
noswf
  1. // forked from fumix's 超速ボロノイ図(Fortune's algorithm)
  2. /**
  3.  * 超速ボロノイアルゴリズム
  4.  * 元ネタ
  5.  * Fortune's algorithm - Wikipedia, the free encyclopedia
  6.  * http://en.wikipedia.org/wiki/Fortune's_algorithm
  7.  * Controul > Speedy Voronoi diagrams in as3/flash
  8.  * http://blog.controul.com/2009/05/speedy-voronoi-diagrams-in-as3flash/
  9.  * 上記blogのasそのままです(Fortuneクラス)。
  10.  * 全然ロジックわからないので誰か解説してほしいです。
  11.  *
  12.  * 母点を800程度にしてますがもう少し多くてもいけそう。
  13.  * fullscreenでもお楽しみいただけます(重いけど)
  14.  * 
  15.  * 日本語の資料(PDF)
  16.  * http://atom.is.ocha.ac.jp/~kanenko/KOUGI/CompGeo/cpgeob.pdf
  17.  * http://i-health.u-aizu.ac.jp/CompuGeo/2008/handouts/chapter4/Chapter4H.pdf
  18.  */
  19. package {
  20.     import flash.display.Bitmap;
  21.     import flash.display.BitmapData;
  22.     import flash.display.Graphics;
  23.     import flash.display.StageQuality;
  24.     import flash.events.Event;
  25.     import flash.display.Sprite;
  26.     import flash.display.StageAlign;
  27.     import flash.display.StageScaleMode;
  28.     import com.flashdynamix.utils.SWFProfiler;
  29.     [SWF(backgroundColor="#000000", frameRate="30", width="465", height="465")]    
  30.     public class Main extends Sprite {
  31.         //キャンパス
  32.         private var _canvas : Sprite;
  33.         //background
  34.         private var _background:BitmapData;
  35.         //voronoi母点数
  36.         private const Q : uint = 800;
  37.         //voronoi作図用のクラス
  38.         private var fortune : Fortune;
  39.         //voronoi母点(パーティクル的な?)
  40.         private var points : Vector.<Number2>;
  41.         private var _first : Number2;
  42.         private var stageWidth : int;
  43.         private var stageHeight : int;
  44.         public function Main() {
  45.             addEventListener(Event.ADDED_TO_STAGE, _initialize);
  46.         }
  47.         /**
  48.          * 初期化
  49.          */
  50.         private function _initialize(event : Event) : void {
  51.             var i : uint,old : Number2,point : Number2;
  52.             removeEventListener(Event.ADDED_TO_STAGE, _initialize);
  53.             SWFProfiler.init(this);
  54.             //ステージ設定
  55.             stage.scaleMode = StageScaleMode.NO_SCALE;
  56.             stage.align = StageAlign.TOP_LEFT;
  57.             stage.quality = StageQuality.LOW;
  58.             
  59.             stageWidth = stage.stageWidth;
  60.             stageHeight = stage.stageHeight;
  61.             //背景カラー
  62.             _background = new BitmapData(stageWidth , stageHeight, false, 0x0);
  63.             addChild(new Bitmap(_background));
  64.             //キャンパス設定
  65.             _canvas = new Sprite();
  66.             _canvas.x = 0;
  67.             _canvas.y = 0;
  68.             addChild(_canvas);
  69.             //voronoi母点生成
  70.             points = new Vector.<Number2>();
  71.             for(i = 0;i < Q;i++) {
  72.                 point = new Number2();
  73.                 point.x = stageWidth * Math.random();
  74.                 point.y = stageHeight * Math.random();
  75.                 //各母点の速度
  76.                 point.vx = Math.random() * 4 - 2;
  77.                 point.vy = Math.random() * 4 - 2;
  78.                 points.push(point);
  79.             }
  80.             //voronoi母点リンクリスト生成
  81.             for(i = 0;i < Q;i++) {
  82.                 point = points[i];
  83.                 if (_first == null) {
  84.                     old = _first = point;
  85.                 } else {
  86.                     old.next = point;
  87.                     old = point;
  88.                 }                
  89.             }
  90.             
  91.             //ボロノイ作図用クラス            
  92.             fortune = new Fortune();
  93.             
  94.             addEventListener(Event.ENTER_FRAME, _updateHandler);            
  95.         }
  96.         //アップデート
  97.         private function _updateHandler(event : Event) : void {
  98.             _interaction();
  99.             _draw();
  100.         }
  101.         //インタラクション
  102.         private function _interaction() : void {
  103.             var point : Number2 = _first;
  104.             do {
  105.                 //母点の位置を更新
  106.                 point.x += point.vx;
  107.                 point.y += point.vy;
  108.                 if(point.x > stageWidth) {
  109.                     point.x -= stageWidth;
  110.                 }else if(point.x < 0) {
  111.                     point.x += stageWidth;
  112.                 }
  113.                 if(point.y > stageHeight) {
  114.                     point.y -= stageHeight;
  115.                 }else if(point.y < 0) {
  116.                     point.y += stageHeight;
  117.                 }
  118.             } while (point = point.next);
  119.             
  120.             //更新した母点をvoronoi作図用クラスに入れる
  121.             fortune.points = points;
  122.         }
  123.         //描画
  124.         private function _draw() : void {
  125.             //ボロノイ頂点
  126.             var segments : Vector.<Number2> = fortune.compute(),
  127.                 i : uint,start : Number2,end : Number2,
  128.                 point : Number2 = _first,
  129.                 g : Graphics = _canvas.graphics;
  130.             //ボロノイ辺の描画
  131.             g.clear();
  132.             g.lineStyle(1, 0xFFFFFF, 0.25);
  133.             for(i = 0;i < segments.length;i += 2) {
  134.                 start = segments[i];
  135.                 end = segments[i + 1];                
  136.                 g.moveTo(start.x, start.y);
  137.                 g.lineTo(end.x, end.y);
  138.             }
  139.             //ボロノイ母点の描画
  140.             g.lineStyle(1, 0xFF0000, 0.5);
  141.             do {
  142.                 g.drawCircle(point.x, point.y, 1);
  143.             } while (point = point.next);
  144.         }
  145.     }
  146. }
  147. /*
  148.  * Fortune's algorithm
  149.  * http://blog.controul.com/2009/05/speedy-voronoi-diagrams-in-as3flash/
  150.  * オリジナルは上記blogからダウンロードして見てください!
  151.  * はっきりいって全然わからないのでなにやってるのかどなたか解説を!
  152.  */
  153. class Fortune {
  154.     //    voronoi図の母点となる点群
  155.     public var points : Vector.<Number2>;
  156.     //    Bounding box.
  157.     private var x0 : Number;
  158.     //    Root of the frontline and next arc to be removed.
  159.     private var root : Arc;
  160.     private var next : Arc;
  161.     //    Reusable objects and pools.
  162.     private var o : Number2 = new Number2;
  163.     private static var arcPoolD : Arc;
  164.     
  165.     
  166.     /**
  167.      * 与えられた母点からvoronoi頂点群を返します.
  168.      * @return A vector or vertices in pairs, describing segments ready for drawing.
  169.      */
  170.     public function compute() : Vector.<Number2> {
  171.         //    Clear the output.
  172.         var out : Vector.<Number2> = new Vector.<Number2>,
  173.                 len : int = 0;
  174.         //    Clear the state.
  175.         root = null;
  176.         next = null;
  177.         //    Read the pools.
  178.         var key : * ,
  179.                 arcPool : Arc = arcPoolD;
  180.         //    Vars:
  181.         var i : int,
  182.                 j : int,
  183.                 w : Number,
  184.                 x : Number,
  185.                 a : Arc,
  186.                 b : Arc,
  187.                 z : Number2,
  188.                 p : Number2 = points[ 0 ],
  189.                 points : Vector.<Number2> = points,
  190.                 n : int = points.length,
  191.             //    Circle events check inlined.
  192.                 circle : Boolean,
  193.                 eventX : Number,
  194.                 c : Arc,
  195.                 d : Arc,
  196.                 aa : Number2,
  197.                 bb : Number2,
  198.                 cc : Number2,
  199.                 A : Number,
  200.                 B : Number,
  201.                 C : Number,
  202.                 D : Number,
  203.                 E : Number,
  204.                 F : Number,
  205.                 G : Number;
  206.         //    与えられた母点をx軸でソート
  207.         /////    Currently insertion sort. Quicksort?
  208.         w = points[ 0 ].x;
  209.         for ( i = 1;i < n;i++ ) {
  210.             p = points[ i ];
  211.             //    Insertion sort.
  212.             x = p.x;
  213.             if ( x < w ) {
  214.                 j = i;
  215.                 while ( ( j > 0 ) && ( points[ int(j - 1) ].x > x ) ) {
  216.                     points[ j ] = points[ int(j - 1) ];
  217.                     j--;
  218.                 }
  219.                 points[ j ] = p;
  220.             }
  221.                 else
  222.                     w = x;
  223.         }
  224.         //    Get x bounds.
  225.         x0 = points[ 0 ].x;
  226.         //    Process.
  227.         i = 0;
  228.         p = points[ 0 ];
  229.         x = p.x;
  230.             
  231.         //多分母点群でループ
  232.         for ( ;; ) {
  233.             //    Check circle events. /////////////////////////
  234.             if ( a ) {
  235.                 //    Check for arc a.
  236.                 circle = false;
  237.                 if ( a.prev && a.next ) {
  238.                     aa = a.prev.p,
  239.                     bb = a.p,
  240.                     cc = a.next.p;
  241.                     //    Algorithm from O'Rourke 2ed p. 189.
  242.                     A = bb.x - aa.x,
  243.                     B = bb.y - aa.y,
  244.                     C = cc.x - aa.x,
  245.                     D = cc.y - aa.y;
  246.                     //    Check that bc is a "right turn" from ab.
  247.                     if ( A * D - C * B <= 0 ) {
  248.                         E = A * ( aa.x + bb.x ) + B * ( aa.y + bb.y ),
  249.                         F = C * ( aa.x + cc.x ) + D * ( aa.y + cc.y ),
  250.                         G = 2 * ( A * ( cc.y - bb.y ) - B * ( cc.x - bb.x ) );
  251.                         //    Check for colinearity.
  252.                         //    if ( G > 0.000000001 || G < -0.000000001 )
  253.                         if ( G ) {
  254.                             //    Point o is the center of the circle.
  255.                             o.x = ( D * E - B * F ) / G;
  256.                             o.y = ( A * F - C * E ) / G;
  257.                             //    o.x plus radius equals max x coordinate.
  258.                             A = aa.x - o.x;
  259.                             B = aa.y - o.y;
  260.                             eventX = o.x + Math.sqrt(A * A + B * B);
  261.                             if ( eventX >= w ) circle = true;
  262.                         }
  263.                     }
  264.                 }
  265.                 //    Remove from queue.
  266.                 if ( a.right )
  267.                         a.right.left = a.left;
  268.                 if ( a.left )
  269.                         a.left.right = a.right;
  270.                 if ( a == next )
  271.                         next = a.right;
  272.                 //    Record event.
  273.                 if ( circle ) {
  274.                     a.endX = eventX;
  275.                     if ( a.endP ) {
  276.                         a.endP.x = o.x;
  277.                         a.endP.y = o.y;
  278.                     } else {
  279.                         a.endP = o;
  280.                         o = new Number2;
  281.                     }
  282.                     d = next;
  283.                     if ( !d ) {
  284.                         next = a;
  285.                     }
  286.                         else for ( ;; ) {
  287.                         if ( d.endX >= eventX ) {
  288.                             a.left = d.left;
  289.                             if ( d.left ) d.left.right = a;
  290.                             if ( next == d ) next = a;
  291.                             a.right = d;
  292.                             d.left = a;
  293.                             break;
  294.                         }
  295.                         if ( !d.right ) {
  296.                             d.right = a;
  297.                             a.left = d;
  298.                             a.right = null;
  299.                             break;
  300.                         }
  301.                         d = d.right;
  302.                     }
  303.                 } else {
  304.                     a.endX = NaN;
  305.                     a.endP = null;
  306.                     a.left = null;
  307.                     a.right = null;
  308.                 }
  309.                 //    Push next arc to check.
  310.                 if ( b ) {
  311.                     a = b;
  312.                     b = null;
  313.                     continue;
  314.                 }
  315.                 if ( c ) {
  316.                     a = c;
  317.                     c = null;
  318.                     continue;
  319.                 }
  320.                 a = null;
  321.             }
  322.             //////////////////////////////////////////////////
  323.             //
  324.             if ( next && next.endX <= x ) {
  325.                 //
  326.                 //    Handle next circle event.
  327.                 //    Get the next event from the queue. ///////////
  328.                 a = next;
  329.                 next = a.right;
  330.                 if ( next )
  331.                         next.left = null;
  332.                 a.right = null;
  333.                 //    Remove the associated arc from the front.
  334.                 if ( a.prev ) {
  335.                     a.prev.next = a.next;
  336.                     a.prev.v1 = a.endP;
  337.                 }
  338.                 if ( a.next ) {
  339.                     a.next.prev = a.prev;
  340.                     a.next.v0 = a.endP;
  341.                 }
  342.                 if ( a.v0 ) {
  343.                     out[ len++ ] = a.v0;
  344.                     a.v0 = null;
  345.                     out[ len++ ] = a.endP;
  346.                 }
  347.                 if ( a.v1 ) {
  348.                     out[ len++ ] = a.v1;
  349.                     a.v1 = null;
  350.                     out[ len++ ] = a.endP;
  351.                 }
  352.                 //    Keep a ref for collection.
  353.                 d = a;
  354.                 //    Recheck circle events on either side of p:
  355.                 w = a.endX;
  356.                 if ( a.prev ) {
  357.                     b = a.prev;
  358.                     a = a.next;
  359.                 } else {
  360.                     a = a.next;
  361.                     b = null;
  362.                 }
  363.                 c = null;
  364.                 //    Collect.
  365.                 d.v0 = null;
  366.                 d.v1 = null;
  367.                 d.p = null;
  368.                 d.prev = null;
  369.                 d.endX = NaN;
  370.                 d.endP = null;
  371.                 d.next = arcPool;
  372.                 arcPool = d;
  373.                     //////////////////////////////////////////////////
  374.                     //
  375.             } else {
  376.                 if ( !p ) break;
  377.                 //
  378.                 //    Handle next site event. //////////////////////
  379.                 if ( !root ) {
  380.                     if ( arcPool ) {
  381.                         root = arcPool;
  382.                         arcPool = arcPool.next;
  383.                         root.next = null;
  384.                     }
  385.                         else
  386.                             root = new Arc;
  387.                     root.p = p;
  388.                 } else {
  389.                     z = new Number2;
  390.                     //    Find the first arc with a point below p,
  391.                     //    and start searching for the intersection around it.
  392.                     a = root.next;
  393.                     if ( a ) {
  394.                             while ( a.next ) {
  395.                                 a = a.next;
  396.                                 if ( a.p.y >= p.y ) break;
  397.                             }
  398.                             //    Find the intersecting curve.
  399.                             intersection(a.prev.p, a.p, p.x, z);
  400.                             if ( z.y <= p.y ) {
  401.                                 
  402.                                 //    Search for the intersection to the south of i.
  403.                                 while ( a.next ) {
  404.                                     a = a.next;
  405.                                     intersection(a.prev.p, a.p, p.x, z);
  406.                                     if ( z.y >= p.y ) {
  407.                                         a = a.prev;
  408.                                         break;
  409.                                     }
  410.                                 }
  411.                             } else {
  412.                                 //    Search for the intersection above i.
  413.                                 a = a.prev;
  414.                                 while ( a.prev ) {
  415.                                     a = a.prev;
  416.                                     intersection(a.p, a.next.p, p.x, z);
  417.                                     if ( z.y <= p.y ) {
  418.                                         a = a.next;
  419.                                         break;
  420.                                     }
  421.                                 }
  422.                             }
  423.                         }
  424.                         else
  425.                             a = root;
  426.                     //    New parabola will intersect arc a. Duplicate a.
  427.                     if ( a.next ) {
  428.                             if ( arcPool ) {
  429.                                 b = arcPool;
  430.                                 arcPool = arcPool.next;
  431.                                 b.next = null;
  432.                             }
  433.                             else
  434.                                 b = new Arc;
  435.                             b.p = a.p;
  436.                             b.prev = a;
  437.                             b.next = a.next;
  438.                             a.next.prev = b;
  439.                             a.next = b;
  440.                         } else {
  441.                             if ( arcPool ) {
  442.                                 b = arcPool;
  443.                                 arcPool = arcPool.next;
  444.                                 b.next = null;
  445.                             }
  446.                             else
  447.                                 b = new Arc;
  448.                             b.p = a.p;
  449.                             b.prev = a;
  450.                             a.next = b;
  451.                         }
  452.                     a.next.v1 = a.v1;
  453.                     //    Find the point of intersection.
  454.                     z.y = p.y;
  455.                     z.x = ( a.p.x * a.p.x + ( a.p.y - p.y ) * ( a.p.y - p.y ) - p.x * p.x ) / ( 2 * a.p.x - 2 * p.x );
  456.                     //    Add p between i and i->next.
  457.                     if ( arcPool ) {
  458.                             b = arcPool;
  459.                             arcPool = arcPool.next;
  460.                             b.next = null;
  461.                         }
  462.                         else
  463.                             b = new Arc;
  464.                     b.p = p;
  465.                     b.prev = a;
  466.                     b.next = a.next;
  467.                     a.next.prev = b;
  468.                     a.next = b;
  469.                     a = a.next;    //    Now a points to the new arc.
  470.                     a.prev.v1 = z;
  471.                         a.next.v0 = z;
  472.                         a.v0 = z;
  473.                         a.v1 = z;
  474.                         //    Check for new circle events around the new arc:
  475.                         b = a.next;
  476.                         a = a.prev;
  477.                         c = null;
  478.                         w = p.x;
  479.                 }
  480.                 //////////////////////////////////////////////////
  481.                 //
  482.                 i++;
  483.                 if ( i >= n ) {
  484.                         p = null;
  485.                         x = Number.MAX_VALUE;
  486.                     } else {
  487.                         p = points[ i ];
  488.                         x = p.x;
  489.                     }
  490.             }
  491.         }
  492.         //    Store the pools.
  493.         arcPoolD = arcPool;
  494.         //
  495.         //
  496.         //    Return the result ready for drawing.
  497.         return out;
  498.     }
  499.         
  500.         
  501.         /**
  502.          * Where do two parabolas intersect?
  503.          * @param    p0 A Number2 object describing the site for the first parabola.
  504.          * @param    p1 A Number2 object describing the site for the second parabola.
  505.          * @param    l The location of the sweep line.
  506.          * @param    res A Number2 object in which to store the intersection.
  507.          * @return The point of intersection.
  508.          */
  509.         public function intersection( p0 : Number2, p1 : Number2, l : Number, res : Number2 ) : Number2 {
  510.             var p : Number2 = p0,
  511.                 ll : Number = l * l;
  512.             if ( p0.x == p1.x )
  513.                 res.y = ( p0.y + p1.y ) / 2;
  514.             else if ( p1.x == l )
  515.                 res.y = p1.y;
  516.             else if ( p0.x == l ) {
  517.                 res.y = p0.y;
  518.                 p = p1;
  519.             } else {
  520.                 //    Use the quadratic formula.
  521.                 var z0 : Number = 0.5 / ( p0.x - l ); // 1 / ( 2*(p0.x - l) )
  522.                 var z1 : Number = 0.5 / ( p1.x - l ); // 1 / ( 2*(p1.x - l) )
  523.                 var a : Number = z0 - z1;
  524.                 var b : Number = -2 * ( p0.y * z0 - p1.y * z1 );
  525.                 var c : Number = ( p0.y * p0.y + p0.x * p0.x - ll ) * z0 - ( p1.y * p1.y + p1.x * p1.x - ll ) * z1;
  526.                 res.y = ( -b - Math.sqrt(b * b - 4 * a * c) ) / ( 2 * a );
  527.             }
  528.             
  529.             //    Plug back into one of the parabola equations.
  530.             res.x = ( p.x * p.x + ( p.y - res.y ) * ( p.y - res.y ) - ll ) / ( 2 * p.x - 2 * l );
  531.             return res;
  532.         }
  533. }
  534. class Arc {
  535.     public var p : Number2;
  536.     public var next : Arc;
  537.     public var prev : Arc;
  538.     public var v0 : Number2;
  539.     public var v1 : Number2;
  540.     //    Circle event data :
  541.     public var left : Arc;
  542.     public var right : Arc;
  543.     public var endX : Number;
  544.     public var endP : Number2;
  545. }
  546. class Number2 {
  547.     public var x : Number;
  548.     public var y : Number;
  549.     //速度
  550.     public var vx : Number;
  551.     public var vy : Number;
  552.     public var next : Number2;
  553. }
noswf
  1. // forked from fumix's 超速ボロノイ図(Fortune's algorithm)
  2. /**
  3.  * 超速ボロノイアルゴリズム
  4.  * 元ネタ
  5.  * Fortune's algorithm - Wikipedia, the free encyclopedia
  6.  * http://en.wikipedia.org/wiki/Fortune's_algorithm
  7.  * Controul > Speedy Voronoi diagrams in as3/flash
  8.  * http://blog.controul.com/2009/05/speedy-voronoi-diagrams-in-as3flash/
  9.  * 上記blogのasそのままです(Fortuneクラス)。
  10.  * 全然ロジックわからないので誰か解説してほしいです。
  11.  *
  12.  * 母点を800程度にしてますがもう少し多くてもいけそう。
  13.  * fullscreenでもお楽しみいただけます(重いけど)
  14.  * 
  15.  * 日本語の資料(PDF)
  16.  * http://atom.is.ocha.ac.jp/~kanenko/KOUGI/CompGeo/cpgeob.pdf
  17.  * http://i-health.u-aizu.ac.jp/CompuGeo/2008/handouts/chapter4/Chapter4H.pdf
  18.  */
  19. package {
  20.     import flash.display.Bitmap;
  21.     import flash.display.BitmapData;
  22.     import flash.display.Graphics;
  23.     import flash.display.StageQuality;
  24.     import flash.events.Event;
  25.     import flash.display.Sprite;
  26.     import flash.display.StageAlign;
  27.     import flash.display.StageScaleMode;
  28.     import com.flashdynamix.utils.SWFProfiler;
  29.     [SWF(backgroundColor="#000000", frameRate="30", width="465", height="465")]    
  30.     public class Main extends Sprite {
  31.         //キャンパス
  32.         private var _canvas : Sprite;
  33.         //background
  34.         private var _background:BitmapData;
  35.         //voronoi母点数
  36.         private const Q : uint = 800;
  37.         //voronoi作図用のクラス
  38.         private var fortune : Fortune;
  39.         //voronoi母点(パーティクル的な?)
  40.         private var points : Vector.<Number2>;
  41.         private var _first : Number2;
  42.         private var stageWidth : int;
  43.         private var stageHeight : int;
  44.         public function Main() {
  45.             addEventListener(Event.ADDED_TO_STAGE, _initialize);
  46.         }
  47.         /**
  48.          * 初期化
  49.          */
  50.         private function _initialize(event : Event) : void {
  51.             var i : uint,old : Number2,point : Number2;
  52.             removeEventListener(Event.ADDED_TO_STAGE, _initialize);
  53.             SWFProfiler.init(this);
  54.             //ステージ設定
  55.             stage.scaleMode = StageScaleMode.NO_SCALE;
  56.             stage.align = StageAlign.TOP_LEFT;
  57.             stage.quality = StageQuality.LOW;
  58.             
  59.             stageWidth = stage.stageWidth;
  60.             stageHeight = stage.stageHeight;
  61.             //背景カラー
  62.             _background = new BitmapData(stageWidth , stageHeight, false, 0x0);
  63.             addChild(new Bitmap(_background));
  64.             //キャンパス設定
  65.             _canvas = new Sprite();
  66.             _canvas.x = 0;
  67.             _canvas.y = 0;
  68.             addChild(_canvas);
  69.             //voronoi母点生成
  70.             points = new Vector.<Number2>();
  71.             for(i = 0;i < Q;i++) {
  72.                 point = new Number2();
  73.                 point.x = stageWidth * Math.random();
  74.                 point.y = stageHeight * Math.random();
  75.                 //各母点の速度
  76.                 point.vx = Math.random() * 0.4 - 0.2;
  77.                 point.vy = Math.random() * 0.4 - 0.2;
  78.                 points.push(point);
  79.             }
  80.             //voronoi母点リンクリスト生成
  81.             for(i = 0;i < Q;i++) {
  82.                 point = points[i];
  83.                 if (_first == null) {
  84.                     old = _first = point;
  85.                 } else {
  86.                     old.next = point;
  87.                     old = point;
  88.                 }
  89.             }
  90.             
  91.             //ボロノイ作図用クラス
  92.             fortune = new Fortune();
  93.             addEventListener(Event.ENTER_FRAME, _updateHandler);
  94.         }
  95.         //アップデート
  96.         private function _updateHandler(event : Event) : void {
  97.             _interaction();
  98.             _draw();
  99.         }
  100.         //インタラクション
  101.         private function _interaction() : void {
  102.             var point : Number2 = _first;
  103.             do {
  104.                 //母点の位置を更新
  105.                 point.x += point.vx;
  106.                 point.y += point.vy;
  107. point.y+=3;
  108.                 if(point.x > stageWidth) {
  109.                     point.x -= stageWidth;
  110.                 }else if(point.x < 0) {
  111.                     point.x += stageWidth;
  112.                 }
  113.                 if(point.y > stageHeight) {
  114.                     point.y -= stageHeight;
  115.                 }else if(point.y < 0) {
  116.                     point.y += stageHeight;
  117.                 }
  118.             } while (point = point.next);
  119.             
  120.             //更新した母点をvoronoi作図用クラスに入れる
  121.             fortune.points = points;
  122.         }
  123.         //描画
  124.         private function _draw() : void {
  125.             //ボロノイ頂点
  126.             var segments : Vector.<Number2> = fortune.compute(),
  127.                 i : uint,start : Number2,end : Number2,
  128.                 point : Number2 = _first,
  129.                 g : Graphics = _canvas.graphics;
  130.             //ボロノイ辺の描画
  131.             g.clear();
  132.             g.lineStyle(1, 0xFFFFFF, 0.25);
  133.             for(i = 0;i < segments.length;i += 2) {
  134.                 start = segments[i];
  135.                 end = segments[i + 1];
  136.                 if(start.y < -100 || end.y < -100continue;
  137.                 if(start.y > 500 || end.y > 500continue;
  138.                 
  139.                 g.moveTo(223+(start.x-223)*300/(500-start.y), 100+15000/(500-start.y));
  140.                 g.lineTo(223+(end.x-223)*300/(500-end.y), 100+15000/(500-end.y));
  141.                 
  142.             }
  143.             //ボロノイ母点の描画
  144.             g.lineStyle(1, 0xFF0000, 0.5);
  145.             do {
  146.             //    g.drawCircle(point.x, point.y, 1);
  147.             } while (point = point.next);
  148.         }
  149.     }
  150. }
  151. /*
  152.  * Fortune's algorithm
  153.  * http://blog.controul.com/2009/05/speedy-voronoi-diagrams-in-as3flash/
  154.  * オリジナルは上記blogからダウンロードして見てください!
  155.  * はっきりいって全然わからないのでなにやってるのかどなたか解説を!
  156.  */
  157. class Fortune {
  158.     //    voronoi図の母点となる点群
  159.     public var points : Vector.<Number2>;
  160.     //    Bounding box.
  161.     private var x0 : Number;
  162.     //    Root of the frontline and next arc to be removed.
  163.     private var root : Arc;
  164.     private var next : Arc;
  165.     //    Reusable objects and pools.
  166.     private var o : Number2 = new Number2;
  167.     private static var arcPoolD : Arc;
  168.     
  169.     
  170.     /**
  171.      * 与えられた母点からvoronoi頂点群を返します.
  172.      * @return A vector or vertices in pairs, describing segments ready for drawing.
  173.      */
  174.     public function compute() : Vector.<Number2> {
  175.         //    Clear the output.
  176.         var out : Vector.<Number2> = new Vector.<Number2>,
  177.             len : int = 0;
  178.         //    Clear the state.
  179.         root = null;
  180.         next = null;
  181.         //    Read the pools.
  182.         var key : * ,
  183.                 arcPool : Arc = arcPoolD;
  184.         //    Vars:
  185.         var i : int,
  186.             j : int,
  187.             w : Number,
  188.             x : Number,
  189.             a : Arc,
  190.             b : Arc,
  191.             z : Number2,
  192.             p : Number2 = points[ 0 ],
  193.             points : Vector.<Number2> = points,
  194.             n : int = points.length,
  195.         //    Circle events check inlined.
  196.             circle : Boolean,
  197.             eventX : Number,
  198.             c : Arc,
  199.             d : Arc,
  200.             aa : Number2,
  201.             bb : Number2,
  202.             cc : Number2,
  203.             A : Number,
  204.             B : Number,
  205.             C : Number,
  206.             D : Number,
  207.             E : Number,
  208.             F : Number,
  209.             G : Number;
  210.         //    与えられた母点をx軸でソート
  211.         /////    Currently insertion sort. Quicksort?
  212.         w = points[ 0 ].x;
  213.         for ( i = 1;i < n;i++ ) {
  214.             p = points[ i ];
  215.             //    Insertion sort.
  216.             x = p.x;
  217.             if ( x < w ) {
  218.                 j = i;
  219.                 while ( ( j > 0 ) && ( points[ int(j - 1) ].x > x ) ) {
  220.                     points[ j ] = points[ int(j - 1) ];
  221.                     j--;
  222.                 }
  223.                 points[ j ] = p;
  224.             }
  225.                 else
  226.                     w = x;
  227.         }
  228.         //    Get x bounds.
  229.         x0 = points[ 0 ].x;
  230.         //    Process.
  231.         i = 0;
  232.         p = points[ 0 ];
  233.         x = p.x;
  234.             
  235.         //多分母点群でループ
  236.         for ( ;; ) {
  237.             //    Check circle events. /////////////////////////
  238.             if ( a ) {
  239.                 //    Check for arc a.
  240.                 circle = false;
  241.                 if ( a.prev && a.next ) {
  242.                     aa = a.prev.p,
  243.                     bb = a.p,
  244.                     cc = a.next.p;
  245.                     //    Algorithm from O'Rourke 2ed p. 189.
  246.                     A = bb.x - aa.x,
  247.                     B = bb.y - aa.y,
  248.                     C = cc.x - aa.x,
  249.                     D = cc.y - aa.y;
  250.                     //    Check that bc is a "right turn" from ab.
  251.                     if ( A * D - C * B <= 0 ) {
  252.                         E = A * ( aa.x + bb.x ) + B * ( aa.y + bb.y ),
  253.                         F = C * ( aa.x + cc.x ) + D * ( aa.y + cc.y ),
  254.                         G = 2 * ( A * ( cc.y - bb.y ) - B * ( cc.x - bb.x ) );
  255.                         //    Check for colinearity.
  256.                         //    if ( G > 0.000000001 || G < -0.000000001 )
  257.                         if ( G ) {
  258.                             //    Point o is the center of the circle.
  259.                             o.x = ( D * E - B * F ) / G;
  260.                             o.y = ( A * F - C * E ) / G;
  261.                             //    o.x plus radius equals max x coordinate.
  262.                             A = aa.x - o.x;
  263.                             B = aa.y - o.y;
  264.                             eventX = o.x + Math.sqrt(A * A + B * B);
  265.                             if ( eventX >= w ) circle = true;
  266.                         }
  267.                     }
  268.                 }
  269.                 //    Remove from queue.
  270.                 if ( a.right )
  271.                         a.right.left = a.left;
  272.                 if ( a.left )
  273.                         a.left.right = a.right;
  274.                 if ( a == next )
  275.                         next = a.right;
  276.                 //    Record event.
  277.                 if ( circle ) {
  278.                     a.endX = eventX;
  279.                     if ( a.endP ) {
  280.                         a.endP.x = o.x;
  281.                         a.endP.y = o.y;
  282.                     } else {
  283.                         a.endP = o;
  284.                         o = new Number2;
  285.                     }
  286.                     d = next;
  287.                     if ( !d ) {
  288.                         next = a;
  289.                     }
  290.                         else for ( ;; ) {
  291.                         if ( d.endX >= eventX ) {
  292.                             a.left = d.left;
  293.                             if ( d.left ) d.left.right = a;
  294.                             if ( next == d ) next = a;
  295.                             a.right = d;
  296.                             d.left = a;
  297.                             break;
  298.                         }
  299.                         if ( !d.right ) {
  300.                             d.right = a;
  301.                             a.left = d;
  302.                             a.right = null;
  303.                             break;
  304.                         }
  305.                         d = d.right;
  306.                     }
  307.                 } else {
  308.                     a.endX = NaN;
  309.                     a.endP = null;
  310.                     a.left = null;
  311.                     a.right = null;
  312.                 }
  313.                 //    Push next arc to check.
  314.                 if ( b ) {
  315.                     a = b;
  316.                     b = null;
  317.                     continue;
  318.                 }
  319.                 if ( c ) {
  320.                     a = c;
  321.                     c = null;
  322.                     continue;
  323.                 }
  324.                 a = null;
  325.             }
  326.             //////////////////////////////////////////////////
  327.             //
  328.             if ( next && next.endX <= x ) {
  329.                 //
  330.                 //    Handle next circle event.
  331.                 //    Get the next event from the queue. ///////////
  332.                 a = next;
  333.                 next = a.right;
  334.                 if ( next )
  335.                         next.left = null;
  336.                 a.right = null;
  337.                 //    Remove the associated arc from the front.
  338.                 if ( a.prev ) {
  339.                     a.prev.next = a.next;
  340.                     a.prev.v1 = a.endP;
  341.                 }
  342.                 if ( a.next ) {
  343.                     a.next.prev = a.prev;
  344.                     a.next.v0 = a.endP;
  345.                 }
  346.                 if ( a.v0 ) {
  347.                     out[ len++ ] = a.v0;
  348.                     a.v0 = null;
  349.                     out[ len++ ] = a.endP;
  350.                 }
  351.                 if ( a.v1 ) {
  352.                     out[ len++ ] = a.v1;
  353.                     a.v1 = null;
  354.                     out[ len++ ] = a.endP;
  355.                 }
  356.                 //    Keep a ref for collection.
  357.                 d = a;
  358.                 //    Recheck circle events on either side of p:
  359.                 w = a.endX;
  360.                 if ( a.prev ) {
  361.                     b = a.prev;
  362.                     a = a.next;
  363.                 } else {
  364.                     a = a.next;
  365.                     b = null;
  366.                 }
  367.                 c = null;
  368.                 //    Collect.
  369.                 d.v0 = null;
  370.                 d.v1 = null;
  371.                 d.p = null;
  372.                 d.prev = null;
  373.                 d.endX = NaN;
  374.                 d.endP = null;
  375.                 d.next = arcPool;
  376.                 arcPool = d;
  377.                     //////////////////////////////////////////////////
  378.                     //
  379.             } else {
  380.                 if ( !p ) break;
  381.                 //
  382.                 //    Handle next site event. //////////////////////
  383.                 if ( !root ) {
  384.                     if ( arcPool ) {
  385.                         root = arcPool;
  386.                         arcPool = arcPool.next;
  387.                         root.next = null;
  388.                     }
  389.                         else
  390.                             root = new Arc;
  391.                     root.p = p;
  392.                 } else {
  393.                     z = new Number2;
  394.                     //    Find the first arc with a point below p,
  395.                     //    and start searching for the intersection around it.
  396.                     a = root.next;
  397.                     if ( a ) {
  398.                             while ( a.next ) {
  399.                                 a = a.next;
  400.                                 if ( a.p.y >= p.y ) break;
  401.                             }
  402.                             //    Find the intersecting curve.
  403.                             intersection(a.prev.p, a.p, p.x, z);
  404.                             if ( z.y <= p.y ) {
  405.                                 
  406.                                 //    Search for the intersection to the south of i.
  407.                                 while ( a.next ) {
  408.                                     a = a.next;
  409.                                     intersection(a.prev.p, a.p, p.x, z);
  410.                                     if ( z.y >= p.y ) {
  411.                                         a = a.prev;
  412.                                         break;
  413.                                     }
  414.                                 }
  415.                             } else {
  416.                                 //    Search for the intersection above i.
  417.                                 a = a.prev;
  418.                                 while ( a.prev ) {
  419.                                     a = a.prev;
  420.                                     intersection(a.p, a.next.p, p.x, z);
  421.                                     if ( z.y <= p.y ) {
  422.                                         a = a.next;
  423.                                         break;
  424.                                     }
  425.                                 }
  426.                             }
  427.                         }
  428.                         else
  429.                             a = root;
  430.                     //    New parabola will intersect arc a. Duplicate a.
  431.                     if ( a.next ) {
  432.                             if ( arcPool ) {
  433.                                 b = arcPool;
  434.                                 arcPool = arcPool.next;
  435.                                 b.next = null;
  436.                             }
  437.                             else
  438.                                 b = new Arc;
  439.                             b.p = a.p;
  440.                             b.prev = a;
  441.                             b.next = a.next;
  442.                             a.next.prev = b;
  443.                             a.next = b;
  444.                         } else {
  445.                             if ( arcPool ) {
  446.                                 b = arcPool;
  447.                                 arcPool = arcPool.next;
  448.                                 b.next = null;
  449.                             }
  450.                             else
  451.                                 b = new Arc;
  452.                             b.p = a.p;
  453.                             b.prev = a;
  454.                             a.next = b;
  455.                         }
  456.                     a.next.v1 = a.v1;
  457.                     //    Find the point of intersection.
  458.                     z.y = p.y;
  459.                     z.x = ( a.p.x * a.p.x + ( a.p.y - p.y ) * ( a.p.y - p.y ) - p.x * p.x ) / ( 2 * a.p.x - 2 * p.x );
  460.                     //    Add p between i and i->next.
  461.                     if ( arcPool ) {
  462.                             b = arcPool;
  463.                             arcPool = arcPool.next;
  464.                             b.next = null;
  465.                         }
  466.                         else
  467.                             b = new Arc;
  468.                     b.p = p;
  469.                     b.prev = a;
  470.                     b.next = a.next;
  471.                     a.next.prev = b;
  472.                     a.next = b;
  473.                     a = a.next;    //    Now a points to the new arc.
  474.                     a.prev.v1 = z;
  475.                         a.next.v0 = z;
  476.                         a.v0 = z;
  477.                         a.v1 = z;
  478.                         //    Check for new circle events around the new arc:
  479.                         b = a.next;
  480.                         a = a.prev;
  481.                         c = null;
  482.                         w = p.x;
  483.                 }
  484.                 //////////////////////////////////////////////////
  485.                 //
  486.                 i++;
  487.                 if ( i >= n ) {
  488.                         p = null;
  489.                         x = Number.MAX_VALUE;
  490.                     } else {
  491.                         p = points[ i ];
  492.                         x = p.x;
  493.                     }
  494.             }
  495.         }
  496.         //    Store the pools.
  497.         arcPoolD = arcPool;
  498.         //
  499.         //
  500.         //    Return the result ready for drawing.
  501.         return out;
  502.     }
  503.         
  504.         
  505.         /**
  506.          * Where do two parabolas intersect?
  507.          * @param    p0 A Number2 object describing the site for the first parabola.
  508.          * @param    p1 A Number2 object describing the site for the second parabola.
  509.          * @param    l The location of the sweep line.
  510.          * @param    res A Number2 object in which to store the intersection.
  511.          * @return The point of intersection.
  512.          */
  513.         public function intersection( p0 : Number2, p1 : Number2, l : Number, res : Number2 ) : Number2 {
  514.             var p : Number2 = p0,
  515.                 ll : Number = l * l;
  516.             if ( p0.x == p1.x )
  517.                 res.y = ( p0.y + p1.y ) / 2;
  518.             else if ( p1.x == l )
  519.                 res.y = p1.y;
  520.             else if ( p0.x == l ) {
  521.                 res.y = p0.y;
  522.                 p = p1;
  523.             } else {
  524.                 //    Use the quadratic formula.
  525.                 var z0 : Number = 0.5 / ( p0.x - l ); // 1 / ( 2*(p0.x - l) )
  526.                 var z1 : Number = 0.5 / ( p1.x - l ); // 1 / ( 2*(p1.x - l) )
  527.                 var a : Number = z0 - z1;
  528.                 var b : Number = -2 * ( p0.y * z0 - p1.y * z1 );
  529.                 var c : Number = ( p0.y * p0.y + p0.x * p0.x - ll ) * z0 - ( p1.y * p1.y + p1.x * p1.x - ll ) * z1;
  530.                 res.y = ( -b - Math.sqrt(b * b - 4 * a * c) ) / ( 2 * a );
  531.             }
  532.             
  533.             //    Plug back into one of the parabola equations.
  534.             res.x = ( p.x * p.x + ( p.y - res.y ) * ( p.y - res.y ) - ll ) / ( 2 * p.x - 2 * l );
  535.             return res;
  536.         }
  537. }
  538. class Arc {
  539.     public var p : Number2;
  540.     public var next : Arc;
  541.     public var prev : Arc;
  542.     public var v0 : Number2;
  543.     public var v1 : Number2;
  544.     //    Circle event data :
  545.     public var left : Arc;
  546.     public var right : Arc;
  547.     public var endX : Number;
  548.     public var endP : Number2;
  549. }
  550. class Number2 {
  551.     public var x : Number;
  552.     public var y : Number;
  553.     //速度
  554.     public var vx : Number;
  555.     public var vy : Number;
  556.     public var next : Number2;
  557. }
noswf
Get Adobe Flash Player