1// ---------------------------------------------------------------------------------------------------------------- 2// Arc wall 3// ---------------------------------------------------------------------------------------------------------------- 4function ArcWall(centerPos, radius, startAngle, endAngle) 5{ 6 this.scene = null; 7 this.center = centerPos; 8 this.radius = radius; 9 this.startAngle = startAngle; 10 this.endAngle = endAngle; 11 this.selected = false; 12 this.visible = true; 13 this.frozen = false; 14 this.convex = false; 15 this.appearance = new Appearance(); 16 this.BRDF = Phong; 17 this.BRDFIndex = 1; 18 this.BRDFOptions = [ Lambert, Phong ]; 19 this.roughness = 0; 20 this.metalness = 0; 21 this.intensity = 1; 22 this.onChangeListeners = []; 23 this.boundsMin = new Vector(Number.MAX_VALUE,Number.MAX_VALUE); 24 this.boundsMax = new Vector(-Number.MAX_VALUE,-Number.MAX_VALUE); 25 26 this.getBoundsMin = function() 27 { 28 return this.boundsMin; 29 } 30 31 this.getBoundsMax = function() 32 { 33 return this.boundsMax; 34 } 35 36 this.saveAsJavascript = function() 37 { 38 var str = "var aw = new ArcWall("; 39 40 str += "new Vector(" + this.center.x + ", " + this.center.y + ")"; 41 str += ", " + this.radius; 42 str += ", " + (this.startAngle * 180 / Math.PI).toFixed(2) + " * Math.PI/180"; 43 str += ", " + (this.endAngle * 180 / Math.PI).toFixed(2) + " * Math.PI/180"; 44 str += ");\n"; 45 46 str += "aw.convex = " + this.convex + ";\n"; 47 str += "aw.roughness = " + this.roughness + ";\n"; 48 str += "aw.metalness = " + this.metalness + ";\n"; 49 str += this.appearance.saveAsJavascript("aw"); 50 str += "aw.intensity = " + this.intensity + ";\n"; 51 str += "aw.BRDFIndex = " + this.BRDFIndex + ";\n"; 52 str += "aw.visible = " + this.visible + ";\n"; 53 str += "aw.frozen = " + this.frozen + ";\n"; 54 str += "aw.onChange();\n"; 55 56 if (this.name != undefined) 57 { 58 str += "aw.name = \"" + this.name + "\";\n"; 59 } 60 61 str += "scene.addObject(aw);\n"; 62 return str; 63 } 64 65 this.addChangeListener = function(listener) 66 { 67 this.onChangeListeners.push(listener); 68 } 69 70 this.onChange = function(changeDetails) 71 { 72 // Backwards compatibility 73 this.appearance.SetFromOldProperties(this); 74 75 this.BRDF = this.BRDFOptions[this.BRDFIndex]; 76 77 this.boundsMin = new Vector(Number.MAX_VALUE,Number.MAX_VALUE); 78 this.boundsMax = new Vector(-Number.MAX_VALUE,-Number.MAX_VALUE); 79 80 var p0 = add(this.center, mul(fromAngle(this.startAngle), this.radius)); 81 var p1 = add(this.center, mul(fromAngle(this.endAngle), this.radius)); 82 83 this.boundsMin = min(this.boundsMin, p0); 84 this.boundsMin = min(this.boundsMin, p1); 85 this.boundsMax = max(this.boundsMax, p0); 86 this.boundsMax = max(this.boundsMax, p1); 87 88 var a90 = Math.ceil(this.startAngle/(Math.PI/2)) * Math.PI/2; 89 for (var a = a90; a <= this.endAngle; a += Math.PI/2) 90 { 91 var p = add(this.center, mul(fromAngle(a), this.radius)); 92 this.boundsMin = min(this.boundsMin, p); 93 this.boundsMax = max(this.boundsMax, p); 94 } 95 96 if (changeDetails == undefined) 97 changeDetails = {}; 98 99 changeDetails.blockersMoved = 1; 100 101 for (var i=0; i!=this.onChangeListeners.length; ++i) 102 { 103 this.onChangeListeners[i](this, changeDetails); 104 } 105 } 106 107 this.draw = function(camera) 108 { 109 if (this.radius <= 0) 110 return; 111 112 camera.drawArc(this.center, this.radius, this.startAngle, this.endAngle, this.appearance.GetLineColor(), this.appearance.GetLineWidth(this.selected), undefined, undefined, undefined, undefined, this); 113 114 var angleStep = 10 * Math.PI / 180; 115 116 if ((this.endAngle - this.startAngle) > 0) 117 { 118 angleStep = (this.endAngle - this.startAngle) / Math.round( Math.abs(this.endAngle - this.startAngle) / angleStep ); 119 } 120 121 var size = sub(this.boundsMax, this.boundsMin).length(); 122 var sizePixels = Math.max(1, size * camera.getUnitScale()); 123 var arcLength = (this.endAngle-this.startAngle) * this.radius; 124 var arcLengthPixels = arcLength * camera.getUnitScale(); 125 var approxCount = Math.floor(arcLengthPixels / Math.min(sizePixels/15, 15)); 126 var stepPixels = arcLengthPixels / approxCount; 127 var stepUnits = stepPixels / camera.getUnitScale(); 128 var stepAngle = stepUnits / this.radius; 129 130 var delta = stepUnits; 131 132 if (this.convex) 133 delta = -delta; 134 135 var hatchPoints = []; 136 137 for (var a = this.startAngle + stepAngle; a <= this.endAngle; a += stepAngle) 138 { 139 var p0 = add(this.center, mul(fromAngle(a), this.radius)); 140 var p1 = add(this.center, mul(fromAngle(a - stepAngle), this.radius + delta)); 141 hatchPoints.push(p0); 142 hatchPoints.push(p1); 143 } 144 145 camera.drawLines(hatchPoints, this.appearance.GetLineColor(), this.appearance.GetLineWidth(this.selected)); 146 147 //camera.drawArc(add(this.center, mul(fromAngle(this.startAngle), this.radius)), 0.1, 0, 2 * Math.PI); 148 //camera.drawText(add(this.center, mul(fromAngle(this.startAngle), this.radius)), (this.startAngle * 180 / Math.PI).toFixed(1)); 149 //camera.drawText(add(this.center, mul(fromAngle(this.endAngle), this.radius)), (this.endAngle * 180 / Math.PI).toFixed(1)); 150 } 151 152 this.hitTest = function(a, b, camera) 153 { 154 var rectMin = min(a, b); 155 var rectMax = max(a, b); 156 157 return overlapRectArc(rectMin, rectMax, this.center, this.radius, this.startAngle, this.endAngle); 158 } 159 160 this.rayHitTest = function(rayPos, rayDir, rayRadius) 161 { 162 var results = [{N:rayDir, P:rayPos, hit:false, tRay:0}]; 163 164 var rayDirL = rayDir.length(); 165 166 var RO = sub(this.center, rayPos); 167 168 var perpDist = Math.abs(dot(RO, transpose(rayDir))/rayDirL); 169 170 // bail if we're too far away 171 if (perpDist > (this.radius + rayRadius)) 172 return results; 173 174 // Distance of arc center along ray. 175 var distanceToArcCenter = dot(RO, rayDir)/rayDirL; 176 177 var effectiveArcRadius = this.radius; 178 179 if (this.convex) 180 effectiveArcRadius += rayRadius; 181 else 182 effectiveArcRadius -= rayRadius; 183 184 // How far do we need to backtrack along the ray such that the distance between the point
185 // on the ray and the center is equal to arc radius? 186 var delta = Math.sqrt(effectiveArcRadius*effectiveArcRadius - perpDist*perpDist); 187 188 // For convex we move backwards, towards the ray origin. For concave, forwards. 189 if (this.convex) 190 delta *= -1; 191 192 // Distance along the ray to the point of impact 193 var distanceToImpact = distanceToArcCenter + delta; 194 195 // if the ray starts inside a convex arc or outside a concave one, bail 196 if (distanceToImpact < -rayRadius) 197 return results; 198 199 // impact point 200 var P = add(rayPos, mul(rayDir, distanceToImpact/rayDirL)); 201 202 if (rayRadius>0) 203 { 204 P = add(P, mul(sub(this.center, P).unit(), this.convex ? rayRadius : -rayRadius)); 205 } 206 207 // check if impact point is outside the (stand,end) angle range 208 var OP = sub(P, this.center); 209 var OPAngle = toAngle(OP); 210 211 if (OPAngle < 0) 212 OPAngle += Math.PI*2; 213 214 var midAngle = (this.startAngle + this.endAngle) * 0.5; 215 216 if (Math.cos(OPAngle - midAngle) < Math.cos(this.startAngle - midAngle)) 217 return results; 218 219 results[0].hit = true; 220 results[0].N = this.convex ? OP.unit() : OP.unit().neg(); 221 results[0].tRay = distanceToImpact/rayDirL; 222 results[0].P = P; 223 //results[0].color = this.appearance.GetLineColorHex(); 224 results[0].roughness = this.roughness; 225 results[0].metalness = this.metalness; 226 results[0].intensity = this.intensity; 227 results[0].BRDF = this.BRDF; 228 229 return results; 230 } 231 232 this.getSnapPoints = function () 233 { 234 var points = [ { type: "center", p: this.center }, 235 { type: "node", p: add(this.center, mul(fromAngle(this.startAngle), this.radius)) }, 236 { type: "node", p: add(this.center, mul(fromAngle(this.endAngle), this.radius))} ]; 237 238 var angleStep = 45 * Math.PI / 180; 239 240 for (var a=Math.ceil(this.startAngle/angleStep)*angleStep; a<=Math.floor(this.endAngle/angleStep)*angleStep; a+=angleStep) 241 { 242 points.push({ type: "node", p: add(this.center, mul(fromAngle(a), this.radius))}); 243 } 244 245 return points; 246 } 247 248 this.getDragPoints = function(localSpace, camera) 249 { 250 if (this.isFrozen()) 251 return []; 252 253 var points = []; 254 255 if (localSpace) 256 { 257 points.push(add(this.center, mul(fromAngle(this.startAngle + (this.endAngle-this.startAngle)/20), this.radius))); 258 points.push(add(this.center, mul(fromAngle(this.startAngle), this.radius*0.95))); 259 260 points.push(add(this.center, mul(fromAngle(this.endAngle - (this.endAngle - this.startAngle) / 20), this.radius))); 261 points.push(add(this.center, mul(fromAngle(this.endAngle), this.radius*0.95))); 262 } 263 else 264 { 265 points.push(add(this.center, mul(fromAngle(this.startAngle), this.radius))); 266 points.push(add(this.center, mul(fromAngle(this.endAngle), this.radius))); 267 points.push(this.center); 268 } 269 270 return points; 271 } 272 273 this.drawDragPoint = function(camera, index, position, localSpace, alpha) 274 { 275 if (alpha == undefined) 276 alpha = 1; 277 278 if (localSpace) 279 { 280 if (index == 0) 281 { 282 camera.drawArc(this.center, this.radius, this.startAngle, this.startAngle + (this.endAngle-this.startAngle)/10, "rgba(255,0,0," + alpha + ")", 4); 283 } 284 else if (index == 1) 285 { 286 camera.drawArrow( add(this.center, mul(fromAngle(this.startAngle), this.radius)), 287 add(this.center, mul(fromAngle(this.startAngle), this.radius - camera.invScale(50))), 13, "rgba(255,0,0," + alpha + ")", 5); 288 } 289 else if (index == 2) 290 { 291 camera.drawArc(this.center, this.radius, this.endAngle - (this.endAngle-this.startAngle)/10, this.endAngle, "rgba(255,0,0," + alpha + ")", 4); 292 } 293 else if (index == 3) 294 { 295 camera.drawArrow( add(this.center, mul(fromAngle(this.endAngle), this.radius)), 296 add(this.center, mul(fromAngle(this.endAngle), this.radius - camera.invScale(50))), 13, "rgba(255,0,0," + alpha + ")", 5); 297 } 298 } 299 else 300 { 301 if (index == 0) 302 camera.drawRectangle(add(this.center, mul(fromAngle(this.startAngle), this.radius)), camera.invScale(10), "rgba(255,0,0," + alpha + ")", 2); 303 else if (index == 1) 304 camera.drawRectangle(add(this.center, mul(fromAngle(this.endAngle), this.radius)), camera.invScale(10), "rgba(255,0,0," + alpha + ")", 2); 305 else if (index == 2) 306 camera.drawRectangle(this.center, camera.invScale(10), "rgba(255,0,0," + alpha + ")", 2); 307 } 308 } 309 310 this.setDragPointPos = function(index, p, localSpace, dragStartPoint, camera) 311 { 312 var startAngleChanged = false;
313 var endAngleChanged = false; 314 var radiusChanged = false; 315 316 if (localSpace) 317 { 318 if (index==0) 319 { 320 this.startAngle = toAngle(sub(p, this.center)); 321 startAngleChanged = true; 322 } 323 else if (index==1 || index==3) 324 { 325 this.radius = distance(p, this.center); 326 radiusChanged = true; 327 } 328 else if (index==2) 329 { 330 this.endAngle = toAngle(sub(p, this.center)); 331 endAngleChanged = true; 332 } 333 } 334 else 335 { 336 if (index==0 || index==1) 337 { 338 var pointA = (index==0) ? p : add(this.center, mul(fromAngle(this.startAngle), this.radius)); 339 var pointB = (index==1) ? p : add(this.center, mul(fromAngle(this.endAngle), this.radius)); 340 341 this.center = avg(pointA, pointB); 342 343 this.startAngle = toAngle(sub(pointA, this.center)); 344 345 this.endAngle = toAngle(sub(pointB, this.center)); 346 347 this.radius = distance(pointA, this.center); 348 349 startAngleChanged = true; 350 endAngleChanged = true; 351 radiusChanged = true; 352 } 353 else if (index==2) 354 { 355 this.center = p; 356 } 357 } 358 359 if (this.startAngle < 0) 360 this.startAngle += Math.PI*2; 361 362 if (this.endAngle < 0) 363 this.endAngle += Math.PI*2; 364 365 if (this.endAngle<=this.startAngle) 366 this.startAngle -= Math.PI * 2; 367 368 if (camera != undefined) 369 { 370 var text = ""; 371 372 if (startAngleChanged) 373 text += "Start Angle: " + (this.startAngle * 180 / Math.PI).toFixed(0) + "°"; 374 375 if (endAngleChanged) 376 text += " End Angle: " + (this.endAngle * 180 / Math.PI).toFixed(0) + "°"; 377 378 if (radiusChanged) 379 text += " Radius: " + this.radius.toFixed(1); 380 381 camera.drawText(this.center, text, "#000000", "center", 0, "12px Arial"); 382 } 383 384 this.onChange(); 385 } 386 387 this.getOrigin = function() 388 { 389 return this.center; 390 } 391 392 this.setOrigin = function(p) 393 { 394 this.center = p; 395 this.onChange(); 396 } 397 398 this.transform = function(currentRect, newRect) 399 { 400 var localCoord = new Vector( dot(sub(this.getOrigin(), currentRect.center), currentRect.scaledXAxis), 401 dot(sub(this.getOrigin(), currentRect.center), currentRect.scaledYAxis) ); 402 403 localCoord.x /= currentRect.scaledXAxis.lengthSqr(); 404 localCoord.y /= currentRect.scaledYAxis.lengthSqr(); 405 406 this.setOrigin( add(mad(localCoord.x, newRect.scaledXAxis, newRect.center), mul(localCoord.y, newRect.scaledYAxis)) ); 407 408 if (newRect.scaledXAxis.lengthSqr() > newRect.scaledYAxis.lengthSqr()) 409 { 410 this.radius *= Math.sqrt(newRect.scaledYAxis.lengthSqr() / currentRect.scaledYAxis.lengthSqr()); 411 } 412 else 413 { 414 this.radius *= Math.sqrt(newRect.scaledXAxis.lengthSqr() / currentRect.scaledXAxis.lengthSqr()); 415 } 416 417 this.startAngle += toAngle(newRect.scaledXAxis) - toAngle(currentRect.scaledXAxis); 418 this.endAngle += toAngle(newRect.scaledXAxis) - toAngle(currentRect.scaledXAxis); 419 420 this.onChange(); 421 } 422 423 this.getProperties = function() 424 { 425 var appearanceControl = new PopoutContainer(undefined, "images/color_wheel.svg"); 426 { 427 appearanceControl.addControl("", new AppearanceControl(this.appearance, true, false, function(){ this.onChange(); }.bind(this)) ); 428 } 429 430 return [ 431 { name: "Appearance", control:appearanceControl }, 432 { name: "", control: new PlainButton("Flip Normals", function () { this.convex = !this.convex; this.onChange(); }.bind(this)) }, 433 { name: "Roughness", control: new PopoutSlider(0, 1, this.roughness, 0.1, function (value) { this.roughness = value; this.onChange(); }.bind(this)) }, 434 { name: "Metalness", control: new PopoutSlider(0, 1, this.metalness, 0.1, function (value) { this.metalness = value; this.onChange(); }.bind(this)) }, 435 { name: "Intensity", control: new PopoutSlider(0, 10, this.intensity, 0.1, function (value) { this.intensity = value; this.onChange(); }.bind(this)) }, 436 { name: "BRDF", control: new Dropdown(["Lambert", "Phong"], this.BRDFIndex, function (value) { this.BRDFIndex = value; this.onChange(); }.bind(this)) }, 437 ]; 438 } 439 440 this.toggleVisibility = function(v) 441 { 442 var newVisible = (v!==undefined) ? v : !this.visible; 443 if (this.visible != newVisible) 444 { 445 this.visible = newVisible; 446 this.onChange(); 447 } 448 } 449 450 this.isVisible = function() 451 { 452 return this.visible; 453 } 454 455 this.toggleFrozen = function(f) 456 { 457 this.frozen = (f!==undefined) ? f : !this.frozen; 458 this.onChange(); 459 } 460 461 this.isFrozen = function() 462 { 463 return this.frozen; 464 } 465 466 this.setSelected = function(selected) 467 { 468 this.selected = selected; 469 } 470 471 this.isSelected = function() 472 { 473 return this.selected; 474 } 475 476 this.onChange(); 477}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.