Erain 3D
--> FDT Pure coding comfort


Author: Max Pellizzaro
Date: October 29th 2008
version: 3.0.3

Extruding using a complex path

Objective of the tutorial

If you have completed the first and the second tutorials of this series, you should be able to extrude any polygon on any path. Since makc is a great developer, he has produce two helper classes in order to facilitate the extrusion on a complex path and on a circular path. This tutorial shows how to use a complex path, the next one shows how to use a circular path.

How to

Set up

No need to set up for this tutorial, just download the classes and they are ready to go.

example45.zip

The AS Code

In this section we report the AS code as a reference, and it will be explained in the next paragraph.

package {
	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageQuality;
	import flash.display.StageScaleMode;
	import flash.events.*;
    import flash.ui.*;
	import flash.geom.Point;
	
	import sandy.core.Scene3D;
	import sandy.core.scenegraph.Camera3D;
	import sandy.core.scenegraph.Group;
	import sandy.core.scenegraph.Shape3D;
	import sandy.materials.*;
	import sandy.materials.attributes.*;
	import sandy.primitive.Box;
	import sandy.primitive.Line3D;
	import sandy.extrusion.Extrusion;
	import sandy.extrusion.data.*;
	import sandy.core.data.*;

	public class Example045 extends Sprite {

		private var scene:Scene3D;
		private var camera:Camera3D;
		private var c:Box;
		private var ext:Extrusion;
		
		public function Example045() {
			
			camera = new Camera3D(stage.stageWidth, stage.stageHeight);
			scene = new Scene3D("myScene", this, camera , new Group("root"));
			
			
			 // this is a line I have used to check if the equation was right
			var arrayLine:Array = new Array();
			for (var j:int = -100; j < 130; j++) {
				arrayLine.push (new Vector (100 * Math.cos(j/8), j, 100 * Math.sin(j/8)));
			}
			var line:Line3D = new Line3D("theline", arrayLine);
			line.z = 100;
			// -- end of test line -- //
			
			var materialAttr:MaterialAttributes = new MaterialAttributes(new LineAttributes(0.5, 0x990000, 0.5));
			var material:Material = new ColorMaterial(0xffcc33, 1, materialAttr);
		
			var app:Appearance = new Appearance(material);
			
			var arrayQuad:Array = new Array();
			arrayQuad[0] = new Point(0,0);
			arrayQuad[1] = new Point(0,10);
			arrayQuad[2] = new Point(10,10);
			arrayQuad[3] = new Point(10,0);
			arrayQuad[4] = new Point(0,0);
			
			var sectionQuad:Polygon2D = new Polygon2D(arrayQuad);
		
		    var helix:Curve3D = new Curve3D;
			for (var i:int = -100; i < 130; i++) {
				helix.v.push (new Vector (100 * Math.cos(i/8), i, 100 * Math.sin(i/8)));
				var tang:Vector = new Vector (-100/8 * Math.sin(i/8) , 1, 100/8 * Math.cos(i/8)); tang.normalize ();
				helix.t.push (tang);
				var norm:Vector = new Vector (-100/64 * Math.cos(i/8), 0, -100/64 * Math.sin(i/8)); norm.crossWith(tang);
				helix.n.push (norm);
				helix.s.push (1);
			}

			// create extrusion
			ext = new Extrusion ("helix", sectionQuad, helix.toSections (), true, true); 
			ext.appearance = new Appearance (new ColorMaterial (0xFFAF00, 1,
				new MaterialAttributes (new LightAttributes( true, 0.1))));
			ext.appearance.frontMaterial.lightingEnable = true;
           
			ext.z = 100;
			//scene.root.addChild(line);
			scene.root.addChild(ext);
			
			
			stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMovedHandler);
			addEventListener(Event.ENTER_FRAME, render);
		}

		private function render(event:Event):void {
			scene.render();
			ext.pan -= 8;
		}
		
		private function mouseMovedHandler(event:MouseEvent):void {
           //ext.pan=(event.stageX-550/2)/5;
		   //ext.tilt=(event.stageY-400/2)/20;
 
        }
	}
}

Examining the code

The Frenet–Serret formulas

Before examining the code one should be familiar (but not too much) with the so called Frenet–Serret formulas. You can read on this article what I'm talking about. Basically the idea is to define a generic curve in the space using the Tangent of the curve point: T, the Normal of the curve point: N and the binormal of the curve point: B. Once it's clear to you these three concepts, it will be fairly simple to use the class we are going to introduce in this tutorial: Curve3D.
In this tutorial we will extrude a simple square section using a helix path, as shown in the following picture.

Helix formula:

 x = r*cos(b*t)
 y = r*sin(b*t)
 z = c*t

The code

Now it's time to start coding.
The poligon2D is prett simple since it is just a square

var arrayQuad:Array = new Array();
arrayQuad[0] = new Point(0,0);
arrayQuad[1] = new Point(0,10);
arrayQuad[2] = new Point(10,10);
arrayQuad[3] = new Point(10,0);
arrayQuad[4] = new Point(0,0);
 
var sectionQuad:Polygon2D = new Polygon2D(arrayQuad);

Now we need to code the Helix, and to do so we will use a new class called: Curve3D. The simple and beauty of this class is that if you know the function of the X, Y Z in the curve, and you remember basic math technique to derive function, you are done..
So let's start by using the coordinate of the points and push in the Curve3D property called: V

helix.v.push (new Vector (100 * Math.cos(i/8), i, 100 * Math.sin(i/8)));

Then we derive once the function of X, Y, Z in order to find the tangent of the curve:

var tang:Vector = new Vector (-100/8 * Math.sin(i/8) , 1, 100/8 * Math.cos(i/8)); tang.normalize ();
helix.t.push (tang);

The we derive a second time in order to find the Normal function:

var norm:Vector = new Vector (-100/64 * Math.cos(i/8), 0, -100/64 * Math.sin(i/8)); 
norm.crossWith(tang);
helix.n.push (norm);

Last but not least we have the possibility to define the scale of the section for each point of the curve:

helix.s.push (1);

So if we put all together:

var helix:Curve3D = new Curve3D;
for (var i:int = -100; i < 130; i++) {
	helix.v.push (new Vector (100 * Math.cos(i/8), i, 100 * Math.sin(i/8)));
	var tang:Vector = new Vector (-100/8 * Math.sin(i/8) , 1, 100/8 * Math.cos(i/8));  
        tang.normalize ();
	helix.t.push (tang);
	var norm:Vector = new Vector (-100/64 * Math.cos(i/8), 0, -100/64 * Math.sin(i/8)); 
        norm.crossWith(tang);
	helix.n.push (norm);
	helix.s.push (1);
}

We have now all the input to our Extrude Class:

ext = new Extrusion ("helix", sectionQuad, helix.toSections (), true, true);

Let’s see our result now.

The output