Skip to content

Commit b5f0fb7

Browse files
authored
Merge pull request #26 from gregzanch/dev-jb
Image Source Updates
2 parents 09025e9 + 11ea72a commit b5f0fb7

File tree

2 files changed

+116
-37
lines changed

2 files changed

+116
-37
lines changed

src/compute/raytracer/image-source/index.ts

Lines changed: 115 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import Solver from "../../solver";
2323
import {uuid} from "uuidv4";
2424
import * as THREE from "three";
25+
import * as ac from "../../acoustics";
2526
import Room from "../../../objects/room";
2627
import Messenger from "../../../messenger";
2728
import { KVP } from "../../../common/key-value-pair";
@@ -34,6 +35,7 @@ import Surface from "../../../objects/surface";
3435
import { LensTwoTone, ThreeSixtyOutlined } from "@material-ui/icons";
3536
import { cloneElement } from "react";
3637
import { SSL_OP_SSLEAY_080_CLIENT_DH_BUG } from "constants";
38+
import { intersection } from "lodash";
3739

3840
interface ImageSourceParams {
3941
baseSource: Source,
@@ -46,6 +48,8 @@ interface ImageSourceParams {
4648

4749
class ImageSource{
4850

51+
// the source that all image sources are based off of
52+
// note: this is not the parent image source! that is below
4953
public baseSource: Source;
5054

5155
public children: ImageSource[];
@@ -73,32 +77,36 @@ class ImageSource{
7377
this.uuid = uuid();
7478
}
7579

76-
public constructPathsForAllDescendents(r: Receiver): ImageSourcePath[]{
80+
public constructPathsForAllDescendents(r: Receiver,constructForThis=true): ImageSourcePath[]{
7781
let paths: ImageSourcePath[] = [];
7882

83+
// compute direct sound path
84+
if(constructForThis){
85+
let thisPath = constructImageSourcePath(this, r);
86+
if(thisPath != null){
87+
paths.push(thisPath);
88+
}
89+
}
90+
7991
for(let i = 0; i<this.children.length; i++){
80-
8192
let p = constructImageSourcePath(this.children[i],r);
82-
p?.markup();
8393

8494
if (p!= null){
8595
paths.push(p);
8696
}
8797

8898
if(this.children[i].hasChildren){
89-
paths = paths.concat(this.children[i].constructPathsForAllDescendents(r));
99+
paths = paths.concat(this.children[i].constructPathsForAllDescendents(r,false));
90100
}
91101

92102
}
93-
94103
return paths;
95104
}
96105

97106
public markup(){
98107
for(let i = 0; i<this.children.length; i++){
99108
let pos: Vector3 = this.children[i].position.clone();
100109
cram.state.renderer.markup.addPoint([pos.x,pos.y,pos.z], [0,0,0]);
101-
102110
if (this.children[i].hasChildren){
103111
this.children[i].markup();
104112
}else{
@@ -131,6 +139,7 @@ class ImageSource{
131139
interface intersection{
132140
point: Vector3;
133141
reflectingSurface: Surface | null;
142+
angle: number | null;
134143
}
135144

136145
class ImageSourcePath{
@@ -149,38 +158,40 @@ class ImageSourcePath{
149158
}
150159
}
151160

152-
isvalid(room_surfaces: Surface[]){
153-
for(let order = 1; order <= this.order; order++){
161+
isvalid(room_surfaces: Surface[]): boolean{
162+
163+
for(let order = 1; order <= this.order+1; order++){
164+
154165
let segmentStart: Vector3 = this.path[order-1].point;
155166
let segmentEnd: Vector3 = this.path[order].point;
156167

157-
let prevReflector: Surface | null;
158-
if(this.path[order-1].reflectingSurface != null){
159-
prevReflector = this.path[order-1].reflectingSurface;
160-
}else{
161-
break;
162-
}
163-
164-
let reflector: Surface | null;
165-
if(this.path[order].reflectingSurface != null){
166-
reflector = this.path[order].reflectingSurface;
167-
}else{
168-
break;
169-
}
168+
let prevReflector: Surface | null = this.path[order-1].reflectingSurface;
169+
let reflector: Surface | null = this.path[order].reflectingSurface;
170170

171171
for(let j = 1; j<room_surfaces.length; j++){
172-
if((room_surfaces[j] != prevReflector) && (room_surfaces[j] != reflector)){
173-
174-
let direction: Vector3 = new Vector3(0,0,0); // from current image source to last image source / receiver
172+
if((room_surfaces[j] !== prevReflector) && (room_surfaces[j] !== reflector)){
173+
174+
// from current image source to last image source / receiver
175+
let direction: Vector3 = new Vector3(0,0,0);
175176
direction.subVectors(segmentEnd, segmentStart);
176177
direction.normalize();
177178

178179
let raycaster = new THREE.Raycaster;
179180
raycaster.set(segmentStart,direction);
180181
let intersections;
181-
intersections = raycaster.intersectObject(room_surfaces[j], true);
182+
intersections = raycaster.intersectObject(room_surfaces[j].mesh, true);
183+
184+
// remove any intersections of surfaces BEHIND the desired end point
185+
// (verify this)
186+
let trueIntersections = [];
187+
for(let i = 0; i<intersections.length; i++){
188+
if(segmentStart.distanceTo(intersections[i].point) < segmentStart.distanceTo(segmentEnd)){
189+
//@ts-ignore
190+
trueIntersections.push(intersections[i]);
191+
}
192+
}
182193

183-
if (intersections.length > 0){
194+
if (trueIntersections.length > 0){
184195
return false;
185196
}
186197
}
@@ -193,6 +204,60 @@ class ImageSourcePath{
193204
public get order(){
194205
return this.path.length - 2;
195206
}
207+
208+
public get totalLength(){
209+
let length: number = 0;
210+
let startingPoint: Vector3;
211+
let endingPoint: Vector3;
212+
for(let i = 1; i<this.path.length; i++){
213+
startingPoint = this.path[i-1].point;
214+
endingPoint = this.path[i].point;
215+
length = length+startingPoint.distanceTo(endingPoint);
216+
}
217+
return length;
218+
}
219+
220+
public arrivalPressure(initialSPL: number[], freqs: number[]): number[]{
221+
222+
let intensity = ac.P2I(ac.Lp2P(initialSPL));
223+
let arrivalPressure = [];
224+
225+
for(let s = 0; s<this.path.length; s++){
226+
227+
let intersection = this.path[s];
228+
if(intersection.reflectingSurface == null){
229+
// either source or a receiver
230+
// do nothing to intensity levels
231+
}else{
232+
// intersected with a surface
233+
for(let findex = 0; findex<freqs.length; findex++){
234+
// @ts-ignore
235+
let reflectionCoefficient = (intersection.reflectingSurface as Surface).reflectionFunction(freqs[findex],intersection.angle);
236+
intensity[findex] = intensity[findex]*reflectionCoefficient;
237+
}
238+
239+
}
240+
241+
}
242+
243+
// convert back to SPL
244+
let arrivalLp = ac.P2Lp(ac.I2P(intensity));
245+
246+
// apply air absorption (dB/m)
247+
const airAttenuationdB = ac.airAttenuation(freqs);
248+
249+
for(let f = 0; f<freqs.length; f++){
250+
arrivalLp[f] = arrivalLp[f] - airAttenuationdB[f]*this.totalLength;
251+
}
252+
253+
// convert to pressure
254+
return ac.Lp2P(arrivalLp) as number[];
255+
256+
}
257+
258+
public arrivalTime(c: number): number{
259+
return this.totalLength / c;
260+
}
196261
}
197262

198263
export interface ImageSourceSolverParams {
@@ -276,7 +341,7 @@ export class ImageSourceSolver extends Solver {
276341

277342
let is: ImageSource = new ImageSource(is_params);
278343

279-
let maxOrder = 1;
344+
let maxOrder = 3;
280345
let is_2 = computeImageSources(is,maxOrder);
281346
is_2?.markup();
282347
console.log(is_2);
@@ -287,7 +352,22 @@ export class ImageSourceSolver extends Solver {
287352
let paths: ImageSourcePath[];
288353
if(is_2 != null){
289354
paths = is_2.constructPathsForAllDescendents(receiver);
290-
console.log(paths);
355+
356+
let f = [125, 250, 500, 1000, 2000, 4000];
357+
let initialSPL = [100,100,100,100,100,100];
358+
359+
let validCount = 0;
360+
for(let i = 0; i<paths.length; i++){
361+
if(paths[i].isvalid(this.room.surfaces.children as Surface[])){
362+
paths[i].markup();
363+
console.log(paths[i]);
364+
console.log(paths[i].totalLength)
365+
console.log(paths[i].arrivalTime(343));
366+
console.log(paths[i].arrivalPressure(initialSPL,f))
367+
validCount++;
368+
}
369+
}
370+
console.log(validCount + " out of " + paths.length + " paths are valid");
291371
}
292372
}
293373

@@ -367,8 +447,8 @@ function computeImageSources(is: ImageSource, maxOrder: number): ImageSource | n
367447
}
368448

369449
function constructImageSourcePath(is: ImageSource, listener: Receiver): ImageSourcePath | null{
370-
// note: will return null
371-
// otherwise, will return array of Vector3's representing path
450+
// note: will return null if no valid path
451+
// otherwise, will return ImageSourcePath object representing path
372452

373453
let path: intersection[] = [];
374454

@@ -377,6 +457,7 @@ function constructImageSourcePath(is: ImageSource, listener: Receiver): ImageSou
377457
let listenerStart: intersection = {
378458
point: listener.position.clone(),
379459
reflectingSurface: null,
460+
angle: null,
380461
}
381462
path[maxOrder+1] = listenerStart;
382463

@@ -393,18 +474,15 @@ function constructImageSourcePath(is: ImageSource, listener: Receiver): ImageSou
393474
raycaster.set(lastPosition,direction);
394475
let intersections;
395476
if(is.reflector != null){
396-
intersections = raycaster.intersectObject(is.reflector,true);
477+
intersections = raycaster.intersectObject(is.reflector.mesh,true);
397478
}
398-
399-
console.log(is);
400-
console.log(order);
401-
console.log(intersections);
402479

403480
if(intersections.length>0){
404481

405482
let intersect: intersection = {
406483
point: intersections[0].point,
407484
reflectingSurface: is.reflector,
485+
angle: direction.clone().multiplyScalar(-1).angleTo(intersections[0].face!.normal),
408486
};
409487

410488
path[order] = intersect;
@@ -421,6 +499,7 @@ function constructImageSourcePath(is: ImageSource, listener: Receiver): ImageSou
421499
let sourceEnd: intersection = {
422500
point: is.position.clone(),
423501
reflectingSurface: null,
502+
angle: null,
424503
};
425504

426505
path[0] = sourceEnd;
@@ -429,7 +508,7 @@ function constructImageSourcePath(is: ImageSource, listener: Receiver): ImageSou
429508
}
430509

431510
function isInFrontOf(surface1: Surface, surface2: Surface): boolean{
432-
// how to check this?
511+
// figure out how to check this
433512
return true;
434513
}
435514

src/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1232,7 +1232,7 @@ window.addEventListener("resize", () => {
12321232
});
12331233

12341234
async function finishedLoading() {
1235-
const filepath = "/res/saves/shoebox.json";
1235+
const filepath = "/res/saves/concord.json";
12361236
const filename = filepath.slice(filepath.lastIndexOf("/") + 1);
12371237
const filedata = await(await fetch(filepath)).text();
12381238
const json = JSON.parse(filedata);

0 commit comments

Comments
 (0)