Skip to content

Commit

Permalink
Create NuclideChartCellModel.ts and cellModelArray to keep track of p…
Browse files Browse the repository at this point in the history
…roton number, neutron number, and decayType of a cell. See #46.
  • Loading branch information
Luisav1 committed Jun 16, 2023
1 parent cd11eae commit d5c848d
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 39 deletions.
20 changes: 19 additions & 1 deletion js/chart-intro/model/ChartIntroModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,38 @@ import buildANucleus from '../../buildANucleus.js';
import BANModel from '../../common/model/BANModel.js';
import ParticleNucleus from './ParticleNucleus.js';
import Vector2 from '../../../../dot/js/Vector2.js';
import ParticleType from '../../common/view/ParticleType.js'; // TODO: move ParticelType into model folder, see: https://github.com/phetsims/chipper/issues/1385
import ParticleType from '../../common/view/ParticleType.js'; // TODO: move ParticleType into model folder, see: https://github.com/phetsims/chipper/issues/1385
import Particle from '../../../../shred/js/model/Particle.js';
import BANConstants from '../../common/BANConstants.js';
import ParticleAtom from '../../../../shred/js/model/ParticleAtom.js';
import Property from '../../../../axon/js/Property.js';
import NuclideChartCellModel from './NuclideChartCellModel.js';

// types
export type SelectedChartType = 'partial' | 'zoom';

// 2D array that defines the table structure.
// The rows are the proton number, for example the first row is protonNumber = 0. The numbers in the rows are the neutron number.
const POPULATED_CELLS = [
[ 1, 4, 6 ],
[ 0, 1, 2, 3, 4, 5, 6 ],
[ 1, 2, 3, 4, 5, 6, 7, 8 ],
[ 1, 2, 3, 4, 5, 6, 7, 8, 9 ],
[ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ],
[ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ],
[ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ],
[ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ],
[ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ],
[ 4, 5, 6, 7, 8, 9, 10, 11, 12 ],
[ 5, 6, 7, 8, 9, 10, 11, 12 ]
];

