December 2008 Archives

(AS3) Tumblrview - Tumblr feed viewer

| No Comments | No TrackBacks
The next step from "(AS3) Reading Tumblr feeds" is to give a fancier appearance to the data.
I wrote some  classes that provide presentations for each type of post Tumblr supports (i.e. text, video, photo, and so on) and made them into a tile view. It's not very different from Tumblr's "archive" pages, but looks good on the wide screen.
I wanted to play videos and audios directly on this page but found it a bit tricky because of Flash's security sandbox restriction.
I also meant to make it possible to change the size of each items and add smooth navigation and scrolling between pages. Or maybe it's also fun to make this with Ajax from the scratch.
If you have a Tumblr account, you can test display your feed. If not, the default is set to an account "kyndnote" that I used while testing.

tumblrview.png

tumblrview -kynd.info

http://kyndnote.tumblr.com/(Tumblrlog for testing)




I've tried out Youtube and Flickr apis. It's quite nice that both services are providing api that return the results in JSONP format.
JSONP(JSON with padding) is "a JSON extension wherein the name of a callback function is specified as an input argument of the call itself." by Wikipedia, or it's an api that returns data in the Javascript's Object format with function call to tell the application that the loading is done.
That means it's a handy way to make a web application only with Javascript circumventing a security limitation which occurs when using XML or other formats.

My idea is that it may be convenient if the keywords related to the original search keyword so that they will help the user to narrow down the results or notice a relationship he/she never thought.
For example, let's look back at 2008. Searching keywords "election 2008" in "YouTube relational word search" shows the movies with familiar names like "Obama", "McCain" and keywords like "President", "USA", "Comedy"(It's interesting that "Comedy" is in the first place with big typeface). Cliking a word will add narrow down the results adding it to the search keywords.



youtube_i.png

(Processing) Primitives 3D

| No Comments | No TrackBacks
This is a simple example made with processings 3D api, in which some gray shperes rotate in the 3D space. To test the performance, I made it able to increase the number of shperes by clicking the movie. In my environment (2.4GHz core duo + 2GB memory), the movie starts to slow down after around ten shperes added to the stage. That is a bit slower than expected.

(Processing) Draw a 3D line in space

| No Comments | No TrackBacks
Clicking or dragging mouse in the gray square draws a line that rotates in the 3D space,

My first sketch made with processing.
Particles are generated every 10 frames and then fly around the stage attracctiong each other with gravity. The diameters of the circles indicates their masses(the bigger, the heavier), while the lines look like tails show the speed and direction of the particles.

(AS3) Making 3D function from the scratch (2)

| No Comments | No TrackBacks
What I made is a sample to understand how 3D objects are renderd by comparing two classes, one that uses the built in API of "Flash Player 10" (FP10api3DSquare) and another implements similar functions made from the scratch(My3DSquare).
Each of the classes draws a white square that can be rotated and be seen from different distances by changing the values in the spin boxes.



Test3D.as(main class)

package {
    import flash.display .Sprite;
    import flash.events.Event;
    public class Test3D extends Sprite {
        var squareA:My3DSquare;
        var squareB:FP10api3DSquare;
       
        public function Test3D() {
            squareA = new My3DSquare();
            squareA.x = 100;
            squareA.y = 100;
            addChild(squareA);
            squareB = new FP10api3DSquare();
            squareB.x = 300;
            squareB.y = 100;
            addChild(squareB);

            //add listeners to the NumericSteppers
            flA.addEventListener(Event.CHANGE, h_stepperChange);
            rxA.addEventListener(Event.CHANGE, h_stepperChange);
            ryA.addEventListener(Event.CHANGE, h_stepperChange);
            rzA.addEventListener(Event.CHANGE, h_stepperChange);
            flB.addEventListener(Event.CHANGE, h_stepperChange);
            rxB.addEventListener(Event.CHANGE, h_stepperChange);
            ryB.addEventListener(Event.CHANGE, h_stepperChange);
            rzB.addEventListener(Event.CHANGE, h_stepperChange);
        }
       
        private function h_stepperChange(evt:Event):void {
            switch(evt.target) {
                case flA:
                squareA.focalLength = evt.target.value;
                break;
                case rxA:
                squareA.rX = evt.target.value;
                break;
                case ryA:
                squareA.rY = evt.target.value;
                break;
                case rzA:
                squareA.rZ = evt.target.value;
                break;
                case flB:
                squareB.focalLength = evt.target.value;
                break;
                case rxB:
                squareB.rotationX = evt.target.value;
                break;
                case ryB:
                squareB.rotationY = evt.target.value;
                break;
                case rzB:
                squareB.rotationZ = evt.target.value;
                break;
            }
        }
    }
}

