Oct 06 2010

Graffiti Analysis Flash Test 2

Tag: flash,gmlTurbo Connard @ 21:20

Ok, j’avais laissé en plan le “graffiti analysis test” mais il fallait quand même que je règle ce problème de vecteur “UP”. J’ai donc trouvé la formule magique pour orienter les graffitis dans le “bon” sens.

En gros les applications qui enregistrent les tags doivent préciser un vecteur “UP” qui détermine l’orientation du graffiti. Certaines applications (ex : Coding With Attitude GML Drawer : MFF2010  ) ne le font pas donc on prendra l’axe Y par défaut, c’est l’orientation qui est la plus “normale”.

Mais d’autres applications (presque toutes d’ailleurs puisqu’il s’agit de portages) ont par défaut un vecteur “UP” sur l’axe des x  : (1,0,0);

Si on opère pas de transformation, certains graffitis vont s’écrire de haut en bas et non pas de gauche à droite. La première solution est de choisir arbitrairement : “bon ben si c’est Y, on touche à rien et si c’est X ben on fait une rotation de -90° et c’est marre…” Mais on vaut quand même mieux que ça !

Donc la technique c’est de trouver l’axe et l’angle de rotation puis d’appliquer la transformation.
Le code est dans le “onload” du xml.

package {
        import flash.display.DisplayObject;
        import flash.display.MovieClip;
        import flash.display.Sprite;
        import flash.display.StageAlign;
        import flash.display.StageScaleMode;
        import flash.events.Event;
        import flash.events.MouseEvent;
        import flash.geom.Matrix3D;
        import flash.geom.Rectangle;
        import flash.geom.Vector3D;
        import flash.net.URLLoader;
        import flash.net.URLRequest;
        /**
         * @author Turboconnard
         */

        public class Test3D extends MovieClip {
                private var yaxis : Sprite;
                private var zaxis : Sprite;
                private var xaxis : DisplayObject;
                private var axe : Sprite;
                private var container : Sprite;
                private var graf : Sprite;
       
                public function Test3D() {
                        //waiting for stage to be instanciate
                        addEventListener(Event.ADDED_TO_STAGE, _add);
                }       
                private function _add(event : Event) : void {
                        /* remember 3D objects may have a z if you want transform thme */
                       
                       
                        stage.scaleMode = StageScaleMode.NO_SCALE;
                        stage.align = StageAlign.TOP_LEFT;
                        stage.addEventListener(Event.RESIZE,resize);
               
                        //creating global container
                        container = new Sprite();
                        container.z = 0;
                        graf = new Sprite();           
                        graf.z = 0;
                        addChild(container);
                        container.addChild(graf);       
                       
                        //building 3D axis viewer
                        xaxis = getLine(0x0000ff);
                        yaxis = getLine(0x00ff00);
                        zaxis = getLine(0xff0000);
                       
                        xaxis.z = 0;
                        yaxis.z = 0;
                        zaxis.z = 0;
                        yaxis.transform.matrix3D.appendRotation(90, Vector3D.Z_AXIS);
                        zaxis.transform.matrix3D.appendRotation(90, Vector3D.Y_AXIS);

                        axe = new Sprite();
                        axe.z = 0;
                        axe.addChild(xaxis);
                        axe.addChild(yaxis);
                        axe.addChild(zaxis);
                        addChild(axe);
                        //load a graffiti
                        load(null);
                        //resize
                        resize(null);
                }
                /**
                 * load a random graffiti
                 */

                public function load(e:MouseEvent) : void {
                        stage.removeEventListener(MouseEvent.CLICK,load);
                        alpha = 0.2;
                        var urlLoader : URLLoader = new URLLoader();
                        urlLoader.addEventListener(Event.COMPLETE, _onLoad);                   
                        urlLoader.load(new URLRequest("http://000000book.com/data/" +"random"+ ".gml"));
                }
                /**
                 *
                 */

                private function _onLoad(event : Event) : void {
                        stage.addEventListener(MouseEvent.CLICK,load);
                        alpha = 1;
                        var gml:XML = XML(URLLoader(event.target).data);
                        var env:XMLList = gml.tag.environment;
                       
                        //Some graffitis aren’t drawn with Y as up axis.
                        //we have to rotate our world to mach our Y up axis.
                        //my up vector in flash                
                        var up:Vector3D =  new Vector3D(0,1,0);
                        //graffiti’s up vector
                        var modelup:Vector3D;
                        if(int(env.up.x) + int(env.up.y) + int(env.up.z) == 0 ) modelup = new Vector3D(0,1,0);
                        else modelup = new Vector3D(env.up.x, env.up.y, env.up.z);
                        //looking for axis to rotate
                        var rotationaxis:Vector3D = up.crossProduct(modelup);
                        //looking for rotation angle
                        var angle:Number = Math.acos( up.dotProduct(modelup) );
                        //rotate objects
                       
                        axe.transform.matrix3D = new Matrix3D();
                        graf.transform.matrix3D = new Matrix3D();
                        axe.transform.matrix3D.appendRotation(angle/Math.PI*180, rotationaxis);
                        graf.transform.matrix3D.appendRotation(angle/Math.PI*180, rotationaxis);
               
                        //draw graffiti
                        graf.graphics.clear();
                        graf.graphics.lineStyle(8,0);
                        for(var i:int=0;i<XMLList(gml.tag.drawing.stroke).length();i++){
                                var pts:XMLList = XMLList(gml.tag.drawing.stroke)[i].pt;
                                for(var k:int=0;k<pts.length();k++){   
                                        if(k==0) graf.graphics.moveTo(pts[k].x*env.screenBounds.x,pts[k].y*env.screenBounds.y);
                                        else graf.graphics.lineTo(pts[k].x*env.screenBounds.x,pts[k].y*env.screenBounds.y);
                                }                              
                        }
                       
                        resize(null);
                }
                /**
                 * resize
                 * @param e Event
                 */

                private function resize(e:Event) : void {
                        axe.x = stage.stageWidth/2;
                        axe.y = stage.stageHeight/2;
                       
                        //moving objects to center
                        var box:Rectangle = container.getRect(container);
                        container.x = – box.x + stage.stageWidth/2 – box.width/2;
                        container.y = – box.y + stage.stageHeight/2 – box.height/2;
                }

                /**
                 * draw an arrow
                 * @param pColor arraow color
                 */

                public  function getLine(pColor : uint) : Sprite {
                        var s : Sprite = new Sprite();
                        s.graphics.lineStyle(1, pColor,1,false,"none");
                        s.graphics.lineTo(20, 0);
                        s.graphics.lineTo(15, -2);
                        s.graphics.moveTo(20, 0);
                        s.graphics.lineTo(15, 2);                      
                        return s;
                }
        }
}
 


