From c838f85d28acbf2fe208a4358aef9cac73b65fbc Mon Sep 17 00:00:00 2001 From: Pushkar Joshi Date: Tue, 3 Apr 2012 10:14:49 -0700 Subject: First attempt at preventing the drifting of the canvas due to floating point roundoff errors when constantly changing stroke width --- js/lib/geom/sub-path.js | 27 +++++- js/tools/PenTool.js | 231 ++++++++++++++++++++++-------------------------- 2 files changed, 133 insertions(+), 125 deletions(-) diff --git a/js/lib/geom/sub-path.js b/js/lib/geom/sub-path.js index 19a1da3b..4ded360c 100755 --- a/js/lib/geom/sub-path.js +++ b/js/lib/geom/sub-path.js @@ -866,6 +866,27 @@ GLSubpath.prototype.getStrokeWidth = function () { return this._strokeWidth; }; +GLSubpath.prototype.translateSubpathPerCanvas = function(elemMediator){ + //check if the canvas was translated + var penCanvasLeft = parseInt(elemMediator.getProperty(this._canvas, "left"));//parseFloat(DocumentControllerModule.DocumentController.GetElementStyle(this._penCanvas, "left")); + var penCanvasTop = parseInt(elemMediator.getProperty(this._canvas, "top"));//parseFloat(DocumentControllerModule.DocumentController.GetElementStyle(this._penCanvas, "top")); + var penCanvasWidth = parseInt(elemMediator.getProperty(this._canvas, "width"));//this._penCanvas.width; + var penCanvasHeight = parseInt(elemMediator.getProperty(this._canvas, "height"));//this._penCanvas.height; + var penCanvasOldX = penCanvasLeft + 0.5 * penCanvasWidth; + var penCanvasOldY = penCanvasTop + 0.5 * penCanvasHeight; + + var translateCanvasX = penCanvasOldX - this._canvasX; + var translateCanvasY = penCanvasOldY - this._canvasY; + + //update the canvasX and canvasY parameters for this subpath and also translate the subpath points (since they're stored in stage world space) + if (Math.abs(translateCanvasX)>=1 || Math.abs(translateCanvasY)>=1){ + this.setCanvasX(translateCanvasX + this._canvasX); + this.setCanvasY(translateCanvasY + this._canvasY); + this.translateAnchors(translateCanvasX, translateCanvasY, 0); + } + this._dirty=true; +}; + GLSubpath.prototype.setStrokeWidth = function (w) { var diffStrokeWidth = w-Math.floor(this._strokeWidth);//if positive, then stroke width grew, else shrunk if (diffStrokeWidth === 0) @@ -874,11 +895,14 @@ GLSubpath.prototype.setStrokeWidth = function (w) { this._strokeWidth = w; this._dirty=true; + var ElementMediator = require("js/mediators/element-mediator").ElementMediator; + this.translateSubpathPerCanvas(ElementMediator); + // **** 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 (X and Y needed only) + //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]; @@ -892,7 +916,6 @@ GLSubpath.prototype.setStrokeWidth = function (w) { var top = Math.round(bboxMid[1] - 0.5 * bboxHeight); var canvasArray=[this._canvas]; - var ElementMediator = require("js/mediators/element-mediator").ElementMediator; 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"); diff --git a/js/tools/PenTool.js b/js/tools/PenTool.js index 98423113..0dbefd16 100755 --- a/js/tools/PenTool.js +++ b/js/tools/PenTool.js @@ -393,22 +393,7 @@ exports.PenTool = Montage.create(ShapeTool, { TranslateSelectedSubpathPerPenCanvas:{ value: function() { if (this._penCanvas!==null) { - //obtain the 2D translation of the canvas due to the Selection tool...assuming this is called in Configure - var penCanvasLeft = parseInt(ElementMediator.getProperty(this._penCanvas, "left"));//parseFloat(DocumentControllerModule.DocumentController.GetElementStyle(this._penCanvas, "left")); - var penCanvasTop = parseInt(ElementMediator.getProperty(this._penCanvas, "top"));//parseFloat(DocumentControllerModule.DocumentController.GetElementStyle(this._penCanvas, "top")); - var penCanvasWidth = parseInt(ElementMediator.getProperty(this._penCanvas, "width"));//this._penCanvas.width; - var penCanvasHeight = parseInt(ElementMediator.getProperty(this._penCanvas, "height"));//this._penCanvas.height; - var penCanvasOldX = penCanvasLeft + 0.5 * penCanvasWidth; - var penCanvasOldY = penCanvasTop + 0.5 * penCanvasHeight; - - var translateCanvasX = penCanvasOldX - this._selectedSubpath.getCanvasX(); - var translateCanvasY = penCanvasOldY - this._selectedSubpath.getCanvasY(); - - //update the canvasX and canvasY parameters for this subpath and also translate the subpath points (since they're stored in stage world space) - this._selectedSubpath.setCanvasX(translateCanvasX + this._selectedSubpath.getCanvasX()); - this._selectedSubpath.setCanvasY(translateCanvasY + this._selectedSubpath.getCanvasY()); - this._selectedSubpath.translateAnchors(translateCanvasX, translateCanvasY, 0); - this._selectedSubpath.createSamples(); //updates the bounding box + this._selectedSubpath.translateSubpathPerCanvas(ElementMediator); } } }, @@ -444,6 +429,113 @@ exports.PenTool = Montage.create(ShapeTool, { } }, + RenderShape: { + value: function (w, h, midPt, planeMat, canvas) { + if ((Math.floor(w) === 0) || (Math.floor(h) === 0)) { + return; + } + + var left = Math.round(midPt[0] - 0.5 * w); + var top = Math.round(midPt[1] - 0.5 * h); + + if (!canvas) { + var newCanvas = null; + newCanvas = NJUtils.makeNJElement("canvas", "Subpath", "shape", {"data-RDGE-id": NJUtils.generateRandom()}, true); + var elementModel = TagTool.makeElement(parseInt(w), parseInt(h), planeMat, midPt, newCanvas); + ElementMediator.addElement(newCanvas, elementModel.data, true); + + // create all the GL stuff + var world = this.getGLWorld(newCanvas, this._useWebGL);//this.options.use3D);//this.CreateGLWorld(planeMat, midPt, newCanvas, this._useWebGL);//fillMaterial, strokeMaterial); + //store a reference to this newly created canvas + this._penCanvas = newCanvas; + + var subpath = this._selectedSubpath; //new GLSubpath(); + subpath.setWorld(world); + subpath.setCanvas(newCanvas); + + world.addObject(subpath); + world.render(); + //TODO this will not work if there are multiple shapes in the same canvas + newCanvas.elementModel.shapeModel.GLGeomObj = subpath; + newCanvas.elementModel.shapeModel.shapeCount++; + if(newCanvas.elementModel.shapeModel.shapeCount === 1) + { + newCanvas.elementModel.selection = "Subpath"; + newCanvas.elementModel.pi = "SubpathPi"; + newCanvas.elementModel.shapeModel.strokeSize = this.options.strokeSize.value + " " + this.options.strokeSize.units; + var strokeColor = subpath.getStrokeColor(); + newCanvas.elementModel.shapeModel.stroke = strokeColor; + if(strokeColor) { + newCanvas.elementModel.shapeModel.border = this.application.ninja.colorController.colorToolbar.stroke; + } + newCanvas.elementModel.shapeModel.strokeMaterial = subpath.getStrokeMaterial(); + + newCanvas.elementModel.shapeModel.GLGeomObj = subpath; + newCanvas.elementModel.shapeModel.useWebGl = this.options.use3D; + } + else + { + // TODO - update the shape's info only. shapeModel will likely need an array of shapes. + } + + //if(newCanvas.elementModel.isShape) + if (true) + { + this.application.ninja.selectionController.selectElement(newCanvas); + } + } //if (!canvas) { + else { + + var world = null; + if (canvas.elementModel.shapeModel && canvas.elementModel.shapeModel.GLWorld) { + world = canvas.elementModel.shapeModel.GLWorld; + } else { + world = this.getGLWorld(canvas, this._useWebGL);//this.options.use3D);//this.CreateGLWorld(planeMat, midPt, canvas, this._useWebGL);//fillMaterial, strokeMaterial); + } + + if (this._entryEditMode !== this.ENTRY_SELECT_CANVAS){ + //update the left and top of the canvas element + var canvasArray=[canvas]; + w= Math.round(w); + h = Math.round(h); + ElementMediator.setProperty(canvasArray, "width", [w+"px"], "Changing", "penTool");//canvas.width = w; + ElementMediator.setProperty(canvasArray, "height", [h+"px"], "Changing", "penTool");//canvas.height = h; + + //var bboxMid = this._selectedSubpath.getLocalBBoxMidInStageWorld(); + //left = Math.round(bboxMid[0] - 0.5 * w); + //top = Math.round(bboxMid[1] - 0.5 * 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"); + + //update the viewport and projection to reflect the new canvas width and height (todo might be unnecessary since we don't use RDGE for now) + world.setViewportFromCanvas(canvas); + if (this._useWebGL){ + var cam = world.renderer.cameraManager().getActiveCamera(); + cam.setPerspective(world.getFOV(), world.getAspect(), world.getZNear(), world.getZFar()); + } + } + + var subpath = this._selectedSubpath; + + subpath.setDrawingTool(this); + subpath.setWorld(world); + + world.addIfNewObject(subpath); + world.render(); + + //TODO this will not work if there are multiple shapes in the same canvas + canvas.elementModel.shapeModel.GLGeomObj = subpath; + + //if(newCanvas.elementModel.isShape) + if (true) + { + this.application.ninja.selectionController.selectElement(canvas); + } + } //else of if (!canvas) { + } //value: function (w, h, planeMat, midPt, canvas) { + }, //RenderShape: { + HandleLeftButtonUp: { value: function (event) { if (this._isAltDown) { @@ -603,113 +695,6 @@ exports.PenTool = Montage.create(ShapeTool, { } }, - RenderShape: { - value: function (w, h, midPt, planeMat, canvas) { - if ((Math.floor(w) === 0) || (Math.floor(h) === 0)) { - return; - } - - var left = Math.round(midPt[0] - 0.5 * w); - var top = Math.round(midPt[1] - 0.5 * h); - - if (!canvas) { - var newCanvas = null; - newCanvas = NJUtils.makeNJElement("canvas", "Subpath", "shape", {"data-RDGE-id": NJUtils.generateRandom()}, true); - var elementModel = TagTool.makeElement(parseInt(w), parseInt(h), planeMat, midPt, newCanvas); - ElementMediator.addElement(newCanvas, elementModel.data, true); - - // create all the GL stuff - var world = this.getGLWorld(newCanvas, this._useWebGL);//this.options.use3D);//this.CreateGLWorld(planeMat, midPt, newCanvas, this._useWebGL);//fillMaterial, strokeMaterial); - //store a reference to this newly created canvas - this._penCanvas = newCanvas; - - var subpath = this._selectedSubpath; //new GLSubpath(); - subpath.setWorld(world); - subpath.setCanvas(newCanvas); - - world.addObject(subpath); - world.render(); - //TODO this will not work if there are multiple shapes in the same canvas - newCanvas.elementModel.shapeModel.GLGeomObj = subpath; - newCanvas.elementModel.shapeModel.shapeCount++; - if(newCanvas.elementModel.shapeModel.shapeCount === 1) - { - newCanvas.elementModel.selection = "Subpath"; - newCanvas.elementModel.pi = "SubpathPi"; - newCanvas.elementModel.shapeModel.strokeSize = this.options.strokeSize.value + " " + this.options.strokeSize.units; - var strokeColor = subpath.getStrokeColor(); - newCanvas.elementModel.shapeModel.stroke = strokeColor; - if(strokeColor) { - newCanvas.elementModel.shapeModel.border = this.application.ninja.colorController.colorToolbar.stroke; - } - newCanvas.elementModel.shapeModel.strokeMaterial = subpath.getStrokeMaterial(); - - newCanvas.elementModel.shapeModel.GLGeomObj = subpath; - newCanvas.elementModel.shapeModel.useWebGl = this.options.use3D; - } - else - { - // TODO - update the shape's info only. shapeModel will likely need an array of shapes. - } - - //if(newCanvas.elementModel.isShape) - if (true) - { - this.application.ninja.selectionController.selectElement(newCanvas); - } - } //if (!canvas) { - else { - - var world = null; - if (canvas.elementModel.shapeModel && canvas.elementModel.shapeModel.GLWorld) { - world = canvas.elementModel.shapeModel.GLWorld; - } else { - world = this.getGLWorld(canvas, this._useWebGL);//this.options.use3D);//this.CreateGLWorld(planeMat, midPt, canvas, this._useWebGL);//fillMaterial, strokeMaterial); - } - - if (this._entryEditMode !== this.ENTRY_SELECT_CANVAS){ - //update the left and top of the canvas element - var canvasArray=[canvas]; - w= Math.round(w); - h = Math.round(h); - ElementMediator.setProperty(canvasArray, "width", [w+"px"], "Changing", "penTool");//canvas.width = w; - ElementMediator.setProperty(canvasArray, "height", [h+"px"], "Changing", "penTool");//canvas.height = h; - - //var bboxMid = this._selectedSubpath.getLocalBBoxMidInStageWorld(); - //left = Math.round(bboxMid[0] - 0.5 * w); - //top = Math.round(bboxMid[1] - 0.5 * 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"); - - //update the viewport and projection to reflect the new canvas width and height (todo might be unnecessary since we don't use RDGE for now) - world.setViewportFromCanvas(canvas); - if (this._useWebGL){ - var cam = world.renderer.cameraManager().getActiveCamera(); - cam.setPerspective(world.getFOV(), world.getAspect(), world.getZNear(), world.getZFar()); - } - } - - var subpath = this._selectedSubpath; - - subpath.setDrawingTool(this); - subpath.setWorld(world); - - world.addIfNewObject(subpath); - world.render(); - - //TODO this will not work if there are multiple shapes in the same canvas - canvas.elementModel.shapeModel.GLGeomObj = subpath; - - //if(newCanvas.elementModel.isShape) - if (true) - { - this.application.ninja.selectionController.selectElement(canvas); - } - } //else of if (!canvas) { - } //value: function (w, h, planeMat, midPt, canvas) { - }, //RenderShape: { - BuildSecondCtrlPoint:{ value: function(p0, p2, p3) { var baselineOrig = VecUtils.vecSubtract(3, p3, p0); -- cgit v1.2.3