My3DSquare.as
package {
    import flash.display .Sprite;
    import flash.events.Event;
    public class My3DSquare extends Sprite {
        private var points:Array = [
                            {x:50,y:50,z:0},
                            {x:50,y:-50,z:0},
                            {x:-50,y:-50,z:0},
                            {x:-50,y:50,z:0}
                            ]
                         
        private var _focalLength:Number = 200, _rotationX:Number = 0, _rotationY:Number = 0, _rotationZ:Number = 0;
       
        public function My3DSquare() {
            draw();
        }
       
        public function set focalLength(n:Number):void {
            _focalLength = n;
            draw();
        }
        public function set rX(n:Number):void {
            _rotationX = n;
            draw();
        }
        public function set rY(n:Number):void {
            _rotationY = n;
            draw();
        }
        public function set rZ(n:Number):void {
            _rotationZ = n;
            draw();
        }
       
       
        private function draw():void {
            graphics.clear();
           
            var i:uint;
            var tPoints:Array = points.concat();;
            var point:Object = new Object;
           
            // rotate
            for (i = 0; i < points.length; i ++) {
                tPoints[i] = rotateX(tPoints[i], _rotationX);
                tPoints[i] = rotateY(tPoints[i], _rotationY);
                tPoints[i] = rotateZ(tPoints[i], _rotationZ);
            }
           
            // project to 2D and Draw
            var p:Object;
            var p3d:Object;
           
            graphics.beginFill(0xFFFFFF);
           
            for (i = 0; i < tPoints.length; i ++) {
                p3d = tPoints[i]
                p = p3Dto2D(p3d, _focalLength);
                if (i == 0) {
                    graphics.moveTo(p.x, p.y);
                } else {
                    graphics.lineTo(p.x, p.y);
                }
            }
            graphics.endFill();
        }
       
        private function rotateX(p3d:Object, angle:Number):Object {
            var p:Object = new Object();
            angle = angle /180 * Math.PI;
            p.x = p3d.x;
            p.y = Math.cos(angle) * p3d.y - Math.sin(angle) * p3d.z;
            p.z = Math.cos(angle) * p3d.z+ Math.sin(angle) * p3d.y;
            return p
        }
       
        private function rotateY(p3d:Object, angle:Number):Object {
            var p:Object = new Object();
            angle = angle /180 * Math.PI;
            p.x = Math.cos(angle) * p3d.x - Math.sin(angle) * p3d.z;
            p.y = p3d.y;
            p.z = Math.cos(angle) * p3d.z+ Math.sin(angle) * p3d.x;
            return p
        }
       
        private function rotateZ(p3d:Object, angle:Number):Object {
            var p:Object = new Object();
            angle = angle /180 * Math.PI;
            p.x = Math.cos(angle) * p3d.x - Math.sin(angle) * p3d.y;
            p.y = Math.cos(angle) * p3d.y+ Math.sin(angle) * p3d.x;
            p.z = p3d.z;
            return p
        }
       
        private function p3Dto2D(p3d:Object, _fl:Number):Object {
            var scale:Number;
            var p:Object = new Object();
            scale = _fl / (_fl + p3d.z);
            p.x = p3d.x  * scale;
            p.y = p3d.y * scale;
            return p
        }
       
    }
}

