Spline Text
だめだ・・
package {
import flash.display.Sprite;
import flash.text.*;
import flash.display.*;
import flash.geom.*;
import flash.filters.*;
import flash.events.*;
// だめだ・・
public class SplineText extends Sprite {
private var splines : Array;
private var tf : TextField;
private var start : Number;
public function SplineText()
{
tf = new TextField();
tf.height = 450;
tf.width = 450;
addChild(tf);
init();
start = 0.0;
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private function onEnterFrame(e : Event) : void
{
if(start >= 10)return;
// splineを描く
graphics.clear();
graphics.lineStyle(1, 0);
var step : Number = 0.05;
for each(var spline : Object in splines){
// var len : int = co.x.a.length;
// tf.appendText(len.toString() + "\n");
graphics.moveTo(
Spline.calc(spline.co.x, start) * 2,
Spline.calc(spline.co.y, start) * 2
);
for(var t : Number = start + step;t < start + spline.len;t+=step){
graphics.lineTo(
Spline.calc(spline.co.x, t) * 2,
Spline.calc(spline.co.y, t) * 2
);
}
}
start += 0.02;
}
private function init() : void
{
var tfmt : TextFormat = new TextFormat("Verdana", 130);
var bmd : BitmapData = getTextBitMap("か", tfmt);
var rect : Rectangle = bmd.getColorBoundsRect(0xffffff, 0x000000, true);
// エッジ抽出
var cf : ConvolutionFilter = new ConvolutionFilter(3, 3, [0, -1, 0, -1, 4, -1, 0, -1, 0]);
bmd.applyFilter(bmd, bmd.rect, new Point(), cf);
// 輪郭線追跡
var pathes : Array = [];
for(var x : int = 0;x < bmd.width;x++){
for(var y : int = 0;y < bmd.height;y++){
if(bmd.getPixel(x, y) == 0xffffff){
pathes.push(tracePath(bmd, x, y));
}
}
}
var newpathes : Array = [];
for each(var path : Array in pathes){
newpathes = newpathes.concat(findIndifferentiable(path));
}
splines = [];
var i : int;
// 適当にポイントを水増し
var step : int = 80;
for each(path in newpathes){
var conti : Array = [];
// if(path.length < 3)continue;
for(i = 0;i < path.length - 3;i+=3){
conti.push(path[i]);
}
conti.push(path.pop());
if(conti.length < 2)continue;
var pc : Point = conti[conti.length - 2];
var pl : Point = conti[conti.length - 1];
var l : int = conti.length;
var p0 : Point = new Point(2 * pl.x - pc.x, 2 * pl.y - pc.y);
conti.push(p0);
var p1 : Point = new Point(2 * p0.x - pl.x, 2 * p0.y - pl.y);
conti.push(p1);
conti = conti.reverse();
tf.appendText(path.length.toString() + "\n");
/*
tf.appendText(conti[0].toString());
tf.appendText(conti[1].toString());
tf.appendText(conti[2].toString() + "\n");
*/
var start : Number = conti[0].x + step;
for(i = 0;i < 8;i++){
conti.unshift(new Point(start + step * i, Math.random() * 450 - 150));
}
splines.push({co : calc2D(conti), len : l});
}
}
private static function tracePath(bmd : BitmapData, x : int, y : int) : Array
{
var pp : Point = new Point(x, y);
var ret : Array = [pp];
while(true){
bmd.setPixel(pp.x, pp.y, 0x000000);
var p : Point = survive(bmd, pp.x, pp.y);
if(p == null)break;
ret.push(p);
pp = p;
}
return ret;
}
private static function survive(bmd : BitmapData, x : int, y : int) : Point
{
if(bmd.getPixel(x - 1, y - 1) != 0x000000)return new Point(x - 1, y - 1);
if(bmd.getPixel(x - 1, y) != 0x000000)return new Point(x - 1, y);
if(bmd.getPixel(x - 1, y + 1) != 0x000000)return new Point(x - 1, y + 1);
if(bmd.getPixel(x, y + 1) != 0x000000)return new Point(x, y + 1);
if(bmd.getPixel(x + 1, y + 1) != 0x000000)return new Point(x + 1, y + 1);
if(bmd.getPixel(x + 1, y) != 0x000000)return new Point(x + 1, y);
if(bmd.getPixel(x + 1, y - 1) != 0x000000)return new Point(x + 1, y - 1);
if(bmd.getPixel(x, y - 1) != 0x000000)return new Point(x, y - 1);
return null;
}
// テキストをBitmapDataに変換
private static function getTextBitMap(text : String, tfmt : TextFormat) : BitmapData {
var tf : TextField = new TextField();
tf.autoSize = TextFieldAutoSize.LEFT;
tf.defaultTextFormat = tfmt;
tf.text = text;
var ret : BitmapData = new BitmapData(tf.width, tf.height, false, 0xffffff);
ret.draw(tf);
return ret;
}
public static function calc2D(a : Array) : Object
{
var xs : Vector.<Number> = new Vector.<Number>();
var ys : Vector.<Number> = new Vector.<Number>();
for each(var p : Point in a){
xs.push(p.x);
ys.push(p.y);
}
return {x : Spline.calcCoordinate(xs), y : Spline.calcCoordinate(ys)};
}
// 微分不可能点のようなものをみつける
public function findIndifferentiable(path : Array) : Array
{
var ret : Array = [];
var dis : int = 5;
var prev : int = 0;
for(var i : int = dis;i < path.length - dis;i++){
var p0 : Point = path[i - dis];
var p1 : Point = path[i];
var p2 : Point = path[i + dis];
var ip : Number = (p2.x - p1.x) * (p1.x - p0.x) + (p2.y - p1.y) * (p1.y - p0.y);
ip /= (Point.distance(p0, p1) * Point.distance(p1, p2));
if(ip < 0.7){
ret.push(path.slice(prev, i));
prev = i;
i++;
}
}
ret.push(path.slice(prev));
return ret;
}
}
}
// @see http://www5d.biglobe.ne.jp/~stssk/maze/spline.html
class Spline {
public static function calc(cs : Object, t : Number) : Number
{
var p : int = t >> 0;
if(p >= cs.a.length)p--;
if(p < 0)p = 0;
var dt : Number = t - p;
return cs.a[p] + (cs.b[p] + (cs.c[p] + cs.d[p] * dt) * dt) * dt;
}
public static function calcCoordinate(a : Vector.<Number>) : Object
{
var n : int = a.length;
var b : Vector.<Number> = new Vector.<Number>();
var c : Vector.<Number> = new Vector.<Number>();
var d : Vector.<Number> = new Vector.<Number>();
var w : Vector.<Number> = new Vector.<Number>();
var i : int;
c.push(0);
for(i = 1;i < n - 1;i++){
c.push(3 * (a[i + 1] - 2 * a[i] + a[i - 1]));
}
c.push(0);
w.push(0);
for(i = 1;i < n - 1;i++){
var l : Number = 4.0 - w[i - 1];
c[i] = (c[i] - c[i - 1]) / l;
w.push(1.0 / l);
}
for(i = n - 2;i > 0;i--){
c[i] -= c[i + 1] * w[i];
}
for(i = 0;i < n - 1;i++){
d.push((c[i + 1] - c[i]) / 3.0);
b.push(a[i + 1] - a[i] - c[i] - d[i]);
}
b.push(0);
d.push(0);
return {a : a, b : b, c : c, d : d};
}
}