2222import Solver from "../../solver" ;
2323import { uuid } from "uuidv4" ;
2424import * as THREE from "three" ;
25+ import * as ac from "../../acoustics" ;
2526import Room from "../../../objects/room" ;
2627import Messenger from "../../../messenger" ;
2728import { KVP } from "../../../common/key-value-pair" ;
@@ -34,6 +35,7 @@ import Surface from "../../../objects/surface";
3435import { LensTwoTone , ThreeSixtyOutlined } from "@material-ui/icons" ;
3536import { cloneElement } from "react" ;
3637import { SSL_OP_SSLEAY_080_CLIENT_DH_BUG } from "constants" ;
38+ import { intersection } from "lodash" ;
3739
3840interface ImageSourceParams {
3941 baseSource : Source ,
@@ -46,6 +48,8 @@ interface ImageSourceParams {
4648
4749class 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{
131139interface intersection {
132140 point : Vector3 ;
133141 reflectingSurface : Surface | null ;
142+ angle : number | null ;
134143}
135144
136145class 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
198263export 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
369449function 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
431510function isInFrontOf ( surface1 : Surface , surface2 : Surface ) : boolean {
432- // how to check this?
511+ // figure out how to check this
433512 return true ;
434513}
435514
0 commit comments