FP10api3DSquare
package {
    import flash.display .Sprite;
    import flash.events.Event;
    import flash.geom.PerspectiveProjection;
    import flash.geom.Point;
   
    public class FP10api3DSquare extends Sprite {
       
        public function FP10api3DSquare() {
            graphics.beginFill(0xFFFFFF);
            graphics.drawRect(-50,-50,100,100);
            graphics.endFill();
            addEventListener(Event.ADDED_TO_STAGE, h_addedToStage);
        }
       
        private function h_addedToStage(evt:Event):void {
            var pp:PerspectiveProjection = new PerspectiveProjection();
            pp.projectionCenter = new Point(300,100);
            pp.focalLength = 200;
            transform.perspectiveProjection = pp;
        }
       
        public function set focalLength(n:Number):void {
            transform.perspectiveProjection.focalLength = n;
        }
    }
}

Install flash player 10 or later if you don't see the sample movie.

(AS3) Strip Html Tags with allowable tags

| No Comments | No TrackBacks
As I was looking for the best way to remove the HTML tags from the feeds retrieved from Tumblr, I finally found this on Flex{er}.
Like strip_tags in PHP, "you could strip all HTML tags but the ones you specified as allowable tags. "

Strip Html Tags - with allowable tags | Flex{er}

(AS3) Reading Tumblr feeds

| No Comments | No TrackBacks
Tumblr is a smart service where a user can collect contents like photos, videos, texts and so on by uploading or clipping them from a website and make them into a fancy blog-like pages.

http://www.tumblr.com/

I really like this service and have been using for about a year. But as the contents accumulates, it's getting harder to look for the old posts because they are separated into a number of pages. So I came up with an idea of a new visual presentation for the service using the API and this is the first step.

What I did here was just to read the XML feed and display it in a DataGrid, a Flash's pre-set component. It's not good-looking or useful so far. I'll work on this topic again later.

The original Tumblrlog to read the feed from: http://kynddev.tumblr.com/

Tumblr API documentation


 package {
    import flash.display.*;
    import flash.net.*;
    import flash.events.*;
    import flash.text.*;
    import fl.controls.DataGrid;
    import fl.data.DataProvider;

    public class TumblrTest extends Sprite {

        var accountName:String = "kynddev";
        var loadingText:TextField;
       
        public function TumblrTest() {
            feedRequest();
        }

        private function feedRequest():void {
            var loader:URLLoader = new URLLoader  ;
            var req = new URLRequest("http://" + accountName + ".tumblr.com/api/read/?num=50");
            req.method = URLRequestMethod.GET;
            loader.addEventListener(Event.COMPLETE,h_completeLoading);
            loader.load(req);
           
            loadingText = new TextField ();
            loadingText.text = "Loading...";
            addChild(loadingText);
        }

        private function h_completeLoading(evt:Event):void {
            removeChild(loadingText);
           
            evt.target.removeEventListener(Event.COMPLETE,h_completeLoading);
            var feed:XML = new XML((evt.target as URLLoader).data);
            var posts:XMLList = feed.posts.post;

            var dg:DataGrid = new DataGrid  ;
            dg.width = 500;
            dg.height = 500;

            dg.columns = ["title","type","desc"];
            dg.columns[0].width = 200;
            dg.columns[1].width = 60;
           
            var dp:DataProvider = new DataProvider  ;
            var item:Object;
            for (var i:uint = 0; i < posts.length(); i++) {
                item = new Object();
               
                item.type = posts[i].@type;
                if (item.type == "photo") {
                    item.title = posts[i].child("photo-caption")[0];
                } else if  (item.type == "video") {
                    item.title = posts[i].child("video-caption")[0];
                } else if (item.type == "quote") {
                    item.title = posts[i].child("quote-text")[0];
                } else {
                    item.title = posts[i].child("link-text")[0];
                }
                item.desc = (posts[i].child("link-description").length() > 0) ? posts[i].child("link-description")[0] : "no description";
                dp.addItem(item);
            }
           
            dg.dataProvider = new DataProvider(dp);
            addChild(dg);
        }
    }
}




Install flash player 10 or later if you don't see the sample movie.

(AS3) Making 3D function from the scratch

