phetsims / quantum-measurement

"Quantum Measurement" is an educational simulation in HTML5, by PhET Interactive Simulations.
GNU General Public License v3.0
0 stars 0 forks source link

Create basic model and view for Screen 2: Photons #52

Open AgustinVallejo opened 1 month ago

AgustinVallejo commented 1 month ago

Patch for initial attempt at the view part:

```diff Subject: [PATCH] HOlaaa --- Index: js/photons/view/PhotonsScreenView.ts IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== diff --git a/js/photons/view/PhotonsScreenView.ts b/js/photons/view/PhotonsScreenView.ts --- a/js/photons/view/PhotonsScreenView.ts (revision 662ff96e3cc66f5df971819427e229598c89c28a) +++ b/js/photons/view/PhotonsScreenView.ts (date 1728506519484) @@ -6,25 +6,116 @@ * @author John Blanco, PhET Interactive Simulations */ -import ScreenView from '../../../../joist/js/ScreenView.js'; -import { Image } from '../../../../scenery/js/imports.js'; +import Multilink from '../../../../axon/js/Multilink.js'; +import Vector2 from '../../../../dot/js/Vector2.js'; +import PhetFont from '../../../../scenery-phet/js/PhetFont.js'; +import { Text } from '../../../../scenery/js/imports.js'; +import RectangularRadioButtonGroup from '../../../../sun/js/buttons/RectangularRadioButtonGroup.js'; import Tandem from '../../../../tandem/js/Tandem.js'; -import photonsScreenMockup_png from '../../../images/photonsScreenMockup_png.js'; +import PhotonsExperimentSceneView from '../../coins/view/PhotonsExperimentSceneView.js'; +import QuantumMeasurementColors from '../../common/QuantumMeasurementColors.js'; import QuantumMeasurementScreenView from '../../common/view/QuantumMeasurementScreenView.js'; import quantumMeasurement from '../../quantumMeasurement.js'; import PhotonsModel from '../model/PhotonsModel.js'; +const SCENE_POSITION = new Vector2( 0, 90 ); // empirically determined to look decent + export default class PhotonsScreenView extends QuantumMeasurementScreenView { + private readonly model: PhotonsModel; + + // the two scene views for the experiments + private readonly singlePhotonPhotonsExperimentSceneView: PhotonsExperimentSceneView; + private readonly manyPhotonsPhotonsExperimentSceneView: PhotonsExperimentSceneView; + public constructor( model: PhotonsModel, tandem: Tandem ) { super( { - mockupImage: new Image( photonsScreenMockup_png, { - scale: ScreenView.DEFAULT_LAYOUT_BOUNDS.width / photonsScreenMockup_png.width - } ), + initialMockupOpacity: 0, tandem: tandem } ); + this.model = model; + + // Add the radio buttons at the top of the screen that will allow users to pick between singlePhoton and manyPhotons. + const experimentTypeItems = [ true, false ].map( singlePhotonMode => ( { + createNode: () => { + return new Text( + singlePhotonMode ? 'Single Photon' : 'Many Photons', + { + font: new PhetFont( { size: 28, weight: 'bold' } ), + fill: singlePhotonMode ? + QuantumMeasurementColors.classicalSceneTextColorProperty : + QuantumMeasurementColors.quantumSceneTextColorProperty, + maxWidth: 300 + } + ); + }, + value: singlePhotonMode, + tandemName: `${singlePhotonMode ? 'single' : 'many'}RadioButton`, + options: { minWidth: 80 } + } ) ); + const deselectedRadioButtonOpacity = 0.3; + const experimentTypeRadioButtonGroup = new RectangularRadioButtonGroup( + model.singlePhotonModeProperty, + experimentTypeItems, + { + orientation: 'horizontal', + spacing: 3, + centerX: this.layoutBounds.centerX, + y: 10, + radioButtonOptions: { + xMargin: 10, + baseColor: QuantumMeasurementColors.selectorButtonSelectedColorProperty, + stroke: QuantumMeasurementColors.selectorButtonSelectedStrokeProperty, + buttonAppearanceStrategyOptions: { + deselectedButtonOpacity: deselectedRadioButtonOpacity, + deselectedFill: QuantumMeasurementColors.selectorButtonDeselectedColorProperty, + deselectedStroke: QuantumMeasurementColors.selectorButtonDeselectedStrokeProperty + }, + contentAppearanceStrategyOptions: { + deselectedContentOpacity: deselectedRadioButtonOpacity + } + }, + tandem: tandem.createTandem( 'experimentTypeRadioButtonGroup' ) + } + ); + this.addChild( experimentTypeRadioButtonGroup ); + + // Add the views for the two scenes that can be shown on this screen. + this.singlePhotonPhotonsExperimentSceneView = new PhotonsExperimentSceneView( model.singlePhotonExperimentSceneModel, { + translation: SCENE_POSITION, + tandem: tandem.createTandem( 'singlePhotonPhotonsExperimentSceneView' ) + } ); + this.addChild( this.singlePhotonPhotonsExperimentSceneView ); + this.manyPhotonsPhotonsExperimentSceneView = new PhotonsExperimentSceneView( model.manyPhotonsExperimentSceneModel, { + translation: SCENE_POSITION, + tandem: tandem.createTandem( 'manyPhotonsPhotonsExperimentSceneView' ) + } ); + this.addChild( this.manyPhotonsPhotonsExperimentSceneView ); + + // Move the mockup image to the front of the Z-order for easier comparisons with added UI elements. + if ( this.mockupImage ) { + this.mockupImage.moveToFront(); + } + + // Changing the background color based on the experiment type + Multilink.multilink( + [ + model.singlePhotonModeProperty, + QuantumMeasurementColors.classicalBackgroundColorProperty, + QuantumMeasurementColors.quantumBackgroundColorProperty + ], + ( singlePhotonMode, singlePhotonBackgroundColor, manyPhotonsBackgroundColor ) => { + QuantumMeasurementColors.screenBackgroundColorProperty.value = singlePhotonMode ? singlePhotonBackgroundColor : manyPhotonsBackgroundColor; + } ); + } + + public override reset(): void { + this.model.reset(); + this.singlePhotonPhotonsExperimentSceneView.reset(); + this.manyPhotonsPhotonsExperimentSceneView.reset(); + super.reset(); } } Index: js/photons/view/PhotonsExperimentSceneView.ts IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== diff --git a/js/photons/view/PhotonsExperimentSceneView.ts b/js/photons/view/PhotonsExperimentSceneView.ts new file mode 100644 --- /dev/null (date 1728506519474) +++ b/js/photons/view/PhotonsExperimentSceneView.ts (date 1728506519474) @@ -0,0 +1,74 @@ +// Copyright 2024, University of Colorado Boulder + +/** + * PhotonsExperimentSceneView presents the views for the classical or the quantum scene on the "Coins" screen depending + * upon how it is configured. + * + * @author John Blanco, PhET Interactive Simulations + */ + +import NumberProperty from '../../../../axon/js/NumberProperty.js'; +import TProperty from '../../../../axon/js/TProperty.js'; +import Range from '../../../../dot/js/Range.js'; +import ScreenView from '../../../../joist/js/ScreenView.js'; +import optionize, { EmptySelfOptions } from '../../../../phet-core/js/optionize.js'; +import WithRequired from '../../../../phet-core/js/types/WithRequired.js'; +import { Color, Line, Node, NodeOptions } from '../../../../scenery/js/imports.js'; +import QuantumMeasurementConstants from '../../common/QuantumMeasurementConstants.js'; +import quantumMeasurement from '../../quantumMeasurement.js'; + +type SelfOptions = EmptySelfOptions; +export type PhotonsExperimentSceneViewOptions = SelfOptions & WithRequired; + +const SCENE_WIDTH = QuantumMeasurementConstants.LAYOUT_BOUNDS.width; +const DIVIDER_X_POSITION_DURING_PREPARATION = Math.floor( ScreenView.DEFAULT_LAYOUT_BOUNDS.width * 0.38 ); +const DIVIDER_X_POSITION_DURING_MEASUREMENT = Math.ceil( ScreenView.DEFAULT_LAYOUT_BOUNDS.width * 0.2 ); +const DIVIDER_HEIGHT = 500; // empirically determined + +export default class PhotonsExperimentSceneView extends Node { + + public constructor( sceneModel: CoinsExperimentSceneModel, providedOptions?: PhotonsExperimentSceneViewOptions ) { + + const options = optionize()( + { + visibleProperty: sceneModel.activeProperty + }, + providedOptions + ); + + super( options ); + + this.dividerXPositionProperty = new NumberProperty( DIVIDER_X_POSITION_DURING_PREPARATION, { + range: new Range( DIVIDER_X_POSITION_DURING_MEASUREMENT, DIVIDER_X_POSITION_DURING_PREPARATION ) + } ); + + // Add the two areas of activity to the scene view. + this.preparationArea = new CoinExperimentPreparationArea( + sceneModel, + options.tandem.createTandem( 'preparationArea' ) + ); + this.addChild( this.preparationArea ); + + this.measurementArea = new CoinExperimentMeasurementArea( + sceneModel, + options.tandem.createTandem( 'measurementArea' ) + ); + this.addChild( this.measurementArea ); + + // Add the vertical line that will sit between the preparation and measurement areas. + const dividingLine = new Line( 0, 0, 0, DIVIDER_HEIGHT, { + stroke: Color.LIGHT_GRAY, + lineWidth: 2, + lineDash: [ 6, 5 ] + } ); + this.addChild( dividingLine ); + + // Position the dividing line and the two areas of activity. + this.dividerXPositionProperty.link( dividerPositionX => { + dividingLine.centerX = dividerPositionX; + } ); + + } +} + +quantumMeasurement.register( 'PhotonsExperimentSceneView', PhotonsExperimentSceneView ); \ No newline at end of file Index: js/photons/model/PhotonsModel.ts IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== diff --git a/js/photons/model/PhotonsModel.ts b/js/photons/model/PhotonsModel.ts --- a/js/photons/model/PhotonsModel.ts (revision 662ff96e3cc66f5df971819427e229598c89c28a) +++ b/js/photons/model/PhotonsModel.ts (date 1728506623678) @@ -12,6 +12,7 @@ * @author John Blanco, PhET Interactive Simulations */ +import BooleanProperty from '../../../../axon/js/BooleanProperty.js'; import NumberProperty from '../../../../axon/js/NumberProperty.js'; import Range from '../../../../dot/js/Range.js'; import Vector2 from '../../../../dot/js/Vector2.js'; @@ -32,6 +33,9 @@ public readonly polarizingBeamSplitter: PolarizingBeamSplitter; // The angle of polarization for the polarizing beam splitter, in degrees. Zero is horizontal and 90 is vertical. + public readonly singlePhotonModeProperty: BooleanProperty; + + // The angle of polarization for the polarizing beam splitter. public readonly photonPolarizationAngleProperty: NumberProperty; // photon detectors @@ -46,6 +50,11 @@ this.photonPolarizationAngleProperty = new NumberProperty( 45, { range: new Range( 0, 90 ), + this.singlePhotonModeProperty = new BooleanProperty( true, { + tandem: providedOptions.tandem.createTandem( 'singlePhotonModeProperty' ) + } ); + + this.photonPolarizationAngleProperty = new NumberProperty( 0, { tandem: providedOptions.tandem.createTandem( 'photonPolarizationAngleProperty' ) } );
samreid commented 1 month ago

CT says we are missing a file PhotonPolarizationAngleControl, maybe something didn't get pushed. I'll push a workaround for now to clear up CTQ.