Skip to content

Instantly share code, notes, and snippets.

@gyuque
Created December 16, 2008 10:16
Show Gist options
  • Save gyuque/36409 to your computer and use it in GitHub Desktop.
Save gyuque/36409 to your computer and use it in GitHub Desktop.
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('<?xml version="1.0" encoding="UTF-8"?>\n<kml xmlns="http://www.opengis.net/kml/2.2">\n<Document>');
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( "<Style id=\"f"+fills[clr]+"\"><PolyStyle><color>ff"+hex+"</color><colorMode>normal</colorMode><outline>0</outline></PolyStyle></Style>" );
}
for (var i:int = 0;i < len;i++) {
for each(var ll:LatLng in polygons[i].coords)
ll.alt = i*100;
poly_elems.push("<Placemark><styleUrl>#f"+polygons[i].sid+"</styleUrl><Polygon><outerBoundaryIs><LinearRing><coordinates>"+polygons[i].coords.join(' ')+"</coordinates></LinearRing></outerBoundaryIs></Polygon></Placemark>");
}
poly_elems.push('</Document></kml>');
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<min) return min;
return v;
}
}
class LatLng
{
public var lng:Number, lat:Number, alt:int;
public function toString():String
{
return lng+","+lat+","+alt;
}
}
interface IGraphics
{
function beginFill(c:uint):void;
function endFill():void;
function moveTo(x:Number, y:Number):void;
function lineTo(x:Number, y:Number):void;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment