diff options
Diffstat (limited to 'js/tools')
-rwxr-xr-x | js/tools/PenTool.js | 362 |
1 files changed, 193 insertions, 169 deletions
diff --git a/js/tools/PenTool.js b/js/tools/PenTool.js index 779b7f16..2eae6adc 100755 --- a/js/tools/PenTool.js +++ b/js/tools/PenTool.js | |||
@@ -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 }, |
@@ -105,7 +108,9 @@ exports.PenTool = Montage.create(ShapeTool, { | |||
105 | snapManager.enableSnapAlign(false); | 108 | snapManager.enableSnapAlign(false); |
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)); |
111 | //todo fix this function to allow us to get the correct location (in 3D) for the mouse position | ||
108 | var unsnappedpos = DrawingToolBase.getHitRecPos(snapManager.snap(point.x, point.y, false)); | 112 | var unsnappedpos = DrawingToolBase.getHitRecPos(snapManager.snap(point.x, point.y, false)); |
113 | this._dragPlane = snapManager.getDragPlane(); | ||
109 | 114 | ||
110 | snapManager.enableElementSnap(elemSnap); | 115 | snapManager.enableElementSnap(elemSnap); |
111 | snapManager.enableGridSnap(gridSnap); | 116 | snapManager.enableGridSnap(gridSnap); |
@@ -214,6 +219,7 @@ exports.PenTool = Montage.create(ShapeTool, { | |||
214 | if (this._selectedSubpath.getIsClosed() && this._makeMultipleSubpaths) { | 219 | if (this._selectedSubpath.getIsClosed() && this._makeMultipleSubpaths) { |
215 | this._penCanvas = null; | 220 | this._penCanvas = null; |
216 | this._penPlaneMat = null; | 221 | this._penPlaneMat = null; |
222 | this._dragPlane = null; | ||
217 | this._snapTarget = null; | 223 | this._snapTarget = null; |
218 | this._selectedSubpath = new SubPath(); | 224 | this._selectedSubpath = new SubPath(); |
219 | this._isNewPath = true; | 225 | this._isNewPath = true; |
@@ -278,8 +284,15 @@ exports.PenTool = Montage.create(ShapeTool, { | |||
278 | this.application.ninja.stage.clearDrawingCanvas(); | 284 | this.application.ninja.stage.clearDrawingCanvas(); |
279 | this._hoveredAnchorIndex = -1; | 285 | this._hoveredAnchorIndex = -1; |
280 | 286 | ||
281 | //set the cursor to be the default cursor | 287 | //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"; | 288 | if (this._selectedSubpath && this._selectedSubpath.getNumAnchors()>0){ |
289 | this.application.ninja.stage.drawingCanvas.style.cursor = //"auto"; | ||
290 | "url('images/cursors/penCursors/Pen_.png') 5 1, default"; | ||
291 | } | ||
292 | else { | ||
293 | this.application.ninja.stage.drawingCanvas.style.cursor = //"auto"; | ||
294 | "url('images/cursors/penCursors/Pen_newPath.png') 5 1, default"; | ||
295 | } | ||
283 | 296 | ||
284 | if (this._isDrawing) { | 297 | if (this._isDrawing) { |
285 | var point = webkitConvertPointFromPageToNode(this.application.ninja.stage.canvas, new WebKitPoint(event.pageX, event.pageY)); | 298 | var point = webkitConvertPointFromPageToNode(this.application.ninja.stage.canvas, new WebKitPoint(event.pageX, event.pageY)); |
@@ -348,15 +361,27 @@ exports.PenTool = Montage.create(ShapeTool, { | |||
348 | 361 | ||
349 | var currMousePos = this._getUnsnappedPosition(event.pageX, event.pageY); | 362 | var currMousePos = this._getUnsnappedPosition(event.pageX, event.pageY); |
350 | if (currMousePos && this._selectedSubpath ){ | 363 | if (currMousePos && this._selectedSubpath ){ |
351 | var selAnchor = this._selectedSubpath.pickAnchor(currMousePos[0], currMousePos[1], currMousePos[2], this._PICK_POINT_RADIUS); | 364 | var selAnchorRetCode = this._selectedSubpath.pickAnchor(currMousePos[0], currMousePos[1], currMousePos[2], this._PICK_POINT_RADIUS); |
352 | if (selAnchor >=0) { | 365 | if (selAnchorRetCode[0] >=0) { |
353 | this._hoveredAnchorIndex = selAnchor; | 366 | this._hoveredAnchorIndex = selAnchorRetCode[0]; |
367 | var lastAnchorIndex = this._selectedSubpath.getNumAnchors()-1; | ||
368 | var cursor = "url('images/cursors/penCursors/Pen_anchorSelect.png') 5 1, default"; | ||
369 | if (this._selectedSubpath.getIsClosed()===false){ | ||
370 | if (this._entryEditMode === this.ENTRY_SELECT_PATH && !this._isPickedEndPointInSelectPathMode && (this._hoveredAnchorIndex===0 || this._hoveredAnchorIndex===lastAnchorIndex)){ | ||
371 | //if we're in SELECT_PATH mode, have not yet clicked on the end anchors, AND we hovered over one of the end anchors | ||
372 | cursor = "url('images/cursors/penCursors/Pen_append.png') 5 1, default"; | ||
373 | } else if ( this._selectedSubpath.getSelectedAnchorIndex()===lastAnchorIndex && this._hoveredAnchorIndex===0) { | ||
374 | //if we've selected the last anchor and hover over the first anchor | ||
375 | cursor = "url('images/cursors/penCursors/Pen_closePath.png') 5 1, default"; | ||
376 | } | ||
377 | } //if path is not closed | ||
378 | this.application.ninja.stage.drawingCanvas.style.cursor = cursor; | ||
354 | } else { | 379 | } else { |
355 | //detect if the current mouse position will hit the path | 380 | //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); | 381 | var pathHitTestData = this._selectedSubpath.pathHitTest(currMousePos[0], currMousePos[1], currMousePos[2], this._PICK_POINT_RADIUS*0.5); |
357 | if (pathHitTestData[0]!==-1){ | 382 | if (pathHitTestData[0]!==-1){ |
358 | //change the cursor | 383 | //change the cursor |
359 | var cursor = "url('images/cursors/penAdd.png') 10 10,default"; | 384 | var cursor = "url('images/cursors/penCursors/Pen_plus.png') 5 1, default"; |
360 | this.application.ninja.stage.drawingCanvas.style.cursor = cursor; | 385 | this.application.ninja.stage.drawingCanvas.style.cursor = cursor; |
361 | } | 386 | } |
362 | } | 387 | } |
@@ -374,22 +399,7 @@ exports.PenTool = Montage.create(ShapeTool, { | |||
374 | TranslateSelectedSubpathPerPenCanvas:{ | 399 | TranslateSelectedSubpathPerPenCanvas:{ |
375 | value: function() { | 400 | value: function() { |
376 | if (this._penCanvas!==null) { | 401 | if (this._penCanvas!==null) { |
377 | //obtain the 2D translation of the canvas due to the Selection tool...assuming this is called in Configure | 402 | 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 | } | 403 | } |
394 | } | 404 | } |
395 | }, | 405 | }, |
@@ -397,22 +407,141 @@ exports.PenTool = Montage.create(ShapeTool, { | |||
397 | ShowSelectedSubpath:{ | 407 | ShowSelectedSubpath:{ |
398 | value: function() { | 408 | value: function() { |
399 | if (this._selectedSubpath){ | 409 | if (this._selectedSubpath){ |
410 | this._selectedSubpath.setPlaneMatrix(this._penPlaneMat); | ||
411 | var planeMatInv = glmat4.inverse( this._penPlaneMat, [] ); | ||
412 | this._selectedSubpath.setPlaneMatrixInverse(planeMatInv); | ||
413 | this._selectedSubpath.setDragPlane(this._dragPlane); | ||
414 | |||
400 | this._selectedSubpath.createSamples(); //dirty bit is checked here | 415 | this._selectedSubpath.createSamples(); //dirty bit is checked here |
401 | var bboxMin = this._selectedSubpath.getBBoxMin(); | 416 | this._selectedSubpath.buildLocalCoord(); //local dirty bit is checked here |
402 | var bboxMax = this._selectedSubpath.getBBoxMax(); | 417 | |
418 | //build the width and height of this canvas by looking at local coordinates (X and Y needed only) | ||
419 | var bboxMin = this._selectedSubpath.getLocalBBoxMin(); | ||
420 | var bboxMax = this._selectedSubpath.getLocalBBoxMax(); | ||
403 | var bboxWidth = bboxMax[0] - bboxMin[0]; | 421 | var bboxWidth = bboxMax[0] - bboxMin[0]; |
404 | var bboxHeight = bboxMax[1] - bboxMin[1]; | 422 | 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 | 423 | ||
407 | this._selectedSubpath.setCanvasX(bboxMid[0]); | 424 | //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]); | 425 | bboxMin = this._selectedSubpath.getBBoxMin(); |
426 | bboxMax = this._selectedSubpath.getBBoxMax(); | ||
427 | var bboxMid = [0.5 * (bboxMax[0] + bboxMin[0]), 0.5 * (bboxMax[1] + bboxMin[1]), 0.5 * (bboxMax[2] + bboxMin[2])]; | ||
409 | 428 | ||
410 | //call render shape with the bbox width and height | 429 | //call render shape with the bbox width and height |
411 | this.RenderShape(bboxWidth, bboxHeight, this._penPlaneMat, bboxMid, this._penCanvas); | 430 | this.RenderShape(bboxWidth, bboxHeight, bboxMid, this._penPlaneMat, this._penCanvas); |
412 | } | 431 | } |
413 | } | 432 | } |
414 | }, | 433 | }, |
415 | 434 | ||
435 | RenderShape: { | ||
436 | value: function (w, h, midPt, planeMat, canvas) { | ||
437 | if ((Math.floor(w) === 0) || (Math.floor(h) === 0)) { | ||
438 | return; | ||
439 | } | ||
440 | |||
441 | var left = Math.round(midPt[0] - 0.5 * w); | ||
442 | var top = Math.round(midPt[1] - 0.5 * h); | ||
443 | this._selectedSubpath.setPlaneCenter(midPt); | ||
444 | this._selectedSubpath.setCanvasLeft(left); | ||
445 | this._selectedSubpath.setCanvasTop(top); | ||
446 | |||
447 | if (!canvas) { | ||
448 | var newCanvas = null; | ||
449 | newCanvas = NJUtils.makeNJElement("canvas", "Subpath", "shape", {"data-RDGE-id": NJUtils.generateRandom()}, true); | ||
450 | var elementModel = TagTool.makeElement(parseInt(w), parseInt(h), planeMat, midPt, newCanvas); | ||
451 | ElementMediator.addElement(newCanvas, elementModel.data, true); | ||
452 | |||
453 | // create all the GL stuff | ||
454 | var world = this.getGLWorld(newCanvas, this._useWebGL);//this.options.use3D);//this.CreateGLWorld(planeMat, midPt, newCanvas, this._useWebGL);//fillMaterial, strokeMaterial); | ||
455 | //store a reference to this newly created canvas | ||
456 | this._penCanvas = newCanvas; | ||
457 | |||
458 | var subpath = this._selectedSubpath; //new GLSubpath(); | ||
459 | subpath.setWorld(world); | ||
460 | subpath.setCanvas(newCanvas); | ||
461 | |||
462 | world.addObject(subpath); | ||
463 | world.render(); | ||
464 | //TODO this will not work if there are multiple shapes in the same canvas | ||
465 | newCanvas.elementModel.shapeModel.GLGeomObj = subpath; | ||
466 | newCanvas.elementModel.shapeModel.shapeCount++; | ||
467 | if(newCanvas.elementModel.shapeModel.shapeCount === 1) | ||
468 | { | ||
469 | newCanvas.elementModel.selection = "Subpath"; | ||
470 | newCanvas.elementModel.pi = "SubpathPi"; | ||
471 | newCanvas.elementModel.shapeModel.strokeSize = this.options.strokeSize.value + " " + this.options.strokeSize.units; | ||
472 | var strokeColor = subpath.getStrokeColor(); | ||
473 | newCanvas.elementModel.shapeModel.stroke = strokeColor; | ||
474 | if(strokeColor) { | ||
475 | newCanvas.elementModel.shapeModel.border = this.application.ninja.colorController.colorToolbar.stroke; | ||
476 | } | ||
477 | newCanvas.elementModel.shapeModel.strokeMaterial = subpath.getStrokeMaterial(); | ||
478 | |||
479 | newCanvas.elementModel.shapeModel.GLGeomObj = subpath; | ||
480 | newCanvas.elementModel.shapeModel.useWebGl = this.options.use3D; | ||
481 | } | ||
482 | else | ||
483 | { | ||
484 | // TODO - update the shape's info only. shapeModel will likely need an array of shapes. | ||
485 | } | ||
486 | |||
487 | //if(newCanvas.elementModel.isShape) | ||
488 | if (true) | ||
489 | { | ||
490 | this.application.ninja.selectionController.selectElement(newCanvas); | ||