class ChartIntroModel extends BANModel<ParticleNucleus> {

public readonly particleNucleus: ParticleNucleus;
public readonly miniParticleAtom: ParticleAtom;
public readonly selectedNuclideChartProperty: Property<SelectedChartType>;
public static cellModelArray = POPULATED_CELLS.map( ( row, rowIndex ) => row.map( column => new NuclideChartCellModel( rowIndex, column ) ) );

public constructor() {

Expand Down
38 changes: 38 additions & 0 deletions js/chart-intro/model/NuclideChartCellModel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright 2023, University of Colorado Boulder

/**
* Model of a cell in the Nuclide Chart. Tracks proton number, neutron number, and decay type of cell.
*
* @author Luisa Vargas
* @author Marla Schulz (PhET Interactive Simulations)
*/

import buildANucleus from '../../buildANucleus.js';
import DecayType from '../../common/view/DecayType.js';
import AtomIdentifier from '../../../../shred/js/AtomIdentifier.js';
import BANColors from '../../common/BANColors.js';
import { ColorProperty } from '../../../../scenery/js/imports.js';

class NuclideChartCellModel {

public readonly protonNumber: number;
public readonly neutronNumber: number;
public readonly decayType: DecayType | null;
public readonly colorProperty: ColorProperty;

public constructor( protonNumber: number, neutronNumber: number ) {

// get first decay in available decays to color the cell according to that decay type
const decayType = AtomIdentifier.getAvailableDecays( protonNumber, neutronNumber )[ 0 ];

this.protonNumber = protonNumber;
this.neutronNumber = neutronNumber;
this.decayType = DecayType.enumeration.getValue( decayType );
this.colorProperty = AtomIdentifier.isStable( protonNumber, neutronNumber ) ? BANColors.stableColorProperty :
decayType === undefined ? BANColors.unknownColorProperty : // no available decays, unknown decay type
this.decayType.colorProperty;
}
}

buildANucleus.register( 'NuclideChartCellModel', NuclideChartCellModel );
export default NuclideChartCellModel;
4 changes: 2 additions & 2 deletions js/chart-intro/view/FocusedNuclideChartNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,9 @@ class FocusedNuclideChartNode extends NuclideChartNode {
nuclideChartCellRow.forEach( nuclideChartCell => {
if ( nuclideChartCell ) {
const protonDelta = Math.abs( chartTransform.viewToModelY( highlightRectangle.center.y )
- BANConstants.Y_SHIFT_HIGHLIGHT_RECTANGLE - nuclideChartCell?.protonNumber );
- BANConstants.Y_SHIFT_HIGHLIGHT_RECTANGLE - nuclideChartCell?.cellModel.protonNumber );
const neutronDelta = Math.abs( chartTransform.viewToModelX( highlightRectangle.center.x )
- BANConstants.X_SHIFT_HIGHLIGHT_RECTANGLE - nuclideChartCell?.neutronNumber );
- BANConstants.X_SHIFT_HIGHLIGHT_RECTANGLE - nuclideChartCell?.cellModel.neutronNumber );
nuclideChartCell?.makeOpaque( protonDelta, neutronDelta );
}
} );
Expand Down
18 changes: 5 additions & 13 deletions js/chart-intro/view/NuclideChartCell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,36 +9,28 @@
import { Color, Rectangle, RectangleOptions, TPaint } from '../../../../scenery/js/imports.js';
import buildANucleus from '../../buildANucleus.js';
import optionize, { EmptySelfOptions } from '../../../../phet-core/js/optionize.js';
import NuclideChartCellModel from '../model/NuclideChartCellModel.js';

type SelfOptions = EmptySelfOptions;

type NuclideChartCellOptions = SelfOptions & RectangleOptions;

class NuclideChartCell extends Rectangle {

public readonly protonNumber: number;
public readonly neutronNumber: number;
public readonly decayType: string;
public readonly decayBackgroundColor: TPaint;
public readonly cellModel: NuclideChartCellModel;

public constructor( cellLength: number, protonNumber: number, neutronNumber: number,
decayType: string, providedOptions: NuclideChartCellOptions ) {
public constructor( cellLength: number, cellModel: NuclideChartCellModel, providedOptions: NuclideChartCellOptions ) {

const options = optionize<NuclideChartCellOptions, SelfOptions, RectangleOptions>()( {
stroke: Color.GRAY,
fill: Color.GRAY
fill: cellModel.colorProperty.value
}, providedOptions );

super( 0, 0, cellLength, cellLength, 0, 0, options );

// TODO: move protonNumber, neutronNumber, and decayType into cellModel.
// TODO: decayEquationModel would have property currentCell (that's a cellModel) which updates the resulting decay equation.
this.protonNumber = protonNumber;
this.neutronNumber = neutronNumber;
this.decayBackgroundColor = options.fill;

// TODO: why not store the decayType as the enumeration and not the string? - FIRST STEP
this.decayType = decayType;
this.cellModel = cellModel;
}

// make cell more opaque to de-emphasize the cell
Expand Down
38 changes: 15 additions & 23 deletions js/chart-intro/view/NuclideChartNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { Color, GridBox, Node, NodeOptions, Path, Text } from '../../../../scene
import AtomIdentifier from '../../../../shred/js/AtomIdentifier.js';
import buildANucleus from '../../buildANucleus.js';
import NuclideChartCell from './NuclideChartCell.js';
import BANColors from '../../common/BANColors.js';
import DecayType from '../../common/view/DecayType.js';
import Vector2 from '../../../../dot/js/Vector2.js';
import Multilink from '../../../../axon/js/Multilink.js';
Expand All @@ -21,6 +20,7 @@ import ArrowNode from '../../../../scenery-phet/js/ArrowNode.js';
import optionize from '../../../../phet-core/js/optionize.js';
import BANConstants from '../../common/BANConstants.js';
import { Shape } from '../../../../kite/js/imports.js';
import ChartIntroModel from '../model/ChartIntroModel.js';

type SelfOptions = {
cellTextFontSize: number;
Expand All @@ -46,7 +46,7 @@ const POPULATED_CELLS = [
];

class NuclideChartNode extends Node {
protected readonly cells: ( NuclideChartCell | null )[][];
protected readonly cells: NuclideChartCell[][];

public constructor( protonCountProperty: TReadOnlyProperty<number>, neutronCountProperty: TReadOnlyProperty<number>,
chartTransform: ChartTransform, providedOptions: NuclideChartNodeOptions ) {
Expand Down Expand Up @@ -110,12 +110,12 @@ class NuclideChartNode extends Node {
assert && assert( highlightedCell, 'The highlighted cell is null at protonRowIndex = ' + protonRowIndex +
' neutronRowIndex = ' + neutronRowIndex );

const decayType = highlightedCell!.decayType;
const decayType = highlightedCell.cellModel.decayType;
if ( !AtomIdentifier.isStable( protonCount, neutronCount ) && decayType !== undefined ) {
const direction = decayType === DecayType.NEUTRON_EMISSION.name ? new Vector2( neutronCount - 1, protonCount ) :
decayType === DecayType.PROTON_EMISSION.name ? new Vector2( neutronCount, protonCount - 1 ) :
decayType === DecayType.BETA_PLUS_DECAY.name ? new Vector2( neutronCount + 1, protonCount - 1 ) :
decayType === DecayType.BETA_MINUS_DECAY.name ? new Vector2( neutronCount - 1, protonCount + 1 ) :
const direction = decayType === DecayType.NEUTRON_EMISSION ? new Vector2( neutronCount - 1, protonCount ) :
decayType === DecayType.PROTON_EMISSION ? new Vector2( neutronCount, protonCount - 1 ) :
decayType === DecayType.BETA_PLUS_DECAY ? new Vector2( neutronCount + 1, protonCount - 1 ) :
decayType === DecayType.BETA_MINUS_DECAY ? new Vector2( neutronCount - 1, protonCount + 1 ) :
new Vector2( neutronCount - 2, protonCount - 2 );
const arrowTip = chartTransform.modelToViewXY( direction.x + BANConstants.X_SHIFT_HIGHLIGHT_RECTANGLE,
direction.y + BANConstants.Y_SHIFT_HIGHLIGHT_RECTANGLE );
Expand All @@ -129,10 +129,10 @@ class NuclideChartNode extends Node {
labelContainer.visible = true;
labelText.string = AtomIdentifier.getSymbol( protonCount );
labelContainer.center = currentCellCenter;
labelText.fill = highlightedCell?.decayType === DecayType.ALPHA_DECAY.name ||
highlightedCell?.decayType === DecayType.BETA_MINUS_DECAY.name ?
labelText.fill = highlightedCell?.cellModel.decayType === DecayType.ALPHA_DECAY ||
highlightedCell?.cellModel.decayType === DecayType.BETA_MINUS_DECAY ?
Color.BLACK : Color.WHITE;
labelTextBackground.fill = highlightedCell!.decayBackgroundColor;
labelTextBackground.fill = highlightedCell.decayBackgroundColor;
}
else {
arrowNode.visible = false;
Expand All @@ -141,25 +141,17 @@ class NuclideChartNode extends Node {
} );
}

public static createNuclideChart( cellLayerNode: Node, chartTransform: ChartTransform, cellLength: number ): ( NuclideChartCell | null )[][] {
const cells: ( NuclideChartCell | null )[][] = [];
public static createNuclideChart( cellLayerNode: Node, chartTransform: ChartTransform, cellLength: number ): NuclideChartCell[][] {
const cells: NuclideChartCell[][] = [];

// create and add the chart cells to the chart. row is proton number and column is neutron number.
chartTransform.forEachSpacing( Orientation.VERTICAL, 1, 0, 'strict', ( row, viewPosition ) => {
const populatedCellsInRow = POPULATED_CELLS[ row ];
const rowCells: ( NuclideChartCell | null )[] = [];
populatedCellsInRow.forEach( column => {

// get first decay in available decays to color the cell according to that decay type
const decayType = AtomIdentifier.getAvailableDecays( row, column )[ 0 ];

const color = AtomIdentifier.isStable( row, column ) ? BANColors.stableColorProperty.value :
decayType === undefined ? BANColors.unknownColorProperty.value : // no available decays, unknown decay type
DecayType.enumeration.getValue( decayType.toString() ).colorProperty.value;
const rowCells: NuclideChartCell[] = [];
populatedCellsInRow.forEach( ( column, columnIndex ) => {

// create and add the NuclideChartCell
const cell = new NuclideChartCell( cellLength, row, column, decayType, {
fill: color,
const cell = new NuclideChartCell( cellLength, ChartIntroModel.cellModelArray[ row ][ columnIndex ], {
lineWidth: chartTransform.modelToViewDeltaX( BANConstants.NUCLIDE_CHART_CELL_LINE_WIDTH )
} );
cell.translation = new Vector2( chartTransform.modelToViewX( column ), viewPosition );
Expand Down

0 comments on commit d5c848d

Please sign in to comment.