diff options
-rw-r--r-- | images/cursors/penAdd.png | bin | 0 -> 3043 bytes | |||
-rwxr-xr-x | js/helper-classes/backup-delete/GLSubpath.js | 147 | ||||
-rwxr-xr-x | js/lib/geom/sub-path.js | 84 | ||||
-rwxr-xr-x | js/tools/PenTool.js | 12 |
4 files changed, 219 insertions, 24 deletions
diff --git a/images/cursors/penAdd.png b/images/cursors/penAdd.png new file mode 100644 index 00000000..c306cc85 --- /dev/null +++ b/images/cursors/penAdd.png | |||
Binary files differ | |||
diff --git a/js/helper-classes/backup-delete/GLSubpath.js b/js/helper-classes/backup-delete/GLSubpath.js index f3d8ad36..2fb91d33 100755 --- a/js/helper-classes/backup-delete/GLSubpath.js +++ b/js/helper-classes/backup-delete/GLSubpath.js | |||
@@ -505,7 +505,6 @@ GLSubpath.prototype._isWithinBoundingBox = function(point, ctrlPts, radius) { | |||
505 | GLSubpath.prototype.pickAnchor = function (pickX, pickY, pickZ, radius) { | 505 | GLSubpath.prototype.pickAnchor = function (pickX, pickY, pickZ, radius) { |
506 | var numAnchors = this._Anchors.length; | 506 | var numAnchors = this._Anchors.length; |
507 | var selAnchorIndex = -1; | 507 | var selAnchorIndex = -1; |
508 | var retCode = this.SEL_NONE; | ||
509 | var radSq = radius * radius; | 508 | var radSq = radius * radius; |
510 | var minDistance = Infinity; | 509 | var minDistance = Infinity; |
511 | //check if the clicked location is close to the currently selected anchor position | 510 | //check if the clicked location is close to the currently selected anchor position |
@@ -515,9 +514,23 @@ GLSubpath.prototype.pickAnchor = function (pickX, pickY, pickZ, radius) { | |||
515 | if (distSq < minDistance && distSq < radSq) { | 514 | if (distSq < minDistance && distSq < radSq) { |
516 | selAnchorIndex = this._selectedAnchorIndex; | 515 | selAnchorIndex = this._selectedAnchorIndex; |
517 | minDistance = distSq; | 516 | minDistance = distSq; |
518 | retCode = retCode | this.SEL_ANCHOR; | 517 | } else { |
518 | //check the prev and next of the selected anchor if the above did not register a hit | ||
519 | distSq = this._Anchors[this._selectedAnchorIndex].getPrevDistanceSq(pickX, pickY, pickZ); | ||
520 | if (distSq < minDistance && distSq < radSq){ | ||
521 | selAnchorIndex = this._selectedAnchorIndex; | ||
522 | minDistance = distSq; | ||
523 | } else { | ||
524 | //check the next for this anchor point | ||
525 | distSq = this._Anchors[this._selectedAnchorIndex].getNextDistanceSq(pickX, pickY, pickZ); | ||
526 | if (distSq<minDistance && distSq<radSq){ | ||
527 | selAnchorIndex = this._selectedAnchorIndex; | ||
528 | minDistance = distSq; | ||
529 | } | ||
530 | } | ||
519 | } | 531 | } |
520 | } | 532 | } |
533 | |||
521 | //now check if the click location is close to any anchor position | 534 | //now check if the click location is close to any anchor position |
522 | if (selAnchorIndex===-1) { | 535 | if (selAnchorIndex===-1) { |
523 | for (var i = 0; i < numAnchors; i++) { | 536 | for (var i = 0; i < numAnchors; i++) { |
@@ -532,12 +545,97 @@ GLSubpath.prototype.pickAnchor = function (pickX, pickY, pickZ, radius) { | |||
532 | return selAnchorIndex; | 545 | return selAnchorIndex; |
533 | } | 546 | } |
534 | 547 | ||
548 | GLSubpath.prototype.isWithinBBox =function(x,y,z){ | ||
549 | if (this._BBoxMin[0]>x || this._BBoxMin[1]>y || this._BBoxMin[2]>z){ | ||
550 | return false; | ||
551 | } | ||
552 | if (this._BBoxMax[0]<x || this._BBoxMax[1]<y || this._BBoxMax[2]<z){ | ||
553 | return false; | ||
554 | } | ||
555 | return true; | ||
556 | } | ||
557 | |||
558 | //pick the path point closest to the specified location, return null if some anchor point (or its handles) is within radius, else return the parameter distance | ||
559 | GLSubpath.prototype.pathHitTest = function (pickX, pickY, pickZ, radius) { | ||
560 | var numAnchors = this._Anchors.length; | ||
561 | var selAnchorIndex = -1; | ||
562 | var retParam = null; | ||
563 | var radSq = radius * radius; | ||
564 | var minDistance = Infinity; | ||
565 | |||
566 | //check if the location is close to the currently selected anchor position | ||
567 | if (this._selectedAnchorIndex>=0 && this._selectedAnchorIndex<this._Anchors.length){ | ||
568 | var distSq = this._Anchors[this._selectedAnchorIndex].getDistanceSq(pickX, pickY, pickZ); | ||
569 | //check the anchor point | ||
570 | if (distSq < minDistance && distSq < radSq) { | ||
571 | selAnchorIndex = this._selectedAnchorIndex; | ||
572 | minDistance = distSq; | ||
573 | } | ||
574 | } | ||
575 | //check the prev and next of the selected anchor if the above did not register a hit | ||
576 | if (this._selectedAnchorIndex>=0 && selAnchorIndex === -1) { | ||
577 | var distSq = this._Anchors[this._selectedAnchorIndex].getPrevDistanceSq(pickX, pickY, pickZ); | ||
578 | if (distSq < minDistance && distSq < radSq){ | ||
579 | selAnchorIndex = this._selectedAnchorIndex; | ||
580 | minDistance = distSq; | ||
581 | } else { | ||
582 | //check the next for this anchor point | ||
583 | distSq = this._Anchors[this._selectedAnchorIndex].getNextDistanceSq(pickX, pickY, pickZ); | ||
584 | if (distSq<minDistance && distSq<radSq){ | ||
585 | selAnchorIndex = this._selectedAnchorIndex; | ||
586 | minDistance = distSq; | ||
587 | } | ||
588 | } | ||
589 | } | ||
590 | |||
591 | //now check if the location is close to any anchor position | ||
592 | if (selAnchorIndex===-1) { | ||
593 | for (var i = 0; i < numAnchors; i++) { | ||
594 | var distSq = this._Anchors[i].getDistanceSq(pickX, pickY, pickZ); | ||
595 | //check the anchor point | ||
596 | if (distSq < minDistance && distSq < radSq) { | ||
597 | selAnchorIndex = i; | ||
598 | minDistance = distSq; | ||
599 | } | ||
600 | }//for every anchor i | ||
601 | } | ||
602 | |||
603 | //finally check if the location is close to the curve itself | ||
604 | if (selAnchorIndex===-1) { | ||
605 | //first check if the input location is within the bounding box | ||
606 | if (this.isWithinBBox(pickX,pickY,pickZ)){ | ||
607 | var numSegments = this._isClosed ? numAnchors : numAnchors-1; | ||
608 | for (var i = 0; i < numSegments; i++) { | ||
609 | var nextIndex = (i+1)%numAnchors; | ||
610 | //check if the point is close to the bezier segment between anchor i and anchor nextIndex | ||
611 | var controlPoints = Vector.create([Vector.create([this._Anchors[i].getPosX(),this._Anchors[i].getPosY(),this._Anchors[i].getPosZ()]), | ||
612 | Vector.create([this._Anchors[i].getNextX(),this._Anchors[i].getNextY(),this._Anchors[i].getNextZ()]), | ||
613 | Vector.create([this._Anchors[nextIndex].getPrevX(),this._Anchors[nextIndex].getPrevY(),this._Anchors[nextIndex].getPrevZ()]), | ||
614 | Vector.create([this._Anchors[nextIndex].getPosX(),this._Anchors[nextIndex].getPosY(),this._Anchors[nextIndex].getPosZ()])]); | ||
615 | var point = Vector.create([pickX, pickY, pickZ]); | ||
616 | if (this._isWithinBoundingBox(point, controlPoints, radius)) { | ||
617 | //var intersectParam = this._checkIntersection(controlPoints, 0.0, 1.0, point, radius); | ||
618 | var intersectParam = this._checkIntersectionWithSamples(this._anchorSampleIndex[i], this._anchorSampleIndex[nextIndex], point, radius); | ||
619 | console.log("intersectParam:"+intersectParam); | ||
620 | if (intersectParam){ | ||
621 | selAnchorIndex=i; | ||
622 | retParam = intersectParam-i; //make the retParam go from 0 to 1 | ||
623 | break; | ||
624 | } | ||
625 | } | ||
626 | }//for every anchor i | ||
627 | }//if is within bbox | ||
628 | } | ||
629 | return [selAnchorIndex,retParam]; | ||
630 | } //GLSubpath.pathHitTest function | ||
631 | |||
535 | 632 | ||
536 | //pick the path point closest to the specified location, return null if some anchor point (or its handles) is within radius, else return the parameter distance | 633 | //pick the path point closest to the specified location, return null if some anchor point (or its handles) is within radius, else return the parameter distance |
537 | GLSubpath.prototype.pickPath = function (pickX, pickY, pickZ, radius) { | 634 | GLSubpath.prototype.pickPath = function (pickX, pickY, pickZ, radius) { |
538 | var numAnchors = this._Anchors.length; | 635 | var numAnchors = this._Anchors.length; |
539 | var selAnchorIndex = -1; | 636 | var selAnchorIndex = -1; |
540 | var retCode = this.SEL_NONE; | 637 | var retCode = this.SEL_NONE; |
638 | var retParam = null; | ||
541 | var radSq = radius * radius; | 639 | var radSq = radius * radius; |
542 | var minDistance = Infinity; | 640 | var minDistance = Infinity; |
543 | //check if the clicked location is close to the currently selected anchor position | 641 | //check if the clicked location is close to the currently selected anchor position |
@@ -580,33 +678,36 @@ GLSubpath.prototype.pickPath = function (pickX, pickY, pickZ, radius) { | |||
580 | } | 678 | } |
581 | } | 679 | } |
582 | } | 680 | } |
583 | var retParam = null; | 681 | |
584 | if (retCode !== this.SEL_NONE) { | 682 | if (retCode !== this.SEL_NONE) { |
585 | retCode = retCode | this.SEL_PATH; //ensure that path is also selected if anything else is selected | 683 | retCode = retCode | this.SEL_PATH; //ensure that path is also selected if anything else is selected |
586 | this._selectedAnchorIndex = selAnchorIndex; | 684 | this._selectedAnchorIndex = selAnchorIndex; |
587 | } else { | 685 | } else { |
588 | this._selectedAnchorIndex = -1; | 686 | this._selectedAnchorIndex = -1; |
589 | var numSegments = this._isClosed ? numAnchors : numAnchors-1; | 687 | //first check if the input location is within the bounding box |
590 | for (var i = 0; i < numSegments; i++) { | 688 | if (this.isWithinBBox(pickX,pickY,pickZ)){ |
591 | var nextIndex = (i+1)%numAnchors; | 689 | var numSegments = this._isClosed ? numAnchors : numAnchors-1; |
592 | //check if the point is close to the bezier segment between anchor i and anchor nextIndex | 690 | for (var i = 0; i < numSegments; i++) { |
593 | var controlPoints = Vector.create([Vector.create([this._Anchors[i].getPosX(),this._Anchors[i].getPosY(),this._Anchors[i].getPosZ()]), | 691 | var nextIndex = (i+1)%numAnchors; |
594 | Vector.create([this._Anchors[i].getNextX(),this._Anchors[i].getNextY(),this._Anchors[i].getNextZ()]), | 692 | //check if the point is close to the bezier segment between anchor i and anchor nextIndex |
595 | Vector.create([this._Anchors[nextIndex].getPrevX(),this._Anchors[nextIndex].getPrevY(),this._Anchors[nextIndex].getPrevZ()]), | 693 | var controlPoints = Vector.create([Vector.create([this._Anchors[i].getPosX(),this._Anchors[i].getPosY(),this._Anchors[i].getPosZ()]), |
596 | Vector.create([this._Anchors[nextIndex].getPosX(),this._Anchors[nextIndex].getPosY(),this._Anchors[nextIndex].getPosZ()])]); | 694 | Vector.create([this._Anchors[i].getNextX(),this._Anchors[i].getNextY(),this._Anchors[i].getNextZ()]), |
597 | var point = Vector.create([pickX, pickY, pickZ]); | 695 | Vector.create([this._Anchors[nextIndex].getPrevX(),this._Anchors[nextIndex].getPrevY(),this._Anchors[nextIndex].getPrevZ()]), |
598 | if (this._isWithinBoundingBox(point, controlPoints, radius)) { | 696 | Vector.create([this._Anchors[nextIndex].getPosX(),this._Anchors[nextIndex].getPosY(),this._Anchors[nextIndex].getPosZ()])]); |
599 | //var intersectParam = this._checkIntersection(controlPoints, 0.0, 1.0, point, radius); | 697 | var point = Vector.create([pickX, pickY, pickZ]); |
600 | var intersectParam = this._checkIntersectionWithSamples(this._anchorSampleIndex[i], this._anchorSampleIndex[nextIndex], point, radius); | 698 | if (this._isWithinBoundingBox(point, controlPoints, radius)) { |
601 | console.log("intersectParam:"+intersectParam); | 699 | //var intersectParam = this._checkIntersection(controlPoints, 0.0, 1.0, point, radius); |
602 | if (intersectParam){ | 700 | var intersectParam = this._checkIntersectionWithSamples(this._anchorSampleIndex[i], this._anchorSampleIndex[nextIndex], point, radius); |
603 | retCode = retCode | this.SEL_PATH; | 701 | console.log("intersectParam:"+intersectParam); |
604 | retParam = intersectParam-i; //make the retParam go from 0 to 1 | 702 | if (intersectParam){ |
605 | this._selectedAnchorIndex = i; | 703 | retCode = retCode | this.SEL_PATH; |
606 | break; | 704 | retParam = intersectParam-i; //make the retParam go from 0 to 1 |
705 | this._selectedAnchorIndex = i; | ||
706 | break; | ||
707 | } | ||
607 | } | 708 | } |
608 | } | 709 | }//for every anchor i |
609 | }//for every anchor i | 710 | }//is within bounding box |
610 | } | 711 | } |
611 | this._selectMode = retCode; | 712 | this._selectMode = retCode; |
612 | return retParam; | 713 | return retParam; |
diff --git a/js/lib/geom/sub-path.js b/js/lib/geom/sub-path.js index ab54d1e9..0a65511b 100755 --- a/js/lib/geom/sub-path.js +++ b/js/lib/geom/sub-path.js | |||
@@ -584,6 +584,90 @@ GLSubpath.prototype.pickAnchor = function (pickX, pickY, pickZ, radius) { | |||
584 | return selAnchorIndex; | 584 | return selAnchorIndex; |
585 | }; | 585 | }; |
586 |