phetsims / bending-light

"Bending Light" is an educational simulation in HTML5, by PhET Interactive Simulations.
http://phet.colorado.edu/en/simulation/bending-light
GNU General Public License v3.0
8 stars 8 forks source link

Intensity Sensor intercepts refracted beam at odd positions #357

Open EthanWJohnson opened 8 years ago

EthanWJohnson commented 8 years ago

Tested on: Chrome, Firefox, Edge, and PhET App

OS: Windows 10 and iOS 10.0.1

Best explained via gif; odd positioning

The lower part of the intensity sensor can intercept the lower beam, even when not touching it, from above.

Strange positioning for intercept affects all refraction indexes, but is most pronounced when the lower material has a high refraction index.

Bug/issue is also present on the sim currently on the website.

RELATION: https://github.com/phetsims/tasks/issues/682

Troubleshooting information (do not edit): Name: ‪Bending Light‬ URL: http://www.colorado.edu/physics/phet/dev/html/bending-light/1.1.0-rc.1/bending-light_en.html Version: 1.1.0-rc.1 2016-08-22 20:48:08 UTC Features missing: touch User Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36 Language: en-US Window: 1366x648 Pixel Ratio: 1/1 WebGL: WebGL 1.0 (OpenGL ES 2.0 Chromium) GLSL: WebGL GLSL ES 1.0 (OpenGL ES GLSL ES 1.0 Chromium) Vendor: WebKit (WebKit WebGL) Vertex: attribs: 16 varying: 30 uniform: 1024 Texture: size: 16384 imageUnits: 16 (vertex: 16, combined: 32) Max viewport: 16384x16384 OES_texture_float: true Dependencies JSON: {"assert":{"sha":"7d27130a","branch":"HEAD"},"axon":{"sha":"1fd91832","branch":"HEAD"},"babel":{"sha":"5e625a61","branch":"master"},"bending-light":{"sha":"09962afa","branch":"HEAD"},"brand":{"sha":"f0b1f7da","branch":"HEAD"},"chipper":{"sha":"136b1d30","branch":"HEAD"},"dot":{"sha":"6e8a26f2","branch":"HEAD"},"joist":{"sha":"ab5582ab","branch":"HEAD"},"kite":{"sha":"88f0c3a0","branch":"HEAD"},"phet-core":{"sha":"c48bf320","branch":"HEAD"},"phetcommon":{"sha":"83ea84c8","branch":"HEAD"},"scenery":{"sha":"0ab22ac3","branch":"HEAD"},"scenery-phet":{"sha":"04cec216","branch":"HEAD"},"sherpa":{"sha":"5ddfccd4","branch":"HEAD"},"sun":{"sha":"061f2ea9","branch":"HEAD"},"tandem":{"sha":"43ebdfb3","branch":"HEAD"}}

samreid commented 8 years ago

@ariel-phet could you help me prioritize/schedule this?

ariel-phet commented 8 years ago

Should be fixed, but marking priority deferred for the moment, until we can get a chunk of @samreid time

samreid commented 4 days ago

I tried this approach and it had similar issues:

