aboutsummaryrefslogtreecommitdiff
path: root/js/tools/PenTool.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/tools/PenTool.js')
-rwxr-xr-xjs/tools/PenTool.js441
1 files changed, 255 insertions, 186 deletions
diff --git a/js/tools/PenTool.js b/js/tools/PenTool.js
index 4a16a491..962f178d 100755
--- a/js/tools/PenTool.js
+++ b/js/tools/PenTool.js
@@ -14,7 +14,7 @@ var ElementMediator = require("js/mediators/element-mediator").ElementMediator;
14var TagTool = require("js/tools/TagTool").TagTool; 14var TagTool = require("js/tools/TagTool").TagTool;
15var ElementController = require("js/controllers/elements/element-controller").ElementController; 15var ElementController = require("js/controllers/elements/element-controller").ElementController;
16var snapManager = require("js/helper-classes/3D/snap-manager").SnapManager; 16var snapManager = require("js/helper-classes/3D/snap-manager").SnapManager;
17 17var ViewUtils = require("js/helper-classes/3D/view-utils").ViewUtils;
18var AnchorPoint = require("js/lib/geom/anchor-point").AnchorPoint; 18var AnchorPoint = require("js/lib/geom/anchor-point").AnchorPoint;
19var SubPath = require("js/lib/geom/sub-path").SubPath; 19var SubPath = require("js/lib/geom/sub-path").SubPath;
20 20
@@ -68,11 +68,14 @@ exports.PenTool = Montage.create(ShapeTool, {
68 //the plane matrix for the first click...so the entire path is on the same plane 68 //the plane matrix for the first click...so the entire path is on the same plane
69 _penPlaneMat: { value: null, writable: true }, 69 _penPlaneMat: { value: null, writable: true },
70 70
71 //the plane equation (in stage world space) for the current path being drawn
72 _dragPlane: {value: null, writable: true},
73
71 //index of the anchor point that the user has hovered over 74 //index of the anchor point that the user has hovered over
72 _hoveredAnchorIndex: {value: -1, writable: true}, 75 _hoveredAnchorIndex: {value: -1, writable: true},
73 76
74 //constants used for picking points --- NOTE: these should be user-settable parameters 77 //constants used for picking points --- NOTE: these should be user-settable parameters
75 _PICK_POINT_RADIUS: { value: 10, writable: false }, 78 _PICK_POINT_RADIUS: { value: 4, writable: false },
76 _DISPLAY_ANCHOR_RADIUS: { value: 5, writable: false }, 79 _DISPLAY_ANCHOR_RADIUS: { value: 5, writable: false },
77 _DISPLAY_SELECTED_ANCHOR_RADIUS: { value: 10, writable: false }, 80 _DISPLAY_SELECTED_ANCHOR_RADIUS: { value: 10, writable: false },
78 _DISPLAY_SELECTED_ANCHOR_PREV_RADIUS: { value: 2, writable: false }, 81 _DISPLAY_SELECTED_ANCHOR_PREV_RADIUS: { value: 2, writable: false },
@@ -106,6 +109,7 @@ exports.PenTool = Montage.create(ShapeTool, {
106 109
107 var point = webkitConvertPointFromPageToNode(this.application.ninja.stage.canvas, new WebKitPoint(x,y)); 110 var point = webkitConvertPointFromPageToNode(this.application.ninja.stage.canvas, new WebKitPoint(x,y));
108 var unsnappedpos = DrawingToolBase.getHitRecPos(snapManager.snap(point.x, point.y, false)); 111 var unsnappedpos = DrawingToolBase.getHitRecPos(snapManager.snap(point.x, point.y, false));
112 this._dragPlane = snapManager.getDragPlane();
109 113
110 snapManager.enableElementSnap(elemSnap); 114 snapManager.enableElementSnap(elemSnap);
111 snapManager.enableGridSnap(gridSnap); 115 snapManager.enableGridSnap(gridSnap);
@@ -214,6 +218,7 @@ exports.PenTool = Montage.create(ShapeTool, {
214 if (this._selectedSubpath.getIsClosed() && this._makeMultipleSubpaths) { 218 if (this._selectedSubpath.getIsClosed() && this._makeMultipleSubpaths) {
215 this._penCanvas = null; 219 this._penCanvas = null;
216 this._penPlaneMat = null; 220 this._penPlaneMat = null;
221 this._dragPlane = null;
217 this._snapTarget = null; 222 this._snapTarget = null;
218 this._selectedSubpath = new SubPath(); 223 this._selectedSubpath = new SubPath();
219 this._isNewPath = true; 224 this._isNewPath = true;
@@ -278,8 +283,15 @@ exports.PenTool = Montage.create(ShapeTool, {
278 this.application.ninja.stage.clearDrawingCanvas(); 283 this.application.ninja.stage.clearDrawingCanvas();
279 this._hoveredAnchorIndex = -1; 284 this._hoveredAnchorIndex = -1;
280 285
281 //set the cursor to be the default cursor 286 //set the cursor to be the default cursor (depending on whether the selected subpath has any points yet)
282 this.application.ninja.stage.drawingCanvas.style.cursor = "auto"; 287 if (this._selectedSubpath && this._selectedSubpath.getNumAnchors()>0){
288 this.application.ninja.stage.drawingCanvas.style.cursor = //"auto";
289 "url('images/cursors/penCursors/Pen_.png') 5 1, default";
290 }
291 else {
292 this.application.ninja.stage.drawingCanvas.style.cursor = //"auto";
293 "url('images/cursors/penCursors/Pen_newPath.png') 5 1, default";
294 }
283 295
284 if (this._isDrawing) { 296 if (this._isDrawing) {
285 var point = webkitConvertPointFromPageToNode(this.application.ninja.stage.canvas, new WebKitPoint(event.pageX, event.pageY)); 297 var point = webkitConvertPointFromPageToNode(this.application.ninja.stage.canvas, new WebKitPoint(event.pageX, event.pageY));
@@ -348,15 +360,27 @@ exports.PenTool = Montage.create(ShapeTool, {
348 360
349 var currMousePos = this._getUnsnappedPosition(event.pageX, event.pageY); 361 var currMousePos = this._getUnsnappedPosition(event.pageX, event.pageY);
350 if (currMousePos && this._selectedSubpath ){ 362 if (currMousePos && this._selectedSubpath ){
351 var selAnchor = this._selectedSubpath.pickAnchor(currMousePos[0], currMousePos[1], currMousePos[2], this._PICK_POINT_RADIUS); 363 var selAnchorRetCode = this._selectedSubpath.pickAnchor(currMousePos[0], currMousePos[1], currMousePos[2], this._PICK_POINT_RADIUS);
352 if (selAnchor >=0) { 364 if (selAnchorRetCode[0] >=0) {
353 this._hoveredAnchorIndex = selAnchor; 365 this._hoveredAnchorIndex = selAnchorRetCode[0];
366 var lastAnchorIndex = this._selectedSubpath.getNumAnchors()-1;
367 var cursor = "url('images/cursors/penCursors/Pen_anchorSelect.png') 5 1, default";
368 if (this._selectedSubpath.getIsClosed()===false){
369 if (this._entryEditMode === this.ENTRY_SELECT_PATH && !this._isPickedEndPointInSelectPathMode && (this._hoveredAnchorIndex===0 || this._hoveredAnchorIndex===lastAnchorIndex)){
370 //if we're in SELECT_PATH mode, have not yet clicked on the end anchors, AND we hovered over one of the end anchors
371 cursor = "url('images/cursors/penCursors/Pen_append.png') 5 1, default";
372 } else if ( this._selectedSubpath.getSelectedAnchorIndex()===lastAnchorIndex && this._hoveredAnchorIndex===0) {
373 //if we've selected the last anchor and hover over the first anchor
374 cursor = "url('images/cursors/penCursors/Pen_closePath.png') 5 1, default";
375 }
376 } //if path is not closed
377 this.application.ninja.stage.drawingCanvas.style.cursor = cursor;
354 } else { 378 } else {
355 //detect if the current mouse position will hit the path 379 //detect if the current mouse position will hit the path (such that clicking here will insert a new anchor)
356 var pathHitTestData = this._selectedSubpath.pathHitTest(currMousePos[0], currMousePos[1], currMousePos[2], this._PICK_POINT_RADIUS); 380 var pathHitTestData = this._selectedSubpath.pathHitTest(currMousePos[0], currMousePos[1], currMousePos[2], this._PICK_POINT_RADIUS*0.5);
357 if (pathHitTestData[0]!==-1){ 381 if (pathHitTestData[0]!==-1){
358 //change the cursor 382 //change the cursor
359 var cursor = "url('images/cursors/penAdd.png') 10 10,default"; 383 var cursor = "url('images/cursors/penCursors/Pen_plus.png') 5 1, default";
360 this.application.ninja.stage.drawingCanvas.style.cursor = cursor; 384 this.application.ninja.stage.drawingCanvas.style.cursor = cursor;
361 } 385 }
362 } 386 }
@@ -374,22 +398,7 @@ exports.PenTool = Montage.create(ShapeTool, {
374 TranslateSelectedSubpathPerPenCanvas:{ 398 TranslateSelectedSubpathPerPenCanvas:{
375 value: function() { 399 value: function() {
376 if (this._penCanvas!==null) { 400 if (this._penCanvas!==null) {
377 //obtain the 2D translation of the canvas due to the Selection tool...assuming this is called in Configure 401 this._selectedSubpath.translateSubpathPerCanvas(ElementMediator);
378 var penCanvasLeft = parseInt(ElementMediator.getProperty(this._penCanvas, "left"));//parseFloat(DocumentControllerModule.DocumentController.GetElementStyle(this._penCanvas, "left"));
379 var penCanvasTop = parseInt(ElementMediator.getProperty(this._penCanvas, "top"));//parseFloat(DocumentControllerModule.DocumentController.GetElementStyle(this._penCanvas, "top"));
380 var penCanvasWidth = parseInt(ElementMediator.getProperty(this._penCanvas, "width"));//this._penCanvas.width;
381 var penCanvasHeight = parseInt(ElementMediator.getProperty(this._penCanvas, "height"));//this._penCanvas.height;
382 var penCanvasOldX = penCanvasLeft + 0.5 * penCanvasWidth;
383 var penCanvasOldY = penCanvasTop + 0.5 * penCanvasHeight;
384
385 var translateCanvasX = penCanvasOldX - this._selectedSubpath.getCanvasX();
386 var translateCanvasY = penCanvasOldY - this._selectedSubpath.getCanvasY();
387
388 //update the canvasX and canvasY parameters for this subpath and also translate the subpath points (since they're stored in stage world space)
389 this._selectedSubpath.setCanvasX(translateCanvasX + this._selectedSubpath.getCanvasX());
390 this._selectedSubpath.setCanvasY(translateCanvasY + this._selectedSubpath.getCanvasY());
391 this._selectedSubpath.translateAnchors(translateCanvasX, translateCanvasY, 0);
392 this._selectedSubpath.createSamples(); //updates the bounding box
393 } 402 }
394 } 403 }
395 }, 404 },
@@ -397,22 +406,141 @@ exports.PenTool = Montage.create(ShapeTool, {
397 ShowSelectedSubpath:{ 406 ShowSelectedSubpath:{
398 value: function() { 407 value: function() {
399 if (this._selectedSubpath){ 408 if (this._selectedSubpath){
409 this._selectedSubpath.setPlaneMatrix(this._penPlaneMat);
410 var planeMatInv = glmat4.inverse( this._penPlaneMat, [] );
411 this._selectedSubpath.setPlaneMatrixInverse(planeMatInv);
412 this._selectedSubpath.setDragPlane(this._dragPlane);
413
400 this._selectedSubpath.createSamples(); //dirty bit is checked here 414 this._selectedSubpath.createSamples(); //dirty bit is checked here
401 var bboxMin = this._selectedSubpath.getBBoxMin(); 415 this._selectedSubpath.buildLocalCoord(); //local dirty bit is checked here
402 var bboxMax = this._selectedSubpath.getBBoxMax(); 416
417 //build the width and height of this canvas by looking at local coordinates (X and Y needed only)
418 var bboxMin = this._selectedSubpath.getLocalBBoxMin();
419 var bboxMax = this._selectedSubpath.getLocalBBoxMax();
403 var bboxWidth = bboxMax[0] - bboxMin[0]; 420 var bboxWidth = bboxMax[0] - bboxMin[0];
404 var bboxHeight = bboxMax[1] - bboxMin[1]; 421 var bboxHeight = bboxMax[1] - bboxMin[1];
405 var bboxMid = [0.5 * (bboxMax[0] + bboxMin[0]), 0.5 * (bboxMax[1] + bboxMin[1]), 0.5 * (bboxMax[2] + bboxMin[2])];
406 422
407 this._selectedSubpath.setCanvasX(bboxMid[0]); 423 //build the 3D position of the plane center of this canvas by looking at midpoint of the bounding box in stage world coords
408 this._selectedSubpath.setCanvasY(bboxMid[1]); 424 bboxMin = this._selectedSubpath.getBBoxMin();
425 bboxMax = this._selectedSubpath.getBBoxMax();
426 var bboxMid = [0.5 * (bboxMax[0] + bboxMin[0]), 0.5 * (bboxMax[1] + bboxMin[1]), 0.5 * (bboxMax[2] + bboxMin[2])];
409 427
410 //call render shape with the bbox width and height 428 //call render shape with the bbox width and height
411 this.RenderShape(bboxWidth, bboxHeight, this._penPlaneMat, bboxMid, this._penCanvas); 429 this.RenderShape(bboxWidth, bboxHeight, bboxMid, this._penPlaneMat, this._penCanvas);
412 } 430 }
413 } 431 }
414 }, 432 },
415 433
434 RenderShape: {
435 value: function (w, h, midPt, planeMat, canvas) {
436 if ((Math.floor(w) === 0) || (Math.floor(h) === 0)) {
437 return;
438 }
439
440 var left = Math.round(midPt[0] - 0.5 * w);
441 var top = Math.round(midPt[1] - 0.5 * h);
442 this._selectedSubpath.setPlaneCenter(midPt);
443 this._selectedSubpath.setCanvasLeft(left);
444 this._selectedSubpath.setCanvasTop(top);
445
446 if (!canvas) {
447 var newCanvas = null;
448 newCanvas = NJUtils.makeNJElement("canvas", "Subpath", "shape", {"data-RDGE-id": NJUtils.generateRandom()}, true);
449 var elementModel = TagTool.makeElement(parseInt(w), parseInt(h), planeMat, midPt, newCanvas);
450 ElementMediator.addElements(newCanvas, elementModel.data, false);
451
452 // create all the GL stuff
453 var world = this.getGLWorld(newCanvas, this._useWebGL);//this.options.use3D);//this.CreateGLWorld(planeMat, midPt, newCanvas, this._useWebGL);//fillMaterial, strokeMaterial);
454 //store a reference to this newly created canvas
455 this._penCanvas = newCanvas;
456
457 var subpath = this._selectedSubpath; //new GLSubpath();
458 subpath.setWorld(world);
459 subpath.setCanvas(newCanvas);
460
461 world.addObject(subpath);
462 world.render();
463 //TODO this will not work if there are multiple shapes in the same canvas
464 newCanvas.elementModel.shapeModel.GLGeomObj = subpath;
465 newCanvas.elementModel.shapeModel.shapeCount++;
466 if(newCanvas.elementModel.shapeModel.shapeCount === 1)
467 {
468 newCanvas.elementModel.selection = "Subpath";
469 newCanvas.elementModel.pi = "SubpathPi";
470 newCanvas.elementModel.shapeModel.strokeSize = this.options.strokeSize.value + " " + this.options.strokeSize.units;
471 var strokeColor = subpath.getStrokeColor();
472 newCanvas.elementModel.shapeModel.stroke = strokeColor;
473 if(strokeColor) {
474 newCanvas.elementModel.shapeModel.border = this.application.ninja.colorController.colorToolbar.stroke;
475 }
476 newCanvas.elementModel.shapeModel.strokeMaterial = subpath.getStrokeMaterial();
477
478 newCanvas.elementModel.shapeModel.GLGeomObj = subpath;
479 newCanvas.elementModel.shapeModel.useWebGl = this.options.use3D;
480