diff --git a/js/energy-skate-park-basics/model/EnergySkateParkBasicsModel.js b/js/energy-skate-park-basics/model/EnergySkateParkBasicsModel.js index d39f5bf7..41e99638 100644 --- a/js/energy-skate-park-basics/model/EnergySkateParkBasicsModel.js +++ b/js/energy-skate-park-basics/model/EnergySkateParkBasicsModel.js @@ -531,7 +531,7 @@ define( function( require ) { } } if ( closestTrack ) { - return { track: closestTrack, u: closestMatch.u, point: closestMatch.point }; + return { track: closestTrack, parametricPosition: closestMatch.parametricPosition, point: closestMatch.point }; } else { return null; @@ -541,10 +541,10 @@ define( function( require ) { // Check to see if the points crossed the track crossedTrack: function( closestTrackAndPositionAndParameter, physicalTracks, beforeX, beforeY, afterX, afterY ) { var track = closestTrackAndPositionAndParameter.track; - var u = closestTrackAndPositionAndParameter.u; + var parametricPosition = closestTrackAndPositionAndParameter.parametricPosition; var trackPoint = closestTrackAndPositionAndParameter.point; - if ( !track.isParameterInBounds( u ) ) { + if ( !track.isParameterInBounds( parametricPosition ) ) { return false; } else { @@ -552,7 +552,7 @@ define( function( require ) { // Linearize the spline, and check to see if the skater crossed by performing a line segment intersection between // the skater's trajectory segment and the linearized track segment. // Note, this has an error for cusps, see #212 - var unitParallelVector = track.getUnitParallelVector( u ); + var unitParallelVector = track.getUnitParallelVector( parametricPosition ); var a = trackPoint.plus( unitParallelVector.times( 100 ) ); var b = trackPoint.plus( unitParallelVector.times( -100 ) ); var intersection = Util.lineSegmentIntersection( a.x, a.y, b.x, b.y, beforeX, beforeY, afterX, afterY ); @@ -588,12 +588,12 @@ define( function( require ) { skaterState.positionX, skaterState.positionY, proposedPosition.x, proposedPosition.y ); var track = closestTrackAndPositionAndParameter.track; - var u = closestTrackAndPositionAndParameter.u; + var parametricPosition = closestTrackAndPositionAndParameter.parametricPosition; var trackPoint = closestTrackAndPositionAndParameter.point; if ( crossed ) { debugAttachDetach && debugAttachDetach( 'attaching' ); - var normal = track.getUnitNormalVector( u ); + var normal = track.getUnitNormalVector( parametricPosition ); var segment = normal.perpendicular(); var beforeVector = skaterState.getPosition().minus( trackPoint ); @@ -602,7 +602,7 @@ define( function( require ) { var newVelocity = segment.times( segment.dot( proposedVelocity ) ); var newSpeed = newVelocity.magnitude(); var newKineticEnergy = 0.5 * skaterState.mass * newVelocity.magnitudeSquared(); - var newPosition = track.getPoint( u ); + var newPosition = track.getPoint( parametricPosition ); var newPotentialEnergy = -skaterState.mass * skaterState.gravity * newPosition.y; var newThermalEnergy = initialEnergy - newKineticEnergy - newPotentialEnergy; @@ -631,25 +631,25 @@ define( function( require ) { assert && assert( isFinite( newThermalEnergy ) ); assert && assert( newThermalEnergy >= 0 ); - var uD = (dot > 0 ? +1 : -1) * newSpeed; - var up = beforeVector.dot( normal ) > 0; + var parametricSpeed = (dot > 0 ? +1 : -1) * newSpeed; + var onTopSideOfTrack = beforeVector.dot( normal ) > 0; - debug && debug( 'attach to track, ' + ', ' + u + ', ' + track.maxPoint ); + debug && debug( 'attach to track, ' + ', ' + parametricPosition + ', ' + track.maxPoint ); - // Double check the velocities and invert uD if incorrect, see #172 + // Double check the velocities and invert parametricSpeed if incorrect, see #172 // Compute the new velocities same as in stepTrack - var unitParallelVector = track.getUnitParallelVector( u ); - var newVelocityX = unitParallelVector.x * uD; - var newVelocityY = unitParallelVector.y * uD; + var unitParallelVector = track.getUnitParallelVector( parametricPosition ); + var newVelocityX = unitParallelVector.x * parametricSpeed; + var newVelocityY = unitParallelVector.y * parametricSpeed; var velocityDotted = skaterState.velocityX * newVelocityX + skaterState.velocityY * newVelocityY; // See if the track attachment will cause velocity to flip, and inverse it if so, see #172 if ( velocityDotted < -1E-6 ) { - uD = uD * -1; + parametricSpeed = parametricSpeed * -1; } - return skaterState.attachToTrack( newThermalEnergy, track, up, u, uD, newVelocity.x, newVelocity.y, newPosition.x, newPosition.y ); + return skaterState.attachToTrack( newThermalEnergy, track, onTopSideOfTrack, parametricPosition, parametricSpeed, newVelocity.x, newVelocity.y, newPosition.x, newPosition.y ); } // It just continued in free fall @@ -762,9 +762,9 @@ define( function( require ) { var origLocX = skaterState.positionX; var origLocY = skaterState.positionY; var thermalEnergy = skaterState.thermalEnergy; - var uD = skaterState.uD; - assert && assert( isFinite( uD ) ); - var u = skaterState.u; + var parametricSpeed = skaterState.parametricSpeed; + assert && assert( isFinite( parametricSpeed ) ); + var parametricPosition = skaterState.parametricPosition; // Component-wise math to prevent allocations, see #50 var netForceX = this.getNetForceWithoutNormalX( skaterState ); @@ -773,18 +773,18 @@ define( function( require ) { var netForceAngle = Math.atan2( netForceY, netForceX ); // Get the net force in the direction of the track. Dot product is a * b * cos(theta) - var a = netForceMagnitude * Math.cos( skaterState.track.getModelAngleAt( u ) - netForceAngle ) / skaterState.mass; - - uD += a * dt; - assert && assert( isFinite( uD ), 'uD should be finite' ); - u += track.getParametricDistance( u, uD * dt + 1 / 2 * a * dt * dt ); - var newPointX = skaterState.track.getX( u ); - var newPointY = skaterState.track.getY( u ); - var unitParallelVector = skaterState.track.getUnitParallelVector( u ); + var a = netForceMagnitude * Math.cos( skaterState.track.getModelAngleAt( parametricPosition ) - netForceAngle ) / skaterState.mass; + + parametricSpeed += a * dt; + assert && assert( isFinite( parametricSpeed ), 'parametricSpeed should be finite' ); + parametricPosition += track.getParametricDistance( parametricPosition, parametricSpeed * dt + 1 / 2 * a * dt * dt ); + var newPointX = skaterState.track.getX( parametricPosition ); + var newPointY = skaterState.track.getY( parametricPosition ); + var unitParallelVector = skaterState.track.getUnitParallelVector( parametricPosition ); var parallelUnitX = unitParallelVector.x; var parallelUnitY = unitParallelVector.y; - var newVelocityX = parallelUnitX * uD; - var newVelocityY = parallelUnitY * uD; + var newVelocityX = parallelUnitX * parametricSpeed; + var newVelocityY = parallelUnitY * parametricSpeed; // Exponentially decay the velocity if already nearly zero and on a flat slope, see #129 if ( parallelUnitX / parallelUnitY > 5 && Math.sqrt( newVelocityX * newVelocityX + newVelocityY * newVelocityY ) < 1E-2 ) { @@ -793,7 +793,7 @@ define( function( require ) { } // choose velocity by using the unit parallel vector to the track - var newState = skaterState.updateUUDVelocityPosition( u, uD, newVelocityX, newVelocityY, newPointX, newPointY ); + var newState = skaterState.updateUUDVelocityPosition( parametricPosition, parametricSpeed, newVelocityX, newVelocityY, newPointX, newPointY ); if ( this.friction > 0 ) { // Compute friction force magnitude component-wise to prevent allocations, see #50 @@ -850,17 +850,17 @@ define( function( require ) { var curvatureDirectionY = this.getCurvatureDirectionY( this.curvatureTemp, skaterState.positionX, skaterState.positionY ); var track = skaterState.track; - var sideVectorX = skaterState.up ? track.getUnitNormalVector( skaterState.u ).x : - track.getUnitNormalVector( skaterState.u ).x * -1; - var sideVectorY = skaterState.up ? track.getUnitNormalVector( skaterState.u ).y : - track.getUnitNormalVector( skaterState.u ).y * -1; + var sideVectorX = skaterState.onTopSideOfTrack ? track.getUnitNormalVector( skaterState.parametricPosition ).x : + track.getUnitNormalVector( skaterState.parametricPosition ).x * -1; + var sideVectorY = skaterState.onTopSideOfTrack ? track.getUnitNormalVector( skaterState.parametricPosition ).y : + track.getUnitNormalVector( skaterState.parametricPosition ).y * -1; // Dot product written out component-wise to avoid allocations, see #50 var outsideCircle = sideVectorX * curvatureDirectionX + sideVectorY * curvatureDirectionY < 0; // compare a to v/r^2 to see if it leaves the track var r = Math.abs( this.curvatureTemp.r ); - var centripetalForce = skaterState.mass * skaterState.uD * skaterState.uD / r; + var centripetalForce = skaterState.mass * skaterState.parametricSpeed * skaterState.parametricSpeed / r; var netForceWithoutNormalX = this.getNetForceWithoutNormalX( skaterState ); var netForceWithoutNormalY = this.getNetForceWithoutNormalY( skaterState ); @@ -898,24 +898,24 @@ define( function( require ) { var correctedState = this.correctEnergy( skaterState, newState ); // Check whether the skater has left the track - if ( skaterState.track.isParameterInBounds( correctedState.u ) ) { + if ( skaterState.track.isParameterInBounds( correctedState.parametricPosition ) ) { return correctedState; } else { // Fly off the left or right side of the track // Off the edge of the track. If the skater transitions from the right edge of the 2nd track directly to the // ground then do not lose thermal energy during the transition, see #164 - if ( correctedState.u > skaterState.track.maxPoint && skaterState.track.slopeToGround ) { + if ( correctedState.parametricPosition > skaterState.track.maxPoint && skaterState.track.slopeToGround ) { var result = correctedState.switchToGround( correctedState.thermalEnergy, correctedState.getSpeed(), 0, correctedState.positionX, 0 ); // Correct the energy discrepancy when switching to the ground, see #301 return this.correctEnergy( skaterState, result ); } else { - debugAttachDetach && debugAttachDetach( 'left edge track: ' + correctedState.u + ', ' + skaterState.track.maxPoint ); + debugAttachDetach && debugAttachDetach( 'left edge track: ' + correctedState.parametricPosition + ', ' + skaterState.track.maxPoint ); // There is a situation in which the `u` of the skater exceeds the track bounds before the - // getClosestPositionAndParameter.u does, which can cause the skater to immediately reattach + // getClosestPositionAndParameter.parametricPosition does, which can cause the skater to immediately reattach // So make sure the skater is far enough from the track so it won't reattach right away, see #167 var freeSkaterState = skaterState.updateTrackUD( null, 0 ); @@ -961,18 +961,18 @@ define( function( require ) { var mass = skaterState.mass; // Find the direction of velocity. This is on the track unless the skater just left the "slope" track - var unit = newSkaterState.track ? newSkaterState.track.getUnitParallelVector( newSkaterState.u ) : + var unit = newSkaterState.track ? newSkaterState.track.getUnitParallelVector( newSkaterState.parametricPosition ) : newSkaterState.getVelocity().normalized(); // Binary search, but bail after too many iterations for ( var i = 0; i < 100; i++ ) { - var dv = ( newSkaterState.getTotalEnergy() - e0 ) / ( mass * newSkaterState.uD ); + var dv = ( newSkaterState.getTotalEnergy() - e0 ) / ( mass * newSkaterState.parametricSpeed ); - var newVelocity = newSkaterState.uD - dv; + var newVelocity = newSkaterState.parametricSpeed - dv; // We can just set the state directly instead of calling update since we are keeping a protected clone of the // newSkaterState - newSkaterState.uD = newVelocity; + newSkaterState.parametricSpeed = newVelocity; var result = unit.times( newVelocity ); newSkaterState.velocityX = result.x; newSkaterState.velocityY = result.y; @@ -1009,7 +1009,7 @@ define( function( require ) { if ( this.trackChangePending ) { return newState; } - var u0 = skaterState.u; + var u0 = skaterState.parametricPosition; var e0 = skaterState.getTotalEnergy(); if ( !isFinite( newState.getTotalEnergy() ) ) { throw new Error( 'not finite' );} @@ -1042,9 +1042,9 @@ define( function( require ) { // search for a place between u and u0 with a better energy var numRecursiveSearches = 10; - var u = newState.u; - var bestAlpha = ( u + u0 ) / 2.0; - var da = ( u - u0 ) / 2; + var parametricPosition = newState.parametricPosition; + var bestAlpha = ( parametricPosition + u0 ) / 2.0; + var da = ( parametricPosition - u0 ) / 2; for ( var i = 0; i < numRecursiveSearches; i++ ) { var numSteps = 10; bestAlpha = this.searchSplineForEnergy( newState, bestAlpha - da, bestAlpha + da, e0, numSteps ); @@ -1086,9 +1086,9 @@ define( function( require ) { var vSq = Math.abs( 2 / newState.mass * ( e0 - newState.getPotentialEnergy() - newState.thermalEnergy ) ); var v = Math.sqrt( vSq ); - // TODO: What if uD ===0? - var newVelocity = v * (newState.uD > 0 ? +1 : -1); - var unitParallelVector = newState.track.getUnitParallelVector( newState.u ); + // TODO: What if parametricSpeed ===0? + var newVelocity = v * (newState.parametricSpeed > 0 ? +1 : -1); + var unitParallelVector = newState.track.getUnitParallelVector( newState.parametricPosition ); var updatedVelocityX = unitParallelVector.x * newVelocity; var updatedVelocityY = unitParallelVector.y * newVelocity; var fixedState = newState.updateUDVelocity( newVelocity, updatedVelocityX, updatedVelocityY ); @@ -1371,17 +1371,17 @@ define( function( require ) { // Note: Energy is not conserved when tracks joined since the user has added or removed energy from the system if ( this.skater.track === a || this.skater.track === b ) { - var originalDirectionVector = this.skater.track.getUnitParallelVector( this.skater.u ).times( this.skater.uD ); + var originalDirectionVector = this.skater.track.getUnitParallelVector( this.skater.parametricPosition ).times( this.skater.parametricSpeed ); // Keep track of the skater direction so we can toggle the 'up' flag if the track orientation changed var originalNormal = this.skater.upVector; var p = newTrack.getClosestPositionAndParameter( this.skater.position.copy() ); this.skater.track = newTrack; - this.skater.u = p.u; - var x2 = newTrack.getX( p.u ); - var y2 = newTrack.getY( p.u ); + this.skater.parametricPosition = p.parametricPosition; + var x2 = newTrack.getX( p.parametricPosition ); + var y2 = newTrack.getY( p.parametricPosition ); this.skater.position = new Vector2( x2, y2 ); - this.skater.angle = newTrack.getViewAngleAt( p.u ) + (this.skater.up ? 0 : Math.PI); + this.skater.angle = newTrack.getViewAngleAt( p.parametricPosition ) + (this.skater.onTopSideOfTrack ? 0 : Math.PI); // Trigger an initial update now so we can get the right up vector, see #150 this.skater.trigger( 'updated' ); @@ -1389,17 +1389,17 @@ define( function( require ) { // If the skater flipped upside down because the track directionality is different, toggle his 'up' flag if ( originalNormal.dot( newNormal ) < 0 ) { - this.skater.up = !this.skater.up; - this.skater.angle = newTrack.getViewAngleAt( p.u ) + (this.skater.up ? 0 : Math.PI); + this.skater.onTopSideOfTrack = !this.skater.onTopSideOfTrack; + this.skater.angle = newTrack.getViewAngleAt( p.parametricPosition ) + (this.skater.onTopSideOfTrack ? 0 : Math.PI); this.skater.trigger( 'updated' ); } // If the skater changed direction of motion because of the track polarity change, flip the parametric velocity - // 'uD' value, see #180 - var newDirectionVector = this.skater.track.getUnitParallelVector( this.skater.u ).times( this.skater.uD ); + // 'parametricSpeed' value, see #180 + var newDirectionVector = this.skater.track.getUnitParallelVector( this.skater.parametricPosition ).times( this.skater.parametricSpeed ); debugAttachDetach && debugAttachDetach( newDirectionVector.dot( originalDirectionVector ) ); if ( newDirectionVector.dot( originalDirectionVector ) < 0 ) { - this.skater.uD = -this.skater.uD; + this.skater.parametricSpeed = -this.skater.parametricSpeed; } } diff --git a/js/energy-skate-park-basics/model/Skater.js b/js/energy-skate-park-basics/model/Skater.js index eecc79e7..c9a0ec6f 100644 --- a/js/energy-skate-park-basics/model/Skater.js +++ b/js/energy-skate-park-basics/model/Skater.js @@ -52,27 +52,25 @@ define( function( require ) { phetioValueType: TTrack }, - //TODO tandem name does not match Property name, see https://github.com/phetsims/energy-skate-park-basics/issues/358 // Parameter along the parametric spline, unitless since it is in parametric space - u: { + parametricPosition: { value: 0, - tandem: tandem.createTandem( 'skaterParametricDistanceAlongTrackProperty' ), + tandem: tandem.createTandem( 'parametricPositionProperty' ), phetioValueType: TNumber() }, // Speed along the parametric spline dimension, formally 'u dot', indicating speed and direction (+/-) along the // track spline in meters per second. Not technically the derivative of 'u' since it is the euclidean speed. - uD: { + parametricSpeed: { value: 0, - tandem: tandem.createTandem( 'uDProperty' ), + tandem: tandem.createTandem( 'parametricSpeedProperty' ), phetioValueType: TNumber() }, - //TODO tandem name does not match Property name, see https://github.com/phetsims/energy-skate-park-basics/issues/358 // True if the skater is pointing up on the track, false if attached to underside of track - up: { + onTopSideOfTrack: { value: true, - tandem: tandem.createTandem( 'skaterUpsideUpOnTrackProperty' ), + tandem: tandem.createTandem( 'onTopSideOfTrackProperty' ), phetioValueType: TBoolean }, @@ -83,79 +81,69 @@ define( function( require ) { phetioValueType: TNumber( { units: 'meters/second/second' } ) }, - //TODO tandem name does not match Property name, see https://github.com/phetsims/energy-skate-park-basics/issues/358 position: { value: new Vector2( 3.5, 0 ), - tandem: tandem.createTandem( 'skaterPositionProperty' ), + tandem: tandem.createTandem( 'positionProperty' ), phetioValueType: TVector2 }, - //TODO tandem name does not match Property name, see https://github.com/phetsims/energy-skate-park-basics/issues/358 // Start in the middle of the MassControlPanel range mass: { value: Constants.DEFAULT_MASS, - tandem: tandem.createTandem( 'skaterMassProperty' ), + tandem: tandem.createTandem( 'massProperty' ), phetioValueType: TNumber( { units: 'kilograms' } ) }, - //TODO tandem name does not match Property name, see https://github.com/phetsims/energy-skate-park-basics/issues/358 // Which way the skater is facing, right or left. Coded as strings instead of boolean in case we add other states // later like 'forward' direction: { value: 'left', - tandem: tandem.createTandem( 'skaterDirectionProperty' ), + tandem: tandem.createTandem( 'directionProperty' ), phetioValueType: TString }, - //TODO tandem name does not match Property name, see https://github.com/phetsims/energy-skate-park-basics/issues/358 velocity: { value: new Vector2( 0, 0 ), - tandem: tandem.createTandem( 'skaterVelocityProperty' ), + tandem: tandem.createTandem( 'velocityProperty' ), phetioValueType: TVector2 }, - //TODO tandem name does not match Property name, see https://github.com/phetsims/energy-skate-park-basics/issues/358 // True if the user is dragging the skater with a pointer dragging: { value: false, - tandem: tandem.createTandem( 'skaterDraggingProperty' ), + tandem: tandem.createTandem( 'draggingProperty' ), phetioValueType: TBoolean }, - //TODO tandem name does not match Property name, see https://github.com/phetsims/energy-skate-park-basics/issues/358 // Energies are in Joules kineticEnergy: { value: 0, - tandem: tandem.createTandem( 'skaterKineticEnergyProperty' ), + tandem: tandem.createTandem( 'kineticEnergyProperty' ), phetioValueType: TNumber( { units: 'joules' } ) }, - //TODO tandem name does not match Property name, see https://github.com/phetsims/energy-skate-park-basics/issues/358 potentialEnergy: { value: 0, - tandem: tandem.createTandem( 'skaterPotentialEnergyProperty' ), + tandem: tandem.createTandem( 'potentialEnergyProperty' ), phetioValueType: TNumber( { units: 'joules' } ) }, - //TODO tandem name does not match Property name, see https://github.com/phetsims/energy-skate-park-basics/issues/358 thermalEnergy: { value: 0, - tandem: tandem.createTandem( 'skaterThermalEnergyProperty' ), + tandem: tandem.createTandem( 'thermalEnergyProperty' ), phetioValueType: TNumber( { units: 'joules' } ) }, - //TODO tandem name does not match Property name, see https://github.com/phetsims/energy-skate-park-basics/issues/358 totalEnergy: { value: 0, - tandem: tandem.createTandem( 'skaterTotalEnergyProperty' ), + tandem: tandem.createTandem( 'totalEnergyProperty' ), phetioValueType: TNumber( { units: 'joules' } ) }, - //TODO tandem name does not match Property name, see https://github.com/phetsims/energy-skate-park-basics/issues/358 // The skater's angle (about the pivot point at the bottom center), in radians angle: { value: 0, - tandem: tandem.createTandem( 'skaterAngleProperty' ), + tandem: tandem.createTandem( 'angleProperty' ), phetioValueType: TNumber( { units: 'radians' } ) }, @@ -211,17 +199,17 @@ define( function( require ) { } } ); - this.link( 'uD', function( uD ) { + this.parametricSpeedProperty.link( function( parametricSpeed ) { // Require the skater to overcome a speed threshold so he won't toggle back and forth rapidly at the bottom of a // well with friction, see #51 var speedThreshold = 0.01; - if ( uD > speedThreshold ) { - self.direction = self.up ? 'right' : 'left'; + if ( parametricSpeed > speedThreshold ) { + self.direction = self.onTopSideOfTrack ? 'right' : 'left'; } - else if ( uD < -speedThreshold ) { - self.direction = self.up ? 'left' : 'right'; + else if ( parametricSpeed < -speedThreshold ) { + self.direction = self.onTopSideOfTrack ? 'left' : 'right'; } else { // Keep the same direction @@ -317,10 +305,10 @@ define( function( require ) { // If the user is on the same track as where he began (and the track hasn't changed), remain on the track, // see #143 and #144 if ( this.startingTrack && this.track === this.startingTrack && arrayEquals( this.track.copyControlPointSources(), this.startingTrackControlPointSources ) ) { - this.u = this.startingU; + this.parametricPosition = this.startingU; this.angle = this.startingAngle; - this.up = this.startingUp; - this.uD = 0; + this.onTopSideOfTrack = this.startingUp; + this.parametricSpeed = 0; } else { this.track = null; @@ -371,15 +359,15 @@ define( function( require ) { released: function( targetTrack, targetU ) { this.dragging = false; this.velocity = new Vector2( 0, 0 ); - this.uD = 0; + this.parametricSpeed = 0; this.track = targetTrack; - this.u = targetU; + this.parametricPosition = targetU; if ( targetTrack ) { - this.position = targetTrack.getPoint( this.u ); + this.position = targetTrack.getPoint( this.parametricPosition ); } this.startingPosition = this.position.copy(); this.startingU = targetU; - this.startingUp = this.up; + this.startingUp = this.onTopSideOfTrack; this.startingTrack = targetTrack; // Record the starting track control points to make sure the track hasn't changed during return this. diff --git a/js/energy-skate-park-basics/model/SkaterState.js b/js/energy-skate-park-basics/model/SkaterState.js index 50d16d10..1eae2dd4 100644 --- a/js/energy-skate-park-basics/model/SkaterState.js +++ b/js/energy-skate-park-basics/model/SkaterState.js @@ -71,9 +71,9 @@ define( function( require ) { // Special handling for values that can be null, false or zero this.track = 'track' in overrides ? overrides.track : source.track; this.angle = 'angle' in overrides ? overrides.angle : source.angle; - this.up = 'up' in overrides ? overrides.up : source.up; - this.u = 'u' in overrides ? overrides.u : source.u; - this.uD = 'uD' in overrides ? overrides.uD : source.uD; + this.onTopSideOfTrack = 'onTopSideOfTrack' in overrides ? overrides.onTopSideOfTrack : source.onTopSideOfTrack; + this.parametricPosition = 'parametricPosition' in overrides ? overrides.parametricPosition : source.parametricPosition; + this.parametricSpeed = 'parametricSpeed' in overrides ? overrides.parametricSpeed : source.parametricSpeed; this.dragging = 'dragging' in overrides ? overrides.dragging : source.dragging; this.thermalEnergy = 'thermalEnergy' in overrides ? overrides.thermalEnergy : source.thermalEnergy; @@ -81,7 +81,7 @@ define( function( require ) { assert && assert( isFinite( this.thermalEnergy ) ); assert && assert( isFinite( this.velocityX ) ); assert && assert( isFinite( this.velocityY ) ); - assert && assert( isFinite( this.uD ) ); + assert && assert( isFinite( this.parametricSpeed ) ); assert && assert( this.thermalEnergy >= 0 ); @@ -105,7 +105,7 @@ define( function( require ) { // Get the curvature at the skater's point on the track, by setting it to the pass-by-reference argument getCurvature: function( curvature ) { - this.track.getCurvature( this.u, curvature ); + this.track.getCurvature( this.parametricPosition, curvature ); }, // Only set values that have changed @@ -121,29 +121,29 @@ define( function( require ) { skater.velocity.y = this.velocityY; skater.velocityProperty.notifyObserversStatic(); - skater.u = this.u; - skater.uD = this.uD; + skater.parametricPosition = this.parametricPosition; + skater.parametricSpeed = this.parametricSpeed; skater.thermalEnergy = this.thermalEnergy; - skater.up = this.up; - skater.angle = skater.track ? skater.track.getViewAngleAt( this.u ) + (this.up ? 0 : Math.PI) : this.angle; + skater.onTopSideOfTrack = this.onTopSideOfTrack; + skater.angle = skater.track ? skater.track.getViewAngleAt( this.parametricPosition ) + (this.onTopSideOfTrack ? 0 : Math.PI) : this.angle; skater.updateEnergy(); }, // Create a new SkaterState with the new values. Provided as a convenience to avoid allocating options argument // (as in update) - updateTrackUD: function( track, uD ) { + updateTrackUD: function( track, parametricSpeed ) { var state = new SkaterState( this, EMPTY_OBJECT ); state.track = track; - state.uD = uD; + state.parametricSpeed = parametricSpeed; return state; }, // Create a new SkaterState with the new values. Provided as a convenience to avoid allocating options argument // (as in update) - updateUUDVelocityPosition: function( u, uD, velocityX, velocityY, positionX, positionY ) { + updateUUDVelocityPosition: function( parametricPosition, parametricSpeed, velocityX, velocityY, positionX, positionY ) { var state = new SkaterState( this, EMPTY_OBJECT ); - state.u = u; - state.uD = uD; + state.parametricPosition = parametricPosition; + state.parametricSpeed = parametricSpeed; state.velocityX = velocityX; state.velocityY = velocityY; state.positionX = positionX; @@ -151,10 +151,10 @@ define( function( require ) { return state; }, - updatePositionAngleUpVelocity: function( positionX, positionY, angle, up, velocityX, velocityY ) { + updatePositionAngleUpVelocity: function( positionX, positionY, angle, onTopSideOfTrack, velocityX, velocityY ) { var state = new SkaterState( this, EMPTY_OBJECT ); state.angle = angle; - state.up = up; + state.onTopSideOfTrack = onTopSideOfTrack; state.velocityX = velocityX; state.velocityY = velocityY; state.positionX = positionX; @@ -170,9 +170,9 @@ define( function( require ) { return state; }, - updateUPosition: function( u, positionX, positionY ) { + updateUPosition: function( parametricPosition, positionX, positionY ) { var state = new SkaterState( this, EMPTY_OBJECT ); - state.u = u; + state.parametricPosition = parametricPosition; state.positionX = positionX; state.positionY = positionY; return state; @@ -184,7 +184,7 @@ define( function( require ) { var state = new SkaterState( this, EMPTY_OBJECT ); state.thermalEnergy = thermalEnergy; state.track = null; - state.up = true; + state.onTopSideOfTrack = true; state.angle = 0; state.velocityX = velocityX; state.velocityY = velocityY; @@ -203,7 +203,7 @@ define( function( require ) { state.velocityX = 0; state.velocityY = 0; state.angle = 0; - state.up = true; + state.onTopSideOfTrack = true; return state; }, @@ -213,7 +213,7 @@ define( function( require ) { leaveTrack: function() { var state = new SkaterState( this, EMPTY_OBJECT ); - state.uD = 0; + state.parametricSpeed = 0; state.track = null; return state; }, @@ -225,9 +225,9 @@ define( function( require ) { return state; }, - updateUDVelocity: function( uD, velocityX, velocityY ) { + updateUDVelocity: function( parametricSpeed, velocityX, velocityY ) { var state = new SkaterState( this, EMPTY_OBJECT ); - state.uD = uD; + state.parametricSpeed = parametricSpeed; state.velocityX = velocityX; state.velocityY = velocityY; return state; @@ -242,15 +242,15 @@ define( function( require ) { return state; }, - attachToTrack: function( thermalEnergy, track, up, u, uD, velocityX, velocityY, positionX, positionY ) { + attachToTrack: function( thermalEnergy, track, onTopSideOfTrack, parametricPosition, parametricSpeed, velocityX, velocityY, positionX, positionY ) { assert && assert( thermalEnergy >= 0 ); var state = new SkaterState( this, EMPTY_OBJECT ); state.thermalEnergy = thermalEnergy; state.track = track; - state.up = up; - state.u = u; - state.uD = uD; + state.onTopSideOfTrack = onTopSideOfTrack; + state.parametricPosition = parametricPosition; + state.parametricSpeed = parametricSpeed; state.velocityX = velocityX; state.velocityY = velocityY; state.positionX = positionX; diff --git a/js/energy-skate-park-basics/model/Track.js b/js/energy-skate-park-basics/model/Track.js index a9059c01..df985a5b 100644 --- a/js/energy-skate-park-basics/model/Track.js +++ b/js/energy-skate-park-basics/model/Track.js @@ -96,7 +96,7 @@ define( function( require ) { this.controlPoints = controlPoints; this.interactive = interactive; - this.u = new FastArray( this.controlPoints.length ); + this.parametricPosition = new FastArray( this.controlPoints.length ); this.x = new FastArray( this.controlPoints.length ); this.y = new FastArray( this.controlPoints.length ); @@ -128,13 +128,13 @@ define( function( require ) { // Arrays are fixed length, so just overwrite values, see #38 for ( var i = 0; i < this.controlPoints.length; i++ ) { - this.u[ i ] = i / this.controlPoints.length; + this.parametricPosition[ i ] = i / this.controlPoints.length; this.x[ i ] = this.controlPoints[ i ].position.x; this.y[ i ] = this.controlPoints[ i ].position.y; } - this.xSpline = numeric.spline( this.u, this.x ); - this.ySpline = numeric.spline( this.u, this.y ); + this.xSpline = numeric.spline( this.parametricPosition, this.x ); + this.ySpline = numeric.spline( this.parametricPosition, this.y ); // Mark search points as dirty this.xSearchPoints = null; @@ -220,14 +220,14 @@ define( function( require ) { bestPoint.x = SplineEvaluation.atNumber( this.xSpline, bestU ); bestPoint.y = SplineEvaluation.atNumber( this.ySpline, bestU ); - return { u: bestU, point: bestPoint, distance: bestDistanceSquared }; + return { parametricPosition: bestU, point: bestPoint, distance: bestDistanceSquared }; }, - getX: function( u ) { return SplineEvaluation.atNumber( this.xSpline, u ); }, - getY: function( u ) { return SplineEvaluation.atNumber( this.ySpline, u ); }, - getPoint: function( u ) { - var x = SplineEvaluation.atNumber( this.xSpline, u ); - var y = SplineEvaluation.atNumber( this.ySpline, u ); + getX: function( parametricPosition ) { return SplineEvaluation.atNumber( this.xSpline, parametricPosition ); }, + getY: function( parametricPosition ) { return SplineEvaluation.atNumber( this.ySpline, parametricPosition ); }, + getPoint: function( parametricPosition ) { + var x = SplineEvaluation.atNumber( this.xSpline, parametricPosition ); + var y = SplineEvaluation.atNumber( this.ySpline, parametricPosition ); return new Vector2( x, y ); }, @@ -249,42 +249,44 @@ define( function( require ) { // For purposes of showing the skater angle, get the view angle of the track here. Note this means inverting the y // values, this is called every step while animating on the track, so it was optimized to avoid new allocations - getViewAngleAt: function( u ) { + getViewAngleAt: function( parametricPosition ) { if ( this.xSplineDiff === null ) { this.xSplineDiff = this.xSpline.diff(); this.ySplineDiff = this.ySpline.diff(); } - return Math.atan2( -SplineEvaluation.atNumber( this.ySplineDiff, u ), SplineEvaluation.atNumber( this.xSplineDiff, u ) ); + return Math.atan2( -SplineEvaluation.atNumber( this.ySplineDiff, parametricPosition ), SplineEvaluation.atNumber( this.xSplineDiff, parametricPosition ) ); }, // Get the model angle at the specified position on the track - getModelAngleAt: function( u ) { + getModelAngleAt: function( parametricPosition ) { // load xSplineDiff, ySplineDiff here if not already loaded if ( this.xSplineDiff === null ) { this.xSplineDiff = this.xSpline.diff(); this.ySplineDiff = this.ySpline.diff(); } - return Math.atan2( SplineEvaluation.atNumber( this.ySplineDiff, u ), SplineEvaluation.atNumber( this.xSplineDiff, u ) ); + return Math.atan2( SplineEvaluation.atNumber( this.ySplineDiff, parametricPosition ), SplineEvaluation.atNumber( this.xSplineDiff, parametricPosition ) ); }, // Get the model unit vector at the specified position on the track - getUnitNormalVector: function( u ) { + getUnitNormalVector: function( parametricPosition ) { + // load xSplineDiff, ySplineDiff here if not already loaded if ( this.xSplineDiff === null ) { this.xSplineDiff = this.xSpline.diff(); this.ySplineDiff = this.ySpline.diff(); } - return new Vector2( -SplineEvaluation.atNumber( this.ySplineDiff, u ), SplineEvaluation.atNumber( this.xSplineDiff, u ) ).normalize(); + return new Vector2( -SplineEvaluation.atNumber( this.ySplineDiff, parametricPosition ), SplineEvaluation.atNumber( this.xSplineDiff, parametricPosition ) ).normalize(); }, // Get the model parallel vector at the specified position on the track - getUnitParallelVector: function( u ) { + getUnitParallelVector: function( parametricPosition ) { + // load xSplineDiff, ySplineDiff here if not already loaded if ( this.xSplineDiff === null ) { this.xSplineDiff = this.xSpline.diff(); this.ySplineDiff = this.ySpline.diff(); } - return new Vector2( SplineEvaluation.atNumber( this.xSplineDiff, u ), SplineEvaluation.atNumber( this.ySplineDiff, u ) ).normalize(); + return new Vector2( SplineEvaluation.atNumber( this.xSplineDiff, parametricPosition ), SplineEvaluation.atNumber( this.ySplineDiff, parametricPosition ) ).normalize(); }, updateLinSpace: function() { @@ -302,7 +304,9 @@ define( function( require ) { // Detect whether a parametric point is in bounds of this track, for purposes of telling whether the skater fell // past the edge of the track - isParameterInBounds: function( u ) { return u >= this.minPoint && u <= this.maxPoint; }, + isParameterInBounds: function( parametricPosition ) { + return parametricPosition >= this.minPoint && parametricPosition <= this.maxPoint; + }, // Setter/getter for physical property, mimic the PropertySet pattern instead of using PropertySet multiple inheritance get physical() { return this.physicalProperty.get(); }, @@ -472,7 +476,7 @@ define( function( require ) { // Used for centripetal force and determining whether the skater flies off the track // Curvature parameter is for storing the result as pass-by-value. // Sorry, see #50 regarding GC - getCurvature: function( u, curvature ) { + getCurvature: function( parametricPosition, curvature ) { if ( this.xSplineDiff === null ) { this.xSplineDiff = this.xSpline.diff(); @@ -484,19 +488,19 @@ define( function( require ) { this.ySplineDiffDiff = this.ySplineDiff.diff(); } - var xP = SplineEvaluation.atNumber( this.xSplineDiff, u ); - var xPP = SplineEvaluation.atNumber( this.xSplineDiffDiff, u ); - var yP = SplineEvaluation.atNumber( this.ySplineDiff, u ); - var yPP = SplineEvaluation.atNumber( this.ySplineDiffDiff, u ); + var xP = SplineEvaluation.atNumber( this.xSplineDiff, parametricPosition ); + var xPP = SplineEvaluation.atNumber( this.xSplineDiffDiff, parametricPosition ); + var yP = SplineEvaluation.atNumber( this.ySplineDiff, parametricPosition ); + var yPP = SplineEvaluation.atNumber( this.ySplineDiffDiff, parametricPosition ); var k = (xP * yPP - yP * xPP) / Math.pow( (xP * xP + yP * yP), 3 / 2 ); // Using component-wise maths to avoid allocations, see #50 - var centerX = this.getX( u ); - var centerY = this.getY( u ); + var centerX = this.getX( parametricPosition ); + var centerY = this.getY( parametricPosition ); - var unitNormalVector = this.getUnitNormalVector( u ); + var unitNormalVector = this.getUnitNormalVector( parametricPosition ); var vectorX = unitNormalVector.x / k + centerX; var vectorY = unitNormalVector.y / k + centerY; @@ -657,12 +661,12 @@ define( function( require ) { // single sampling point. var numDivisions = 400; var du = (this.maxPoint - this.minPoint) / numDivisions; - for ( var u = this.minPoint; u < this.maxPoint; u += du ) { - this.getCurvature( u, curvature ); + for ( var parametricPosition = this.minPoint; parametricPosition < this.maxPoint; parametricPosition += du ) { + this.getCurvature( parametricPosition, curvature ); var r = Math.abs( curvature.r ); if ( r < minRadius ) { minRadius = r; - bestU = u; + bestU = parametricPosition; } } return bestU; @@ -680,8 +684,8 @@ define( function( require ) { // single sampling point. var numDivisions = 400; var du = (this.maxPoint - this.minPoint) / numDivisions; - for ( var u = this.minPoint; u < this.maxPoint; u += du ) { - this.getCurvature( u, curvature ); + for ( var parametricPosition = this.minPoint; parametricPosition < this.maxPoint; parametricPosition += du ) { + this.getCurvature( parametricPosition, curvature ); var r = Math.abs( curvature.r ); if ( r < minRadius ) { minRadius = r; diff --git a/js/energy-skate-park-basics/view/PlaybackSpeedControl.js b/js/energy-skate-park-basics/view/PlaybackSpeedControl.js index 37ca6805..d3e072dd 100644 --- a/js/energy-skate-park-basics/view/PlaybackSpeedControl.js +++ b/js/energy-skate-park-basics/view/PlaybackSpeedControl.js @@ -16,9 +16,6 @@ define( function( require ) { var TandemText = require( 'TANDEM/scenery/nodes/TandemText' ); var PhetFont = require( 'SCENERY_PHET/PhetFont' ); - // phet-io modules - var TString = require( 'ifphetio!PHET_IO/types/TString' ); - // strings var normalString = require( 'string!ENERGY_SKATE_PARK_BASICS/normal' ); var slowMotionString = require( 'string!ENERGY_SKATE_PARK_BASICS/slow.motion' ); diff --git a/js/energy-skate-park-basics/view/SkaterNode.js b/js/energy-skate-park-basics/view/SkaterNode.js index f0575256..226a9985 100644 --- a/js/energy-skate-park-basics/view/SkaterNode.js +++ b/js/energy-skate-park-basics/view/SkaterNode.js @@ -123,19 +123,19 @@ define( function( require ) { // to use binary search for position on the track var closestTrackAndPositionAndParameter = getClosestTrackAndPositionAndParameter( position, getPhysicalTracks() ); var closeEnough = false; - if ( closestTrackAndPositionAndParameter && closestTrackAndPositionAndParameter.track && closestTrackAndPositionAndParameter.track.isParameterInBounds( closestTrackAndPositionAndParameter.u ) ) { + if ( closestTrackAndPositionAndParameter && closestTrackAndPositionAndParameter.track && closestTrackAndPositionAndParameter.track.isParameterInBounds( closestTrackAndPositionAndParameter.parametricPosition ) ) { var closestPoint = closestTrackAndPositionAndParameter.point; var distance = closestPoint.distance( position ); if ( distance < 0.5 ) { position = closestPoint; targetTrack = closestTrackAndPositionAndParameter.track; - targetU = closestTrackAndPositionAndParameter.u; + targetU = closestTrackAndPositionAndParameter.parametricPosition; // Choose the right side of the track, i.e. the side of the track that would have the skater upside up var normal = targetTrack.getUnitNormalVector( targetU ); - skater.up = normal.y > 0; + skater.onTopSideOfTrack = normal.y > 0; - skater.angle = targetTrack.getViewAngleAt( targetU ) + (skater.up ? 0 : Math.PI); + skater.angle = targetTrack.getViewAngleAt( targetU ) + (skater.onTopSideOfTrack ? 0 : Math.PI); closeEnough = true; } @@ -146,7 +146,7 @@ define( function( require ) { // make skater upright if not near the track skater.angle = 0; - skater.up = true; + skater.onTopSideOfTrack = true; skater.position = position; } diff --git a/js/energy-skate-park-basics/view/TrackNode.js b/js/energy-skate-park-basics/view/TrackNode.js index 1b3aa6d1..523fccb9 100644 --- a/js/energy-skate-park-basics/view/TrackNode.js +++ b/js/energy-skate-park-basics/view/TrackNode.js @@ -172,8 +172,8 @@ define( function( require ) { // Update the skater if the track is moved while the sim is paused, see #84 if ( model.skater.track === track && model.paused ) { - model.skater.position = track.getPoint( model.skater.u ); - model.skater.angle = model.skater.track.getViewAngleAt( model.skater.u ) + (model.skater.up ? 0 : Math.PI); + model.skater.position = track.getPoint( model.skater.parametricPosition ); + model.skater.angle = model.skater.track.getViewAngleAt( model.skater.parametricPosition ) + (model.skater.onTopSideOfTrack ? 0 : Math.PI); model.skater.trigger( 'updated' ); } }