Skip to content

Commit

Permalink
Factor out functions that determine the electron cloud size from Char…
Browse files Browse the repository at this point in the history
…tIntroScreenView.ts and DecayScreenView.ts to BANScreenView.ts. See #46.
  • Loading branch information
Luisav1 committed Oct 14, 2022
1 parent 3574cf7 commit 13a67dc
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 94 deletions.
49 changes: 2 additions & 47 deletions js/chart-intro/view/ChartIntroScreenView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,12 @@ import ChartIntroModel from '../model/ChartIntroModel.js';
import optionize, { EmptySelfOptions } from '../../../../phet-core/js/optionize.js';
import BANScreenView, { BANScreenViewOptions } from '../../common/view/BANScreenView.js';
import BANConstants from '../../common/BANConstants.js';
import { Color, RadialGradient, Text } from '../../../../scenery/js/imports.js';
import { Color, Text } from '../../../../scenery/js/imports.js';
import PhetFont from '../../../../scenery-phet/js/PhetFont.js';
import AtomIdentifier from '../../../../shred/js/AtomIdentifier.js';
import Particle from '../../../../shred/js/model/Particle.js';
import ParticleAtom from '../../../../shred/js/model/ParticleAtom.js';
import ParticleType from '../../common/view/ParticleType.js';
import LinearFunction from '../../../../dot/js/LinearFunction.js';
import Multilink from '../../../../axon/js/Multilink.js';
import PeriodicTableAndIsotopeSymbol from './PeriodicTableAndIsotopeSymbol.js';