```diff Subject: [PATCH] Check each ray to see if it is emitted from within the medium, see https://github.com/phetsims/bending-light/issues/358 --- Index: js/common/model/LightRay.ts IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== diff --git a/js/common/model/LightRay.ts b/js/common/model/LightRay.ts --- a/js/common/model/LightRay.ts (revision c9d2238f4bdb18075912f93a8ed18a107b898819) +++ b/js/common/model/LightRay.ts (date 1732281351835) @@ -16,6 +16,7 @@ import BendingLightConstants from '../BendingLightConstants.js'; import WaveParticle from './WaveParticle.js'; import LaserViewEnum from './LaserViewEnum.js'; +import Utils from '../../../../dot/js/Utils.js'; // constants @@ -201,31 +202,23 @@ /** * Check to see if this light ray hits the specified sensor region * @param sensorRegion - sensor region of intensity meter - * @param rayType - 'incident', 'transmitted' or 'reflected' + * @param rayType */ - public getIntersections( sensorRegion: Shape, rayType: string ): RayIntersection[] { + public getIntersections( sensorRegion: Shape, rayType: 'incident' | 'transmitted' | 'reflected' ): RayIntersection[] { if ( this.waveShape ) { - // Create a ray that is parallel to the light ray and within the beam width that is closest to the center - // of the sensor. This is the most straightforward way to check for the closest intersection to the sensor - // region. - const p = sensorRegion.getBounds().center; - - const tip = this.tip; - const tail = this.tail; - - // Compute the distance from the sensor to the ray, using - // https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line - const n = tip.minus( tail ).normalized(); - const a = tail; - const aMinusP = a.minus( p ); - let distanceToRay = aMinusP.minus( n.timesScalar( aMinusP.dot( n ) ) ).magnitude; - + // Sample 10 rays across the breadth of the beam and aggregate all hits. const perpendicular = Vector2.createPolar( 1, this.getAngle() + Math.PI / 2 ); - const sign = perpendicular.dot( p.minus( a ) ) < 0 ? -1 : +1; - distanceToRay = sign * Math.min( distanceToRay, this.waveWidth / 2 ); - return sensorRegion.intersection( this.createParallelRay( distanceToRay, rayType ) ); + const sign = perpendicular.dot( sensorRegion.getBounds().center.minus( this.tail ) ) < 0 ? -1 : +1; + + const allIntersections: RayIntersection[] = []; + for ( let i = 0; i < 10; i++ ) { + const span = Utils.linear( 0, 10, -this.waveWidth / 2, this.waveWidth / 2, i ); + const intersections = sensorRegion.intersection( this.createParallelRay( sign * span, rayType ) ); + allIntersections.push( ...intersections ); + } + return allIntersections; } else { const direction = Vector2.createPolar( 1, this.getAngle() + ( rayType === 'incident' ? Math.PI : 0 ) ); Index: js/intro/model/IntroModel.ts IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== diff --git a/js/intro/model/IntroModel.ts b/js/intro/model/IntroModel.ts --- a/js/intro/model/IntroModel.ts (revision c9d2238f4bdb18075912f93a8ed18a107b898819) +++ b/js/intro/model/IntroModel.ts (date 1732281351821) @@ -287,20 +287,24 @@ // if it intersected, then absorb the ray let rayAbsorbed = intersects.length > 0; if ( rayAbsorbed ) { - let x; - let y; - assert && assert( intersects.length <= 2, 'too many intersections' ); - if ( intersects.length === 1 ) { + // let x; + // let y; + // assert && assert( intersects.length <= 2, 'too many intersections' ); + // if ( intersects.length === 1 ) { + // + // // intersect point at sensor shape start position when laser within sensor region + // x = intersects[ 0 ].point.x; + // y = intersects[ 0 ].point.y; + // } + // else { + // assert && assert( intersects.length === 2 ); + // x = ( intersects[ 0 ].point.x + intersects[ 1 ].point.x ) / 2; + // y = ( intersects[ 0 ].point.y + intersects[ 1 ].point.y ) / 2; + // } - // intersect point at sensor shape start position when laser within sensor region - x = intersects[ 0 ].point.x; - y = intersects[ 0 ].point.y; - } - else { - assert && assert( intersects.length === 2 ); - x = ( intersects[ 0 ].point.x + intersects[ 1 ].point.x ) / 2; - y = ( intersects[ 0 ].point.y + intersects[ 1 ].point.y ) / 2; - } + // average all intersections, no matter how many + const x = intersects.reduce( ( sum, intersection ) => sum + intersection.point.x, 0 ) / intersects.length; + const y = intersects.reduce( ( sum, intersection ) => sum + intersection.point.y, 0 ) / intersects.length; const distance = Math.sqrt( x * x + y * y ); const interrupted = new LightRay( ```

Having investigated this again, I think if we decide to solve it, I would schedule 2x developers to collaborate for about 8 hours.