| No Comments | No TrackBacks
This is a short study to grasp how a 3D object is projected onto a 2D plane.
I could have used Vector3D or other original classes to represent the points in 3D space or sets of points(the sets making up lines), but I didn't because the point is not to write a clean code but only to show the basic concepts.

The keys points are
1. the line that determines how the perspective affects the scale of the object scale = _fl / (_fl + p3d.z);
2. and the codes to rotate the object about the y-axis p.x = Math.cos(angle) * p3d.x - Math.sin(angle) * p3d.z;
p.y = p3d.y; p.z = Math.cos(angle) * p3d.z+ Math.sin(angle) * p3d.x;

for more about rotation, see Rotation (mathematics) on Wikipedia.


package {
    import flash.display .Sprite;
    import flash.events.Event;
    public class Test3D extends Sprite {
        private var points:Array = [
                            {x:50,y:50,z:50},
                            {x:50,y:50,z:-50},
                            {x:-50,y:50,z:-50},
                            {x:-50,y:50,z:50},
                           
                            {x:50,y:-50,z:50},
                            {x:50,y:-50,z:-50},
                            {x:-50,y:-50,z:-50},
                            {x:-50,y:-50,z:50},
                            ]
        private var lines:Array = [
                           [0,1],
                           [1,2],
                           [2,3],
                           [3,0],
                           [4,5],
                           [5,6],
                           [6,7],
                           [7,4],
                           [0,4],
                           [1,5],
                           [2,6],
                           [3,7]
                           ];
                          
        private var cx:Number,cy:Number;
        private var focalLength = 200;
       
        public function Test3D() {
            //center point
            cx = stage.stageWidth / 2;
            cy = stage.stageHeight / 2;
           
            addEventListener(Event.ENTER_FRAME, h_enterframe);
        }
       
        private function h_enterframe(evt:Event):void {
            graphics.clear();
           
            var i:uint;
           
            for (i = 0; i < points.length; i ++) {
                points[i] = rotateY(points[i], 5);
            }
            for (i = 0; i < lines.length; i ++) {
                drawLine(lines[i]);
            }
        }
       
        private function rotateY(p3d:Object, angle:Number):Object {
            var p:Object = new Object();
            angle = angle /180 * Math.PI;
            p.x = Math.cos(angle) * p3d.x - Math.sin(angle) * p3d.z;
            p.y = p3d.y;
            p.z = Math.cos(angle) * p3d.z+ Math.sin(angle) * p3d.x;
            return p
        }
       
       
        private function drawLine(line:Array):void {
            graphics.lineStyle(1, 0xFFFFFF);
            var p:Object;
            var p3d:Object;
           
            p3d = points[line[0]];
            p = p3Dto2D(p3d, focalLength);
            graphics.moveTo(cx + p.x, cy + p.y);
           
            p3d = points[line[1]];
            p = p3Dto2D(p3d, focalLength);
            graphics.lineTo(cx + p.x, cy + p.y);
        }
       
        private function p3Dto2D(p3d:Object, _fl:Number):Object {
            var scale:Number;
            var p:Object = new Object();
            scale = _fl / (_fl + p3d.z);
            p.x = p3d.x  * scale;
            p.y = p3d.y * scale;
            return p
        }
       
    }
}




Install flash player 10 or later if you don't see the sample movie.

(physics) the fomura of gravitation

| No Comments | No TrackBacks
force = G * m1 * m2 / distance2

G = (6.6742 ± 0.0010) * 10-11 * m3 * kg-1 * s-2

(AS3) Making 3D objects move

| 1 Comment | No TrackBacks
The 3D functions of Flash Player 10 seems not designed to making complex polygon models but rather to add simple 3D effects to existing DisplayObjects that are basically flat.

Here I tried to animate a number of triangles in a 3D space. Each triangle is a instance of an object that inherits the Shape class. As I expected, creating too many instances of the DisplayObjects drastically slows the performance of the player, which means it's not realistic to use DisplayObjects to represent individual polygons.

