phetsims / charges-and-fields

"Charges And Fields" is an educational simulation in HTML5, by PhET Interactive Simulations.
GNU General Public License v3.0
8 stars 7 forks source link

More robust handling of charges that are colocated #126

Open veillette opened 7 years ago

veillette commented 7 years ago

Given that charges can be snapped to the grid (see #98), it is much easier to have configurations of charges that are on top of one another.

The previous implementation attempted to determined if the E field is zero everywhere. However the check was not exhaustive since it was incredibly unlikely (and difficult) to generate such charge configurations. This is no longer the case when you can snapped charges to specific positions. This should be addressed.

We should revisit the algorithm for updateIsPlayAreaCharged:

   /**
     * Function that determines if there is at least one active and "uncompensated" charge
     * on the board. If this is not the case, it implies that the E-field is zero everywhere
     * (see https://github.com/phetsims/charges-and-fields/issues/46)
     * @private
     */
    updateIsPlayAreaCharged: function() {
      var netElectricCharge = 0; // {number} Total electric charge on screen
      var numberActiveChargedParticles = 0; // {number} Total active charged particles on screen

      this.activeChargedParticles.forEach( function( chargedParticle ) {
        numberActiveChargedParticles++;
        netElectricCharge += chargedParticle.charge;
      } );

      // If net charge is nonzero, there must be an electric field (by Gauss's law)
      if ( netElectricCharge !== 0 ) {
        this.isPlayAreaChargedProperty.set( true );
      }

      // No charged particles on screen, hence no electric field
      else if ( numberActiveChargedParticles === 0 ) {
        this.isPlayAreaChargedProperty.set( false );
      }

      // If this is a pair, it must be a +- pair. If charges are co-located, don't show field.
      else if ( numberActiveChargedParticles === 2 ) {

        // {boolean} indicator for a co-located pair
        var colocated = this.activeChargedParticles.get( 1 ).positionProperty.get()
                          .minus( this.activeChargedParticles.get( 0 ).positionProperty.get() )
                          .magnitude() < MIN_DISTANCE_SCALE;

        this.isPlayAreaChargedProperty.set( colocated ? false : true );

        if ( colocated ) {
          this.electricField = Vector2.ZERO;
        }
      }

      // Check for two compensating pairs
      else if ( numberActiveChargedParticles === 4 ) {
        var positiveChargePositionArray = [];
        var negativeChargePositionArray = [];
        this.activeChargedParticles.forEach( function( chargedParticle ) {
          if ( chargedParticle.charge === 1 ) {
            positiveChargePositionArray.push( chargedParticle.positionProperty.get() );
          }
          else {
            negativeChargePositionArray.push( chargedParticle.positionProperty.get() );
          }
        } );

        if (
          ( negativeChargePositionArray[ 0 ].equals( positiveChargePositionArray[ 0 ] ) &&
            negativeChargePositionArray[ 1 ].equals( positiveChargePositionArray[ 1 ] ) ) ||
          ( negativeChargePositionArray[ 0 ].equals( positiveChargePositionArray[ 1 ] ) &&
            negativeChargePositionArray[ 1 ].equals( positiveChargePositionArray[ 0 ] ) ) ) {
          this.isPlayAreaChargedProperty.set( false );
          this.electricField = Vector2.ZERO;
        }
        else {
          this.isPlayAreaChargedProperty.set( true );
        }
      }
      // for more than six charges
      else {
        // there are cases with six charges (and above) that can be compensated
        // however it is quite expensive to make this type of check as well as
        // incredibly unlikely to be the case in the first place.
        this.isPlayAreaChargedProperty.set( true );
      }
    },

An assertion can be triggered when 3 positive and three negative charges are put on top of one another.

charges and fields screenshot 1

:8080/assert/js/assert.js:30 enabling assert assert.js:20 Assertion failed: the magnitude of the electric field is zero: initial Electric Field assert.js:21 Uncaught Error: Assertion failed: the magnitude of the electric field is zero: initial Electric Field at window.assertions.assertFunction (assert.js:21) at ElectricPotentialLine.getNextPositionAlongEquipotentialWithElectricPotential (ElectricPotentialLine.js?bust=1500170287700:99) at ElectricPotentialLine.getEquipotentialPositionArray (ElectricPotentialLine.js?bust=1500170287700:193) at new ElectricPotentialLine (ElectricPotentialLine.js?bust=1500170287700:59) at ChargesAndFieldsModel.addElectricPotentialLine (ChargesAndFieldsModel.js?bust=1500170287700:625) at listener (ElectricPotentialSensorNode.js?bust=1500170287700:133) at PushButtonModel.js?bust=1500170287700:168 at Array.forEach () at PushButtonModel.fire (PushButtonModel.js?bust=1500170287700:167) at Array. (PushButtonModel.js?bust=1500170287700:102)

arouinfar commented 7 years ago

@veillette I noticed that I was able to to draw the 0 V equipotential line in the middle of a dipole, but the tool fails to draw 0 V lines for a quadrupole (which would intersect). I'm not sure how pedagogically beneficial it would be to draw the zero lines, so I wonder if it would be better for the draw button to become inactive when at a zero point.