From f4eccf3e7cb76a14a3546a646575162dbd831538 Mon Sep 17 00:00:00 2001 From: Pushkar Joshi Date: Wed, 4 Apr 2012 15:52:41 -0700 Subject: draw the path overlay (and anchor points) taking into account the transformation applied to the element canvas and the stage canvas. Still quite buggy. --- js/lib/geom/sub-path.js | 57 +++++++++++++++++++++++++----- js/tools/BrushTool.js | 1 - js/tools/PenTool.js | 82 +++++++++++++++++++++++++++++++++---------- js/tools/drawing-tool-base.js | 2 ++ 4 files changed, 114 insertions(+), 28 deletions(-) diff --git a/js/lib/geom/sub-path.js b/js/lib/geom/sub-path.js index 35070915..bca4e1c5 100755 --- a/js/lib/geom/sub-path.js +++ b/js/lib/geom/sub-path.js @@ -310,6 +310,9 @@ GLSubpath.prototype = new GeomObj(); GLSubpath.prototype.setCanvas = function (c) { this._canvas = c; }; +GLSubpath.prototype.getCanvas = function() { + return this._canvas; +}; GLSubpath.prototype.setWorld = function (world) { this._world = world; @@ -875,6 +878,22 @@ GLSubpath.prototype.translateSubpathPerCanvas = function(elemMediator){ this._dirty=true; }; +GLSubpath.prototype.computeLeftTopWidthHeight = function() { + //build the width and height of this canvas by looking at local coordinates + var bboxMin = this.getLocalBBoxMin(); + var bboxMax = this.getLocalBBoxMax(); + var bboxWidth = bboxMax[0] - bboxMin[0]; + var bboxHeight = bboxMax[1] - bboxMin[1]; + + //build the 3D position of the plane center of this canvas by looking at midpoint of the bounding box in stage world coords + bboxMin = this.getBBoxMin(); + bboxMax = this.getBBoxMax(); + var bboxMid = [0.5 * (bboxMax[0] + bboxMin[0]), 0.5 * (bboxMax[1] + bboxMin[1]), 0.5 * (bboxMax[2] + bboxMin[2])]; + var left = Math.round(bboxMid[0] - 0.5 * bboxWidth); + var top = Math.round(bboxMid[1] - 0.5 * bboxHeight); + return [left, top, bboxWidth, bboxHeight]; +}; + GLSubpath.prototype.setStrokeWidth = function (w) { var diffStrokeWidth = w-Math.floor(this._strokeWidth);//if positive, then stroke width grew, else shrunk if (diffStrokeWidth === 0) @@ -891,7 +910,7 @@ GLSubpath.prototype.setStrokeWidth = function (w) { // **** adjust the left, top, width, and height to adjust for the change in stroke width **** this.createSamples(); //dirty bit is checked here this.buildLocalCoord(); //local dirty bit is checked here - +/* //build the width and height of this canvas by looking at local coordinates var bboxMin = this.getLocalBBoxMin(); var bboxMax = this.getLocalBBoxMax(); @@ -904,14 +923,15 @@ GLSubpath.prototype.setStrokeWidth = function (w) { var bboxMid = [0.5 * (bboxMax[0] + bboxMin[0]), 0.5 * (bboxMax[1] + bboxMin[1]), 0.5 * (bboxMax[2] + bboxMin[2])]; var left = Math.round(bboxMid[0] - 0.5 * bboxWidth); var top = Math.round(bboxMid[1] - 0.5 * bboxHeight); - +*/ + var ltwh = this.computeLeftTopWidthHeight(); var canvasArray=[this._canvas]; - ElementMediator.setProperty(canvasArray, "width", [bboxWidth+"px"], "Changing", "penTool");//canvas.width = w; - ElementMediator.setProperty(canvasArray, "height", [bboxHeight+"px"], "Changing", "penTool");//canvas.height = h; - ElementMediator.setProperty(canvasArray, "left", [left+"px"],"Changing", "penTool");//DocumentControllerModule.DocumentController.SetElementStyle(canvas, "left", parseInt(left) + "px"); - ElementMediator.setProperty(canvasArray, "top", [top + "px"],"Changing", "penTool");//DocumentControllerModule.DocumentController.SetElementStyle(canvas, "top", parseInt(top) + "px"); - this.setCanvasLeft(left); - this.setCanvasTop(top); + ElementMediator.setProperty(canvasArray, "width", [ltwh[2]+"px"], "Changing", "penTool");//canvas.width = w; + ElementMediator.setProperty(canvasArray, "height", [ltwh[3]+"px"], "Changing", "penTool");//canvas.height = h; + ElementMediator.setProperty(canvasArray, "left", [ltwh[0]+"px"],"Changing", "penTool");//DocumentControllerModule.DocumentController.SetElementStyle(canvas, "left", parseInt(left) + "px"); + ElementMediator.setProperty(canvasArray, "top", [ltwh[1]+ "px"],"Changing", "penTool");//DocumentControllerModule.DocumentController.SetElementStyle(canvas, "top", parseInt(top) + "px"); + this.setCanvasLeft(ltwh[0]); + this.setCanvasTop(ltwh[1]); }; GLSubpath.prototype.getStrokeMaterial = function () { @@ -1098,6 +1118,25 @@ GLSubpath.prototype._unprojectPt = function(pt, pespectiveDist) { return retPt; }; +//return the local coord. of the anchor at the specified index, null if the anchor does not have a local coord yet +GLSubpath.prototype.getAnchorLocalCoord = function(index){ + if (this._isDirty){ + this.createSamples(); + } + if (this._isLocalDirty){ + this.buildLocalCoord(); + } + if (index<0 || index>= this._Anchors.length || index>=this._anchorSampleIndex.length){ + return null; + } + var anchorSampleIndex = this._anchorSampleIndex[index]; + if (anchorSampleIndex>=this._LocalPoints.length){ + return null; + } + var localCoord = this._LocalPoints[anchorSampleIndex].slice(0); + return localCoord; +}; + //buildLocalCoord GLSubpath.prototype.buildLocalCoord = function () { if (!this._isLocalDirty) { @@ -1435,6 +1474,8 @@ GLSubpath.prototype.makeFillMaterial = function() { }; GLSubpath.prototype.getNearVertex = function( eyePt, dir ){ + //todo BUILD A BBOX USING LOCAL COORD. (NO z NEEDED) + //get the parameters used for computing perspective transformation var bboxDim = []; var bboxMid = []; diff --git a/js/tools/BrushTool.js b/js/tools/BrushTool.js index f7f0e4bf..78d1e7e6 100644 --- a/js/tools/BrushTool.js +++ b/js/tools/BrushTool.js @@ -134,7 +134,6 @@ exports.BrushTool = Montage.create(ShapeTool, { snapManager.enableSnapAlign(false); var point = webkitConvertPointFromPageToNode(this.application.ninja.stage.canvas, new WebKitPoint(x,y)); - //todo fix this function to allow us to get the correct location (in 3D) for the mouse position var unsnappedpos = DrawingToolBase.getHitRecPos(snapManager.snap(point.x, point.y, false)); this._draggingPlane = snapManager.getDragPlane(); diff --git a/js/tools/PenTool.js b/js/tools/PenTool.js index 2eae6adc..f1c79153 100755 --- a/js/tools/PenTool.js +++ b/js/tools/PenTool.js @@ -14,7 +14,7 @@ var ElementMediator = require("js/mediators/element-mediator").ElementMediator; var TagTool = require("js/tools/TagTool").TagTool; var ElementController = require("js/controllers/elements/element-controller").ElementController; var snapManager = require("js/helper-classes/3D/snap-manager").SnapManager; - +var ViewUtils = require("js/helper-classes/3D/view-utils").ViewUtils; var AnchorPoint = require("js/lib/geom/anchor-point").AnchorPoint; var SubPath = require("js/lib/geom/sub-path").SubPath; @@ -108,7 +108,6 @@ exports.PenTool = Montage.create(ShapeTool, { snapManager.enableSnapAlign(false); var point = webkitConvertPointFromPageToNode(this.application.ninja.stage.canvas, new WebKitPoint(x,y)); - //todo fix this function to allow us to get the correct location (in 3D) for the mouse position var unsnappedpos = DrawingToolBase.getHitRecPos(snapManager.snap(point.x, point.y, false)); this._dragPlane = snapManager.getDragPlane(); @@ -830,14 +829,12 @@ exports.PenTool = Montage.create(ShapeTool, { //display the subpath as a sequence of cubic beziers ctx.lineWidth = 1;//TODO replace hardcoded stroke width with some programmatically set value (should not be same as stroke width) ctx.strokeStyle = "green"; - //if (subpath.getStrokeColor()) - // ctx.strokeStyle = MathUtils.colorToHex( subpath.getStrokeColor() ); - + var i=0; ctx.beginPath(); var p0x = subpath.getAnchor(0).getPosX()+ horizontalOffset; var p0y = subpath.getAnchor(0).getPosY()+ verticalOffset; ctx.moveTo(p0x, p0y); - for (var i = 1; i < numAnchors; i++) { + for (i = 1; i < numAnchors; i++) { var p1x = subpath.getAnchor(i - 1).getNextX()+ horizontalOffset; var p1y = subpath.getAnchor(i - 1).getNextY()+ verticalOffset; var p2x = subpath.getAnchor(i).getPrevX()+ horizontalOffset; @@ -858,6 +855,34 @@ exports.PenTool = Montage.create(ShapeTool, { } ctx.stroke(); + + //draw the stage world points by projecting them to screen space + //get the screen coords of this anchor from its stage world coord + ctx.beginPath(); + ctx.strokeStyle = "red"; + var localToGlobalMat = ViewUtils.getLocalToGlobalMatrix(subpath.getCanvas()); + var currentLTWH = subpath.computeLeftTopWidthHeight(); + var deltaX = currentLTWH[0] - parseInt(ElementMediator.getProperty(subpath.getCanvas(), "left")); + var deltaY = currentLTWH[1] - parseInt(ElementMediator.getProperty(subpath.getCanvas(), "top")); + + var localCoord = subpath.getAnchorLocalCoord(0); + var sp = MathUtils.transformAndDivideHomogeneousPoint(localCoord,localToGlobalMat); + //add the difference between the current left and top and the canvas left and top + sp[0]+=deltaX; sp[1]+=deltaY; + + ctx.moveTo(sp[0],sp[1]); + for (i = 1; i < numAnchors; i++) { + localCoord = subpath.getAnchorLocalCoord(i); + sp = MathUtils.transformAndDivideHomogeneousPoint(localCoord,localToGlobalMat); + //add the difference between the current left and top and the canvas left and top + sp[0]+=deltaX; sp[1]+=deltaY; + ctx.lineTo(sp[0],sp[1]); + } + if (subpath.getIsClosed()){ + ctx.closePath(); + } + ctx.stroke(); + ctx.restore(); } //function (subpath) }, //DrawSubpathSVG @@ -879,37 +904,56 @@ exports.PenTool = Montage.create(ShapeTool, { var horizontalOffset = this.application.ninja.stage.userContentLeft;//stageManagerModule.stageManager.userContentLeft; var verticalOffset = this.application.ninja.stage.userContentTop;//stageManagerModule.stageManager.userContentTop; - //display circles and squares near all control points + var localToGlobalMat = ViewUtils.getLocalToGlobalMatrix(subpath.getCanvas()); + + var currentLTWH = subpath.computeLeftTopWidthHeight(); + var deltaX = currentLTWH[0] - parseInt(ElementMediator.getProperty(subpath.getCanvas(), "left")); + var deltaY = currentLTWH[1] - parseInt(ElementMediator.getProperty(subpath.getCanvas(), "top")); + + //display circles and squares near all control points ctx.fillStyle = "#FFFFFF"; ctx.lineWidth = 1; ctx.strokeStyle = "green"; var anchorDelta = 2; var selAnchorDelta = 4; for (var i = 0; i < numAnchors; i++) { - var px = subpath.getAnchor(i).getPosX(); - var py = subpath.getAnchor(i).getPosY(); + var px = subpath.getAnchor(i).getPosX()+horizontalOffset; + var py = subpath.getAnchor(i).getPosY()+verticalOffset; + var localCoord = subpath.getAnchorLocalCoord(i); + if (localCoord) { + var sp = MathUtils.transformAndDivideHomogeneousPoint(localCoord,localToGlobalMat); + px = sp[0]; py=sp[1]; + sp[0]+=deltaX; sp[1]+=deltaY; + } ctx.beginPath(); //ctx.arc(px + horizontalOffset, py + verticalOffset, this._DISPLAY_ANCHOR_RADIUS, 0, 2 * Math.PI, false); - ctx.moveTo(px-anchorDelta+horizontalOffset, py-anchorDelta+verticalOffset); - ctx.lineTo(px+anchorDelta+horizontalOffset, py-anchorDelta+verticalOffset); - ctx.lineTo(px+anchorDelta+horizontalOffset, py+anchorDelta+verticalOffset); - ctx.lineTo(px-anchorDelta+horizontalOffset, py+anchorDelta+verticalOffset); + ctx.moveTo(px-anchorDelta, py-anchorDelta); + ctx.lineTo(px+anchorDelta, py-anchorDelta); + ctx.lineTo(px+anchorDelta, py+anchorDelta); + ctx.lineTo(px-anchorDelta, py+anchorDelta); ctx.closePath(); ctx.fill(); ctx.stroke(); + } //display the hovered over anchor point ctx.lineWidth = 2; if (this._hoveredAnchorIndex>=0 && this._hoveredAnchorIndex