From ed6ab009eaf457a28aab49ddb9b9b352a3a055f9 Mon Sep 17 00:00:00 2001 From: Yi-Ting Tu Date: Tue, 21 May 2024 14:33:10 -0400 Subject: [PATCH] Add `Scene.opticalObjs` --- simulator/js/Scene.js | 7 ++++++- simulator/js/objs/BaseGrinGlass.js | 14 ++++++------- simulator/js/simulator.js | 32 ++++++++++++++++++------------ 3 files changed, 32 insertions(+), 21 deletions(-) diff --git a/simulator/js/Scene.js b/simulator/js/Scene.js index 894466ff..f1da6b66 100644 --- a/simulator/js/Scene.js +++ b/simulator/js/Scene.js @@ -7,7 +7,7 @@ const DATA_VERSION = 5; /** * Represents the scene in this simulator. * @class Scene - * @property {BaseSceneObj[]} objs - The objects (optical elements and/or decorations created by the user with "Tools") in the scene. + * @property {Array} objs - The objects (optical elements and/or decorations created by the user with "Tools") in the scene. * @property {string} mode - The mode of the scene. Possible values: 'rays' (Rays), 'extended' (Extended Rays), 'images' (All Images), 'observer' (Seen by Observer). * @property {number} rayModeDensity - The density of rays in 'rays' and 'extended' modes. * @property {number} imageModeDensity - The density of rays in 'images' and 'observer' modes. @@ -73,6 +73,11 @@ class Scene { } } + /** @property {Array} opticalObjs - The objects in the scene which are optical. If the user edits only the non-optical part of the scene, then the content of this array will not change. */ + get opticalObjs() { + return this.objs.filter(obj => obj.constructor.isOptical); + } + /** * The callback function when the entire scene or a resource (e.g. image) is loaded. * @callback fromJSONCallback diff --git a/simulator/js/objs/BaseGrinGlass.js b/simulator/js/objs/BaseGrinGlass.js index a13ab502..4734d6d8 100644 --- a/simulator/js/objs/BaseGrinGlass.js +++ b/simulator/js/objs/BaseGrinGlass.js @@ -228,16 +228,16 @@ class BaseGrinGlass extends BaseGlass { */ initRefIndex(ray) { let obj_tmp; - for (let i = 0; i < this.scene.objs.length; i++) { - if ((this.scene.objs[i] instanceof BaseGrinGlass) && (scene.objs[i].isOnBoundary(ray.p1) || scene.objs[i].isInsideGlass(ray.p1))) { + for (let obj of this.scene.opticalObjs) { + if ((obj instanceof BaseGrinGlass) && (obj.isOnBoundary(ray.p1) || obj.isInsideGlass(ray.p1))) { if (!obj_tmp) { obj_tmp = {}; - obj_tmp.p = scene.objs[i].shiftOrigin(scene.objs[i].p); - obj_tmp.fn_p = scene.objs[i].fn_p; - obj_tmp.fn_p_der_x = scene.objs[i].fn_p_der_x; - obj_tmp.fn_p_der_y = scene.objs[i].fn_p_der_y; + obj_tmp.p = obj.shiftOrigin(obj.p); + obj_tmp.fn_p = obj.fn_p; + obj_tmp.fn_p_der_x = obj.fn_p_der_x; + obj_tmp.fn_p_der_y = obj.fn_p_der_y; } else { - obj_tmp = scene.objs[i].multRefIndex(obj_tmp); + obj_tmp = obj.multRefIndex(obj_tmp); } } } diff --git a/simulator/js/simulator.js b/simulator/js/simulator.js index 5e0935f4..491419b6 100644 --- a/simulator/js/simulator.js +++ b/simulator/js/simulator.js @@ -140,9 +140,13 @@ function draw_(skipLight, skipGrid) { { var i = mapped[j].index; scene.objs[i].draw(ctx0.constructor == C2S ? canvasRenderer : canvasRenderer0, false, scene.objs[i] === mouseObj); - if (!skipLight) - { - const ret = scene.objs[i].onSimulationStart(); + + } + + if (!skipLight) { + // Initialize the simulation (e.g. add the rays and reset the detector readings) + for (let obj of scene.opticalObjs) { + const ret = obj.onSimulationStart(); if (ret) { if (ret.newRays) { waitingRays.push(...ret.newRays); @@ -153,6 +157,7 @@ function draw_(skipLight, skipGrid) { } } } + } if (!skipLight) { @@ -210,6 +215,7 @@ function shootWaitingRays() { var rpd; var surfaceMergingObjs = []; + const opticalObjs = scene.opticalObjs; if (scene.simulateColors) { ctxLight.globalCompositeOperation = 'screen'; @@ -226,7 +232,7 @@ function shootWaitingRays() { document.getElementById('forceStop').style.display = ''; document.getElementById('simulatorStatus').innerHTML = getMsg("ray_count") + shotRayCount + '
' + getMsg("total_truncation") + totalTruncation.toFixed(3) + '
' + getMsg("time_elapsed") + (new Date() - drawBeginTime) + '
'; - draw(true, true); // Redraw the scene.objs to avoid outdated information (e.g. detector readings). + draw(true, true); // Redraw the opticalObjs to avoid outdated information (e.g. detector readings). return; } if (isExporting && shotRayCount > exportRayCountLimit) @@ -265,30 +271,30 @@ function shootWaitingRays() { surfaceMergingObjs = []; // The objects whose surface is to be merged with s_obj s_lensq = Infinity; observed = false; // Whether waitingRays[j] is observed by the observer - for (var i = 0; i < scene.objs.length; i++) + for (var i = 0; i < opticalObjs.length; i++) { - // Test whether scene.objs[i] intersects with the ray - s_point_temp = scene.objs[i].checkRayIntersects(waitingRays[j]); + // Test whether opticalObjs[i] intersects with the ray + s_point_temp = opticalObjs[i].checkRayIntersects(waitingRays[j]); if (s_point_temp) { - // Here scene.objs[i] intersects with the ray at s_point_temp + // Here opticalObjs[i] intersects with the ray at s_point_temp s_lensq_temp = geometry.distanceSquared(waitingRays[j].p1, s_point_temp); - if (s_point && geometry.distanceSquared(s_point_temp, s_point) < minShotLength_squared && (scene.objs[i].constructor.supportsSurfaceMerging || s_obj.constructor.supportsSurfaceMerging)) + if (s_point && geometry.distanceSquared(s_point_temp, s_point) < minShotLength_squared && (opticalObjs[i].constructor.supportsSurfaceMerging || s_obj.constructor.supportsSurfaceMerging)) { // The ray is shot on two objects at the same time, and at least one of them supports surface merging if (s_obj.constructor.supportsSurfaceMerging) { - if (scene.objs[i].constructor.supportsSurfaceMerging) + if (opticalObjs[i].constructor.supportsSurfaceMerging) { // Both of them supports surface merging (e.g. two glasses with one common edge - surfaceMergingObjs[surfaceMergingObjs.length] = scene.objs[i]; + surfaceMergingObjs[surfaceMergingObjs.length] = opticalObjs[i]; } else { // Only the first shot object supports surface merging // Set the object to be shot to be the one not supporting surface merging (e.g. if one surface of a glass coincides with a blocker, then only block the ray) - s_obj = scene.objs[i]; + s_obj = opticalObjs[i]; s_obj_index = i; s_point = s_point_temp; s_lensq = s_lensq_temp; @@ -299,7 +305,7 @@ function shootWaitingRays() { } else if (s_lensq_temp < s_lensq && s_lensq_temp > minShotLength_squared) { - s_obj = scene.objs[i]; // Update the object to be shot + s_obj = opticalObjs[i]; // Update the object to be shot s_obj_index = i; s_point = s_point_temp; s_lensq = s_lensq_temp;