Ticket #892: pathplacer.js

File pathplacer.js, 5.6 KB (added by historic_bruno, 12 years ago)

work in progress

Line 
1
2/////////////////////////////////////////////////////////////////////////////////////////
3// PathPlacer
4//
5// Class for creating a winding path between two points
6//
7// x1,z1: Starting point of path
8// x2,z2: Ending point of path
9// width: Width of the path
10// a: Waviness - how wavy the path will be (higher is wavier, 0.0 is straight line)
11// b: Smoothness - how smooth the path will be (higher is smoother)
12// c: Offset - max amplitude of waves along the path (0.0 is straight line)
13// taper: Tapering - how much the width of the path changes from start to end
14// if positive, the width will decrease by that factor, if negative the width
15// will increase by that factor
16//
17/////////////////////////////////////////////////////////////////////////////////////////
18
19function PathPlacer(x1, z1, x2, z2, width, a, b, c, taper)
20{
21 this.x1 = x1;
22 this.z1 = z1;
23 this.x2 = x2;
24 this.z2 = z2;
25 this.width = width;
26 this.a = a;
27 this.b = b;
28 this.c = c;
29 this.taper = taper;
30}
31
32PathPlacer.prototype.place = function(constraint)
33{
34 // Preliminary bounds check
35 if (!g_Map.validT(this.x1, this.z1) || !constraint.allows(this.x1, this.z1) ||
36 !g_Map.validT(this.x2, this.z2) || !constraint.allows(this.x2, this.z2))
37 {
38 return undefined;
39 }
40
41 var dx = (this.x2 - this.x1);
42 var dz = (this.z2 - this.z1);
43 var dist = Math.sqrt(dx*dx + dz*dz);
44 dx /= dist;
45 dz /= dist;
46
47 var numSteps = 1 + Math.floor(dist/4 * this.a);
48 var numISteps = 1 + Math.floor(dist/4 * this.b);
49 var totalSteps = numSteps*numISteps;
50 var offset = 1 + Math.floor(dist/4 * this.c);
51
52 // Generate random offsets
53 var ctrlVals = new Float32Array(numSteps); //float32
54 for (var j = 1; j < (numSteps-1); ++j)
55 {
56 ctrlVals[j] = randFloat(-offset, offset);
57 }
58
59 // Interpolate for smoothed 1D noise
60 var noise = new Float32Array(totalSteps+1); //float32
61 for (var j = 0; j < numSteps; ++j)
62 {
63 // Cubic interpolation
64 var v0 = ctrlVals[(j+numSteps-1)%numSteps];
65 var v1 = ctrlVals[j];
66 var v2 = ctrlVals[(j+1)%numSteps];
67 var v3 = ctrlVals[(j+2)%numSteps];
68 var P = (v3 - v2) - (v0 - v1);
69 var Q = (v0 - v1) - P;
70 var R = v2 - v0;
71 var S = v1;
72
73 for (var k = 0; k < numISteps; ++k)
74 {
75 var t = k/numISteps;
76 noise[j*numISteps + k] = P*t*t*t + Q*t*t + R*t + S;
77 }
78 }
79
80 var halfWidth = 0.5 * this.width;
81
82 // Add smoothed noise to straight path
83 var segments1 = [];
84 var segments2 = [];
85 for (var j = 0; j < totalSteps; ++j)
86 {
87 // Interpolated points along straight path
88 var t = j/totalSteps;
89 var tx = this.x1 * (1.0 - t) + this.x2 * t;
90 var tz = this.z1 * (1.0 - t) + this.z2 * t;
91 var t2 = (j+1)/totalSteps;
92 var tx2 = this.x1 * (1.0 - t2) + this.x2 * t2;
93 var tz2 = this.z1 * (1.0 - t2) + this.z2 * t2;
94
95 // Find noise offset points
96 var nx = (tx - dz * noise[j]);
97 var nz = (tz + dx * noise[j]);
98 var nx2 = (tx2 - dz * noise[j+1]);
99 var nz2 = (tz2 + dx * noise[j+1]);
100
101 // Find slope of offset points
102 var ndx = (nx2 - nx);
103 var ndz = (nz2 - nz);
104 var dist = Math.sqrt(ndx*ndx + ndz*ndz);
105 ndx /= dist;
106 ndz /= dist;
107
108 var taperedWidth = (1.0 - t*this.taper) * halfWidth;
109
110 // Find slope of offset path
111 var px = (nx - ndz * -taperedWidth);
112 var pz = (nz + ndx * -taperedWidth);
113 segments1.push(new PointXZ(px, pz));
114 var px2 = (nx2 - ndz * taperedWidth);
115 var pz2 = (nz2 + ndx * taperedWidth);
116 segments2.push(new PointXZ(px2, pz2));
117 }
118
119 var retVec = [];
120
121 // Draw path segments
122 var num = segments1.length - 1;
123 for (var j = 0; j < num; ++j)
124 {
125 // Fill quad formed by these 4 points
126 var pt11 = segments1[j];
127 var pt12 = segments1[j+1];
128 var pt21 = segments2[j];
129 var pt22 = segments2[j+1];
130
131 var tris = [[pt12, pt11, pt21], [pt12, pt21, pt22]];
132
133 for (var t = 0; t < 2; ++t)
134 {
135 // Sort vertices by min z
136 var tri = tris[t].sort(
137 function(a, b)
138 {
139 return a.z - b.z;
140 }
141 );
142 var A = tri[0];
143 var B = tri[1];
144 var C = tri[2];
145 var dx1 = (B.z != A.z) ? ((B.x - A.x) / (B.z - A.z)) : 0;
146 var dx2 = (C.z != A.z) ? ((C.x - A.x) / (C.z - A.z)) : 0;
147 var dx3 = (C.z != B.z) ? ((C.x - B.x) / (C.z - B.z)) : 0;
148
149 var z = Math.round(A.z);
150 var minX = A.x
151 var maxX = A.x
152
153 if (dx1 > dx2)
154 {
155 while (z <= B.z)
156 {
157 minX = Math.round(minX);
158 maxX = Math.round(maxX);
159 for (var x = minX; x < maxX; ++x)
160 {
161 if (g_Map.validT(x, z) && constraint.allows(x, z))
162 {
163 retVec.push(new PointXZ(x, z));
164 }
165 }
166
167 ++z;
168 minX += dx2;
169 maxX += dx1;
170 }
171
172 maxX = B.x;
173
174 while (z <= C.z)
175 {
176 minX = Math.round(minX);
177 maxX = Math.round(maxX);
178 for (var x = minX; x < maxX; ++x)
179 {
180 if (g_Map.validT(x, z) && constraint.allows(x, z))
181 {
182 retVec.push(new PointXZ(x, z));
183 }
184 }
185
186 ++z;
187 minX += dx2;
188 maxX += dx3;
189 }
190 }
191 else
192 {
193 while (z <= B.z)
194 {
195 minX = Math.round(minX);
196 maxX = Math.round(maxX);
197 for (var x = minX; x < maxX; ++x)
198 {
199 if (g_Map.validT(x, z) && constraint.allows(x, z))
200 {
201 retVec.push(new PointXZ(x, z));
202 }
203 }
204
205 ++z;
206 minX += dx1;
207 maxX += dx2;
208 }
209
210 minX = B.x;
211
212 while (z <= C.z)
213 {
214 minX = Math.round(minX);
215 maxX = Math.round(maxX);
216 for (var x = minX; x < maxX; ++x)
217 {
218 if (g_Map.validT(x, z) && constraint.allows(x, z))
219 {
220 retVec.push(new PointXZ(x, z));
221 }
222 }
223
224 ++z;
225 minX += dx3;
226 maxX += dx2;
227 }
228 }
229 }
230 }
231
232 return retVec;
233}