aboutsummaryrefslogtreecommitdiff
path: root/js/lib/geom/sub-path.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/lib/geom/sub-path.js')
-rwxr-xr-xjs/lib/geom/sub-path.js1288
1 files changed, 1288 insertions, 0 deletions
diff --git a/js/lib/geom/sub-path.js b/js/lib/geom/sub-path.js
new file mode 100755
index 00000000..ab54d1e9
--- /dev/null
+++ b/js/lib/geom/sub-path.js
@@ -0,0 +1,1288 @@
1/* <copyright>
2This file contains proprietary software owned by Motorola Mobility, Inc.<br/>
3No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.<br/>
4(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved.
5</copyright> */
6
7
8var VecUtils = require("js/helper-classes/3D/vec-utils").VecUtils;
9
10var GeomObj = require("js/lib/geom/geom-obj").GeomObj;
11var AnchorPoint = require("js/lib/geom/anchor-point").AnchorPoint;
12var MaterialsModel = require("js/models/materials-model").MaterialsModel;
13
14// TODO Those function do not seems to be used. We should remove them
15function SubpathOffsetPoint(pos, mapPos) {
16 this.Pos = [pos[0],pos[1],pos[2]];
17 this.CurveMapPos = [mapPos[0], mapPos[1], mapPos[2]];
18}
19
20function SubpathOffsetTriangle(v0, v1, v2) {
21 this.v0 = v0;
22 this.v1 = v1;
23 this.v2 = v2;
24 this.n = [0,0,1]; //replace with the actual cross product later
25}
26
27function sortNumberAscending(a,b){
28 return a-b;
29}
30function sortNumberDescending(a,b){
31 return b-a;
32}
33function SegmentIntersections(){
34 this.paramArray = [];
35}
36
37///////////////////////////////////////////////////////////////////////
38// Class GLSubpath
39// representation a sequence of cubic bezier curves.
40// Derived from class GeomObj
41///////////////////////////////////////////////////////////////////////
42
43var GLSubpath = function GLSubpath() {
44 ///////////////////////////////////////////////////
45 // Instance variables
46 ///////////////////////////////////////////////////
47 this._Anchors = [];
48 this._BBoxMin = [0, 0, 0];
49 this._BBoxMax = [0, 0, 0];
50 this._isClosed = false;
51
52 this._samples = []; //polyline representation of this curve
53 this._sampleParam = []; //parametric distance of samples, within [0, N], where N is # of Bezier curves (=# of anchor points if closed, =#anchor pts -1 if open)
54 this._anchorSampleIndex = []; //index within _samples corresponding to anchor points
55
56 this._UnprojectedAnchors = [];
57
58 //initially set the _dirty bit so we will construct samples
59 this._dirty = true;
60
61 //whether or not to use the canvas drawing to stroke/fill
62 this._useCanvasDrawing = true;
63
64 //the X and Y location of this subpath's canvas in stage world space of Ninja
65 this._canvasX = 0;
66 this._canvasY = 0;
67
68 //stroke information
69 this._strokeWidth = 0.0;
70 this._strokeColor = [0.4, 0.4, 0.4, 1.0];
71 this._strokeMaterial = null
72 this._strokeStyle = "Solid";
73 this._materialAmbient = [0.2, 0.2, 0.2, 1.0];
74 this._materialDiffuse = [0.4, 0.4, 0.4, 1.0];
75 this._materialSpecular = [0.4, 0.4, 0.4, 1.0];
76 this._fillColor = [0.4, 0.4, 0.4, 1.0];
77 this._fillMaterial = null;
78 this._DISPLAY_ANCHOR_RADIUS = 5;
79 //drawing context
80 this._world = null;
81
82 //tool that owns this subpath
83 this._drawingTool = null;
84 this._planeMat = null;
85 this._planeMatInv = null;
86 this._planeCenter = null;
87
88 //used to query what the user selected, OR-able for future extensions
89 this.SEL_NONE = 0; //nothing was selected
90 this.SEL_ANCHOR = 1; //anchor point was selected
91 this.SEL_PREV = 2; //previous handle of anchor point was selected
92 this.SEL_NEXT = 4; //next handle of anchor point was selected
93 this.SEL_PATH = 8; //the path itself was selected
94 this._selectMode = this.SEL_NONE;
95 this._selectedAnchorIndex = -1;
96
97 this._SAMPLING_EPSILON = 0.5; //epsilon used for sampling the curve
98 this._DEFAULT_STROKE_WIDTH = 20; //use only if stroke width not specified
99 this._MAX_OFFSET_ANGLE = 10; //max angle (in degrees) between consecutive vectors from curve to offset path
100
101 // (current GeomObj complains if buildBuffers/render is added to GLSubpath prototype)
102 //buildBuffers
103 // Build the stroke vertices, normals, textures and colors
104 // Add that array data to the GPU using OpenGL data binding
105 this.buildBuffers = function () {
106 // return; //no need to do anything for now
107 };
108
109 //render
110 // specify how to render the subpath in Canvas2D
111 this.render = function () {
112 // get the world
113 var world = this.getWorld();
114 if (!world) throw( "null world in subpath render" );
115
116 // get the context
117 var ctx = world.get2DContext();
118 if (!ctx) throw ("null context in subpath render")
119
120 var numAnchors = this.getNumAnchors();
121 if (numAnchors === 0) {
122 return; //nothing to do for empty paths
123 }
124
125 ctx.save();
126
127 this.createSamples(); //dirty bit checked in this function...will generate a polyline representation
128 var bboxMin = this.getBBoxMin();
129 var bboxMax = this.getBBoxMax();
130 var bboxWidth = bboxMax[0] - bboxMin[0];
131 var bboxHeight = bboxMax[1] - bboxMin[1];
132 var bboxMid = [0.5 * (bboxMax[0] + bboxMin[0]), 0.5 * (bboxMax[1] + bboxMin[1]), 0.5 * (bboxMax[2] + bboxMin[2])];
133
134 ctx.clearRect(0, 0, bboxWidth, bboxHeight);
135
136 ctx.lineWidth = this._strokeWidth;
137 ctx.strokeStyle = "black";
138 if (this._strokeColor) {
139 ctx.strokeStyle = MathUtils.colorToHex( this._strokeColor );
140 }
141
142 ctx.fillStyle = "white";
143 if (this._fillColor){
144 //ctx.fillStyle = MathUtils.colorToHex( this._fillColor );
145 var fillColorStr = "rgba("+parseInt(255*this._fillColor[0])+","+parseInt(255*this._fillColor[1])+","+parseInt(255*this._fillColor[2])+","+this._fillColor[3]+")";
146 ctx.fillStyle = fillColorStr;
147 }
148 var lineCap = ['butt','round','square'];
149 ctx.lineCap = lineCap[1];
150 ctx.beginPath();
151
152 /*
153 commenting this out for now because of Chrome bug where coincident endpoints of bezier curve cause the curve to not be rendered
154 var prevAnchor = this.getAnchor(0);
155 ctx.moveTo(prevAnchor.getPosX()-bboxMin[0],prevAnchor.getPosY()-bboxMin[1]);
156 for (var i = 1; i < numAnchors; i++) {
157 var currAnchor = this.getAnchor(i);
158 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]);
159 prevAnchor = currAnchor;
160 }
161 if (this._isClosed === true) {
162 var currAnchor = this.getAnchor(0);
163 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]);
164 prevAnchor = currAnchor;
165 ctx.fill();
166 }
167 */
168
169
170 var numPoints = this._samples.length/3;
171 ctx.moveTo(this._samples[0]-bboxMin[0],this._samples[1]-bboxMin[1]);
172 for (var i=0;i<numPoints;i++){
173 ctx.lineTo(this._samples[3*i]-bboxMin[0],this._samples[3*i + 1]-bboxMin[1]);
174 }
175 if (this._isClosed === true) {
176 ctx.lineTo(this._samples[0]-bboxMin[0],this._samples[1]-bboxMin[1]);
177 }
178 ctx.fill();
179 ctx.stroke();
180 ctx.restore();
181 }; //render()
182
183 this.geomType = function () {
184 return this.GEOM_TYPE_CUBIC_BEZIER;
185 };
186
187 this.setWidth = function (newW) {
188 if (newW<1) {
189 newW=1; //clamp minimum width to 1
190 }
191
192 //scale the contents of this subpath to lie within this width
193 //determine the scale factor by comparing with the old width
194 var oldWidth = this._BBoxMax[0]-this._BBoxMin[0];
195 if (oldWidth<1) {
196 oldWidth=1;
197 }
198
199 var scaleX = newW/oldWidth;
200 if (scaleX===1) {
201 return; //no need to do anything
202 }
203
204 //scale the anchor point positions such that the width of the bbox is the newW
205 var origX = this._BBoxMin[0];
206 var numAnchors = this._Anchors.length;
207 for (var i=0;i<numAnchors;i++){
208 //compute the distance from the bboxMin
209 var oldW = this._Anchors[i].getPosX() - origX;
210 var prevW = this._Anchors[i].getPrevX() - origX;
211 var nextW = this._Anchors[i].getNextX() - origX;
212
213 this._Anchors[i].setPos(origX + oldW*scaleX,this._Anchors[i].getPosY(),this._Anchors[i].getPosZ());
214 this._Anchors[i].setPrevPos(origX + prevW*scaleX,this._Anchors[i].getPrevY(),this._Anchors[i].getPrevZ());
215 this._Anchors[i].setNextPos(origX + nextW*scaleX,this._Anchors[i].getNextY(),this._Anchors[i].getNextZ());
216 }
217 this.makeDirty();
218 };
219
220 this.setHeight = function (newH) {
221 if (newH<1) {
222 newH=1; //clamp minimum width to 1
223 }
224 //scale the contents of this subpath to lie within this height
225 //determine the scale factor by comparing with the old height
226 var oldHeight = this._BBoxMax[1]-this._BBoxMin[1];
227 if (oldHeight<1){
228 oldHeight=1;
229 }
230
231 var scaleY = newH/oldHeight;
232 if (scaleY===1){
233 return; //no need to do anything
234 }
235
236 //scale the anchor point positions such that the height of the bbox is the newH
237 var origY = this._BBoxMin[1];
238 var numAnchors = this._Anchors.length;
239 for (var i=0;i<numAnchors;i++){
240 //compute the distance from the bboxMin
241 var oldW = this._Anchors[i].getPosY() - origY;
242 var prevW = this._Anchors[i].getPrevY() - origY;
243 var nextW = this._Anchors[i].getNextY() - origY;