package
{
import flash.text.*;
import flash.events.*;
import fl.events.SliderEvent;
import flash.display.*;
import flash.ui.Keyboard;
import flash.utils.Timer;
import de.polygonal.ds.*;
import org.papervision3d.cameras.*;
import org.papervision3d.events.*;
import org.papervision3d.materials.*;
import org.papervision3d.objects.*;
import org.papervision3d.scenes.*;
//import org.papervision3d.components.as3.utils.ObjectController;
public class Main extends Sprite {
// Sizing
public static const k_nodeRadius:int = 10;
public static const k_nodeHeight:int = 36; // 0.34*21*radius/2
public static const k_gridWidth:int = 26;
public static const k_gridHeight:int = 26;
public static const k_gridSpacing:int = k_nodeRadius * 2;
// Node
private var graph:Graph;
private var grid:Array2;
private var nodeCanvas:Sprite;
private var nodeNumbers:LinkedStack;
private var nodeCount:int = 0;
// Path
// 3D render
private var container:Sprite;
private var scene:Scene3D;
private var camera:Camera3D;
private var rootNode:DisplayObject3D;
private var cylinderList:Array;
private var angle:Number = 0;
public static const camera_x_offset:int = 150;
public static const camera_y_offset:int = 260;
public static const camera_z_offset:int = k_nodeHeight/2;
// Misc
public static var MyriadProFont:Font = new MyriadPro();
public function Main() {
configureListeners();
stage.quality = "HIGH";
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
// 3D stuff
cylinderList = new Array();
// Creates scene
container = new Sprite();
container.x = 150;
container.y = 20;
renderPanel.addChild(container);
scene = new Scene3D(container);
rootNode = new DisplayObject3D("rootNode");
scene.addChild(rootNode);
// Creates cameras
camera = new Camera3D();
camera.zoom = 5;
camera.focus = 200;
camera.target.z = camera_z_offset;
addEventListener(Event.ENTER_FRAME, tick);
// Creates 2D slice grid
grid = new Array2(k_gridWidth, k_gridHeight);
graph = new Graph(grid.size);
Node.RADIUS = k_nodeRadius;
slicePanel.addChild(nodeCanvas = new Sprite());
nodeCanvas.x = nodeCanvas.y = k_nodeRadius * 2;
nodeNumbers = new LinkedStack();
// Add a mask for slicePanel
var rect:Shape = new Shape();
rect.graphics.lineStyle(1, 0x000000);
rect.graphics.beginFill(0xff0000);
rect.graphics.drawRect(10, 10, 310, 570);
rect.graphics.endFill();
slicePanel.addChild(rect);
nodeCanvas.mask = rect;
nodeCanvas.x = -100;
nodeCanvas.y = -100;
nodeCanvas.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown)
nodeCanvas.addEventListener(MouseEvent.MOUSE_UP, mouseReleased);
//create rectangular array of nodes
var i:int = 0;
var node:Node;
for (var y:int = 0; y < grid.height; y++)
{
for (var x:int = 0; x < grid.width; x++)
{
node = new Node(i);
nodeCanvas.addChild(node);
if ((x % 2) ^ (y % 2)) {
node.y = y*k_nodeRadius*3*1.05 + k_nodeRadius;
} else {
node.y = y*k_nodeRadius*3*1.05;
}
node.x = x*k_nodeRadius*1.7320*1.1
var tf:TextField = node.getChildAt(0) as TextField;
var tfm:TextFormat = tf.getTextFormat();
tfm.size = 14;
tf.defaultTextFormat = tfm;
graph.addNode(node, i);
grid.set(x, y, node);
i++;
node.addEventListener(MouseEvent.MOUSE_MOVE, onMove, false, 1000);
node.addEventListener(MouseEvent.MOUSE_OUT, onMouseOut, false, 1000);
node.addEventListener(MouseEvent.CLICK, onClick, false, 1000);
}
}
}
private function mouseDown(event:MouseEvent):void {
nodeCanvas.startDrag();
}
private function mouseReleased(event:MouseEvent):void {
nodeCanvas.stopDrag();
}
private function addCylinder(p_x:Number, p_y:Number, p_z:Number):void {
var cylinderIndex:uint = cylinderList.length;
var newCylinderMaterial:CompositeMaterial = new CompositeMaterial()
newCylinderMaterial.addMaterial(new ColorMaterial(0x03a3f0));
newCylinderMaterial.addMaterial(new WireframeMaterial(0x000000));
var newCylinder:Cylinder = new Cylinder(newCylinderMaterial, k_nodeRadius+2, k_nodeHeight, 10, 6, 0, null);
newCylinder.rotationX = 90;
rootNode.addChild(newCylinder);
cylinderList[cylinderIndex] = newCylinder;
newCylinder.x = p_x;
newCylinder.y = p_y;
newCylinder.z = p_z;
}
private function tick(event:Event):void {
// A tick of the engine
camera.x = Math.round(Math.cos(angle)*750 + camera_x_offset);
camera.z = Math.round(Math.sin(angle)*750 + camera_z_offset);
angle += 0.03;
scene.renderCamera(camera);
basePanel.renderText.text = "cam.x: " + camera.z.toString() +
" cam.z: " + camera.z.toString();
}
private function configureListeners():void {
basePanel.zoomslider.addEventListener(SliderEvent.CHANGE, sliderChanged);
basePanel.zoomslider.addEventListener(SliderEvent.THUMB_RELEASE, sliderRelease);
basePanel.focusslider.addEventListener(SliderEvent.CHANGE, focussliderChanged);
basePanel.focusslider.addEventListener(SliderEvent.THUMB_RELEASE, foucssliderRelease);
}
private function sliderRelease(e:SliderEvent):void {
camera.zoom = e.target.value;
}
private function sliderChanged(e:SliderEvent):void {
basePanel.zoomsliderLabel.text = e.target.value;
}
private function foucssliderRelease(e:SliderEvent):void {
camera.y = e.target.value;
}
private function focussliderChanged(e:SliderEvent):void {
basePanel.focussliderLabel.text = e.target.value;
}
private function onClick(e:MouseEvent):void
{
// check if target is marked
if (e.target.marked) {
// check if pairedNeighbor is marked
if (e.target.pairedNeighbor.marked) {
var a:Array = new Array();
// unmark and recover numbers
a.push(e.target.unmark());
a.push(e.target.pairedNeighbor.unmark());
a.sort();
nodeNumbers.push(a[0]);
nodeNumbers.push(a[1]);
// unpair
e.target.neighbor.pairedNeighbor = null;
e.target.pairedNeighbor = null;
}
} else if (!e.target.marked) { // target is unmarked
if (e.target.neighbor == null) {
return; // return if no neighbors
}
if (!e.target.neighbor.marked) { // if neighbor is unmarked
var parity:int;
parity = getNodeParity(e.target);
//var s:int = nodeNumbers.size();
if (nodeNumbers.peek() == null) {
nodeNumbers.push(nodeCount);
nodeCount += 1;
nodeNumbers.push(nodeCount);
nodeCount += 1;
}
var odd:int = nodeNumbers.pop();
var even:int = nodeNumbers.pop();
// mark nodes
if (parity == 1) {
e.target.neighbor.mark(even);
e.target.mark(odd);
} else {
e.target.mark(even);
e.target.neighbor.mark(odd);
}
// pair nodes
e.target.pairedNeighbor = e.target.neighbor;
e.target.neighbor.pairedNeighbor = e.target;
// Path update
// 3D render
addCylinder(e.target.x, -e.target.y, 0);
addCylinder(e.target.neighbor.x, -e.target.neighbor.y, 0);
centerXY();
}
}
}
private function getDist(x1:int,x2:int,y1:int,y2:int):int {
return Math.sqrt(Math.pow(x1-x2,2)+Math.pow(y1-y2,2));
}
private function centerXY() {
var n:Node;
var maxX:int = 0;
var maxY:int = 0;
var minX:int = 9999;
var minY:int = 9999;
var midX:int = 0;
var midY:int = 0;
for (var row:int = 0; row < grid.height; row++)
{
for (var col:int = 0; col < grid.width; col++)
{
n = grid.get(col, row);
if (!n.marked) continue;
if (n.x > maxX) {
maxX = n.x;
}
if (n.x < minX) {
minX = n.x;
}
if (n.y > maxY) {
maxY = n.y;
}
if (n.y < minY) {
minY = n.y;
}
}
}
midX = (maxX+minX)/2;
midY = (maxY+minY)/2;
camera.target.x = midX;
camera.target.y = -(midY - camera_y_offset);
camera.y = -(midY-camera_y_offset);
trace(camera.y)
}
private function getNodeParity(n:Object):int
{
var rowcol:Array = [];
var row:int;
var col:int;
var parity:int;
rowcol = grid.rowcolIndex(n); // get (x,y) coords of node
row = rowcol[0];
col = rowcol[1];
parity = (row % 2) ^ (col % 2); // get parity
return parity;
}
private function getRowColParity(row:int, col:int):int
{
return (row % 2) ^ (col % 2);
}
private function getRowCol(n:Object):Array
{
var rowcol:Array = [];
rowcol = grid.rowcolIndex(n);
return rowcol
}
private function onMouseOut(e:MouseEvent):void
{
var neighbors:Array = new Array();
var rowcol:Array;
var row:int;
var col:int;
var parity:int;
rowcol = getRowCol(e.target);
row = rowcol[0];
col = rowcol[1]
parity = getRowColParity(row, col);
// get row + 1 if valid
if (row < k_gridWidth-1) {
neighbors.push(grid.get(row+1,col));
}
// get row - 1 if valid
if (row > 0) {
neighbors.push(grid.get(row-1,col));
}
if (parity == 1) { // get col + 1 if valid
if (col < k_gridHeight-1) {
neighbors.push(grid.get(row,col+1));
}
} else { // get col+1 if valid
if (col > 0) {
neighbors.push(grid.get(row,col-1));
}
}
var i:int;
for (i = 0; i < neighbors.length; i++)
{
neighbors[i].unhover()
}
e.target.unhover();
}
private function onMove(e:MouseEvent):void
{
var x:int = e.target.x;
var y:int = e.target.y;
var row:int;
var col:int;
var rowcol:Array = [];
var parity:int;
var dist:int;
var minDist:int = 9999;
var neighbor:Node;
var pairedNeighbor:Node;
var nearestNeighbor:Node;
var neighbors:Array = new Array();
var nearestNeighborIndex:int;
var info:String = "";
rowcol = getRowCol(e.target);
row = rowcol[0];
col = rowcol[1];
parity = getRowColParity(row, col);
info += "mouse:" + e.stageX + "," + e.stageY + "\n";
info += "node " + e.target.graphIndex + ": " + x + "," + y + "\n";
info += "marked: " + e.target.marked + "\n";
info += "neighbor: " + e.target.neighbor + "\n";
if (e.target.pairedNeighbor != null) {
pairedNeighbor = e.target.pairedNeighbor;
e.target.pairedhover();
pairedNeighbor.pairedhover();
basePanel.sliceText.text = info;
return;
}
// get row + 1 if valid
if (row < k_gridWidth-1) {
neighbor = grid.get(row+1,col)
neighbors.push(neighbor);
}
// get row - 1 if valid
if (row > 0) {
neighbor = grid.get(row-1,col)
neighbors.push(neighbor);
}
if (parity == 1) { // get col + 1 if valid
if (col < k_gridHeight-1) {
neighbor = grid.get(row,col+1)
neighbors.push(neighbor);
}
} else { // get col+1 if valid
if (col > 0) {
neighbor = grid.get(row,col-1)
neighbors.push(neighbor);
}
}
var i:int;
if (neighbors.length > 0) {
for (i = 0; i < neighbors.length; i++) {
dist = getDist(e.stageX,neighbors[i].x+20,
e.stageY,neighbors[i].y+20);
info += "[" + neighbors[i].graphIndex + ":" +
dist + "] ";
if (neighbors[i].pairedNeighbor != null) {
continue;
}
if (dist < minDist) {
minDist = dist;
nearestNeighborIndex = i;
}
}
nearestNeighbor = neighbors[nearestNeighborIndex]
if (nearestNeighbor == pairedNeighbor) {
nearestNeighbor.pairedhover();
neighbors.splice(nearestNeighborIndex,1);
} else if (nearestNeighbor.pairedNeighbor != null) {
return;
} else {
nearestNeighbor.hover();
e.target.neighbor = nearestNeighbor;
e.target.neighbor.neighbor = e.target;
neighbors.splice(nearestNeighborIndex,1);
}
for (i = 0; i < neighbors.length; i++)
{
neighbors[i].unhover();
}
}
basePanel.sliceText.text = info;
}
}
}