package { import flash.display.*; import flash.text.*; import flash.events.*; public class Conv extends Sprite { private var mText:TextField; function Conv() { mText = new TextField(); mText.width = 800; mText.height = 600; addChild(mText); mText.type = TextFieldType.INPUT; mText.background = true; mText.backgroundColor = 0xffffff; mText.multiline = true; var btn:StartButton = new StartButton(); addChild(btn); btn.y = 580; btn.buttonMode = true; btn.addEventListener(MouseEvent.CLICK, onClick); // tx.height = 500; // removeChild(tx); // addChild(tx); // tx.y = 340; // tx.width = 400; } private function onClick(e:MouseEvent):void { var s:SVGConverter = new SVGConverter(mText.text); var canvas:Sprite = new Sprite(); addChild(canvas); canvas.y = 220; var gen:KMLGenerator = new KMLGenerator() s.renderShapes(gen); mText.text = gen.dump(); } } } class SVGConverter { import flash.geom.*; import flash.display.*; private var X:XML; private var mShapes:Array = []; private var mCurPt:Point; function SVGConverter(src:String) { X = new XML(src); var list:XMLList = X.children(); for each(var ch:XML in list) { if (ch.localName() == "path") addPath(ch); } } public function renderShapes(g:IGraphics):void { for each(var sh:SVGShape in mShapes) { renderAShape(sh, g); } } private function renderAShape(sh:SVGShape, g:IGraphics):void { g.beginFill(sh.fill); // g.lineStyle(0, 0xffffff); for each(var seg:Segment in sh.segments) { drawSegment(seg, g); } g.endFill(); } public static function nearZero(v:Number):Boolean { return (v < 0.1) && (v > -0.1); } private function drawSegment(s:Segment, g:IGraphics):void { var len:int = s.points.length; var pt2:Point; var pt3:Point; for (var i:int = 0;i < len;i++) { var pt:Point = s.points[i] as Point; if (i == 0) { if (mCurPt && nearZero(mCurPt.x - pt.x) && nearZero(mCurPt.y - pt.y)) { } else { g.moveTo(pt.x, pt.y); mCurPt = pt; } continue; } if (s.curved) { pt2 = s.points[++i] as Point; pt3 = s.points[++i] as Point; b3(g, mCurPt.x, mCurPt.y, pt.x, pt.y, pt2.x, pt2.y, pt3.x, pt3.y, 3); mCurPt = pt3; } else { mCurPt = pt; g.lineTo(pt.x, pt.y); } } } private function b3(g:IGraphics, x0:Number,y0:Number,x1:Number,y1:Number,x2:Number,y2:Number,x3:Number,y3:Number,divs:uint = 100):void { var up:Number = 1.0 / (divs + 1); var tm:Number; for (var t:Number = 0; t < 1;t += up) { tm = 1 - t; g.lineTo( x0 * Math.pow(tm, 3) + 3 * x1 * t *Math.pow(tm, 2) + 3 * x2 * Math.pow(t, 2) * tm + x3 * Math.pow(t, 3), y0 * Math.pow(tm, 3) + 3 * y1 * t *Math.pow(tm, 2) + 3 * y2 * Math.pow(t, 2) * tm + y3 * Math.pow(t, 3) ); } g.lineTo(x3, y3); } private function addPath(x:XML):void { var d:String = x.@d[0]; var records:Array = d.split(/ +/); var op:String = null; var index:int = 0; var pt:Point = new Point(); var sh:SVGShape = new SVGShape(); var seg:Segment; for each(var r:String in records) { var n:Number; if (r == '') continue; if (/[a-zA-Z]/.test(r)) n = NaN; else n = parseFloat(r); if (isNaN(n)) { if (seg && (r == 'M' || r == 'Z' || (seg.points.length > 1 && ((r == 'L' && seg.curved) || (r == 'C' && !seg.curved))) )) { sh.addSegment(seg); seg = null; } if (!seg) seg = new Segment(); if (r == 'C') seg.curved = true; if ((r == 'C' || r == 'L') && seg.points.length == 0) seg.addPoint(pt); op = r; index = 0; continue; } else { if ((index%2) == 0) { pt.x = n; } else { pt.y = n; seg.addPoint(pt); } } index++; } mShapes.push(sh); sh.fill = parseInt(x.@fill[0].substring(1), 16); // STDOUT.puts(x.@d[0]); } } class SVGShape { public var segments:Array = []; public var fill:uint; public function addSegment(s:Segment):void { segments.push(s); } } class Segment { import flash.geom.*; public var curved:Boolean = false; public var points:Array = []; public function addPoint(pt:Point):void { var pt2:Point = new Point(pt.x, pt.y); points.push(pt2); } } class StartButton extends flash.display.Sprite { import flash.display.*; import flash.geom.*; public static const G_COLORS:Array = [0xaaaaaa, 0x555555]; public static const G_ALPHAS:Array = [1, 1]; public static const G_RATIOS:Array = [0, 255]; private var mGradTrans:Matrix; function StartButton() { mGradTrans = new Matrix(); mGradTrans.createGradientBox(30, 30, Math.PI/2); var g:Graphics = graphics; g.beginGradientFill(GradientType.LINEAR, G_COLORS, G_ALPHAS, G_RATIOS, mGradTrans); g.drawRect(0, 0, 40, 20); g.endFill(); } } class KMLGenerator implements IGraphics { import flash.utils.*; private var polygons:Array = []; private var coords:Array = []; private var fills:Dictionary = new Dictionary(); private var mScale:Number = 0.0007; private var mNextStyleId:int = 1; private var mCurStyleId:int; public function dump():String { var poly_elems:Array = []; var len:int = polygons.length; poly_elems.push('\n\n'); for (var clr:String in fills) { var bgr:uint = parseInt(clr); bgr = (bgr&0x00ff00) | ((bgr&0xff0000)>>16) | ((bgr&0xff)<<16); var hex:String = ("000000" + bgr.toString(16)); hex = hex.substring(hex.length - 6); poly_elems.push( "" ); } for (var i:int = 0;i < len;i++) { for each(var ll:LatLng in polygons[i].coords) ll.alt = i*100; poly_elems.push("#f"+polygons[i].sid+""+polygons[i].coords.join(' ')+""); } poly_elems.push(''); return poly_elems.join("\n"); } public function beginFill(c:uint):void { if (fills[c]) { mCurStyleId = fills[c] as int; } else { fills[c] = mNextStyleId++; mCurStyleId = fills[c]; } coords = []; } public function endFill():void { if (coords.length > 0) { polygons.push({sid: mCurStyleId, coords: coords}); coords = []; } } public function moveTo(x:Number, y:Number):void { endFill(); var ll:LatLng = new LatLng(); XYtoLatLng(x * mScale, y * mScale + 0.2, ll); coords.push(ll); } public function lineTo(x:Number, y:Number):void { var ll:LatLng = new LatLng(); XYtoLatLng(x * mScale, y * mScale + 0.2, ll); coords.push(ll); } public static function XYtoLatLng(x:Number, y:Number, out:LatLng):Boolean { const PI:Number = Math.PI; const DPI:Number = PI * 2.0; const HPI:Number = PI / 2.0; var lng:Number = bround((x-0.5) * DPI, -PI, PI); var g:Number = (y-0.5) * -DPI; var lat:Number = 2.0 * Math.atan( Math.exp(g) ) - HPI; out.lat = lat * 180.0 / PI; out.lng = lng * 180.0 / PI; return true; } private static function bround(v:Number, min:Number, max:Number):Number { if (v>max) return max; if (v