aboutsummaryrefslogtreecommitdiff
path: root/js/helper-classes/RDGE/GLSubpath.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/helper-classes/RDGE/GLSubpath.js')
-rw-r--r--js/helper-classes/RDGE/GLSubpath.js2312
1 files changed, 882 insertions, 1430 deletions
diff --git a/js/helper-classes/RDGE/GLSubpath.js b/js/helper-classes/RDGE/GLSubpath.js
index 25b12093..fd2f3560 100644
--- a/js/helper-classes/RDGE/GLSubpath.js
+++ b/js/helper-classes/RDGE/GLSubpath.js
@@ -34,6 +34,7 @@ function SegmentIntersections(){
34// representation a sequence of cubic bezier curves. 34// representation a sequence of cubic bezier curves.
35// Derived from class GLGeomObj 35// Derived from class GLGeomObj
36/////////////////////////////////////////////////////////////////////// 36///////////////////////////////////////////////////////////////////////
37
37function GLSubpath() { 38function GLSubpath() {
38 /////////////////////////////////////////////////// 39 ///////////////////////////////////////////////////
39 // Instance variables 40 // Instance variables
@@ -49,14 +50,6 @@ function GLSubpath() {
49 50
50 this._UnprojectedAnchors = []; 51 this._UnprojectedAnchors = [];
51 52
52 //offset path samples and the points on the input path they map to
53 this._offsetPointsLeft = [];
54 this._offsetPointsRight = [];
55
56 //triangles determined by the offset points
57 this._offsetTrianglesLeft = [];
58 this._offsetTrianglesRight = [];
59
60 //initially set the _dirty bit so we will construct samples 53 //initially set the _dirty bit so we will construct samples
61 this._dirty = true; 54 this._dirty = true;
62 55
@@ -87,7 +80,6 @@ function GLSubpath() {
87 this._planeMatInv = null; 80 this._planeMatInv = null;
88 this._planeCenter = null; 81 this._planeCenter = null;
89 82
90 // initialize the inherited members
91 this.inheritedFrom = GLGeomObj; 83 this.inheritedFrom = GLGeomObj;
92 this.inheritedFrom(); 84 this.inheritedFrom();
93 85
@@ -104,681 +96,540 @@ function GLSubpath() {
104 this._DEFAULT_STROKE_WIDTH = 20; //use only if stroke width not specified 96 this._DEFAULT_STROKE_WIDTH = 20; //use only if stroke width not specified
105 this._MAX_OFFSET_ANGLE = 10; //max angle (in degrees) between consecutive vectors from curve to offset path 97 this._MAX_OFFSET_ANGLE = 10; //max angle (in degrees) between consecutive vectors from curve to offset path
106 98
107 ///////////////////////////////////////////////////////// 99 // (current GLGeomObj complains if buildBuffers/render is added to GLSubpath prototype)
108 // Property Accessors/Setters 100 //buildBuffers
109 ///////////////////////////////////////////////////////// 101 // Build the stroke vertices, normals, textures and colors
110 this.setWorld = function (world) { this._world = world; } 102 // Add that array data to the GPU using OpenGL data binding
111 this.getWorld = function () { return this._world; } 103 this.buildBuffers = function () {
112 this.makeDirty = function () {this._dirty = true;} 104 return; //no need to do anything for now
113 this.geomType = function () { return this.GEOM_TYPE_CUBIC_BEZIER; } 105 }//buildBuffers()
114 this.setDrawingTool = function (tool) {this._drawingTool = tool;}
115 this.getDrawingTool = function () {return this._drawingTool;}
116 this.setPlaneMatrix = function(planeMat){this._planeMat = planeMat;}
117 this.setPlaneMatrixInverse = function(planeMatInv){this._planeMatInv = planeMatInv;}
118 this.setPlaneCenter = function(pc){this._planeCenter = pc;}
119
120 this.getCanvasX = function(){return this._canvasX;}
121 this.getCanvasY = function(){return this._canvasY;}
122 this.setCanvasX = function(cx){this._canvasX=cx;}
123 this.setCanvasY = function(cy){this._canvasY=cy;}
124
125 this.getIsClosed = function () {return this._isClosed;}
126 this.setIsClosed = function (isClosed) {
127 if (this._isClosed !== isClosed) {
128 this._isClosed = isClosed;
129 this._dirty = true;
130 }
131 }
132 this.getNumAnchors = function () { return this._Anchors.length; }
133 this.getAnchor = function (index) { return this._Anchors[index]; }
134 this.addAnchor = function (anchorPt) {
135 this._Anchors.push(anchorPt);
136 this._selectedAnchorIndex = this._Anchors.length-1;
137 this._dirty = true;
138 }
139 106
140 this.insertAnchor = function(anchorPt, index){ 107 //render
141 this._Anchors.splice(index, 0, anchorPt); 108 // specify how to render the subpath in Canvas2D
142 } 109 this.render = function () {
110 // get the world
111 var world = this.getWorld();
112 if (!world) throw( "null world in subpath render" );
143 113
144 //remove and return anchor at specified index, return null on error 114 // get the context
145 this.removeAnchor = function (index) { 115 var ctx = world.get2DContext();
146 var retAnchor = null; 116 if (!ctx) throw ("null context in subpath render")
147 if (index < this._Anchors.length) {
148 retAnchor = this._Anchors.splice(index, 1);
149 this._dirty = true;
150 }
151 //deselect the removed anchor if necessary
152 if (this._selectedAnchorIndex === index){
153 this._selectedAnchorIndex = -1;
154 }
155 return retAnchor;
156 }
157 117
158 //remove all the anchor points 118 var numAnchors = this.getNumAnchors();
159 this.clearAllAnchors = function () { 119 if (numAnchors === 0)
160 this._Anchors = []; 120 return; //nothing to do for empty paths
161 this._isClosed = false;
162 this._dirty = true;
163 }
164 121
165 this.insertAnchorAtParameter = function(index, param) { 122 ctx.save();
166 if (index+1 >= this._Anchors.length && !this._isClosed) {
167 return;
168 }
169 //insert an anchor after the specified index using the parameter, using De Casteljau subdivision
170 var nextIndex = (index+1)%this._Anchors.length;
171 123
172 //build the De Casteljau points 124 this.createSamples(); //dirty bit checked in this function...will generate a polyline representation
173 var P0P1 = VecUtils.vecInterpolate(3, this._Anchors[index].getPos(), this._Anchors[index].getNext(), param); 125 var bboxMin = this.getBBoxMin();
174 var P1P2 = VecUtils.vecInterpolate(3, this._Anchors[index].getNext(), this._Anchors[nextIndex].getPrev(), param); 126 var bboxMax = this.getBBoxMax();
175 var P2P3 = VecUtils.vecInterpolate(3, this._Anchors[nextIndex].getPrev(), this._Anchors[nextIndex].getPos(), param); 127 var bboxWidth = bboxMax[0] - bboxMin[0];
128 var bboxHeight = bboxMax[1] - bboxMin[1];
129 var bboxMid = Vector.create([0.5 * (bboxMax[0] + bboxMin[0]), 0.5 * (bboxMax[1] + bboxMin[1]), 0.5 * (bboxMax[2] + bboxMin[2])]);
176 130
177 var P0P1P2 = VecUtils.vecInterpolate(3, P0P1, P1P2, param); 131 ctx.clearRect(0, 0, bboxWidth, bboxHeight);
178 var P1P2P3 = VecUtils.vecInterpolate(3, P1P2, P2P3, param);
179 var anchorPos = VecUtils.vecInterpolate(3, P0P1P2, P1P2P3, param);
180 132
181 133
182 //update the next of the anchor at index and prev of anchor at nextIndex 134 ctx.lineWidth = this._strokeWidth;
183 var isPrevCoincident = false; 135 ctx.strokeStyle = "black";
184 var isNextCoincident = false; 136 if (this._strokeColor)
185 if (VecUtils.vecDist( 3, P0P1, this._Anchors[index].getNext()) < this._SAMPLING_EPSILON) { 137 ctx.strokeStyle = MathUtils.colorToHex( this._strokeColor );
186 //no change to the next point 138 ctx.fillStyle = "white";
187 isPrevCoincident = true; 139 if (this._fillColor)
188 } else { 140 ctx.fillStyle = MathUtils.colorToHex( this._fillColor );
189 this._Anchors[index].setNextPos(P0P1[0], P0P1[1], P0P1[2]); 141 var lineCap = ['butt','round','square'];
142 ctx.lineCap = lineCap[1];
143 ctx.beginPath();
144
145 var prevAnchor = this.getAnchor(0);
146 ctx.moveTo(prevAnchor.getPosX()-bboxMin[0],prevAnchor.getPosY()-bboxMin[1]);
147 for (var i = 1; i < numAnchors; i++) {
148 var currAnchor = this.getAnchor(i);
149 ctx.bezierCurveTo(prevAnchor.getNextX()-bboxMin[0],prevAnchor.getNextY()-bboxMin[1], currAnchor.getPrevX()-bboxMin[0], currAnchor.getPrevY()-bboxMin[1], currAnchor.getPosX()-bboxMin[0], currAnchor.getPosY()-bboxMin[1]);
150 prevAnchor = currAnchor;
151 }
152 if (this._isClosed === true) {
153 var currAnchor = this.getAnchor(0);
154 ctx.bezierCurveTo(prevAnchor.getNextX()-bboxMin[0],prevAnchor.getNextY()-bboxMin[1], currAnchor.getPrevX()-bboxMin[0], currAnchor.getPrevY()-bboxMin[1], currAnchor.getPosX()-bboxMin[0], currAnchor.getPosY()-bboxMin[1]);
155 prevAnchor = currAnchor;
156 }
157 if (this._isClosed){
158 ctx.fill();
190 } 159 }
191 160
192 if (VecUtils.vecDist( 3, P2P3, this._Anchors[nextIndex].getPrev()) < this._SAMPLING_EPSILON) { 161 /*
193 //no change to the prev point 162 var numPoints = this._samples.length/3;
194 isNextCoincident = true; 163 ctx.moveTo(this._samples[0],this._samples[1]);
195 } else { 164 for (var i=0;i<numPoints;i++){
196 this._Anchors[nextIndex].setPrevPos(P2P3[0], P2P3[1], P2P3[2]); 165 ctx.lineTo(this._samples[3*i]-bboxMin[0],this._samples[3*i + 1]-bboxMin[1]);
197 } 166 }
167 */
168 ctx.stroke();
169 ctx.restore();
170 } //render()
171
172 this.geomType = function () { return this.GEOM_TYPE_CUBIC_BEZIER; }
173} //function GLSubpath ...class definition
174
175
198 176
199 //create a new anchor point
200 var newAnchor = new GLAnchorPoint();
201 177
202 if (isPrevCoincident && isNextCoincident){
203 anchorPos[0]=P1P2[0];anchorPos[1]=P1P2[1];anchorPos[2]=P1P2[2];
204 newAnchor.setPos(anchorPos[0],anchorPos[1],anchorPos[2]);
205 newAnchor.setPrevPos(anchorPos[0],anchorPos[1],anchorPos[2]);
206 newAnchor.setNextPos(anchorPos[0],anchorPos[1],anchorPos[2]);
207 } else {
208 newAnchor.setPrevPos(P0P1P2[0], P0P1P2[1], P0P1P2[2]);
209 newAnchor.setNextPos(P1P2P3[0], P1P2P3[1], P1P2P3[2]);
210 newAnchor.setPos(anchorPos[0], anchorPos[1], anchorPos[2]);
211 }
212 178
213 //insert the new anchor point at the correct index and set it as the selected anchor 179
214 this._Anchors.splice(nextIndex, 0, newAnchor); 180 /////////////////////////////////////////////////////////
215 this._selectedAnchorIndex = nextIndex; 181 // Property Accessors/Setters
182 /////////////////////////////////////////////////////////
183GLSubpath.prototype.setWorld = function (world) { this._world = world; }
184GLSubpath.prototype.getWorld = function () { return this._world; }
185GLSubpath.prototype.makeDirty = function () {this._dirty = true;}
186GLSubpath.prototype.setDrawingTool = function