root/lang/actionscript/metro-map/mkmap/PolyLine.as @ 6839

Revision 6839, 7.3 kB (checked in by gyuque, 5 years ago)

metro-map: imported

Line 
1package mkmap
2{
3        import flash.display.*;
4        import flash.events.*;
5        import flash.geom.*;
6        public class PolyLine extends CanvasObject
7        {
8                private var mFirst:Segment;
9                private var mLast:Segment;
10                private var mCanvas:MCanvas;
11                private var mCornerR:int;
12               
13                private var mThick:int;
14                private var mLineColor:uint;
15               
16                function PolyLine(c:MCanvas, initY:int = 10)
17                {
18                        mCornerR = 19;
19                        mThick = 6;
20                        mLineColor = 0x4466ff;
21                       
22                        setInitialSegment(new Segment(10, initY, 110, initY+100));
23                        mCanvas = c;
24                        mouseEnabled = false;
25                }
26               
27                public function set lineColor(c:uint):void
28                {
29                        mLineColor = c;
30                        updateView();
31                }
32               
33                private function setInitialSegment(s:Segment):void
34                {
35                        mFirst = s;
36                        mLast  = s;
37                       
38                        s.next = null;
39                        s.prev = null;
40                       
41                        var hb:AnchorButton = new AnchorButton(false);
42                        var tb:AnchorButton = new AnchorButton(false);
43                        var mb:AnchorButton = new AnchorButton(true);
44                       
45                        addChild(hb);
46                        addChild(tb);
47                        addChild(mb);
48                        hb.onMoved = onAnchorMove;
49                        tb.onMoved = onAnchorMove;
50                        mb.onMoved = onAnchorMove;
51                       
52                        updateView();
53                       
54                        s.headAnc = hb;
55                        s.midAnc  = mb;
56                        s.tailAnc = tb;
57                        s.updateAnchors();
58                       
59                        tb.backSegment   = s;
60                        mb.middleSegment = s;
61                }
62               
63                private function mid_point(x1:int, y1:int, x2:int, y2:int, t:Number, pout:Point):void
64                {
65                        var vx:Number = x2 - x1;
66                        var vy:Number = y2 - y1;
67                       
68                        var nrm:Number = Math.sqrt(vx*vx + vy*vy);
69                        if (nrm < t)
70                        {
71                                pout.x = x2;
72                                pout.y = y2;
73                                return;
74                        }
75                       
76                        var fct:Number = (nrm-t) / nrm;
77                        pout.x = x1 + vx*fct;
78                        pout.y = y1 + vy*fct;
79                }
80               
81                private var _tmpPt1:Point = new Point();
82                private var _tmpPt2:Point = new Point();
83                private function updateView():void
84                {
85                        var s:Segment;
86                        graphics.clear();
87
88                        var g:Graphics = graphics;
89                       
90                        for (var phase:int = 0;phase < 2;phase++)
91                        {
92                                g.lineStyle(mThick + (1-phase)*2, (phase == 0) ? 0xffffff : mLineColor, 1, true, LineScaleMode.NONE, CapsStyle.ROUND);
93                                for(s = mFirst; s != null; s=s.next)
94                                {
95                                        if (s == mFirst)
96                                                g.moveTo(s.x1, s.y1);
97                                       
98                                        if (s.next != null)
99                                        {
100                                                var nx:Segment = s.next;
101                                                mid_point(s.x1, s.y1, s.x2, s.y2, mCornerR, _tmpPt1);
102                                                mid_point(nx.x2, nx.y2, nx.x1, nx.y1, mCornerR, _tmpPt2);
103                                                g.lineTo(_tmpPt1.x, _tmpPt1.y);
104                                                g.curveTo(s.x2, s.y2, _tmpPt2.x, _tmpPt2.y);
105                                        }
106                                        else
107                                                g.lineTo(s.x2, s.y2);
108                                }
109                        }
110                       
111                        for(s = mFirst; s != null; s=s.next)
112                                drawCenterLine(s);
113                }
114               
115                private function onAnchorMove(anc:AnchorButton, e:MouseEvent):void
116                {
117                        var p:Point = new Point();
118                        mCanvas.getSnappedMousePosition(p);
119                       
120                        if (anc.middleSegment != null)
121                        {
122                                if (doFold(anc.middleSegment, p.x, p.y))
123                                        updateView();
124                        }
125                        else if (anc.backSegment != null)
126                        {
127                                moveEndAnchor(anc.backSegment, anc.backSegment.next, p.x, p.y);
128                                checkUnfold(anc);
129                                updateView();
130                                anc.backSegment.updateAnchors();
131                                if (anc.backSegment.next)
132                                        anc.backSegment.next.updateAnchors();
133                        }
134                        else
135                        {
136                                if (anc == mFirst.headAnc)
137                                {
138                                        moveEndAnchor(null, mFirst, p.x, p.y);
139                                        updateView();
140                                        mFirst.updateAnchors();
141                                        if (mFirst.next)
142                                                mFirst.next.updateAnchors();
143                                }
144                        }
145                }
146               
147                private function distance2_from_sprite(x:int, y:int, s:Sprite):Number
148                {
149                        var dx:int = x - s.x;
150                        var dy:int = y - s.y;
151                        return dx*dx + dy*dy;
152                }
153               
154                private function divideSegmentAt(x:int, y:int, s:Segment):Segment
155                {
156                        var oldNext:Segment = s.next;
157                        var newSeg:Segment = new Segment(x, y, s.x2, s.y2);
158
159                        var tb:AnchorButton = new AnchorButton(false);
160                        var mb:AnchorButton = new AnchorButton(true);
161                        addChild(tb);
162                        addChild(mb);
163                        tb.onMoved = onAnchorMove;
164                        mb.onMoved = onAnchorMove;
165                        tb.backSegment   = newSeg;
166                        mb.middleSegment = newSeg;
167                       
168                        newSeg.headAnc = s.tailAnc;
169                        newSeg.midAnc  = mb;
170                        newSeg.tailAnc = tb;
171                       
172                        s.x2 = x;
173                        s.y2 = y;
174                       
175                        s.next = newSeg;
176                        newSeg.prev = s;
177                       
178                        newSeg.next = oldNext;
179                        if (oldNext)
180                        {
181                                oldNext.prev = newSeg;
182                                oldNext.headAnc = tb;
183                        }
184                       
185                        if (s == mLast)
186                                mLast = newSeg;
187                       
188                        s.updateAnchors();
189                        newSeg.updateAnchors();
190                        if (oldNext)
191                                oldNext.updateAnchors();
192                       
193                        return newSeg;
194                }
195               
196                private function doFold(seg:Segment, x:int, y:int):Boolean
197                {
198                        if (distance2_from_sprite(x, y, seg.midAnc) > 400)
199                        {
200                                seg.midAnc.forceRelease();
201                               
202                                divideSegmentAt(x, y, seg);
203                                seg.tailAnc.forceDown();
204                               
205                                return true;
206                        }
207                       
208                        return false;
209                }
210               
211                private function nearZero(v:Number):Boolean
212                {
213                        return (v > -0.01 && v < 0.01);
214                }
215               
216                private function calcNormalDP(vx1:Number, vy1:Number, vx2:Number, vy2:Number):Number
217                {
218                        var nrm1:Number = Math.sqrt(vx1*vx1 + vy1*vy1);
219                        if (nearZero(nrm1))
220                                return 0;
221
222                        var nrm2:Number = Math.sqrt(vx2*vx2 + vy2*vy2);
223                        if (nearZero(nrm2))
224                                return 0;
225                       
226                        vx1 /= nrm1;
227                        vy1 /= nrm1;
228                        vx2 /= nrm2;
229                        vy2 /= nrm2;
230                       
231                        return vx1*vx2 + vy1*vy2;
232                }
233               
234                private function checkUnfold(anc:AnchorButton):Boolean
235                {
236                        var seg1:Segment = anc.backSegment;
237                        if (seg1 == null)
238                                return false;
239
240                        var seg2:Segment = seg1.next;
241                        if (seg2 == null)
242                                return false;
243                       
244                        var vx1:int = seg1.x2 - seg1.x1;
245                        var vy1:int = seg1.y2 - seg1.y1;
246                       
247                        var vx2:int = seg2.x2 - seg2.x1;
248                        var vy2:int = seg2.y2 - seg2.y1;
249                       
250                        if (calcNormalDP(vx1, vy1, vx2, vy2) > 0.98)
251                                unfold(seg1, seg2);
252                       
253                        return true;
254                }
255               
256                private function unfold(seg1:Segment, seg2:Segment):void
257                {
258                        // remove seg2
259                       
260                        seg1.x2 = seg2.x2;
261                        seg1.y2 = seg2.y2;
262                       
263                        seg1.next = seg2.next;
264                        if (seg2.next)
265                                seg2.next.prev = seg1;
266                       
267                        // remove anchors
268                        seg2.midAnc.onMoved = null;
269                        removeChild(seg2.midAnc);
270                       
271                        seg1.tailAnc.onMoved = null;
272                        removeChild(seg1.tailAnc);
273                       
274                        seg1.tailAnc = seg2.tailAnc;
275                        seg1.tailAnc.backSegment = seg1;
276                       
277                        if (seg2 == mLast)
278                                mLast = seg1;
279                }
280               
281                private function moveEndAnchor(seg1:Segment, seg2:Segment, x:int, y:int):void
282                {
283                        if (seg1 != null)
284                        {
285                                seg1.x2 = x;
286                                seg1.y2 = y;
287                        }
288
289                        if (seg2 != null)
290                        {
291                                seg2.x1 = x;
292                                seg2.y1 = y;
293                        }
294                       
295                }
296               
297                private function drawCenterLine(s:Segment):void
298                {
299                        var g:Graphics = graphics;
300                        g.lineStyle(3, 0xffffff, 1, true);
301                        g.moveTo(s.x1, s.y1);
302                        g.lineTo(s.x2, s.y2);
303
304                        g.lineStyle(1, 0x000000, 1, true);
305                        g.moveTo(s.x1, s.y1);
306                        g.lineTo(s.x2, s.y2);
307                }
308               
309                private static function makeHexColor(c:uint):String
310                {
311                        var R:String = ((c&0xff0000) >> 16).toString(16);
312                        var G:String = ((c&0x00ff00) >>  8).toString(16);
313                        var B:String = ( c&0x0000ff       ).toString(16);
314                       
315                        if (R.length<2) R = "0"+R;
316                        if (G.length<2) G = "0"+G;
317                        if (B.length<2) B = "0"+B;
318                       
319                        return R+G+B;
320                }
321               
322                public override function serialize():String
323                {
324                        var attrs:Array = [];
325                        var points:Array = [];
326                       
327                        attrs.push("color=\"#"+makeHexColor(mLineColor)+"\"");
328                       
329                        for(var s:Segment = mFirst; s != null; s=s.next)
330                        {
331                                points.push(s.x1+" "+s.y1);
332                                if (s.next == null)
333                                        points.push(s.x2+" "+s.y2);
334                        }
335                       
336                        return "<polyline " +attrs.join(" ")+ ">" + points.join(",") + "</polyline>"
337                }
338        }
339}
Note: See TracBrowser for help on using the browser.