Expand All @@ -43,52 +42,8 @@ class ChartIntroScreenView extends BANScreenView<ChartIntroModel> {

this.model = model;

// function that updates the size of the electron cloud based on the protonNumber since the nuclides created are neutral
// meaning the number of electrons is the same as the number of protons
const updateCloudSize = ( protonCount: number ) => {
if ( protonCount === 0 ) {
this.electronCloud.radius = 1E-5; // arbitrary non-zero value
this.electronCloud.fill = 'transparent';
}
else {
const radius = this.modelViewTransform.modelToViewDeltaX( getElectronShellDiameter( protonCount ) / 2 );
this.electronCloud.radius = radius * 0.65;
this.electronCloud.fill = new RadialGradient( 0, 0, 0, 0, 0, radius * 0.65 )
.addColorStop( 0, 'rgba( 0, 0, 255, 200 )' )
.addColorStop( 0.9, 'rgba( 0, 0, 255, 0 )' );
}
};

// update the cloud size as the massNumber changes
model.particleAtom.protonCountProperty.link( updateCloudSize );

// Maps a number of electrons to a diameter in screen coordinates for the electron shell. This mapping function is
// based on the real size relationships between the various atoms, but has some tweakable parameters to reduce the
// range and scale to provide values that are usable for our needs on the canvas.
const getElectronShellDiameter = ( numElectrons: number ) => {
const maxElectrons = this.model.protonCountRange.max; // for uranium
const atomicRadius = AtomIdentifier.getAtomicRadius( numElectrons );
if ( atomicRadius ) {
return reduceRadiusRange( atomicRadius, this.model.protonCountRange.min + 1, maxElectrons );
}
else {
assert && assert( numElectrons <= maxElectrons, `Atom has more than supported number of electrons, ${numElectrons}` );
return 0;
}
};

// This method increases the value of the smaller radius values and decreases the value of the larger ones.
// This effectively reduces the range of radii values used.
// This is a very specialized function for the purposes of this class.
const reduceRadiusRange = ( value: number, minShellRadius: number, maxShellRadius: number ) => {
// The following two factors define the way in which an input value is increased or decreased. These values
// can be adjusted as needed to make the cloud size appear as desired.
const minChangedRadius = 70;
const maxChangedRadius = 95;

const compressionFunction = new LinearFunction( minShellRadius, maxShellRadius, minChangedRadius, maxChangedRadius );
return compressionFunction.evaluate( value );
};
model.particleAtom.protonCountProperty.link( protonCount => this.updateCloudSize( protonCount, 0.65, 10, 20 ) );

// Create the textual readout for the element name.
const elementName = new Text( '', {
Expand Down
52 changes: 52 additions & 0 deletions js/common/view/BANScreenView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import AtomNode from '../../../../shred/js/view/AtomNode.js';
import Property from '../../../../axon/js/Property.js';
import StringUtils from '../../../../phetcommon/js/util/StringUtils.js';
import ShredConstants from '../../../../shred/js/ShredConstants.js';
import LinearFunction from '../../../../dot/js/LinearFunction.js';

// empirically determined, from the ElectronCloudView radius
const MIN_ELECTRON_CLOUD_RADIUS = 42.5;
Expand Down Expand Up @@ -479,6 +480,57 @@ abstract class BANScreenView<M extends BANModel> extends ScreenView {
this.protonArrowButtons = protonArrowButtons;
}

/**
* This method increases the value of the smaller radius values and decreases the value of the larger ones.
* This effectively reduces the range of radii values used.
* This is a very specialized function for the purposes of this class.
*
* minChangedRadius and maxChangedRadius define the way in which an input value is increased or decreased. These values
* can be adjusted as needed to make the cloud size appear as desired.
*/
private static reduceRadiusRange( value: number, minShellRadius: number, maxShellRadius: number,
minChangedRadius: number, maxChangedRadius: number ): number {
const compressionFunction = new LinearFunction( minShellRadius, maxShellRadius, minChangedRadius, maxChangedRadius );
return compressionFunction.evaluate( value );
}

/**
* Maps a number of electrons to a diameter in screen coordinates for the electron shell. This mapping function is
* based on the real size relationships between the various atoms, but has some tweakable parameters to reduce the
* range and scale to provide values that are usable for our needs on the canvas.
*/
private getElectronShellDiameter( numElectrons: number, minChangedRadius: number, maxChangedRadius: number ): number {
const maxElectrons = this.model.protonCountRange.max;
const atomicRadius = AtomIdentifier.getAtomicRadius( numElectrons );
if ( atomicRadius ) {
return BANScreenView.reduceRadiusRange( atomicRadius, this.model.protonCountRange.min + 1, maxElectrons,
minChangedRadius, maxChangedRadius );
}
else {
assert && assert( numElectrons <= maxElectrons, `Atom has more than supported number of electrons, ${numElectrons}` );
return 0;
}
}

/**
* Update size of electron cloud based on protonNumber since the nuclides created are neutral, meaning the number of
* electrons is the same as the number of protons.
*/
protected updateCloudSize( protonCount: number, factor: number, minChangedRadius: number, maxChangedRadius: number ): void {
if ( protonCount === 0 ) {
this.electronCloud.radius = 1E-5; // arbitrary non-zero value
this.electronCloud.fill = 'transparent';
}
else {
const radius = this.modelViewTransform.modelToViewDeltaX(
this.getElectronShellDiameter( protonCount, minChangedRadius, maxChangedRadius ) / 2 );
this.electronCloud.radius = radius * factor;
this.electronCloud.fill = new RadialGradient( 0, 0, 0, 0, 0, radius * factor )
.addColorStop( 0, 'rgba( 0, 0, 255, 200 )' )
.addColorStop( 0.9, 'rgba( 0, 0, 255, 0 )' );
}
}

/**
* Get information for a specific particle type.
*/
Expand Down
49 changes: 2 additions & 47 deletions js/decay/view/DecayScreenView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import Particle from '../../../../shred/js/model/Particle.js';
import ParticleAtom from '../../../../shred/js/model/ParticleAtom.js';
import ParticleType from '../../common/view/ParticleType.js';
import Checkbox from '../../../../sun/js/Checkbox.js';
import LinearFunction from '../../../../dot/js/LinearFunction.js';
import dotRandom from '../../../../dot/js/dotRandom.js';
import Animation from '../../../../twixt/js/Animation.js';
import Easing from '../../../../twixt/js/Easing.js';
Expand Down Expand Up @@ -253,54 +252,10 @@ class DecayScreenView extends BANScreenView<DecayModel> {
};
model.doesNuclideExistBooleanProperty.link( updateStabilityIndicatorVisibility );

// function that updates the size of the electron cloud based on the protonNumber since the nuclides created are neutral
// meaning the number of electrons is the same as the number of protons
const updateCloudSize = ( protonCount: number ) => {
if ( protonCount === 0 ) {
this.electronCloud.radius = 1E-5; // arbitrary non-zero value
this.electronCloud.fill = 'transparent';
}
else {
const radius = this.modelViewTransform.modelToViewDeltaX( getElectronShellDiameter( protonCount ) / 2 );
this.electronCloud.radius = radius * 2;
this.electronCloud.fill = new RadialGradient( 0, 0, 0, 0, 0, radius * 2 )
.addColorStop( 0, 'rgba( 0, 0, 255, 200 )' )
.addColorStop( 0.9, 'rgba( 0, 0, 255, 0 )' );
}
};

// update the cloud size as the massNumber changes
model.particleAtom.protonCountProperty.link( updateCloudSize );

// TODO: should be moved to BANScreenView bc repeated in Chart screen view
// Maps a number of electrons to a diameter in screen coordinates for the electron shell. This mapping function is
// based on the real size relationships between the various atoms, but has some tweakable parameters to reduce the
// range and scale to provide values that are usable for our needs on the canvas.
const getElectronShellDiameter = ( numElectrons: number ) => {
const maxElectrons = this.model.protonCountRange.max; // for uranium
const atomicRadius = AtomIdentifier.getAtomicRadius( numElectrons );
if ( atomicRadius ) {
return reduceRadiusRange( atomicRadius, this.model.protonCountRange.min + 1, maxElectrons );
}
else {
assert && assert( numElectrons <= maxElectrons, `Atom has more than supported number of electrons, ${numElectrons}` );
return 0;
}
};

// This method increases the value of the smaller radius values and decreases the value of the larger ones.
// This effectively reduces the range of radii values used.
// This is a very specialized function for the purposes of this class.
const reduceRadiusRange = ( value: number, minShellRadius: number, maxShellRadius: number ) => {
// The following two factors define the way in which an input value is increased or decreased. These values
// can be adjusted as needed to make the cloud size appear as desired.
const minChangedRadius = 70;
const maxChangedRadius = 95;

const compressionFunction = new LinearFunction( minShellRadius, maxShellRadius, minChangedRadius, maxChangedRadius );
return compressionFunction.evaluate( value );
};
model.particleAtom.protonCountProperty.link( protonCount => this.updateCloudSize( protonCount, 2, 70, 95 ) );

// TODO: move elementName to BANScreenView bc text node the same, just positioning different
// Create the textual readout for the element name.
const elementName = new Text( '', {
font: LABEL_FONT,
Expand Down

0 comments on commit 13a67dc

Please sign in to comment.