We still need to resort to third-party libraries PaperVison 3D or to implement the rendering functions ourselves in order to create full 3D animation with Flash. I mean to try latter for study during this winter holidays.




Install flash player 10 or later if you don't see the sample movie.

(AS3) 3D functions basic

| No Comments | No TrackBacks
Let's examine the 3D functions newly introduced to Flash CS4.
The first example is quite simple, which shows how the 3D-related properties added to DisplayObject work.
- A gray plane with a red dot on its top rotates according to the place of the mouse on the stage, which shows how the rotationX and rotationY properties work.
- Dragging the mouse on the stage background changes the z-coordinate and rotationZ of the square
- Dragging the square itself changes the x and y coordinates of the square. Note that the object moves along the plane that it is on according to its rotationX/Y property.




download sample

Install flash player 10 or later if you don't see the sample movie.
Using the 'SoundSequencePlayer' from the last post, this sample turns the lines drawn on the stage into sounds. The x-coordinate corresponds to the pitch of the sound, while the y-coordinate corresponds to the volume.
Try dragging the mouse on the gray square to listen to the result.



download sample

Install flash player 10 or later if you don't see the sample movie.

(AS3) Dynamic sound generation(3)

| No Comments | No TrackBacks
To make it more intuitive to control dynamic sound, I wrote a utility class, 'SoundSequencePlayer'.
With this class, sequences of sound can be assigned with a set of a pitch and a volume for given time. Here's a sample to show how to use this class:



import fl.events.ComponentEvent;
button.label = "play";
button.addEventListener(ComponentEvent.BUTTON_DOWN, h_playButtonDown);
var seq:SoundSequence = new SoundSequence();
seq.addPoint(0,C4,0);
seq.addPoint(1000,C4,1);
seq.addPoint(1500,D4,0.5);
seq.addPoint(2000,D4,0.5);
seq.addPoint(2500,E4,1);
seq.addPoint(3000,E4,1);
seq.addPoint(3500,D4,0.5);
seq.addPoint(4000,C4,0.2);
seq.addPoint(5000,C4,0.2);
seq.addPoint(5500,C4,0);
var player = new SoundSequencePlayer(seq);

function h_playButtonDown(evt:ComponentEvent):void {
    player.play();
}

const A4:Number = 440;
const As4:Number = 466.1637615180899;
const B4:Number = 493.8833012561241;
const C4:Number = 523.2511306011972;
const Cs4:Number = 554.3652619537442;
const D4:Number = 587.3295358348151;
const Ds4:Number = 622.2539674441618;
const E4:Number = 659.2551138257398;
const F4:Number = 698.4564628660078;
const Fs4:Number = 739.9888454232688;
const G4:Number = 783.9908719634985;
const Gs4:Number = 830.6093951598903;
const A5:Number = 880;
const As5:Number = 932.3275230361799;
const B5:Number = 987.7666025122483;
const C5:Number = 1046.5022612023945;
const Cs5:Number = 1108.7305239074883;
const D5:Number = 1174.6590716696303;
const Ds5:Number = 1244.5079348883237;
const E5:Number = 1318.5102276514797;
const F5:Number = 1396.9129257320155;
const Fs5:Number = 1479.9776908465376;
const G5:Number = 1567.981743926997;
const Gs5:Number = 1661.2187903197805;
const A6:Number = 1760;


download sample

Install flash player 10 or later if you don't see the sample movie.

strfriend:visualizing regurar expression

| No Comments | No TrackBacks
strfriend
http://strfriend.com/

This site generates a graphical representation of a regular expression into a visual graphic.
It's so helpful when reading a code someone wrote or checking if what you wrote is logically correct.

(AS3) Dynamic sound generation(2)

| No Comments | No TrackBacks
I made it possible to choose a pitch of the sound and change the amount of harmonic overtone which affects the timbre.
Ratio between a note and another half step away is 2 to the power of 1/12 and by multiplying the ratio by base frequency(A4 = 440 Hz), the frequency for each note can be obtained.

For details, sample code can be downloaded.

download sample
Install flash player 10 or later if you don't see the sample.