Aug 11 2010

Graffiti Analysis Flash Test

Tag: android,flashTurbo Connard @ 12:50

Faisant du flash depuis pas mal d’annése, c’était plus facile pour moi de faire un prototype en flash avant d’attaquer la version Java / android de l’application.
La première partie consiste à charger les tags et les afficher. J’ai fait une classe simple pour tenter de lisser un peu mieux mes “bords de courbe”. Je suis pas mal satisfait du résultat que voila :

Il reste un truc à faire mais j’ai la flemme… dans un fichier gml il y a un vecteur “up” qui définit la verticale du monde 3D. Il faudrait appliquer une rotation au container pour que les tags soient toujours bien orientés. Il arrive de tomber sur des tags qui sont dans le mauvais sens.

Cliquer pour charger un tag aléatoire.

sources :

package
{
        import flash.display.StageAlign;
        import flash.display.StageScaleMode;
        import flash.display.Sprite;
        import flash.events.Event;
        import flash.events.MouseEvent;
        import flash.geom.Point;
        import flash.net.URLLoader;
        import flash.net.URLRequest;
        import flash.utils.getTimer;

        /**
         * @author turboconnard
         * http://www.turboconnard.com
         */

        public class Main extends Sprite
        {
                private static var HEIGHT:Number = 400;
               
                private static var LINESTYLE:Number = 2;
                private static var LINEALPHA:Number = 1  ;
                private static var ALPHA:Number = 0.8;
                private static var FADEIN:Number = 0;
                private static var FADEOUT:Number = 8;
               
                private static var STROKEBASE:Number = 30;
                private static var STROKE:Number;
                private static var MAXSTROKE:Number = 20;
                private static var EASE:Number = 5;

                private var tag:String = "19126";

                private var gml:XML;
                private var _count:int;
                private var _container:Sprite;
                private var _startTime:Number;
                private var _strokes:Vector.<XMLList > ;
                private var _stroke:int;

                private var oldPoint:Point;
                private var oldP1:Point;
                private var oldP2:Point;
                private var oldStroke:Number;
                private var angle:Number;
               
                public function Main()
                {
                        load();
                        stage.scaleMode = StageScaleMode.NO_SCALE;
                        stage.align = StageAlign.TOP_LEFT;
                        stage.addEventListener(MouseEvent.CLICK, _clic);
                }

                private function _clic(event : MouseEvent):void
                {
                        load();
                }

                public function load():void
                {
                        var urlLoader : URLLoader = new URLLoader();
                        urlLoader.addEventListener(Event.COMPLETE, _onLoad);
                        urlLoader.load(new URLRequest("http://000000book.com/data/"+tag+".gml"));
                        tag = "random";
                }

                private function _onLoad(event : Event):void
                {
                        HEIGHT = stage.stageHeight;
                        while (numChildren)     removeChildAt(0);
                       
                        _strokes = new Vector.<XMLList>();
                        _stroke = 0;
                        gml = XML(URLLoader(event.target).data);
                        for (var i : int = 0; i < gml.tag.drawing.stroke.length(); i++)
                        {
                                _strokes.push(gml.tag.drawing.stroke[i].pt);
                        }
                        createStroke();
                        _startTime = getTimer();
                        addEventListener(Event.ENTER_FRAME, _draw);
                }
                private function end()
                {
                        removeEventListener(Event.ENTER_FRAME, _draw);
                }
                private function _draw(event : Event):void
                {
                        if ((getTimer() – _startTime) > (_strokes[_stroke][_count].time * 1000)){
                                _count++;
                                if (_count >= _strokes[_stroke].length())
                                {
                                        _stroke++;
                                        if (_stroke >= _strokes.length)
                                        {
                                                end();
                                                return;
                                        }
                                        else
                                        {
                                                createStroke();
                                        }
                                }
                                draw();
                        }
                }
                public function createStroke():void
                {
                        _count = 0;
                        oldPoint = new Point(_strokes[_stroke][0].x * HEIGHT,_strokes[_stroke][0].y * HEIGHT);
                        oldP1 = oldPoint.clone();
                        oldP2 = oldPoint.clone();
                        oldStroke = STROKE = MAXSTROKE/2;
                       
                        _container = new Sprite();
                        _container.y = HEIGHT;
                        _container.rotation = -90;
                        addChild(_container);
                }
                public function drawOne(point:Point):void
                {
                        var a:Number
                        if(_count ==0){
                                a =  Math.PI / 2Math.atan2(_strokes[_stroke][1].x * HEIGHT – oldPoint.x, _strokes[_stroke][1].y * HEIGHT – oldPoint.y);
                        }else{
                                a =  Math.atan2(point.y – oldPoint.y,point.x – oldPoint.x);
                        }
                       
                        var dist:Number = Math.sqrt(Math.pow(point.x – oldPoint.x,2) + Math.pow(point.y – oldPoint.y,2));
                        STROKE += ((STROKEBASE / dist > MAXSTROKE ? MAXSTROKE : STROKEBASE / dist) – STROKE)/EASE;

                        var p0:Point = oldPoint.add(new Point(Math.cos(a + Math.PI / 2) * oldStroke,Math.sin(a + Math.PI / 2) * oldStroke));
                        var p1:Point = oldPoint.add(new Point(Math.cos(a – Math.PI / 2) * oldStroke,Math.sin(a – Math.PI / 2) * oldStroke));
                        var p2:Point = point.add(new Point(Math.cos(a + Math.PI / 2) * STROKE,Math.sin(a + Math.PI / 2) * STROKE));
                        var p3:Point = point.add(new Point(Math.cos(a – Math.PI / 2) * STROKE,Math.sin(a – Math.PI / 2) * STROKE));

                        var c : Sprite = new Sprite();
                        _container.addChild(c);
                        var leng = _strokes[_stroke].length();
                        if(_count<FADEIN)c.graphics.beginFill(0xffffff, _count/FADEIN * ALPHA);
                        else if(_count >leng-FADEOUT) c.graphics.beginFill(0xffffff,(leng-_count)/FADEOUT * ALPHA);
                        else c.graphics.beginFill(0xffffff, ALPHA);
                        //c.graphics.beginFill(0xffffff, ALPHA);
                        c.graphics.lineStyle(undefined);
                        if(LINESTYLE>0) c.graphics.lineStyle(LINESTYLE, 0, LINEALPHA);
                        c.graphics.moveTo(oldP1.x, oldP1.y);
                        c.graphics.lineTo(p0.x, p0.y);
                        c.graphics.lineTo(p2.x, p2.y);
                        c.graphics.lineStyle(undefined);
                        c.graphics.lineTo(p3.x, p3.y);
                        if(LINESTYLE>0) c.graphics.lineStyle(LINESTYLE, 0, LINEALPHA);
                        c.graphics.lineTo(p1.x, p1.y);
                        c.graphics.lineTo(oldP2.x, oldP2.y);
                        c.graphics.lineStyle(undefined);
                        oldStroke = STROKE;
                        oldP1 = point.add(new Point(Math.cos(a + Math.PI / 2) * oldStroke,Math.sin(a + Math.PI / 2) * oldStroke));
                        oldP2 = point.add(new Point(Math.cos(a – Math.PI / 2) * oldStroke,Math.sin(a – Math.PI / 2) * oldStroke));
                        oldPoint = point;
                }
                public function draw():void
                {
                        var curPoint:Point = new Point(_strokes[_stroke][_count].x * HEIGHT,_strokes[_stroke][_count].y * HEIGHT);
                        drawOne(curPoint);
                }
        }
}
 


Aug 05 2010

Grafitti Analysis : WIP

J’espère que vous connaissez déjà graffiti Analysis (un super projet d’Evan Roth) qui tente de mémoriser et d’archiver des données de “tag”. La base de données est ouverte et on peut donc charger les tags au format “GML” (graffiti mark up language). Je vais essayer de terminer une appli de lecture de tags et écriture de tag. J’ai déjà réussi à lire de tags, la j’en crée. Il ne me reste plus qu’a tout mettre ensemble pour faire une appli finie. Je balancerai bien sûr toutes les sources.