diff --git a/contrib/common/lib/test/TstMotionBasedCanting.py b/contrib/common/lib/test/TstMotionBasedCanting.py index a0469d58f..355b5b26d 100755 --- a/contrib/common/lib/test/TstMotionBasedCanting.py +++ b/contrib/common/lib/test/TstMotionBasedCanting.py @@ -64,7 +64,7 @@ from opencsp.common.lib.geometry.FunctionXYContinuous import FunctionXYContinuous from opencsp.common.lib.geometry.Intersection import Intersection from opencsp.common.lib.geometry.Pxyz import Pxyz -from opencsp.common.lib.geometry.RegionXY import Resolution +from opencsp.common.lib.geometry.Resolution import Resolution from opencsp.common.lib.geometry.TransformXYZ import TransformXYZ from opencsp.common.lib.geometry.Uxyz import Uxyz from opencsp.common.lib.geometry.Vxyz import Vxyz diff --git a/doc/source/example/csp/base_classes_and_ray_trace.ipynb b/doc/source/example/csp/base_classes_and_ray_trace.ipynb index 3a1b40eb7..1f0116876 100644 --- a/doc/source/example/csp/base_classes_and_ray_trace.ipynb +++ b/doc/source/example/csp/base_classes_and_ray_trace.ipynb @@ -1166,7 +1166,7 @@ "source": [ "import opencsp.common.lib.csp.RayTrace as rt\n", "import opencsp.common.lib.render_control.RenderControlRayTrace as rcrt\n", - "from opencsp.common.lib.geometry.RegionXY import Resolution\n", + "from opencsp.common.lib.geometry.Resolution import Resolution\n", "\n", "point_source.location_in_space = Pxyz([0, 0, 0.5])\n", "\n", diff --git a/example/csp/example_optics_and_ray_tracing.py b/example/csp/example_optics_and_ray_tracing.py index 27ae1c855..2c29071eb 100644 --- a/example/csp/example_optics_and_ray_tracing.py +++ b/example/csp/example_optics_and_ray_tracing.py @@ -23,7 +23,8 @@ import opencsp.common.lib.csp.RayTrace as rt from opencsp.common.lib.csp.Scene import Scene from opencsp.common.lib.geometry.Pxyz import Pxyz -from opencsp.common.lib.geometry.RegionXY import RegionXY, Resolution +from opencsp.common.lib.geometry.RegionXY import RegionXY +from opencsp.common.lib.geometry.Resolution import Resolution from opencsp.common.lib.geometry.TransformXYZ import TransformXYZ from opencsp.common.lib.geometry.Uxyz import Uxyz from opencsp.common.lib.geometry.Vxy import Vxy diff --git a/example/mirror/data/input/ExampleMirrorOutput/ExampleMirrorOutput.log b/example/mirror/data/input/ExampleMirrorOutput/ExampleMirrorOutput.log index 195bac370..820da5c4d 100644 --- a/example/mirror/data/input/ExampleMirrorOutput/ExampleMirrorOutput.log +++ b/example/mirror/data/input/ExampleMirrorOutput/ExampleMirrorOutput.log @@ -1,73 +1,110 @@ -INFO:singleprocessing:Start run 2024-05-22 12:07:22 +INFO:singleprocessing:Start run 2026-02-14 12:16:01 INFO:singleprocessing:Clearing files in directory "mirror\data\output\ExampleMirrorOutput"... INFO:singleprocessing:Initializing render control structures... -INFO:singleprocessing:Beginning examples... +INFO:singleprocessing:Beginning tests... INFO:singleprocessing: Starting ExampleMirrorOutput.example_mirror()... INFO:singleprocessing:Closing existing plot windows... INFO:singleprocessing:Resetting figure management structure... -INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\tmo001_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_Face_Up_3d.png -INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\tmo001_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_Face_Up_3d.txt +INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\emo001_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_Face_Up_3d.png +INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\emo001_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_Face_Up_3d.txt INFO:singleprocessing: -Starting ExampleMirrorOutput.example_mirror_halfpi_rotation()... +Starting ExampleMirrorOutput.example_pentagon_elevation_30deg()... INFO:singleprocessing:Closing existing plot windows... INFO:singleprocessing:Resetting figure management structure... -INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\tmo002_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_Face_Horizon_3d.png -INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\tmo002_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_Face_Horizon_3d.txt +INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\emo002_Mirror_pentagon_f_eq_2.0m_Elevation_30_Degrees_3d.png +INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\emo002_Mirror_pentagon_f_eq_2.0m_Elevation_30_Degrees_3d.txt +INFO:singleprocessing: + +Starting ExampleMirrorOutput.example_deep_pentagon_elevation_60deg_embedding()... +INFO:singleprocessing:Closing existing plot windows... +INFO:singleprocessing:Resetting figure management structure... +INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\emo010_Mirror_pentagon_f_eq_1.0m_Elevation_60_Degrees_Embedding_Surface_3d.png +INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\emo010_Mirror_pentagon_f_eq_1.0m_Elevation_60_Degrees_Embedding_Surface_3d.txt +INFO:singleprocessing: + +Starting ExampleMirrorOutput.example_deep_pentagon_elevation_face_up_embedding()... +INFO:singleprocessing:Closing existing plot windows... +INFO:singleprocessing:Resetting figure management structure... +INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\emo011_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_3d.png +INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\emo011_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_3d.txt +INFO:singleprocessing: + +Starting ExampleMirrorOutput.example_deep_pentagon_elevation_face_up_embedding()... +INFO:singleprocessing:Closing existing plot windows... +INFO:singleprocessing:Resetting figure management structure... +WARNING:singleprocessing:WARNING: In View3d.show(), setting equal axes while also setting axis limits can prevent axis limits from taking effect. +INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\emo012_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_xy.png +INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\emo012_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_xy.txt +INFO:singleprocessing: + +Starting ExampleMirrorOutput.example_deep_pentagon_elevation_face_up_embedding()... +INFO:singleprocessing:Closing existing plot windows... +INFO:singleprocessing:Resetting figure management structure... +WARNING:singleprocessing:WARNING: In View3d.show(), setting equal axes while also setting axis limits can prevent axis limits from taking effect. +INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\emo013_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_xz.png +INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\emo013_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_xz.txt +INFO:singleprocessing: + +Starting ExampleMirrorOutput.example_deep_pentagon_elevation_face_up_embedding()... +INFO:singleprocessing:Closing existing plot windows... +INFO:singleprocessing:Resetting figure management structure... +WARNING:singleprocessing:WARNING: In View3d.show(), setting equal axes while also setting axis limits can prevent axis limits from taking effect. +INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\emo014_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_yz.png +INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\emo014_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_yz.txt INFO:singleprocessing: Starting ExampleMirrorOutput.example_facet()... INFO:singleprocessing:Closing existing plot windows... INFO:singleprocessing:Resetting figure management structure... -INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\tmo004_Facet_from_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_3d.png -INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\tmo004_Facet_from_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_3d.txt +INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\emo020_Facet_from_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_3d.png +INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\emo020_Facet_from_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_3d.txt INFO:singleprocessing: Starting ExampleMirrorOutput.example_heliostat_surface_normals()... INFO:singleprocessing:Closing existing plot windows... INFO:singleprocessing:Resetting figure management structure... -INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\tmo006_Heliostat_with_Parametrically_Defined_Facets_3d.png -INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\tmo006_Heliostat_with_Parametrically_Defined_Facets_3d.txt +INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\emo021_Heliostat_with_Parametrically_Defined_Facets_3d.png +INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\emo021_Heliostat_with_Parametrically_Defined_Facets_3d.txt INFO:singleprocessing: Starting ExampleMirrorOutput.example_solar_field()... INFO:singleprocessing:Closing existing plot windows... INFO:singleprocessing:Resetting figure management structure... -INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\tmo007_Two_Heliostats_3d.png -INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\tmo007_Two_Heliostats_3d.txt +INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\emo030_Two_Heliostats_3d.png +INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\emo030_Two_Heliostats_3d.txt INFO:singleprocessing: Starting ExampleMirrorOutput.example_heliostat_05W01_and_14W01()... INFO:singleprocessing:Closing existing plot windows... INFO:singleprocessing:Resetting figure management structure... -INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\tmo017_NSTTF_Heliostat_5W01_long_normals__xy.png -INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\tmo017_NSTTF_Heliostat_5W01_long_normals__xy.txt -INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\tmo018_NSTTF_Heliostat_14W01_long_normals__xy.png -INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\tmo018_NSTTF_Heliostat_14W01_long_normals__xy.txt -INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\tmo019_Two_NSTTF_Heliostats_5W01_and_14W01_very_long_normals__yz.png -INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\tmo019_Two_NSTTF_Heliostats_5W01_and_14W01_very_long_normals__yz.txt -INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\tmo020_NSTTF_Heliostat_5W01_exaggerated_z__3d_3.71z4.42.png -INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\tmo020_NSTTF_Heliostat_5W01_exaggerated_z__3d_3.71z4.42.txt -INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\tmo021_NSTTF_Heliostat_5W01_exaggerated_z__yz_3.71z4.42.png -INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\tmo021_NSTTF_Heliostat_5W01_exaggerated_z__yz_3.71z4.42.txt -INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\tmo022_NSTTF_Heliostat_14W01_exaggerated_z__3d_4.36z5.07.png -INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\tmo022_NSTTF_Heliostat_14W01_exaggerated_z__3d_4.36z5.07.txt -INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\tmo023_NSTTF_Heliostat_14W01_exaggerated_z__yz_4.36z5.07.png -INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\tmo023_NSTTF_Heliostat_14W01_exaggerated_z__yz_4.36z5.07.txt +INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\emo040_NSTTF_Heliostat_5W01_long_normals__xy.png +INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\emo040_NSTTF_Heliostat_5W01_long_normals__xy.txt +INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\emo041_NSTTF_Heliostat_14W01_long_normals__xy.png +INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\emo041_NSTTF_Heliostat_14W01_long_normals__xy.txt +INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\emo042_Two_NSTTF_Heliostats_5W01_and_14W01_very_long_normals__yz.png +INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\emo042_Two_NSTTF_Heliostats_5W01_and_14W01_very_long_normals__yz.txt +INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\emo050_NSTTF_Heliostat_5W01_exaggerated_z__3d_3.71z4.42.png +INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\emo050_NSTTF_Heliostat_5W01_exaggerated_z__3d_3.71z4.42.txt +INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\emo051_NSTTF_Heliostat_5W01_exaggerated_z__yz_3.71z4.42.png +INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\emo051_NSTTF_Heliostat_5W01_exaggerated_z__yz_3.71z4.42.txt +INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\emo052_NSTTF_Heliostat_14W01_exaggerated_z__3d_4.36z5.07.png +INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\emo052_NSTTF_Heliostat_14W01_exaggerated_z__3d_4.36z5.07.txt +INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\emo053_NSTTF_Heliostat_14W01_exaggerated_z__yz_4.36z5.07.png +INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\emo053_NSTTF_Heliostat_14W01_exaggerated_z__yz_4.36z5.07.txt INFO:singleprocessing: Starting ExampleMirrorOutput.example_heliostat_stages()... INFO:singleprocessing:Closing existing plot windows... INFO:singleprocessing:Resetting figure management structure... -INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\tmo024_NSTTF_Heliostat_Short_Focal_Length_Without_Canting_3d.png -INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\tmo024_NSTTF_Heliostat_Short_Focal_Length_Without_Canting_3d.txt -INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\tmo025_NSTTF_Heliostat_Short_Focal_Length_Canted_and_Lifted_3d.png -INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\tmo025_NSTTF_Heliostat_Short_Focal_Length_Canted_and_Lifted_3d.txt -INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\tmo026_NSTTF_Heliostat_Short_Focal_Length_With_Canting_3d.png -INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\tmo026_NSTTF_Heliostat_Short_Focal_Length_With_Canting_3d.txt -INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\tmo027_NSTTF_Heliostat_Short_Focal_Length_With_Canting_and_Tracking_3d.png -INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\tmo027_NSTTF_Heliostat_Short_Focal_Length_With_Canting_and_Tracking_3d.txt -INFO:singleprocessing:All examples complete. -INFO:singleprocessing:Closing created plot windows... +INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\emo060_NSTTF_Heliostat_Short_Focal_Length_Without_Canting_3d.png +INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\emo060_NSTTF_Heliostat_Short_Focal_Length_Without_Canting_3d.txt +INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\emo061_NSTTF_Heliostat_Short_Focal_Length_Canted_and_Lifted_3d.png +INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\emo061_NSTTF_Heliostat_Short_Focal_Length_Canted_and_Lifted_3d.txt +INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\emo062_NSTTF_Heliostat_Short_Focal_Length_With_Canting_3d.png +INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\emo062_NSTTF_Heliostat_Short_Focal_Length_With_Canting_3d.txt +INFO:singleprocessing:In View3d.save(), saving figure: mirror\data\output\ExampleMirrorOutput\emo063_NSTTF_Heliostat_Short_Focal_Length_With_Canting_and_Tracking_3d.png +INFO:singleprocessing:Saving figure text: mirror\data\output\ExampleMirrorOutput\emo063_NSTTF_Heliostat_Short_Focal_Length_With_Canting_and_Tracking_3d.txt +INFO:singleprocessing:All tests complete. diff --git a/example/mirror/data/input/ExampleMirrorOutput/emo001_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_Face_Up_3d.png b/example/mirror/data/input/ExampleMirrorOutput/emo001_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_Face_Up_3d.png new file mode 100644 index 000000000..97f6866bb Binary files /dev/null and b/example/mirror/data/input/ExampleMirrorOutput/emo001_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_Face_Up_3d.png differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/tmo001_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_Face_Up_3d.txt b/example/mirror/data/input/ExampleMirrorOutput/emo001_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_Face_Up_3d.txt similarity index 85% rename from example/mirror/data/input/ExampleMirrorOutput/tmo001_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_Face_Up_3d.txt rename to example/mirror/data/input/ExampleMirrorOutput/emo001_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_Face_Up_3d.txt index 0825749fb..fec505db9 100644 --- a/example/mirror/data/input/ExampleMirrorOutput/tmo001_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_Face_Up_3d.txt +++ b/example/mirror/data/input/ExampleMirrorOutput/emo001_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_Face_Up_3d.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 1 -Name: tmo001_Mirror (rectangle 2.0m x 3.0m, f=2.0m), Face Up, Face Up +Name: emo001_Mirror (rectangle 2.0m x 3.0m, f=2.0m), Face Up, Face Up Title: Mirror (rectangle 2.0m x 3.0m, f=2.0m), Face Up, Face Up Code tag: ExampleMirrorOutput.example_mirror() View spec: 3d diff --git a/example/mirror/data/input/ExampleMirrorOutput/emo002_Mirror_pentagon_f_eq_2.0m_Elevation_30_Degrees_3d.png b/example/mirror/data/input/ExampleMirrorOutput/emo002_Mirror_pentagon_f_eq_2.0m_Elevation_30_Degrees_3d.png new file mode 100644 index 000000000..e939cb36f Binary files /dev/null and b/example/mirror/data/input/ExampleMirrorOutput/emo002_Mirror_pentagon_f_eq_2.0m_Elevation_30_Degrees_3d.png differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/emo002_Mirror_pentagon_f_eq_2.0m_Elevation_30_Degrees_3d.txt b/example/mirror/data/input/ExampleMirrorOutput/emo002_Mirror_pentagon_f_eq_2.0m_Elevation_30_Degrees_3d.txt new file mode 100644 index 000000000..91939f6f4 --- /dev/null +++ b/example/mirror/data/input/ExampleMirrorOutput/emo002_Mirror_pentagon_f_eq_2.0m_Elevation_30_Degrees_3d.txt @@ -0,0 +1,17 @@ +Metadata: +Figure number: 1 +Name: emo002_Mirror (pentagon, f=2.0m), Elevation 30 Degrees +Title: Mirror (pentagon, f=2.0m), Elevation 30 Degrees +Code tag: ExampleMirrorOutput.example_pentagon_elevation_30deg() +View spec: 3d + +Title: +Mirror (pentagon, f=2.0m), Elevation 30 Degrees + +Caption: +A single mirror of shape (pentagon), analytically defined with focal length f=2.0m, facing 30 degrees above the horizon. + +Comments: +Oriented face 30 deg up from level. +Render mirror surface only. + diff --git a/example/mirror/data/input/ExampleMirrorOutput/emo010_Mirror_pentagon_f_eq_1.0m_Elevation_60_Degrees_Embedding_Surface_3d.png b/example/mirror/data/input/ExampleMirrorOutput/emo010_Mirror_pentagon_f_eq_1.0m_Elevation_60_Degrees_Embedding_Surface_3d.png new file mode 100644 index 000000000..2820670da Binary files /dev/null and b/example/mirror/data/input/ExampleMirrorOutput/emo010_Mirror_pentagon_f_eq_1.0m_Elevation_60_Degrees_Embedding_Surface_3d.png differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/emo010_Mirror_pentagon_f_eq_1.0m_Elevation_60_Degrees_Embedding_Surface_3d.txt b/example/mirror/data/input/ExampleMirrorOutput/emo010_Mirror_pentagon_f_eq_1.0m_Elevation_60_Degrees_Embedding_Surface_3d.txt new file mode 100644 index 000000000..63d232dee --- /dev/null +++ b/example/mirror/data/input/ExampleMirrorOutput/emo010_Mirror_pentagon_f_eq_1.0m_Elevation_60_Degrees_Embedding_Surface_3d.txt @@ -0,0 +1,16 @@ +Metadata: +Figure number: 1 +Name: emo010_Mirror (pentagon, f=1.0m), Elevation 60 Degrees, Embedding Surface +Title: Mirror (pentagon, f=1.0m), Elevation 60 Degrees, Embedding Surface +Code tag: ExampleMirrorOutput.example_deep_pentagon_elevation_60deg_embedding() +View spec: 3d + +Title: +Mirror (pentagon, f=1.0m), Elevation 60 Degrees, Embedding Surface + +Caption: +A single mirror of shape (pentagon), analytically defined with focal length f=1.0m, facing 60 degrees above the horizon. + +Comments: +Oriented face 60 deg up from level. + diff --git a/example/mirror/data/input/ExampleMirrorOutput/emo011_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_3d.png b/example/mirror/data/input/ExampleMirrorOutput/emo011_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_3d.png new file mode 100644 index 000000000..b9debc7fa Binary files /dev/null and b/example/mirror/data/input/ExampleMirrorOutput/emo011_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_3d.png differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/emo011_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_3d.txt b/example/mirror/data/input/ExampleMirrorOutput/emo011_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_3d.txt new file mode 100644 index 000000000..044b7ef16 --- /dev/null +++ b/example/mirror/data/input/ExampleMirrorOutput/emo011_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_3d.txt @@ -0,0 +1,16 @@ +Metadata: +Figure number: 1 +Name: emo011_Mirror (pentagon, f=1.0m), Face Up, Embedding Surface +Title: Mirror (pentagon, f=1.0m), Face Up, Embedding Surface +Code tag: ExampleMirrorOutput.example_deep_pentagon_elevation_face_up_embedding() +View spec: 3d + +Title: +Mirror (pentagon, f=1.0m), Face Up, Embedding Surface + +Caption: +A single mirror of shape (pentagon), analytically defined with focal length f=1.0m, facing up, with embedding suraface and origin slices. + +Comments: +Oriented face up. + diff --git a/example/mirror/data/input/ExampleMirrorOutput/emo012_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_xy.png b/example/mirror/data/input/ExampleMirrorOutput/emo012_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_xy.png new file mode 100644 index 000000000..637d6d798 Binary files /dev/null and b/example/mirror/data/input/ExampleMirrorOutput/emo012_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_xy.png differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/emo012_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_xy.txt b/example/mirror/data/input/ExampleMirrorOutput/emo012_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_xy.txt new file mode 100644 index 000000000..00c66f53b --- /dev/null +++ b/example/mirror/data/input/ExampleMirrorOutput/emo012_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_xy.txt @@ -0,0 +1,16 @@ +Metadata: +Figure number: 1 +Name: emo012_Mirror (pentagon, f=1.0m), Face Up, Embedding Surface +Title: Mirror (pentagon, f=1.0m), Face Up, Embedding Surface +Code tag: ExampleMirrorOutput.example_deep_pentagon_elevation_face_up_embedding() +View spec: xy + +Title: +Mirror (pentagon, f=1.0m), Face Up, Embedding Surface + +Caption: +A single mirror of shape (pentagon), analytically defined with focal length f=1.0m, facing up, with embedding suraface and origin slices. + +Comments: +Oriented face up. + diff --git a/example/mirror/data/input/ExampleMirrorOutput/emo013_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_xz.png b/example/mirror/data/input/ExampleMirrorOutput/emo013_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_xz.png new file mode 100644 index 000000000..b2b573a1e Binary files /dev/null and b/example/mirror/data/input/ExampleMirrorOutput/emo013_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_xz.png differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/emo013_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_xz.txt b/example/mirror/data/input/ExampleMirrorOutput/emo013_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_xz.txt new file mode 100644 index 000000000..747d72346 --- /dev/null +++ b/example/mirror/data/input/ExampleMirrorOutput/emo013_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_xz.txt @@ -0,0 +1,16 @@ +Metadata: +Figure number: 1 +Name: emo013_Mirror (pentagon, f=1.0m), Face Up, Embedding Surface +Title: Mirror (pentagon, f=1.0m), Face Up, Embedding Surface +Code tag: ExampleMirrorOutput.example_deep_pentagon_elevation_face_up_embedding() +View spec: xz + +Title: +Mirror (pentagon, f=1.0m), Face Up, Embedding Surface + +Caption: +A single mirror of shape (pentagon), analytically defined with focal length f=1.0m, facing up, with embedding suraface and origin slices. + +Comments: +Oriented face up. + diff --git a/example/mirror/data/input/ExampleMirrorOutput/emo014_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_yz.png b/example/mirror/data/input/ExampleMirrorOutput/emo014_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_yz.png new file mode 100644 index 000000000..fa503b938 Binary files /dev/null and b/example/mirror/data/input/ExampleMirrorOutput/emo014_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_yz.png differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/emo014_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_yz.txt b/example/mirror/data/input/ExampleMirrorOutput/emo014_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_yz.txt new file mode 100644 index 000000000..5e37291f3 --- /dev/null +++ b/example/mirror/data/input/ExampleMirrorOutput/emo014_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_yz.txt @@ -0,0 +1,16 @@ +Metadata: +Figure number: 1 +Name: emo014_Mirror (pentagon, f=1.0m), Face Up, Embedding Surface +Title: Mirror (pentagon, f=1.0m), Face Up, Embedding Surface +Code tag: ExampleMirrorOutput.example_deep_pentagon_elevation_face_up_embedding() +View spec: yz + +Title: +Mirror (pentagon, f=1.0m), Face Up, Embedding Surface + +Caption: +A single mirror of shape (pentagon), analytically defined with focal length f=1.0m, facing up, with embedding suraface and origin slices. + +Comments: +Oriented face up. + diff --git a/example/mirror/data/input/ExampleMirrorOutput/emo020_Facet_from_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_3d.png b/example/mirror/data/input/ExampleMirrorOutput/emo020_Facet_from_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_3d.png new file mode 100644 index 000000000..e282f1fda Binary files /dev/null and b/example/mirror/data/input/ExampleMirrorOutput/emo020_Facet_from_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_3d.png differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/tmo004_Facet_from_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_3d.txt b/example/mirror/data/input/ExampleMirrorOutput/emo020_Facet_from_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_3d.txt similarity index 87% rename from example/mirror/data/input/ExampleMirrorOutput/tmo004_Facet_from_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_3d.txt rename to example/mirror/data/input/ExampleMirrorOutput/emo020_Facet_from_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_3d.txt index 4945a707c..afd632bef 100644 --- a/example/mirror/data/input/ExampleMirrorOutput/tmo004_Facet_from_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_3d.txt +++ b/example/mirror/data/input/ExampleMirrorOutput/emo020_Facet_from_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_3d.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 1 -Name: tmo004_Facet, from Mirror (rectangle 2.0m x 3.0m, f=2.0m), Face Up +Name: emo020_Facet, from Mirror (rectangle 2.0m x 3.0m, f=2.0m), Face Up Title: Facet, from Mirror (rectangle 2.0m x 3.0m, f=2.0m), Face Up Code tag: ExampleMirrorOutput.example_facet() View spec: 3d diff --git a/example/mirror/data/input/ExampleMirrorOutput/emo021_Heliostat_with_Parametrically_Defined_Facets_3d.png b/example/mirror/data/input/ExampleMirrorOutput/emo021_Heliostat_with_Parametrically_Defined_Facets_3d.png new file mode 100644 index 000000000..f13261053 Binary files /dev/null and b/example/mirror/data/input/ExampleMirrorOutput/emo021_Heliostat_with_Parametrically_Defined_Facets_3d.png differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/tmo006_Heliostat_with_Parametrically_Defined_Facets_3d.txt b/example/mirror/data/input/ExampleMirrorOutput/emo021_Heliostat_with_Parametrically_Defined_Facets_3d.txt similarity index 87% rename from example/mirror/data/input/ExampleMirrorOutput/tmo006_Heliostat_with_Parametrically_Defined_Facets_3d.txt rename to example/mirror/data/input/ExampleMirrorOutput/emo021_Heliostat_with_Parametrically_Defined_Facets_3d.txt index 3e00f747e..46234f0cd 100644 --- a/example/mirror/data/input/ExampleMirrorOutput/tmo006_Heliostat_with_Parametrically_Defined_Facets_3d.txt +++ b/example/mirror/data/input/ExampleMirrorOutput/emo021_Heliostat_with_Parametrically_Defined_Facets_3d.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 1 -Name: tmo006_Heliostat with Parametrically Defined Facets +Name: emo021_Heliostat with Parametrically Defined Facets Title: Heliostat with Parametrically Defined Facets Code tag: ExampleMirrorOutput.example_heliostat_surface_normals() View spec: 3d diff --git a/example/mirror/data/input/ExampleMirrorOutput/emo030_Two_Heliostats_3d.png b/example/mirror/data/input/ExampleMirrorOutput/emo030_Two_Heliostats_3d.png new file mode 100644 index 000000000..8d02e9087 Binary files /dev/null and b/example/mirror/data/input/ExampleMirrorOutput/emo030_Two_Heliostats_3d.png differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/tmo007_Two_Heliostats_3d.txt b/example/mirror/data/input/ExampleMirrorOutput/emo030_Two_Heliostats_3d.txt similarity index 93% rename from example/mirror/data/input/ExampleMirrorOutput/tmo007_Two_Heliostats_3d.txt rename to example/mirror/data/input/ExampleMirrorOutput/emo030_Two_Heliostats_3d.txt index 34fe8760d..ceca1e973 100644 --- a/example/mirror/data/input/ExampleMirrorOutput/tmo007_Two_Heliostats_3d.txt +++ b/example/mirror/data/input/ExampleMirrorOutput/emo030_Two_Heliostats_3d.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 1 -Name: tmo007_Two Heliostats +Name: emo030_Two Heliostats Title: Two Heliostats Code tag: ExampleMirrorOutput.example_solar_field() View spec: 3d diff --git a/example/mirror/data/input/ExampleMirrorOutput/emo040_NSTTF_Heliostat_5W01_long_normals__xy.png b/example/mirror/data/input/ExampleMirrorOutput/emo040_NSTTF_Heliostat_5W01_long_normals__xy.png new file mode 100644 index 000000000..2170cf443 Binary files /dev/null and b/example/mirror/data/input/ExampleMirrorOutput/emo040_NSTTF_Heliostat_5W01_long_normals__xy.png differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/tmo017_NSTTF_Heliostat_5W01_long_normals__xy.txt b/example/mirror/data/input/ExampleMirrorOutput/emo040_NSTTF_Heliostat_5W01_long_normals__xy.txt similarity index 87% rename from example/mirror/data/input/ExampleMirrorOutput/tmo017_NSTTF_Heliostat_5W01_long_normals__xy.txt rename to example/mirror/data/input/ExampleMirrorOutput/emo040_NSTTF_Heliostat_5W01_long_normals__xy.txt index 45569d60c..12e9134bf 100644 --- a/example/mirror/data/input/ExampleMirrorOutput/tmo017_NSTTF_Heliostat_5W01_long_normals__xy.txt +++ b/example/mirror/data/input/ExampleMirrorOutput/emo040_NSTTF_Heliostat_5W01_long_normals__xy.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 1 -Name: tmo017_NSTTF Heliostat 5W01 (long normals) +Name: emo040_NSTTF Heliostat 5W01 (long normals) Title: NSTTF Heliostat 5W01 (long normals) Code tag: ExampleMirrorOutput.example_heliostat_05W01_and_14W01() View spec: xy diff --git a/example/mirror/data/input/ExampleMirrorOutput/emo041_NSTTF_Heliostat_14W01_long_normals__xy.png b/example/mirror/data/input/ExampleMirrorOutput/emo041_NSTTF_Heliostat_14W01_long_normals__xy.png new file mode 100644 index 000000000..92925af22 Binary files /dev/null and b/example/mirror/data/input/ExampleMirrorOutput/emo041_NSTTF_Heliostat_14W01_long_normals__xy.png differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/tmo018_NSTTF_Heliostat_14W01_long_normals__xy.txt b/example/mirror/data/input/ExampleMirrorOutput/emo041_NSTTF_Heliostat_14W01_long_normals__xy.txt similarity index 87% rename from example/mirror/data/input/ExampleMirrorOutput/tmo018_NSTTF_Heliostat_14W01_long_normals__xy.txt rename to example/mirror/data/input/ExampleMirrorOutput/emo041_NSTTF_Heliostat_14W01_long_normals__xy.txt index 1887df975..1f5620475 100644 --- a/example/mirror/data/input/ExampleMirrorOutput/tmo018_NSTTF_Heliostat_14W01_long_normals__xy.txt +++ b/example/mirror/data/input/ExampleMirrorOutput/emo041_NSTTF_Heliostat_14W01_long_normals__xy.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 2 -Name: tmo018_NSTTF Heliostat 14W01 (long normals) +Name: emo041_NSTTF Heliostat 14W01 (long normals) Title: NSTTF Heliostat 14W01 (long normals) Code tag: ExampleMirrorOutput.example_heliostat_05W01_and_14W01() View spec: xy diff --git a/example/mirror/data/input/ExampleMirrorOutput/emo042_Two_NSTTF_Heliostats_5W01_and_14W01_very_long_normals__yz.png b/example/mirror/data/input/ExampleMirrorOutput/emo042_Two_NSTTF_Heliostats_5W01_and_14W01_very_long_normals__yz.png new file mode 100644 index 000000000..568c61101 Binary files /dev/null and b/example/mirror/data/input/ExampleMirrorOutput/emo042_Two_NSTTF_Heliostats_5W01_and_14W01_very_long_normals__yz.png differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/tmo019_Two_NSTTF_Heliostats_5W01_and_14W01_very_long_normals__yz.txt b/example/mirror/data/input/ExampleMirrorOutput/emo042_Two_NSTTF_Heliostats_5W01_and_14W01_very_long_normals__yz.txt similarity index 89% rename from example/mirror/data/input/ExampleMirrorOutput/tmo019_Two_NSTTF_Heliostats_5W01_and_14W01_very_long_normals__yz.txt rename to example/mirror/data/input/ExampleMirrorOutput/emo042_Two_NSTTF_Heliostats_5W01_and_14W01_very_long_normals__yz.txt index 3bf524f63..35e12e964 100644 --- a/example/mirror/data/input/ExampleMirrorOutput/tmo019_Two_NSTTF_Heliostats_5W01_and_14W01_very_long_normals__yz.txt +++ b/example/mirror/data/input/ExampleMirrorOutput/emo042_Two_NSTTF_Heliostats_5W01_and_14W01_very_long_normals__yz.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 3 -Name: tmo019_Two NSTTF Heliostats: 5W01 and 14W01 (very long normals) +Name: emo042_Two NSTTF Heliostats: 5W01 and 14W01 (very long normals) Title: Two NSTTF Heliostats: 5W01 and 14W01 (very long normals) Code tag: ExampleMirrorOutput.example_heliostat_05W01_and_14W01() View spec: yz diff --git a/example/mirror/data/input/ExampleMirrorOutput/emo050_NSTTF_Heliostat_5W01_exaggerated_z__3d_3.71z4.42.png b/example/mirror/data/input/ExampleMirrorOutput/emo050_NSTTF_Heliostat_5W01_exaggerated_z__3d_3.71z4.42.png new file mode 100644 index 000000000..8f3af024c Binary files /dev/null and b/example/mirror/data/input/ExampleMirrorOutput/emo050_NSTTF_Heliostat_5W01_exaggerated_z__3d_3.71z4.42.png differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/tmo020_NSTTF_Heliostat_5W01_exaggerated_z__3d_3.71z4.42.txt b/example/mirror/data/input/ExampleMirrorOutput/emo050_NSTTF_Heliostat_5W01_exaggerated_z__3d_3.71z4.42.txt similarity index 87% rename from example/mirror/data/input/ExampleMirrorOutput/tmo020_NSTTF_Heliostat_5W01_exaggerated_z__3d_3.71z4.42.txt rename to example/mirror/data/input/ExampleMirrorOutput/emo050_NSTTF_Heliostat_5W01_exaggerated_z__3d_3.71z4.42.txt index d9f44c028..91b52fcff 100644 --- a/example/mirror/data/input/ExampleMirrorOutput/tmo020_NSTTF_Heliostat_5W01_exaggerated_z__3d_3.71z4.42.txt +++ b/example/mirror/data/input/ExampleMirrorOutput/emo050_NSTTF_Heliostat_5W01_exaggerated_z__3d_3.71z4.42.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 4 -Name: tmo020_NSTTF Heliostat 5W01 (exaggerated z) +Name: emo050_NSTTF Heliostat 5W01 (exaggerated z) Title: NSTTF Heliostat 5W01 (exaggerated z) Code tag: ExampleMirrorOutput.example_heliostat_05W01_and_14W01() View spec: 3d diff --git a/example/mirror/data/input/ExampleMirrorOutput/emo051_NSTTF_Heliostat_5W01_exaggerated_z__yz_3.71z4.42.png b/example/mirror/data/input/ExampleMirrorOutput/emo051_NSTTF_Heliostat_5W01_exaggerated_z__yz_3.71z4.42.png new file mode 100644 index 000000000..287d92481 Binary files /dev/null and b/example/mirror/data/input/ExampleMirrorOutput/emo051_NSTTF_Heliostat_5W01_exaggerated_z__yz_3.71z4.42.png differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/tmo021_NSTTF_Heliostat_5W01_exaggerated_z__yz_3.71z4.42.txt b/example/mirror/data/input/ExampleMirrorOutput/emo051_NSTTF_Heliostat_5W01_exaggerated_z__yz_3.71z4.42.txt similarity index 87% rename from example/mirror/data/input/ExampleMirrorOutput/tmo021_NSTTF_Heliostat_5W01_exaggerated_z__yz_3.71z4.42.txt rename to example/mirror/data/input/ExampleMirrorOutput/emo051_NSTTF_Heliostat_5W01_exaggerated_z__yz_3.71z4.42.txt index 49e73aa13..3ab74a6e2 100644 --- a/example/mirror/data/input/ExampleMirrorOutput/tmo021_NSTTF_Heliostat_5W01_exaggerated_z__yz_3.71z4.42.txt +++ b/example/mirror/data/input/ExampleMirrorOutput/emo051_NSTTF_Heliostat_5W01_exaggerated_z__yz_3.71z4.42.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 5 -Name: tmo021_NSTTF Heliostat 5W01 (exaggerated z) +Name: emo051_NSTTF Heliostat 5W01 (exaggerated z) Title: NSTTF Heliostat 5W01 (exaggerated z) Code tag: ExampleMirrorOutput.example_heliostat_05W01_and_14W01() View spec: yz diff --git a/example/mirror/data/input/ExampleMirrorOutput/emo052_NSTTF_Heliostat_14W01_exaggerated_z__3d_4.36z5.07.png b/example/mirror/data/input/ExampleMirrorOutput/emo052_NSTTF_Heliostat_14W01_exaggerated_z__3d_4.36z5.07.png new file mode 100644 index 000000000..a0187278c Binary files /dev/null and b/example/mirror/data/input/ExampleMirrorOutput/emo052_NSTTF_Heliostat_14W01_exaggerated_z__3d_4.36z5.07.png differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/tmo022_NSTTF_Heliostat_14W01_exaggerated_z__3d_4.36z5.07.txt b/example/mirror/data/input/ExampleMirrorOutput/emo052_NSTTF_Heliostat_14W01_exaggerated_z__3d_4.36z5.07.txt similarity index 87% rename from example/mirror/data/input/ExampleMirrorOutput/tmo022_NSTTF_Heliostat_14W01_exaggerated_z__3d_4.36z5.07.txt rename to example/mirror/data/input/ExampleMirrorOutput/emo052_NSTTF_Heliostat_14W01_exaggerated_z__3d_4.36z5.07.txt index 93cd6523f..94057351a 100644 --- a/example/mirror/data/input/ExampleMirrorOutput/tmo022_NSTTF_Heliostat_14W01_exaggerated_z__3d_4.36z5.07.txt +++ b/example/mirror/data/input/ExampleMirrorOutput/emo052_NSTTF_Heliostat_14W01_exaggerated_z__3d_4.36z5.07.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 6 -Name: tmo022_NSTTF Heliostat 14W01 (exaggerated z) +Name: emo052_NSTTF Heliostat 14W01 (exaggerated z) Title: NSTTF Heliostat 14W01 (exaggerated z) Code tag: ExampleMirrorOutput.example_heliostat_05W01_and_14W01() View spec: 3d diff --git a/example/mirror/data/input/ExampleMirrorOutput/emo053_NSTTF_Heliostat_14W01_exaggerated_z__yz_4.36z5.07.png b/example/mirror/data/input/ExampleMirrorOutput/emo053_NSTTF_Heliostat_14W01_exaggerated_z__yz_4.36z5.07.png new file mode 100644 index 000000000..e56e2e6ab Binary files /dev/null and b/example/mirror/data/input/ExampleMirrorOutput/emo053_NSTTF_Heliostat_14W01_exaggerated_z__yz_4.36z5.07.png differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/tmo023_NSTTF_Heliostat_14W01_exaggerated_z__yz_4.36z5.07.txt b/example/mirror/data/input/ExampleMirrorOutput/emo053_NSTTF_Heliostat_14W01_exaggerated_z__yz_4.36z5.07.txt similarity index 87% rename from example/mirror/data/input/ExampleMirrorOutput/tmo023_NSTTF_Heliostat_14W01_exaggerated_z__yz_4.36z5.07.txt rename to example/mirror/data/input/ExampleMirrorOutput/emo053_NSTTF_Heliostat_14W01_exaggerated_z__yz_4.36z5.07.txt index 35b698942..b4e632567 100644 --- a/example/mirror/data/input/ExampleMirrorOutput/tmo023_NSTTF_Heliostat_14W01_exaggerated_z__yz_4.36z5.07.txt +++ b/example/mirror/data/input/ExampleMirrorOutput/emo053_NSTTF_Heliostat_14W01_exaggerated_z__yz_4.36z5.07.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 7 -Name: tmo023_NSTTF Heliostat 14W01 (exaggerated z) +Name: emo053_NSTTF Heliostat 14W01 (exaggerated z) Title: NSTTF Heliostat 14W01 (exaggerated z) Code tag: ExampleMirrorOutput.example_heliostat_05W01_and_14W01() View spec: yz diff --git a/example/mirror/data/input/ExampleMirrorOutput/emo060_NSTTF_Heliostat_Short_Focal_Length_Without_Canting_3d.png b/example/mirror/data/input/ExampleMirrorOutput/emo060_NSTTF_Heliostat_Short_Focal_Length_Without_Canting_3d.png new file mode 100644 index 000000000..a803b8923 Binary files /dev/null and b/example/mirror/data/input/ExampleMirrorOutput/emo060_NSTTF_Heliostat_Short_Focal_Length_Without_Canting_3d.png differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/tmo024_NSTTF_Heliostat_Short_Focal_Length_Without_Canting_3d.txt b/example/mirror/data/input/ExampleMirrorOutput/emo060_NSTTF_Heliostat_Short_Focal_Length_Without_Canting_3d.txt similarity index 84% rename from example/mirror/data/input/ExampleMirrorOutput/tmo024_NSTTF_Heliostat_Short_Focal_Length_Without_Canting_3d.txt rename to example/mirror/data/input/ExampleMirrorOutput/emo060_NSTTF_Heliostat_Short_Focal_Length_Without_Canting_3d.txt index fd6e70850..58dd8338d 100644 --- a/example/mirror/data/input/ExampleMirrorOutput/tmo024_NSTTF_Heliostat_Short_Focal_Length_Without_Canting_3d.txt +++ b/example/mirror/data/input/ExampleMirrorOutput/emo060_NSTTF_Heliostat_Short_Focal_Length_Without_Canting_3d.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 1 -Name: tmo024_NSTTF Heliostat Short Focal Length, Without Canting +Name: emo060_NSTTF Heliostat Short Focal Length, Without Canting Title: NSTTF Heliostat Short Focal Length, Without Canting Code tag: ExampleMirrorOutput.example_heliostat_stages() View spec: 3d diff --git a/example/mirror/data/input/ExampleMirrorOutput/emo061_NSTTF_Heliostat_Short_Focal_Length_Canted_and_Lifted_3d.png b/example/mirror/data/input/ExampleMirrorOutput/emo061_NSTTF_Heliostat_Short_Focal_Length_Canted_and_Lifted_3d.png new file mode 100644 index 000000000..767b44dc2 Binary files /dev/null and b/example/mirror/data/input/ExampleMirrorOutput/emo061_NSTTF_Heliostat_Short_Focal_Length_Canted_and_Lifted_3d.png differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/tmo025_NSTTF_Heliostat_Short_Focal_Length_Canted_and_Lifted_3d.txt b/example/mirror/data/input/ExampleMirrorOutput/emo061_NSTTF_Heliostat_Short_Focal_Length_Canted_and_Lifted_3d.txt similarity index 85% rename from example/mirror/data/input/ExampleMirrorOutput/tmo025_NSTTF_Heliostat_Short_Focal_Length_Canted_and_Lifted_3d.txt rename to example/mirror/data/input/ExampleMirrorOutput/emo061_NSTTF_Heliostat_Short_Focal_Length_Canted_and_Lifted_3d.txt index 8e70e6dd1..cc462086c 100644 --- a/example/mirror/data/input/ExampleMirrorOutput/tmo025_NSTTF_Heliostat_Short_Focal_Length_Canted_and_Lifted_3d.txt +++ b/example/mirror/data/input/ExampleMirrorOutput/emo061_NSTTF_Heliostat_Short_Focal_Length_Canted_and_Lifted_3d.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 2 -Name: tmo025_NSTTF Heliostat Short Focal Length, Canted and Lifted +Name: emo061_NSTTF Heliostat Short Focal Length, Canted and Lifted Title: NSTTF Heliostat Short Focal Length, Canted and Lifted Code tag: ExampleMirrorOutput.example_heliostat_stages() View spec: 3d diff --git a/example/mirror/data/input/ExampleMirrorOutput/emo062_NSTTF_Heliostat_Short_Focal_Length_With_Canting_3d.png b/example/mirror/data/input/ExampleMirrorOutput/emo062_NSTTF_Heliostat_Short_Focal_Length_With_Canting_3d.png new file mode 100644 index 000000000..27fccc708 Binary files /dev/null and b/example/mirror/data/input/ExampleMirrorOutput/emo062_NSTTF_Heliostat_Short_Focal_Length_With_Canting_3d.png differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/tmo026_NSTTF_Heliostat_Short_Focal_Length_With_Canting_3d.txt b/example/mirror/data/input/ExampleMirrorOutput/emo062_NSTTF_Heliostat_Short_Focal_Length_With_Canting_3d.txt similarity index 84% rename from example/mirror/data/input/ExampleMirrorOutput/tmo026_NSTTF_Heliostat_Short_Focal_Length_With_Canting_3d.txt rename to example/mirror/data/input/ExampleMirrorOutput/emo062_NSTTF_Heliostat_Short_Focal_Length_With_Canting_3d.txt index 757f7d423..ea22fae26 100644 --- a/example/mirror/data/input/ExampleMirrorOutput/tmo026_NSTTF_Heliostat_Short_Focal_Length_With_Canting_3d.txt +++ b/example/mirror/data/input/ExampleMirrorOutput/emo062_NSTTF_Heliostat_Short_Focal_Length_With_Canting_3d.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 3 -Name: tmo026_NSTTF Heliostat Short Focal Length, With Canting +Name: emo062_NSTTF Heliostat Short Focal Length, With Canting Title: NSTTF Heliostat Short Focal Length, With Canting Code tag: ExampleMirrorOutput.example_heliostat_stages() View spec: 3d diff --git a/example/mirror/data/input/ExampleMirrorOutput/emo063_NSTTF_Heliostat_Short_Focal_Length_With_Canting_and_Tracking_3d.png b/example/mirror/data/input/ExampleMirrorOutput/emo063_NSTTF_Heliostat_Short_Focal_Length_With_Canting_and_Tracking_3d.png new file mode 100644 index 000000000..a128dcd39 Binary files /dev/null and b/example/mirror/data/input/ExampleMirrorOutput/emo063_NSTTF_Heliostat_Short_Focal_Length_With_Canting_and_Tracking_3d.png differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/tmo027_NSTTF_Heliostat_Short_Focal_Length_With_Canting_and_Tracking_3d.txt b/example/mirror/data/input/ExampleMirrorOutput/emo063_NSTTF_Heliostat_Short_Focal_Length_With_Canting_and_Tracking_3d.txt similarity index 89% rename from example/mirror/data/input/ExampleMirrorOutput/tmo027_NSTTF_Heliostat_Short_Focal_Length_With_Canting_and_Tracking_3d.txt rename to example/mirror/data/input/ExampleMirrorOutput/emo063_NSTTF_Heliostat_Short_Focal_Length_With_Canting_and_Tracking_3d.txt index fce266edc..65df2e5c5 100644 --- a/example/mirror/data/input/ExampleMirrorOutput/tmo027_NSTTF_Heliostat_Short_Focal_Length_With_Canting_and_Tracking_3d.txt +++ b/example/mirror/data/input/ExampleMirrorOutput/emo063_NSTTF_Heliostat_Short_Focal_Length_With_Canting_and_Tracking_3d.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 4 -Name: tmo027_NSTTF Heliostat Short Focal Length, With Canting and Tracking +Name: emo063_NSTTF Heliostat Short Focal Length, With Canting and Tracking Title: NSTTF Heliostat Short Focal Length, With Canting and Tracking Code tag: ExampleMirrorOutput.example_heliostat_stages() View spec: 3d diff --git a/example/mirror/data/input/ExampleMirrorOutput/tmo001_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_Face_Up_3d.png b/example/mirror/data/input/ExampleMirrorOutput/tmo001_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_Face_Up_3d.png deleted file mode 100755 index 180fd4312..000000000 Binary files a/example/mirror/data/input/ExampleMirrorOutput/tmo001_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_Face_Up_3d.png and /dev/null differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/tmo002_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_Face_Horizon_3d.png b/example/mirror/data/input/ExampleMirrorOutput/tmo002_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_Face_Horizon_3d.png deleted file mode 100755 index bf218c406..000000000 Binary files a/example/mirror/data/input/ExampleMirrorOutput/tmo002_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_Face_Horizon_3d.png and /dev/null differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/tmo002_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_Face_Horizon_3d.txt b/example/mirror/data/input/ExampleMirrorOutput/tmo002_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_Face_Horizon_3d.txt deleted file mode 100644 index 83fb81594..000000000 --- a/example/mirror/data/input/ExampleMirrorOutput/tmo002_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_Face_Horizon_3d.txt +++ /dev/null @@ -1,17 +0,0 @@ -Metadata: -Figure number: 1 -Name: tmo002_Mirror (rectangle 2.0m x 3.0m, f=2.0m), Face Up, Face Horizon -Title: Mirror (rectangle 2.0m x 3.0m, f=2.0m), Face Up, Face Horizon -Code tag: ExampleMirrorOutput.example_mirror_halfpi_rotation() -View spec: 3d - -Title: -Mirror (rectangle 2.0m x 3.0m, f=2.0m), Face Up, Face Horizon - -Caption: -A single mirror of shape (rectangle 2.0m x 3.0m), analytically defined with focal length f=2.0m, facing the horizon. - -Comments: -Oriented face 45 deg up from level. -Render surface only. - diff --git a/example/mirror/data/input/ExampleMirrorOutput/tmo004_Facet_from_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_3d.png b/example/mirror/data/input/ExampleMirrorOutput/tmo004_Facet_from_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_3d.png deleted file mode 100755 index d8a6b3f64..000000000 Binary files a/example/mirror/data/input/ExampleMirrorOutput/tmo004_Facet_from_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_3d.png and /dev/null differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/tmo006_Heliostat_with_Parametrically_Defined_Facets_3d.png b/example/mirror/data/input/ExampleMirrorOutput/tmo006_Heliostat_with_Parametrically_Defined_Facets_3d.png deleted file mode 100755 index 99be2bfb1..000000000 Binary files a/example/mirror/data/input/ExampleMirrorOutput/tmo006_Heliostat_with_Parametrically_Defined_Facets_3d.png and /dev/null differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/tmo007_Two_Heliostats_3d.png b/example/mirror/data/input/ExampleMirrorOutput/tmo007_Two_Heliostats_3d.png deleted file mode 100755 index d2cb09a38..000000000 Binary files a/example/mirror/data/input/ExampleMirrorOutput/tmo007_Two_Heliostats_3d.png and /dev/null differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/tmo017_NSTTF_Heliostat_5W01_long_normals__xy.png b/example/mirror/data/input/ExampleMirrorOutput/tmo017_NSTTF_Heliostat_5W01_long_normals__xy.png deleted file mode 100755 index 08476352d..000000000 Binary files a/example/mirror/data/input/ExampleMirrorOutput/tmo017_NSTTF_Heliostat_5W01_long_normals__xy.png and /dev/null differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/tmo018_NSTTF_Heliostat_14W01_long_normals__xy.png b/example/mirror/data/input/ExampleMirrorOutput/tmo018_NSTTF_Heliostat_14W01_long_normals__xy.png deleted file mode 100755 index af0007119..000000000 Binary files a/example/mirror/data/input/ExampleMirrorOutput/tmo018_NSTTF_Heliostat_14W01_long_normals__xy.png and /dev/null differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/tmo019_Two_NSTTF_Heliostats_5W01_and_14W01_very_long_normals__yz.png b/example/mirror/data/input/ExampleMirrorOutput/tmo019_Two_NSTTF_Heliostats_5W01_and_14W01_very_long_normals__yz.png deleted file mode 100755 index 9d433cb21..000000000 Binary files a/example/mirror/data/input/ExampleMirrorOutput/tmo019_Two_NSTTF_Heliostats_5W01_and_14W01_very_long_normals__yz.png and /dev/null differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/tmo020_NSTTF_Heliostat_5W01_exaggerated_z__3d_3.71z4.42.png b/example/mirror/data/input/ExampleMirrorOutput/tmo020_NSTTF_Heliostat_5W01_exaggerated_z__3d_3.71z4.42.png deleted file mode 100755 index c5d9632b3..000000000 Binary files a/example/mirror/data/input/ExampleMirrorOutput/tmo020_NSTTF_Heliostat_5W01_exaggerated_z__3d_3.71z4.42.png and /dev/null differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/tmo021_NSTTF_Heliostat_5W01_exaggerated_z__yz_3.71z4.42.png b/example/mirror/data/input/ExampleMirrorOutput/tmo021_NSTTF_Heliostat_5W01_exaggerated_z__yz_3.71z4.42.png deleted file mode 100755 index 94747718f..000000000 Binary files a/example/mirror/data/input/ExampleMirrorOutput/tmo021_NSTTF_Heliostat_5W01_exaggerated_z__yz_3.71z4.42.png and /dev/null differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/tmo022_NSTTF_Heliostat_14W01_exaggerated_z__3d_4.36z5.07.png b/example/mirror/data/input/ExampleMirrorOutput/tmo022_NSTTF_Heliostat_14W01_exaggerated_z__3d_4.36z5.07.png deleted file mode 100755 index 4ab182cef..000000000 Binary files a/example/mirror/data/input/ExampleMirrorOutput/tmo022_NSTTF_Heliostat_14W01_exaggerated_z__3d_4.36z5.07.png and /dev/null differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/tmo023_NSTTF_Heliostat_14W01_exaggerated_z__yz_4.36z5.07.png b/example/mirror/data/input/ExampleMirrorOutput/tmo023_NSTTF_Heliostat_14W01_exaggerated_z__yz_4.36z5.07.png deleted file mode 100755 index dc0e06e31..000000000 Binary files a/example/mirror/data/input/ExampleMirrorOutput/tmo023_NSTTF_Heliostat_14W01_exaggerated_z__yz_4.36z5.07.png and /dev/null differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/tmo024_NSTTF_Heliostat_Short_Focal_Length_Without_Canting_3d.png b/example/mirror/data/input/ExampleMirrorOutput/tmo024_NSTTF_Heliostat_Short_Focal_Length_Without_Canting_3d.png deleted file mode 100755 index f9aeae2d9..000000000 Binary files a/example/mirror/data/input/ExampleMirrorOutput/tmo024_NSTTF_Heliostat_Short_Focal_Length_Without_Canting_3d.png and /dev/null differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/tmo025_NSTTF_Heliostat_Short_Focal_Length_Canted_and_Lifted_3d.png b/example/mirror/data/input/ExampleMirrorOutput/tmo025_NSTTF_Heliostat_Short_Focal_Length_Canted_and_Lifted_3d.png deleted file mode 100755 index 1a8d81007..000000000 Binary files a/example/mirror/data/input/ExampleMirrorOutput/tmo025_NSTTF_Heliostat_Short_Focal_Length_Canted_and_Lifted_3d.png and /dev/null differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/tmo026_NSTTF_Heliostat_Short_Focal_Length_With_Canting_3d.png b/example/mirror/data/input/ExampleMirrorOutput/tmo026_NSTTF_Heliostat_Short_Focal_Length_With_Canting_3d.png deleted file mode 100755 index e87579a18..000000000 Binary files a/example/mirror/data/input/ExampleMirrorOutput/tmo026_NSTTF_Heliostat_Short_Focal_Length_With_Canting_3d.png and /dev/null differ diff --git a/example/mirror/data/input/ExampleMirrorOutput/tmo027_NSTTF_Heliostat_Short_Focal_Length_With_Canting_and_Tracking_3d.png b/example/mirror/data/input/ExampleMirrorOutput/tmo027_NSTTF_Heliostat_Short_Focal_Length_With_Canting_and_Tracking_3d.png deleted file mode 100755 index 7c16bd2d9..000000000 Binary files a/example/mirror/data/input/ExampleMirrorOutput/tmo027_NSTTF_Heliostat_Short_Focal_Length_With_Canting_and_Tracking_3d.png and /dev/null differ diff --git a/example/mirror/example_MirrorOutput.py b/example/mirror/example_MirrorOutput.py index 0f04c7ec8..3f66a2570 100644 --- a/example/mirror/example_MirrorOutput.py +++ b/example/mirror/example_MirrorOutput.py @@ -1,29 +1,35 @@ +""" +Demonstrate mirror plotting routines. +""" + import copy import datetime from typing import Callable -import matplotlib import numpy as np import pytz from scipy.spatial.transform import Rotation +import opencsp.common.lib.csp.embedding_mirror_surface as ems from opencsp.common.lib.csp.FacetEnsemble import FacetEnsemble from opencsp.common.lib.csp.LightSourceSun import LightSourceSun from opencsp.common.lib.csp.Scene import Scene from opencsp.common.lib.geometry.Pxyz import Pxyz -from opencsp.common.lib.geometry.RegionXY import RegionXY, Resolution +from opencsp.common.lib.geometry.RegionXY import RegionXY from opencsp.common.lib.geometry.Pxy import Pxy from opencsp.common.lib.geometry.TransformXYZ import TransformXYZ from opencsp.common.lib.geometry.Vxyz import Vxyz import opencsp.common.lib.opencsp_path.data_path_for_test as dpft import opencsp.common.lib.render.figure_management as fm import opencsp.common.lib.render.view_spec as vs -import opencsp.common.lib.render_control.RenderControlEnsemble as rce +import opencsp.common.lib.render_control.RenderControlAxis as rca import opencsp.common.lib.render_control.RenderControlFacet as rcf +import opencsp.common.lib.render_control.RenderControlFacetEnsemble as rcfe import opencsp.common.lib.render_control.RenderControlHeliostat as rch +import opencsp.common.lib.render_control.RenderControlLightPath as rclp import opencsp.common.lib.render_control.RenderControlMirror as rcm +import opencsp.common.lib.render_control.RenderControlMirrorEmbedded as rcme +import opencsp.common.lib.render_control.RenderControlMirrorProjected as rcmp import opencsp.common.lib.render_control.RenderControlSolarField as rcsf -import opencsp.common.lib.render_control.RenderControlLightPath as rclp -import opencsp.common.lib.render_control.RenderControlRayTrace as rcrt import opencsp.common.lib.test.TestOutput as to import opencsp.common.lib.tool.log_tools as lt import opencsp.common.lib.tool.string_tools as st @@ -32,9 +38,7 @@ from opencsp.common.lib.csp.MirrorParametricRectangular import MirrorParametricRectangular from opencsp.common.lib.csp.MirrorParametric import MirrorParametric from opencsp.common.lib.csp.SolarField import SolarField -import opencsp.common.lib.render_control.RenderControlFacetEnsemble as rcfe import opencsp.common.lib.geo.lon_lat_nsttf as lln -import opencsp.common.lib.csp.RayTrace as rt PI = np.pi @@ -51,7 +55,7 @@ class ExampleMirrorOutput(to.TestOutput): def setUpClass( cls, source_file_body: str = 'ExampleMirrorOutput', # Set these here, because pytest calls - figure_prefix_root: str = 'tmo', + figure_prefix_root: str = 'emo', interactive: bool = False, verify: bool = True, ): @@ -65,14 +69,12 @@ def setUpClass( ) def setUp(self): - # create a scnene for placing optics + # Create a scene for placing optics. self.scene = Scene() # Mirror, based on a parameteric model. self.m1_focal_length = 2.0 # meters - self.m1_fxn = self.lambda_symmetric_paraboloid( - self.m1_focal_length - ) # Include self as a parameter, because this setup_class() function is a @classmethod. + self.m1_fxn = self.lambda_symmetric_paraboloid(self.m1_focal_length) self.m1_len_x = 2.0 # m self.m1_len_y = 3.0 # m self.m1_rectangle_xy = (self.m1_len_x, self.m1_len_y) @@ -97,6 +99,35 @@ def setUp(self): ) pentagon_region = RegionXY.from_vertices(pentagon_vertices) self.m_pentagon = MirrorParametric(self.m1_fxn, pentagon_region) + self.m_pentagon_shape_description = 'pentagon' + self.m_pentagon_title = ( + 'Mirror (' + self.m_pentagon_shape_description + ', f=' + str(self.m1_focal_length) + 'm)' + ) + self.m_pentagon_caption = ( + 'A single mirror of shape (' + + self.m_pentagon_shape_description + + '), analytically defined with focal length f=' + + str(self.m1_focal_length) + + 'm.' + ) + self.m_pentagon_comments = [] + + # Deep pentagonal mirror, based on a parametric model. + self.m_deep_focal_length = 1.0 # meters + self.m_deep_fxn = self.lambda_symmetric_paraboloid(self.m_deep_focal_length) + self.m_deep_pentagon = MirrorParametric(self.m_deep_fxn, pentagon_region) + self.m_deep_pentagon_shape_description = 'pentagon' + self.m_deep_pentagon_title = ( + 'Mirror (' + self.m_pentagon_shape_description + ', f=' + str(self.m_deep_focal_length) + 'm)' + ) + self.m_deep_pentagon_caption = ( + 'A single mirror of shape (' + + self.m_pentagon_shape_description + + '), analytically defined with focal length f=' + + str(self.m_deep_focal_length) + + 'm.' + ) + self.m_deep_pentagon_comments = [] # Facet, based on a parameteric mirror. self.f1 = Facet(self.m1) @@ -117,7 +148,7 @@ def setUp(self): self.h2x2_f4 = Facet(copy.deepcopy(self.m1)) fe2x2 = FacetEnsemble([self.h2x2_f1, self.h2x2_f2, self.h2x2_f3, self.h2x2_f4]) facet_positions = Pxyz([[-1.1, 1.1, -1.1, 1.1], [1.6, 1.6, -1.6, -1.6], [0, 0, 0, 0]]) - fe2x2.set_facet_positions(facet_positions) # fe2x2 := facet emsenble, two by two + fe2x2.set_facet_positions(facet_positions) # fe2x2 := facet ensemble, two by two # Set canting angles. cos5 = np.cos(np.deg2rad(8)) @@ -200,31 +231,37 @@ def example_mirror(self) -> None: comments=local_comments, code_tag=self.code_tag, ) - self.m1.draw(fig_record.view, mirror_control) + self.m1.draw(view=fig_record.view, mirror_style=mirror_control) # Output. self.show_save_and_check_figure(fig_record) - def example_mirror_halfpi_rotation(self) -> None: + def example_pentagon_elevation_30deg(self) -> None: """ - Draws a pentagonal mirror that is rotated 90 deg in space. Should look like a mirror with its normal parallel in the xy plane. + Draws a pentagonal mirror that is rotated 30 deg in space. + Should look like a mirror with its normal pointing 30 degrees above the xy plane. """ # Initialize test. self.start_test() - local_comments = self.m1_comments.copy() + local_comments = self.m_pentagon_comments.copy() # Position/Rotation in space. tran = Vxyz([0, 0, 0]) - rot = Rotation.from_euler('x', 45, True) + # Rotation about x rotates face-up surface normal down from zenith, + # so we rotate by (90-30) degrees. + desired_elevation_deg = 30.0 + rot = Rotation.from_euler('x', (90.0 - desired_elevation_deg), True) transform = TransformXYZ.from_R_V(rot, tran) + # Copy the mirror because we will want to use it again later without the rotation. + m_pentagon_copy = copy.deepcopy(self.m_pentagon) - local_comments.append('Oriented face 45 deg up from level.') - self.scene.add_object(self.m_pentagon) - self.scene.set_position_in_space(self.m_pentagon, transform) + local_comments.append('Oriented face 30 deg up from level.') + self.scene.add_object(m_pentagon_copy) + self.scene.set_position_in_space(m_pentagon_copy, transform) # Setup render control. mirror_control = rcm.RenderControlMirror() - local_comments.append('Render surface only.') + local_comments.append('Render mirror surface only.') # Draw. fig_record = fm.setup_figure_for_3d_data( @@ -234,12 +271,113 @@ def example_mirror_halfpi_rotation(self) -> None: # Figure numbers needed because titles may be identical. Hard-code number because test order is unpredictable. number_in_name=False, input_prefix=self.figure_prefix(2), - title=self.m1_title + ', Face Horizon', - caption=st.add_to_last_sentence(self.m1_caption, ', facing the horizon'), + title=self.m_pentagon_title + ', Elevation 30 Degrees', + caption=st.add_to_last_sentence(self.m_pentagon_caption, ', facing 30 degrees above the horizon'), comments=local_comments, code_tag=self.code_tag, ) - self.m_pentagon.draw(fig_record.view, mirror_control) + m_pentagon_copy.draw(view=fig_record.view, mirror_style=mirror_control) + + # Output. + self.show_save_and_check_figure(fig_record) + + def example_deep_pentagon_elevation_60deg_embedding(self) -> None: + """ + Draws a deep pentagonal mirror that is rotated 60 deg in space. + Should look like a mirror with its normal pointing 60 degrees + above the xy plane. + Also demonstrates embedding surface and slice drawing, all + including transform. + """ + # Initialize test. + self.start_test() + local_comments = self.m_deep_pentagon_comments.copy() + + # Position/Rotation in space. + tran = Vxyz([0, 0, 0.6]) + # Rotation about x rotates face-up surface normal down from zenith, + # so we rotate by (90-30) degrees. + desired_elevation_deg = 60.0 + rot = Rotation.from_euler('x', (90.0 - desired_elevation_deg), True) + transform = TransformXYZ.from_R_V(rot, tran) + # Copy the mirror because we will want to use it again later without the rotation. + m_deep_pentagon_copy = copy.deepcopy(self.m_deep_pentagon) + + local_comments.append('Oriented face 60 deg up from level.') + self.scene.add_object(m_deep_pentagon_copy) + self.scene.set_position_in_space(m_deep_pentagon_copy, transform) + + # Setup render control. + mirror_control = rcm.RenderControlMirror() + # See below for multi-part projection and slice control settings. + + # Draw. + fig_record = fm.setup_figure_for_3d_data( + figure_control=self.figure_control, + axis_control=rca.meters(grid=False), # Drawing axis grid and surface grid is confusing. + view_spec=vs.view_spec_3d(), + # Figure numbers needed because titles may be identical. Hard-code number because test order is unpredictable. + number_in_name=False, + input_prefix=self.figure_prefix(10), + title=self.m_deep_pentagon_title + ', Elevation 60 Degrees, Embedding Surface', + caption=st.add_to_last_sentence(self.m_deep_pentagon_caption, ', facing 60 degrees above the horizon'), + comments=local_comments, + code_tag=self.code_tag, + ) + m_deep_pentagon_copy.draw(view=fig_record.view, mirror_style=mirror_control) + ems.draw_mirror_and_embedding_mirror( + m_deep_pentagon_copy, + view=fig_record.view, + mirror_style=rcm.RenderControlMirror(), + draw_projection=True, + projected_style=rcmp.mirror_boundary(), + embedding_style=rcme.standard_embedding_mirror(), + transform=transform, + ) + + # Output. + self.show_save_and_check_figure(fig_record) + + def example_deep_pentagon_elevation_face_up_embedding(self, view_spec: dict, figure_idx) -> None: + """ + Draws a deep pentagonal mirror that is face up, with embedding + surface and origin slices. + """ + # Initialize test. + self.start_test() + local_comments = self.m_deep_pentagon_comments.copy() + + # Position/Rotation in space. + local_comments.append('Oriented face up.') + + # Setup render control. + mirror_control = rcm.RenderControlMirror() + # See below for multi-part projection and slice control settings. + + # Draw. + fig_record = fm.setup_figure_for_3d_data( + figure_control=self.figure_control, + axis_control=rca.meters(grid=False), # Drawing axis grid and surface grid is confusing. + view_spec=view_spec, + # Figure numbers needed because titles may be identical. Hard-code number because test order is unpredictable. + number_in_name=False, + input_prefix=self.figure_prefix(figure_idx), + title=self.m_deep_pentagon_title + ', Face Up, Embedding Surface', + caption=st.add_to_last_sentence( + self.m_deep_pentagon_caption, ', facing up, with embedding suraface and origin slices' + ), + comments=local_comments, + code_tag=self.code_tag, + ) + self.m_deep_pentagon.draw(view=fig_record.view, mirror_style=mirror_control) + ems.draw_mirror_and_embedding_mirror( + self.m_deep_pentagon, + view=fig_record.view, + mirror_style=rcm.RenderControlMirror(), + draw_projection=True, + projected_style=rcmp.mirror_boundary(), + embedding_style=rcme.standard_embedding_mirror(), + ) # Output. self.show_save_and_check_figure(fig_record) @@ -280,7 +418,7 @@ def example_facet(self) -> None: vs.view_spec_3d(), # Figure numbers needed because titles may be identical. Hard-code number because test order is unpredictable. number_in_name=False, - input_prefix=self.figure_prefix(4), + input_prefix=self.figure_prefix(20), title=self.f1_title, caption=self.f1_caption, comments=local_comments, @@ -322,7 +460,7 @@ def example_heliostat_surface_normals(self) -> None: # Figure numbers needed because titles may be identical. # Hard-code number because test order is unpredictable. number_in_name=False, - input_prefix=self.figure_prefix(6), + input_prefix=self.figure_prefix(21), title=self.h2x2_title, caption=self.h2x2_caption, comments=local_comments, @@ -380,7 +518,7 @@ def example_solar_field(self) -> None: vs.view_spec_3d(), # Figure numbers needed because titles may be identical. Hard-code number because test order is unpredictable. number_in_name=False, - input_prefix=self.figure_prefix(7), + input_prefix=self.figure_prefix(30), title=self.sf2x2_title, caption=self.sf2x2_caption, comments=local_comments, @@ -535,7 +673,7 @@ def fn_14W01(x, y): vs.view_spec_xy(), # Figure numbers needed because titles may be identical. Hard-code number because test order is unpredictable. number_in_name=False, - input_prefix=self.figure_prefix(17), + input_prefix=self.figure_prefix(40), title=title_5W01 + ' (long normals)', caption=caption_5W01, comments=comments, @@ -551,7 +689,7 @@ def fn_14W01(x, y): vs.view_spec_xy(), # Figure numbers needed because titles may be identical. Hard-code number because test order is unpredictable. number_in_name=False, - input_prefix=self.figure_prefix(18), + input_prefix=self.figure_prefix(41), title=title_14W01 + ' (long normals)', caption=caption_14W01, comments=comments, @@ -590,7 +728,7 @@ def fn_14W01(x, y): vs.view_spec_yz(), # Figure numbers needed because titles may be identical. Hard-code number because test order is unpredictable. number_in_name=False, - input_prefix=self.figure_prefix(19), + input_prefix=self.figure_prefix(42), title=title_sf + ' (very long normals)', caption=caption_sf, comments=comments, @@ -636,7 +774,7 @@ def fn_14W01(x, y): vs.view_spec_3d(), # Figure numbers needed because titles may be identical. Hard-code number because test order is unpredictable. number_in_name=False, - input_prefix=self.figure_prefix(20), + input_prefix=self.figure_prefix(50), title=title_5W01 + ' (exaggerated z)', caption=caption_5W01, comments=comments, @@ -653,7 +791,7 @@ def fn_14W01(x, y): vs.view_spec_yz(), # Figure numbers needed because titles may be identical. Hard-code number because test order is unpredictable. number_in_name=False, - input_prefix=self.figure_prefix(21), + input_prefix=self.figure_prefix(51), title=title_5W01 + ' (exaggerated z)', caption=caption_5W01, comments=comments, @@ -673,7 +811,7 @@ def fn_14W01(x, y): vs.view_spec_3d(), # Figure numbers needed because titles may be identical. Hard-code number because test order is unpredictable. number_in_name=False, - input_prefix=self.figure_prefix(22), + input_prefix=self.figure_prefix(52), title=title_14W01 + ' (exaggerated z)', caption=caption_14W01, comments=comments, @@ -690,7 +828,7 @@ def fn_14W01(x, y): vs.view_spec_yz(), # Figure numbers needed because titles may be identical. Hard-code number because test order is unpredictable. number_in_name=False, - input_prefix=self.figure_prefix(23), + input_prefix=self.figure_prefix(53), title=title_14W01 + ' (exaggerated z)', caption=caption_14W01, comments=comments, @@ -771,7 +909,7 @@ def fn(x: float, y: float): vs.view_spec_3d(), # Figure numbers needed because titles may be identical. Hard-code number because test order is unpredictable. number_in_name=False, - input_prefix=self.figure_prefix(24), + input_prefix=self.figure_prefix(60), title=title + ', Without Canting', caption=st.add_to_last_sentence(caption, ' without canting'), comments=comments, @@ -800,7 +938,7 @@ def fn(x: float, y: float): vs.view_spec_3d(), # Figure numbers needed because titles may be identical. Hard-code number because test order is unpredictable. number_in_name=False, - input_prefix=self.figure_prefix(25), + input_prefix=self.figure_prefix(61), title=title + ', Canted and Lifted', caption=st.add_to_last_sentence(caption, ' with canting angle and lifted'), comments=comments, @@ -818,7 +956,7 @@ def fn(x: float, y: float): vs.view_spec_3d(), # Figure numbers needed because titles may be identical. Hard-code number because test order is unpredictable. number_in_name=False, - input_prefix=self.figure_prefix(26), + input_prefix=self.figure_prefix(62), title=title + ', With Canting', caption=st.add_to_last_sentence(caption, ' with canting'), comments=comments, @@ -837,7 +975,7 @@ def fn(x: float, y: float): vs.view_spec_3d(), # Figure numbers needed because titles may be identical. Hard-code number because test order is unpredictable. number_in_name=False, - input_prefix=self.figure_prefix(27), + input_prefix=self.figure_prefix(63), title=title + ', With Canting and Tracking', caption=st.add_to_last_sentence(caption, ' with canting and tracking'), comments=comments, @@ -847,28 +985,41 @@ def fn(x: float, y: float): self.show_save_and_check_figure(fig_record) -# MAIN EXECUTION -if __name__ == "__main__": +def example_driver(verify=True): # Control flags. interactive = False # Set verify to False when you want to generate all figures and then copy # them into the expected_output directory. - # (Does not affect pytest, which uses default value.) + # Or, just run the pytest example, and then move the newly created + # output\ExampleMirrorOutput directory to the location + # input\ExampleMirrorOutput. + # Setup. example_object = ExampleMirrorOutput() - example_object.setUpClass(interactive=interactive, verify=False) + example_object.setUpClass(interactive=interactive, verify=verify) example_object.setUp() - # Examples. - lt.info('Beginning examples...') + + # Tests. + lt.info('Beginning tests...') example_object.example_mirror() - example_object.example_mirror_halfpi_rotation() + example_object.example_pentagon_elevation_30deg() + example_object.example_deep_pentagon_elevation_60deg_embedding() + example_object.example_deep_pentagon_elevation_face_up_embedding(vs.view_spec_3d(), 11) + example_object.example_deep_pentagon_elevation_face_up_embedding(vs.view_spec_xy(), 12) + example_object.example_deep_pentagon_elevation_face_up_embedding(vs.view_spec_xz(), 13) + example_object.example_deep_pentagon_elevation_face_up_embedding(vs.view_spec_yz(), 14) example_object.example_facet() example_object.example_heliostat_surface_normals() example_object.example_solar_field() example_object.example_heliostat_05W01_and_14W01() example_object.example_heliostat_stages() - lt.info('All examples complete.') + lt.info('All tests complete.') # Cleanup. if interactive: input("Press Enter...") - example_object.tearDown() + + +# MAIN EXECUTION +if __name__ == "__main__": + # When running from the debugger, we typically do not want verify turned on. + example_driver(verify=False) diff --git a/example/raytrace/example_RayTraceOutput.py b/example/raytrace/example_RayTraceOutput.py index ef59c8ff3..80fce9fb4 100644 --- a/example/raytrace/example_RayTraceOutput.py +++ b/example/raytrace/example_RayTraceOutput.py @@ -18,7 +18,7 @@ import opencsp.common.lib.csp.RayTrace as rt import opencsp.common.lib.csp.SolarField as sf import opencsp.common.lib.geo.lon_lat_nsttf as lln -from opencsp.common.lib.geometry.RegionXY import Resolution +from opencsp.common.lib.geometry.Resolution import Resolution from opencsp.common.lib.geometry.TransformXYZ import TransformXYZ import opencsp.common.lib.opencsp_path.data_path_for_test as dpft import opencsp.common.lib.render.figure_management as fm @@ -250,7 +250,7 @@ def example_mirror_trace(self) -> None: view1 = fig_record.view trace1.draw(view1, RenderControlRayTrace(light_path_control=light_path_control)) - m1.draw(view1, mirror_control) + m1.draw(view=view1, mirror_style=mirror_control) # Output. self.show_save_and_check_figure(fig_record) diff --git a/example/sofast_fringe/example_process_in_debug_mode.py b/example/sofast_fringe/example_process_in_debug_mode.py index 044a18c98..6e5ec69dd 100644 --- a/example/sofast_fringe/example_process_in_debug_mode.py +++ b/example/sofast_fringe/example_process_in_debug_mode.py @@ -74,6 +74,8 @@ def example_process_in_debug_mode(): # Define save dir dir_save = join(dirname(__file__), "data/output/sofast_with_debug_mode_on") ft.create_directories_if_necessary(dir_save) + dir_save_debug = join(dir_save, "debug") + ft.create_directories_if_necessary(dir_save_debug) # Set up logger lt.logger(join(dir_save, "log.txt"), lt.log.INFO) @@ -112,6 +114,12 @@ def example_process_in_debug_mode(): # Turn on debug mode sofast.params.debug_geometry.debug_active = True + sofast.params.debug_geometry.debug_active = True + sofast.params.debug_geometry.save_dir = dir_save_debug + sofast.params.debug_geometry.figure_idx = 0 + sofast.params.debug_slope_solver.debug_active = True + sofast.params.debug_slope_solver.save_dir = dir_save_debug + sofast.params.debug_slope_solver.figure_idx = 100 # Process try: diff --git a/example/sofast_fringe/single_facet/example_process_single_facet.py b/example/sofast_fringe/single_facet/example_process_single_facet.py index d4c97079e..381ce49c9 100644 --- a/example/sofast_fringe/single_facet/example_process_single_facet.py +++ b/example/sofast_fringe/single_facet/example_process_single_facet.py @@ -20,8 +20,9 @@ B1_projected_fringes - The patterns sent to the display during the SOFAST measurement of the optic. B2_captured_fringes - The captured images of the displayed patterns as seen by the SOFAST camera. - B3_analysis - The processed data from SOFAST. - B4_plots - The output figure suite from a SOFAST characterization. + B3_diagnostics - Output reporting the progress of SOFAST. + B4_analysis - The processed data from SOFAST. + B5_plots - The output figure suite from a SOFAST characterization. """ @@ -33,6 +34,8 @@ import imageio.v3 as imageio +import numpy as np + from opencsp.app.sofast.lib.DisplayShape import DisplayShape as Display from opencsp.app.sofast.lib.DefinitionFacet import DefinitionFacet from opencsp.app.sofast.lib.Fringes import Fringes @@ -42,15 +45,22 @@ from opencsp.app.sofast.lib.SofastConfiguration import SofastConfiguration from opencsp.app.sofast.lib.SpatialOrientation import SpatialOrientation from opencsp.common.lib.camera.Camera import Camera +import opencsp.common.lib.csp.embedding_mirror_surface as ems from opencsp.common.lib.csp.LightSourceSun import LightSourceSun from opencsp.common.lib.csp.MirrorParametric import MirrorParametric, SYMMETRIC_PARABOLOID, ASTIGMATIC_PARABOLOID, PLANO from opencsp.common.lib.csp.MirrorPoint import NEAREST_INTERPOLATION +from opencsp.common.lib.geometry.RegionXY import RegionXY from opencsp.common.lib.csp.StandardPlotOutput import StandardPlotOutput from opencsp.common.lib.deflectometry.Surface2DParabolic import Surface2DParabolic from opencsp.common.lib.deflectometry.Surface2DPlano import Surface2DPlano from opencsp.common.lib.geometry.Uxyz import Uxyz from opencsp.common.lib.geometry.Vxyz import Vxyz from opencsp.common.lib.opencsp_path.opencsp_root_path import opencsp_code_dir +import opencsp.common.lib.render.view_spec as vs +import opencsp.common.lib.render_control.RenderControlFigure as rcfg +import opencsp.common.lib.render_control.RenderControlMirror as rcm +import opencsp.common.lib.render_control.RenderControlMirrorEmbedded as rcme +import opencsp.common.lib.render_control.RenderControlPointSeq as rcps import opencsp.common.lib.tool.file_tools as ft import opencsp.common.lib.tool.log_tools as lt import opencsp.common.lib.tool.string_tools as st @@ -92,6 +102,7 @@ def process_single_facet( 4. Processes data with SOFAST and save processed data to HDF5 5. Generate plot suite and save image files """ + # General setup # ============= @@ -138,52 +149,127 @@ def process_single_facet( # Save mask (like a pixel mask value (all 0s, all 255s)) images for idx_image in [0, 1]: image = measurement.mask_images[..., idx_image] - imageio.imwrite(join(dir_save_cur, output_file_prefix + f"mask_{idx_image:02d}.png"), image) + imageio.imwrite( + join(dir_save_cur, output_file_prefix + f"mask_{idx_image:02d}.png"), image.astype(np.uint8) + ) # Save y images (when lines were vertical, e.g.) for idx_image in range(measurement.num_y_ims): image = measurement.fringe_images_y[..., idx_image] - imageio.imwrite(join(dir_save_cur, output_file_prefix + f"y_{idx_image:02d}.png"), image) + imageio.imwrite(join(dir_save_cur, output_file_prefix + f"y_{idx_image:02d}.png"), image.astype(np.uint8)) # Save x images (when lines were horizontal, e.g.) for idx_image in range(measurement.num_x_ims): image = measurement.fringe_images_x[..., idx_image] - imageio.imwrite(join(dir_save_cur, output_file_prefix + f"x_{idx_image:02d}.png"), image) + imageio.imwrite(join(dir_save_cur, output_file_prefix + f"x_{idx_image:02d}.png"), image.astype(np.uint8)) - # 4. Processes data with Sofast and save processed data to HDF5 - # ============================================================= - dir_save_cur = join(dir_save, "B3_analysis") + # 4. Review and check input + # ========================= + # Diagnostic output directory + dir_save_cur = join(dir_save, "B3_diagnostics") ft.create_directories_if_necessary(dir_save_cur) - # Define surface definition (parabolic surface), this is the mirror - if (reference_mirror_surface_type == SYMMETRIC_PARABOLOID) or ( - reference_mirror_surface_type == ASTIGMATIC_PARABOLOID - ): + # Construct the expected mirror and initial fit surface + # based on the input nominal optic definition. + facet_vertices = facet_data.v_facet_corners.projXY() + facet_region = RegionXY.from_vertices(facet_vertices) + if reference_mirror_surface_type == SYMMETRIC_PARABOLOID: + mirror_reference = MirrorParametric.generate_symmetric_paraboloid(reference_mirror_focal_length_x, facet_region) + fit_surface = Surface2DParabolic( + initial_focal_lengths_xy=(fit_initial_focal_length_x, fit_initial_focal_length_x), + robust_least_squares=fit_robust_least_squares, + downsample=fit_downsample, + ) + elif reference_mirror_surface_type == ASTIGMATIC_PARABOLOID: + mirror_reference = MirrorParametric.generate_astigmatic_xy_paraboloid( + reference_mirror_focal_length_x, reference_mirror_focal_length_y, facet_region + ) fit_surface = Surface2DParabolic( initial_focal_lengths_xy=(fit_initial_focal_length_x, fit_initial_focal_length_y), robust_least_squares=fit_robust_least_squares, downsample=fit_downsample, ) elif reference_mirror_surface_type == PLANO: + mirror_reference = MirrorParametric.generate_flat(facet_region) fit_surface = Surface2DPlano(robust_least_squares=fit_robust_least_squares, downsample=fit_downsample) else: lt.error_and_raise( ValueError, - f'Reference mirror surface type {reference_mirror_surface_type} is not one of ["{SYMMETRIC_PARABOLOID}", "{ASTIGMATIC_PARABOLOID}, "{PLANO}"].', + f'Reference mirror surface type {reference_mirror_surface_type} is not one of ["{SYMMETRIC_PARABOLOID}," "{ASTIGMATIC_PARABOLOID}," or "{PLANO}"].', ) + mirror_reference = None # Eliminate Pylint error message. Never executes. fit_surface = None # Eliminate Pylint error message. Never executes. + # &&&& DELETE-SCAFFOLDING -- ADD EXAGGERATED Z + + # Draw plot of reference mirror, to enable review of what is requested. + fig_control = rcfg.RenderControlFigure(tile_array=(2, 1), tile_square=True) + view_spec_list = [vs.view_spec_3d(), vs.view_spec_xy(), vs.view_spec_xz(), vs.view_spec_yz()] + debug_figure_idx = 0 + for view_spec in view_spec_list: + # Draw the expected mirror and its embedding surface. + fig_record = ems.setup_and_draw_mirror_and_embedding_mirror( + figure_control=fig_control, + parametric_mirror=mirror_reference, + title='Expected Mirror', + view_spec=view_spec, + mirror_style=rcm.RenderControlMirror(), + embedding_style=rcme.RenderControlMirrorEmbedded(margin=0.01, round_to=0.25), + ) + # Draw the expected mirror centroid defined by the facet definition file. + facet_data.v_facet_centroid.draw_points(figure=fig_record, style=rcps.marker()) + # Save. + figure_file_body = fig_record.title.replace(' ', '_') + figure_dir_body_ext = join(dir_save_cur, f'{debug_figure_idx:02d}_input_{figure_file_body}.png') + debug_figure_idx += 1 + fig_record.save( + output_dir=dir_save_cur, + output_file_body=figure_dir_body_ext, + dpi=200, + format='png', + close_after_save=True, + include_view_suffix=True, + include_limit_suffix=False, + ) + # Calibrate fringes - (aka sinosoidal image) measurement.calibrate_fringe_images(calibration) + # &&&& DELETE-SCAFFOLDING -- ADD PLOT OF CALIBRATION + + # 5. Process data with Sofast + # ============================= + # Instantiate sofast object sofast = Sofast(measurement, orientation, camera, display) - # Process - sofast.process_optic_singlefacet(facet_data, fit_surface) - - # Get measurement statistics - config = SofastConfiguration() - config.load_sofast_object(sofast) - measurement_stats = config.get_measurement_stats() + # Turn on debug mode + if verbose: + sofast.params.debug_geometry.debug_active = True + sofast.params.debug_geometry.save_dir = dir_save_cur + sofast.params.debug_geometry.figure_idx = debug_figure_idx + sofast.params.debug_slope_solver.debug_active = True + sofast.params.debug_slope_solver.save_dir = dir_save_cur + sofast.params.debug_slope_solver.figure_idx = 100 + + # Process SOFAST + try: + # Process + sofast.process_optic_singlefacet(facet_data, fit_surface) + # Get measurement statistics + config = SofastConfiguration() + config.load_sofast_object(sofast) + measurement_stats = config.get_measurement_stats() + except ValueError: + # Save all debug figures + save_all_debug_figures(dir_save_cur, sofast) + return + + # Save all debug figures + save_all_debug_figures(dir_save_cur, sofast) + + # 6. Save processed data to HDF5 + # ============================================================= + dir_save_cur = join(dir_save, "B4_analysis") + ft.create_directories_if_necessary(dir_save_cur) # Save processed data to HDF5 format sofast.save_to_hdf(join(dir_save_cur, output_file_prefix + "data_sofast_processed.h5")) @@ -192,9 +278,9 @@ def process_single_facet( with open(join(dir_save_cur, output_file_prefix + "measurement_statistics.json"), "w", encoding="utf-8") as f: json.dump(measurement_stats, f, indent=3) - # 5. Generate plot suite and save images files + # 7. Generate plot suite and save images files # ============================================ - dir_save_cur = join(dir_save, "B4_plots") + dir_save_cur = join(dir_save, "B5_plots") ft.create_directories_if_necessary(dir_save_cur) # Get measured and reference optics @@ -214,7 +300,7 @@ def process_single_facet( else: lt.error_and_raise( ValueError, - f'Reference mirror surface type {reference_mirror_surface_type} is not one of ["{SYMMETRIC_PARABOLOID}", "{ASTIGMATIC_PARABOLOID}, "{PLANO}"].', + f'Reference mirror surface type {reference_mirror_surface_type} is not one of ["{SYMMETRIC_PARABOLOID}," "{ASTIGMATIC_PARABOLOID}," or "{PLANO}"].', ) mirror_reference = None # Eliminate Pylint error message. Never executes. @@ -228,6 +314,18 @@ def process_single_facet( plots.plot() +def save_all_debug_figures(dir_save_cur: str, sofast: Sofast) -> None: + lt.info(f'Saving all debug figures to {dir_save_cur}.') + for idx, fig in enumerate(sofast.params.debug_geometry.figures): + debug_geometry_figure_dir_body_ext = join(dir_save_cur, f'debug_geometry_{idx:02d}.png') + print("In process_single_facet(), saving debug_geometry figure:", debug_geometry_figure_dir_body_ext) + fig.savefig(debug_geometry_figure_dir_body_ext) + for idx_2, fig in enumerate(sofast.params.debug_slope_solver.slope_solver_figures): + debug_slope_solver_figure_dir_body_ext = join(dir_save_cur, f'debug_slope_solver_{idx_2:02d}.png') + print("In process_single_facet(), saving debug_slope_solver figure:", debug_slope_solver_figure_dir_body_ext) + fig.savefig(debug_slope_solver_figure_dir_body_ext) + + def example_process_single_facet_driver(arg_settings_dir_body_ext: str = None, verbose_param=None): """ Sets up and runs the example_process_single_facet() routine. @@ -269,18 +367,19 @@ def example_process_single_facet_driver(arg_settings_dir_body_ext: str = None, v # Strings denoting computation. measurement_id = "Time_Mirror_InstrumentMode" post_process_id = "PostSpec" + # Reference mirror surface + reference_mirror_surface_type = SYMMETRIC_PARABOLOID # Strings from MirrorParametric.py: SYMMETRIC_PARABOLOID, ASTIGMATIC_PARABOLOID, or PLANO + reference_mirror_focal_length_x = 100.0 # Ignored if plano + reference_mirror_focal_length_y = 100.0 # Ignored if plano or symmetric paraboloid # Analysis control - fit_initial_focal_length_x = 300.0 - fit_initial_focal_length_y = 300.0 + initial_fit_factor = 2.0 # Dimensionless + fit_initial_focal_length_x = reference_mirror_focal_length_x * initial_fit_factor # 300.0 + fit_initial_focal_length_y = reference_mirror_focal_length_y * initial_fit_factor # 300.0 fit_robust_least_squares = True fit_downsample = 10 # Measured mirror surface measured_interpolation_type = NEAREST_INTERPOLATION # Strings from MirrorPoint.py: GIVEN_INTERPOLATION, BILINEAR_INTERPOLATION, CLOUGH_TOCHER_INTERPOLATION, or NEAREST_INTERPOLATION - # Reference mirror surface - reference_mirror_surface_type = SYMMETRIC_PARABOLOID # Strings from MirrorParametric.py: SYMMETRIC_PARABOLOID, ASTIGMATIC_PARABOLOID, or PLANO - reference_mirror_focal_length_x = 100.0 # Ignored if plano - reference_mirror_focal_length_y = 100.0 # Ignored if plano or symmetric paraboloid # Output rendering control output_fringe_images = True # Set plot control parameters to the values we want for the default example. diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/ExampleSolarFieldOutput.log b/example/solarfield/data/input/ExampleSolarFieldOutput/ExampleSolarFieldOutput.log deleted file mode 100644 index b6c51f674..000000000 --- a/example/solarfield/data/input/ExampleSolarFieldOutput/ExampleSolarFieldOutput.log +++ /dev/null @@ -1,94 +0,0 @@ -INFO:singleprocessing:Start run 2024-05-22 12:47:51 -INFO:singleprocessing:Clearing files in directory "solarfield\data\output\ExampleSolarFieldOutput"... -INFO:singleprocessing:Initializing render control structures... -INFO:singleprocessing:Beginning tests... -INFO:singleprocessing: - -Starting ExampleSolarFieldOutput.example_single_heliostat()... -INFO:singleprocessing:Closing existing plot windows... -INFO:singleprocessing:Resetting figure management structure... -INFO:singleprocessing:In View3d.save(), saving figure: solarfield\data\output\ExampleSolarFieldOutput\tsfo001_Heliostat_5E10_Face_West_3d.png -INFO:singleprocessing:Saving figure text: solarfield\data\output\ExampleSolarFieldOutput\tsfo001_Heliostat_5E10_Face_West_3d.txt -INFO:singleprocessing: - -Starting ExampleSolarFieldOutput.example_annotated_heliostat()... -INFO:singleprocessing:Closing existing plot windows... -INFO:singleprocessing:Resetting figure management structure... -INFO:singleprocessing:In View3d.save(), saving figure: solarfield\data\output\ExampleSolarFieldOutput\tsfo002_Heliostat_5E10_with_Highlighting_3d.png -INFO:singleprocessing:Saving figure text: solarfield\data\output\ExampleSolarFieldOutput\tsfo002_Heliostat_5E10_with_Highlighting_3d.txt -INFO:singleprocessing: - -Starting ExampleSolarFieldOutput.example_multi_heliostat()... -INFO:singleprocessing:Closing existing plot windows... -INFO:singleprocessing:Resetting figure management structure... -INFO:singleprocessing:In View3d.save(), saving figure: solarfield\data\output\ExampleSolarFieldOutput\tsfo003_Example_Poses_and_Styles_3d.png -INFO:singleprocessing:Saving figure text: solarfield\data\output\ExampleSolarFieldOutput\tsfo003_Example_Poses_and_Styles_3d.txt -INFO:singleprocessing: - -Starting ExampleSolarFieldOutput.example_solar_field_h_names()... -INFO:singleprocessing:Closing existing plot windows... -INFO:singleprocessing:Resetting figure management structure... -INFO:singleprocessing:In View3d.save(), saving figure: solarfield\data\output\ExampleSolarFieldOutput\tsfo004_Heliostat_Names_xy.png -INFO:singleprocessing:Saving figure text: solarfield\data\output\ExampleSolarFieldOutput\tsfo004_Heliostat_Names_xy.txt -INFO:singleprocessing: - -Starting ExampleSolarFieldOutput.example_solar_field_h_centroids()... -INFO:singleprocessing:Closing existing plot windows... -INFO:singleprocessing:Resetting figure management structure... -INFO:singleprocessing:In View3d.save(), saving figure: solarfield\data\output\ExampleSolarFieldOutput\tsfo005_Heliostat_Centroids_3d.png -INFO:singleprocessing:Saving figure text: solarfield\data\output\ExampleSolarFieldOutput\tsfo005_Heliostat_Centroids_3d.txt -INFO:singleprocessing:In View3d.save(), saving figure: solarfield\data\output\ExampleSolarFieldOutput\tsfo006_Heliostat_Centroids_xy.png -INFO:singleprocessing:Saving figure text: solarfield\data\output\ExampleSolarFieldOutput\tsfo006_Heliostat_Centroids_xy.txt -INFO:singleprocessing:In View3d.save(), saving figure: solarfield\data\output\ExampleSolarFieldOutput\tsfo007_Heliostat_Centroids_xz.png -INFO:singleprocessing:Saving figure text: solarfield\data\output\ExampleSolarFieldOutput\tsfo007_Heliostat_Centroids_xz.txt -INFO:singleprocessing:In View3d.save(), saving figure: solarfield\data\output\ExampleSolarFieldOutput\tsfo008_Heliostat_Centroids_yz.png -INFO:singleprocessing:Saving figure text: solarfield\data\output\ExampleSolarFieldOutput\tsfo008_Heliostat_Centroids_yz.txt -INFO:singleprocessing: - -Starting ExampleSolarFieldOutput.example_solar_field_h_centroids_names()... -INFO:singleprocessing:Closing existing plot windows... -INFO:singleprocessing:Resetting figure management structure... -INFO:singleprocessing:In View3d.save(), saving figure: solarfield\data\output\ExampleSolarFieldOutput\tsfo009_Heliostat_Labelled_Centroids_xy.png -INFO:singleprocessing:Saving figure text: solarfield\data\output\ExampleSolarFieldOutput\tsfo009_Heliostat_Labelled_Centroids_xy.txt -INFO:singleprocessing: - -Starting ExampleSolarFieldOutput.example_solar_field_h_outlines()... -INFO:singleprocessing:Closing existing plot windows... -INFO:singleprocessing:Resetting figure management structure... -INFO:singleprocessing:In View3d.save(), saving figure: solarfield\data\output\ExampleSolarFieldOutput\tsfo010_Heliostat_Outlines_3d.png -INFO:singleprocessing:Saving figure text: solarfield\data\output\ExampleSolarFieldOutput\tsfo010_Heliostat_Outlines_3d.txt -INFO:singleprocessing: - -Starting ExampleSolarFieldOutput.example_annotated_solar_field()... -INFO:singleprocessing:Closing existing plot windows... -INFO:singleprocessing:Resetting figure management structure... -INFO:singleprocessing:In View3d.save(), saving figure: solarfield\data\output\ExampleSolarFieldOutput\tsfo011_Solar_Field_Situation_3d.png -INFO:singleprocessing:Saving figure text: solarfield\data\output\ExampleSolarFieldOutput\tsfo011_Solar_Field_Situation_3d.txt -INFO:singleprocessing: - -Starting ExampleSolarFieldOutput.example_solar_field_subset()... -INFO:singleprocessing:Closing existing plot windows... -INFO:singleprocessing:Resetting figure management structure... -INFO:singleprocessing:In View3d.save(), saving figure: solarfield\data\output\ExampleSolarFieldOutput\tsfo012_Selected_Heliostats_3d.png -INFO:singleprocessing:Saving figure text: solarfield\data\output\ExampleSolarFieldOutput\tsfo012_Selected_Heliostats_3d.txt -INFO:singleprocessing: - -Starting ExampleSolarFieldOutput.example_heliostat_vector_field()... -INFO:singleprocessing:Closing existing plot windows... -INFO:singleprocessing:Resetting figure management structure... -INFO:singleprocessing:In View3d.save(), saving figure: solarfield\data\output\ExampleSolarFieldOutput\tsfo013_Heliostat_Vector_Field_3d.png -INFO:singleprocessing:Saving figure text: solarfield\data\output\ExampleSolarFieldOutput\tsfo013_Heliostat_Vector_Field_3d.txt -INFO:singleprocessing:In View3d.save(), saving figure: solarfield\data\output\ExampleSolarFieldOutput\tsfo014_Heliostat_Vector_Field_xy.png -INFO:singleprocessing:Saving figure text: solarfield\data\output\ExampleSolarFieldOutput\tsfo014_Heliostat_Vector_Field_xy.txt -INFO:singleprocessing:In View3d.save(), saving figure: solarfield\data\output\ExampleSolarFieldOutput\tsfo015_Heliostat_Vector_Field_xz.png -INFO:singleprocessing:Saving figure text: solarfield\data\output\ExampleSolarFieldOutput\tsfo015_Heliostat_Vector_Field_xz.txt -INFO:singleprocessing:In View3d.save(), saving figure: solarfield\data\output\ExampleSolarFieldOutput\tsfo016_Heliostat_Vector_Field_yz.png -INFO:singleprocessing:Saving figure text: solarfield\data\output\ExampleSolarFieldOutput\tsfo016_Heliostat_Vector_Field_yz.txt -INFO:singleprocessing: - -Starting ExampleSolarFieldOutput.example_dense_vector_field()... -INFO:singleprocessing:Closing existing plot windows... -INFO:singleprocessing:Resetting figure management structure... -INFO:singleprocessing:In View3d.save(), saving figure: solarfield\data\output\ExampleSolarFieldOutput\tsfo017_Dense_Tracking_Vector_Field_xy.png -INFO:singleprocessing:Saving figure text: solarfield\data\output\ExampleSolarFieldOutput\tsfo017_Dense_Tracking_Vector_Field_xy.txt -INFO:singleprocessing:All tests complete. diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/esfo001_Heliostat_5E10_Face_West_3d.png b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo001_Heliostat_5E10_Face_West_3d.png new file mode 100644 index 000000000..b32acb965 Binary files /dev/null and b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo001_Heliostat_5E10_Face_West_3d.png differ diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo001_Heliostat_5E10_Face_West_3d.txt b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo001_Heliostat_5E10_Face_West_3d.txt old mode 100755 new mode 100644 similarity index 91% rename from example/solarfield/data/input/ExampleSolarFieldOutput/tsfo001_Heliostat_5E10_Face_West_3d.txt rename to example/solarfield/data/input/ExampleSolarFieldOutput/esfo001_Heliostat_5E10_Face_West_3d.txt index 577b85294..c7425dfcc --- a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo001_Heliostat_5E10_Face_West_3d.txt +++ b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo001_Heliostat_5E10_Face_West_3d.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 1 -Name: tsfo001_Heliostat 5E10, Face West +Name: esfo001_Heliostat 5E10, Face West Title: Heliostat 5E10, Face West Code tag: ExampleSolarFieldOutput.example_single_heliostat() View spec: 3d diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/esfo002_Heliostat_5E10_with_Highlighting_3d.png b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo002_Heliostat_5E10_with_Highlighting_3d.png new file mode 100644 index 000000000..aa72cf92a Binary files /dev/null and b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo002_Heliostat_5E10_with_Highlighting_3d.png differ diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo002_Heliostat_5E10_with_Highlighting_3d.txt b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo002_Heliostat_5E10_with_Highlighting_3d.txt old mode 100755 new mode 100644 similarity index 91% rename from example/solarfield/data/input/ExampleSolarFieldOutput/tsfo002_Heliostat_5E10_with_Highlighting_3d.txt rename to example/solarfield/data/input/ExampleSolarFieldOutput/esfo002_Heliostat_5E10_with_Highlighting_3d.txt index e9580382f..634103c6a --- a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo002_Heliostat_5E10_with_Highlighting_3d.txt +++ b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo002_Heliostat_5E10_with_Highlighting_3d.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 1 -Name: tsfo002_Heliostat 5E10, with Highlighting +Name: esfo002_Heliostat 5E10, with Highlighting Title: Heliostat 5E10, with Highlighting Code tag: ExampleSolarFieldOutput.example_annotated_heliostat() View spec: 3d diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/esfo003_Example_Poses_and_Styles_3d.png b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo003_Example_Poses_and_Styles_3d.png new file mode 100644 index 000000000..19eb0f4d9 Binary files /dev/null and b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo003_Example_Poses_and_Styles_3d.png differ diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo003_Example_Poses_and_Styles_3d.txt b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo003_Example_Poses_and_Styles_3d.txt old mode 100755 new mode 100644 similarity index 83% rename from example/solarfield/data/input/ExampleSolarFieldOutput/tsfo003_Example_Poses_and_Styles_3d.txt rename to example/solarfield/data/input/ExampleSolarFieldOutput/esfo003_Example_Poses_and_Styles_3d.txt index 7c90740d3..a1dcc2c5e --- a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo003_Example_Poses_and_Styles_3d.txt +++ b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo003_Example_Poses_and_Styles_3d.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 1 -Name: tsfo003_Example Poses and Styles +Name: esfo003_Example Poses and Styles Title: Example Poses and Styles Code tag: ExampleSolarFieldOutput.example_multi_heliostat() View spec: 3d diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/esfo004_Heliostat_Names_xy.png b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo004_Heliostat_Names_xy.png new file mode 100644 index 000000000..ff15b55df Binary files /dev/null and b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo004_Heliostat_Names_xy.png differ diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo004_Heliostat_Names_xy.txt b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo004_Heliostat_Names_xy.txt old mode 100755 new mode 100644 similarity index 91% rename from example/solarfield/data/input/ExampleSolarFieldOutput/tsfo004_Heliostat_Names_xy.txt rename to example/solarfield/data/input/ExampleSolarFieldOutput/esfo004_Heliostat_Names_xy.txt index 163942980..3c456d134 --- a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo004_Heliostat_Names_xy.txt +++ b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo004_Heliostat_Names_xy.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 1 -Name: tsfo004_Heliostat Names +Name: esfo004_Heliostat Names Title: Heliostat Names Code tag: ExampleSolarFieldOutput.example_solar_field_h_names() View spec: xy diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/esfo005_Heliostat_Centroids_3d.png b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo005_Heliostat_Centroids_3d.png new file mode 100644 index 000000000..0426c56a9 Binary files /dev/null and b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo005_Heliostat_Centroids_3d.png differ diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo005_Heliostat_Centroids_3d.txt b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo005_Heliostat_Centroids_3d.txt old mode 100755 new mode 100644 similarity index 90% rename from example/solarfield/data/input/ExampleSolarFieldOutput/tsfo005_Heliostat_Centroids_3d.txt rename to example/solarfield/data/input/ExampleSolarFieldOutput/esfo005_Heliostat_Centroids_3d.txt index 2dddb0ec7..7bad83f15 --- a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo005_Heliostat_Centroids_3d.txt +++ b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo005_Heliostat_Centroids_3d.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 1 -Name: tsfo005_Heliostat Centroids +Name: esfo005_Heliostat Centroids Title: Heliostat Centroids Code tag: ExampleSolarFieldOutput.example_solar_field_h_centroids() View spec: 3d diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/esfo006_Heliostat_Centroids_xy.png b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo006_Heliostat_Centroids_xy.png new file mode 100644 index 000000000..0f655748a Binary files /dev/null and b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo006_Heliostat_Centroids_xy.png differ diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo006_Heliostat_Centroids_xy.txt b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo006_Heliostat_Centroids_xy.txt old mode 100755 new mode 100644 similarity index 90% rename from example/solarfield/data/input/ExampleSolarFieldOutput/tsfo006_Heliostat_Centroids_xy.txt rename to example/solarfield/data/input/ExampleSolarFieldOutput/esfo006_Heliostat_Centroids_xy.txt index 5fd5fe23e..fc56ebf80 --- a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo006_Heliostat_Centroids_xy.txt +++ b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo006_Heliostat_Centroids_xy.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 2 -Name: tsfo006_Heliostat Centroids +Name: esfo006_Heliostat Centroids Title: Heliostat Centroids Code tag: ExampleSolarFieldOutput.example_solar_field_h_centroids() View spec: xy diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/esfo007_Heliostat_Centroids_xz.png b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo007_Heliostat_Centroids_xz.png new file mode 100644 index 000000000..4bcbbbadb Binary files /dev/null and b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo007_Heliostat_Centroids_xz.png differ diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo007_Heliostat_Centroids_xz.txt b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo007_Heliostat_Centroids_xz.txt old mode 100755 new mode 100644 similarity index 90% rename from example/solarfield/data/input/ExampleSolarFieldOutput/tsfo007_Heliostat_Centroids_xz.txt rename to example/solarfield/data/input/ExampleSolarFieldOutput/esfo007_Heliostat_Centroids_xz.txt index 1771c68a3..763ccab27 --- a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo007_Heliostat_Centroids_xz.txt +++ b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo007_Heliostat_Centroids_xz.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 3 -Name: tsfo007_Heliostat Centroids +Name: esfo007_Heliostat Centroids Title: Heliostat Centroids Code tag: ExampleSolarFieldOutput.example_solar_field_h_centroids() View spec: xz diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/esfo008_Heliostat_Centroids_yz.png b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo008_Heliostat_Centroids_yz.png new file mode 100644 index 000000000..ba59f8ab4 Binary files /dev/null and b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo008_Heliostat_Centroids_yz.png differ diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo008_Heliostat_Centroids_yz.txt b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo008_Heliostat_Centroids_yz.txt old mode 100755 new mode 100644 similarity index 90% rename from example/solarfield/data/input/ExampleSolarFieldOutput/tsfo008_Heliostat_Centroids_yz.txt rename to example/solarfield/data/input/ExampleSolarFieldOutput/esfo008_Heliostat_Centroids_yz.txt index 8ffdc9a32..bf95047e0 --- a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo008_Heliostat_Centroids_yz.txt +++ b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo008_Heliostat_Centroids_yz.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 4 -Name: tsfo008_Heliostat Centroids +Name: esfo008_Heliostat Centroids Title: Heliostat Centroids Code tag: ExampleSolarFieldOutput.example_solar_field_h_centroids() View spec: yz diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/esfo009_Heliostat_Labelled_Centroids_xy.png b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo009_Heliostat_Labelled_Centroids_xy.png new file mode 100644 index 000000000..308c07e89 Binary files /dev/null and b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo009_Heliostat_Labelled_Centroids_xy.png differ diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo009_Heliostat_Labelled_Centroids_xy.txt b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo009_Heliostat_Labelled_Centroids_xy.txt old mode 100755 new mode 100644 similarity index 87% rename from example/solarfield/data/input/ExampleSolarFieldOutput/tsfo009_Heliostat_Labelled_Centroids_xy.txt rename to example/solarfield/data/input/ExampleSolarFieldOutput/esfo009_Heliostat_Labelled_Centroids_xy.txt index 843b54176..84f1d6ed4 --- a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo009_Heliostat_Labelled_Centroids_xy.txt +++ b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo009_Heliostat_Labelled_Centroids_xy.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 1 -Name: tsfo009_Heliostat Labelled Centroids +Name: esfo009_Heliostat Labelled Centroids Title: Heliostat Labelled Centroids Code tag: ExampleSolarFieldOutput.example_solar_field_h_centroids_names() View spec: xy diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/esfo010_Heliostat_Outlines_3d.png b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo010_Heliostat_Outlines_3d.png new file mode 100644 index 000000000..f46262751 Binary files /dev/null and b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo010_Heliostat_Outlines_3d.png differ diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo010_Heliostat_Outlines_3d.txt b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo010_Heliostat_Outlines_3d.txt old mode 100755 new mode 100644 similarity index 89% rename from example/solarfield/data/input/ExampleSolarFieldOutput/tsfo010_Heliostat_Outlines_3d.txt rename to example/solarfield/data/input/ExampleSolarFieldOutput/esfo010_Heliostat_Outlines_3d.txt index 12082a23e..177e906b5 --- a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo010_Heliostat_Outlines_3d.txt +++ b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo010_Heliostat_Outlines_3d.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 1 -Name: tsfo010_Heliostat Outlines +Name: esfo010_Heliostat Outlines Title: Heliostat Outlines Code tag: ExampleSolarFieldOutput.example_solar_field_h_outlines() View spec: 3d diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/esfo011_Solar_Field_Situation_3d.png b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo011_Solar_Field_Situation_3d.png new file mode 100644 index 000000000..b60527969 Binary files /dev/null and b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo011_Solar_Field_Situation_3d.png differ diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo011_Solar_Field_Situation_3d.txt b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo011_Solar_Field_Situation_3d.txt old mode 100755 new mode 100644 similarity index 94% rename from example/solarfield/data/input/ExampleSolarFieldOutput/tsfo011_Solar_Field_Situation_3d.txt rename to example/solarfield/data/input/ExampleSolarFieldOutput/esfo011_Solar_Field_Situation_3d.txt index ae38b6f1e..86c62be64 --- a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo011_Solar_Field_Situation_3d.txt +++ b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo011_Solar_Field_Situation_3d.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 1 -Name: tsfo011_Solar Field Situation +Name: esfo011_Solar Field Situation Title: Solar Field Situation Code tag: ExampleSolarFieldOutput.example_annotated_solar_field() View spec: 3d diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/esfo012_Selected_Heliostats_3d.png b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo012_Selected_Heliostats_3d.png new file mode 100644 index 000000000..8802187f7 Binary files /dev/null and b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo012_Selected_Heliostats_3d.png differ diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo012_Selected_Heliostats_3d.txt b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo012_Selected_Heliostats_3d.txt old mode 100755 new mode 100644 similarity index 94% rename from example/solarfield/data/input/ExampleSolarFieldOutput/tsfo012_Selected_Heliostats_3d.txt rename to example/solarfield/data/input/ExampleSolarFieldOutput/esfo012_Selected_Heliostats_3d.txt index f604a2f5a..24dee0b66 --- a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo012_Selected_Heliostats_3d.txt +++ b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo012_Selected_Heliostats_3d.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 1 -Name: tsfo012_Selected Heliostats +Name: esfo012_Selected Heliostats Title: Selected Heliostats Code tag: ExampleSolarFieldOutput.example_solar_field_subset() View spec: 3d diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/esfo013_Heliostat_Vector_Field_3d.png b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo013_Heliostat_Vector_Field_3d.png new file mode 100644 index 000000000..dcb65bc48 Binary files /dev/null and b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo013_Heliostat_Vector_Field_3d.png differ diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo013_Heliostat_Vector_Field_3d.txt b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo013_Heliostat_Vector_Field_3d.txt old mode 100755 new mode 100644 similarity index 90% rename from example/solarfield/data/input/ExampleSolarFieldOutput/tsfo013_Heliostat_Vector_Field_3d.txt rename to example/solarfield/data/input/ExampleSolarFieldOutput/esfo013_Heliostat_Vector_Field_3d.txt index f582f344c..6c4828144 --- a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo013_Heliostat_Vector_Field_3d.txt +++ b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo013_Heliostat_Vector_Field_3d.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 1 -Name: tsfo013_Heliostat Vector Field +Name: esfo013_Heliostat Vector Field Title: Heliostat Vector Field Code tag: ExampleSolarFieldOutput.example_heliostat_vector_field() View spec: 3d diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/esfo014_Heliostat_Vector_Field_xy.png b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo014_Heliostat_Vector_Field_xy.png new file mode 100644 index 000000000..1d5597f57 Binary files /dev/null and b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo014_Heliostat_Vector_Field_xy.png differ diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo014_Heliostat_Vector_Field_xy.txt b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo014_Heliostat_Vector_Field_xy.txt old mode 100755 new mode 100644 similarity index 90% rename from example/solarfield/data/input/ExampleSolarFieldOutput/tsfo014_Heliostat_Vector_Field_xy.txt rename to example/solarfield/data/input/ExampleSolarFieldOutput/esfo014_Heliostat_Vector_Field_xy.txt index 61f92f061..1223948fb --- a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo014_Heliostat_Vector_Field_xy.txt +++ b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo014_Heliostat_Vector_Field_xy.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 2 -Name: tsfo014_Heliostat Vector Field +Name: esfo014_Heliostat Vector Field Title: Heliostat Vector Field Code tag: ExampleSolarFieldOutput.example_heliostat_vector_field() View spec: xy diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/esfo015_Heliostat_Vector_Field_xz.png b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo015_Heliostat_Vector_Field_xz.png new file mode 100644 index 000000000..bcaff186a Binary files /dev/null and b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo015_Heliostat_Vector_Field_xz.png differ diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo015_Heliostat_Vector_Field_xz.txt b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo015_Heliostat_Vector_Field_xz.txt old mode 100755 new mode 100644 similarity index 87% rename from example/solarfield/data/input/ExampleSolarFieldOutput/tsfo015_Heliostat_Vector_Field_xz.txt rename to example/solarfield/data/input/ExampleSolarFieldOutput/esfo015_Heliostat_Vector_Field_xz.txt index 72a78197e..af18459b9 --- a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo015_Heliostat_Vector_Field_xz.txt +++ b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo015_Heliostat_Vector_Field_xz.txt @@ -1,16 +1,16 @@ -Metadata: -Figure number: 3 -Name: tsfo015_Heliostat Vector Field -Title: Heliostat Vector Field -Code tag: ExampleSolarFieldOutput.example_heliostat_vector_field() -View spec: xz - -Title: -Heliostat Vector Field - -Caption: -Rendering of the normal vector at the heliostat origin, for each heliostat in a field of tracking heliostats. - -Comments: -Each heliostat's surface normal, which can be viewed as a vector field. - +Metadata: +Figure number: 3 +Name: esfo015_Heliostat Vector Field +Title: Heliostat Vector Field +Code tag: ExampleSolarFieldOutput.example_heliostat_vector_field() +View spec: xz + +Title: +Heliostat Vector Field + +Caption: +Rendering of the normal vector at the heliostat origin, for each heliostat in a field of tracking heliostats. + +Comments: +Each heliostat's surface normal, which can be viewed as a vector field. + diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/esfo016_Heliostat_Vector_Field_yz.png b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo016_Heliostat_Vector_Field_yz.png new file mode 100644 index 000000000..6f8690914 Binary files /dev/null and b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo016_Heliostat_Vector_Field_yz.png differ diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo016_Heliostat_Vector_Field_yz.txt b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo016_Heliostat_Vector_Field_yz.txt old mode 100755 new mode 100644 similarity index 87% rename from example/solarfield/data/input/ExampleSolarFieldOutput/tsfo016_Heliostat_Vector_Field_yz.txt rename to example/solarfield/data/input/ExampleSolarFieldOutput/esfo016_Heliostat_Vector_Field_yz.txt index c95f94a80..c4d54ce14 --- a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo016_Heliostat_Vector_Field_yz.txt +++ b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo016_Heliostat_Vector_Field_yz.txt @@ -1,16 +1,16 @@ -Metadata: -Figure number: 4 -Name: tsfo016_Heliostat Vector Field -Title: Heliostat Vector Field -Code tag: ExampleSolarFieldOutput.example_heliostat_vector_field() -View spec: yz - -Title: -Heliostat Vector Field - -Caption: -Rendering of the normal vector at the heliostat origin, for each heliostat in a field of tracking heliostats. - -Comments: -Each heliostat's surface normal, which can be viewed as a vector field. - +Metadata: +Figure number: 4 +Name: esfo016_Heliostat Vector Field +Title: Heliostat Vector Field +Code tag: ExampleSolarFieldOutput.example_heliostat_vector_field() +View spec: yz + +Title: +Heliostat Vector Field + +Caption: +Rendering of the normal vector at the heliostat origin, for each heliostat in a field of tracking heliostats. + +Comments: +Each heliostat's surface normal, which can be viewed as a vector field. + diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/esfo017_Dense_Tracking_Vector_Field_xy.png b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo017_Dense_Tracking_Vector_Field_xy.png new file mode 100644 index 000000000..19ef2a053 Binary files /dev/null and b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo017_Dense_Tracking_Vector_Field_xy.png differ diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo017_Dense_Tracking_Vector_Field_xy.txt b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo017_Dense_Tracking_Vector_Field_xy.txt old mode 100755 new mode 100644 similarity index 94% rename from example/solarfield/data/input/ExampleSolarFieldOutput/tsfo017_Dense_Tracking_Vector_Field_xy.txt rename to example/solarfield/data/input/ExampleSolarFieldOutput/esfo017_Dense_Tracking_Vector_Field_xy.txt index d7c7f190f..affc021a5 --- a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo017_Dense_Tracking_Vector_Field_xy.txt +++ b/example/solarfield/data/input/ExampleSolarFieldOutput/esfo017_Dense_Tracking_Vector_Field_xy.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 1 -Name: tsfo017_Dense Tracking Vector Field +Name: esfo017_Dense Tracking Vector Field Title: Dense Tracking Vector Field Code tag: ExampleSolarFieldOutput.example_dense_vector_field() View spec: xy diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo001_Heliostat_5E10_Face_West_3d.png b/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo001_Heliostat_5E10_Face_West_3d.png deleted file mode 100755 index c1fd9b2be..000000000 Binary files a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo001_Heliostat_5E10_Face_West_3d.png and /dev/null differ diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo002_Heliostat_5E10_with_Highlighting_3d.png b/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo002_Heliostat_5E10_with_Highlighting_3d.png deleted file mode 100755 index 5bea42e1e..000000000 Binary files a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo002_Heliostat_5E10_with_Highlighting_3d.png and /dev/null differ diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo003_Example_Poses_and_Styles_3d.png b/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo003_Example_Poses_and_Styles_3d.png deleted file mode 100755 index d5620e0fe..000000000 Binary files a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo003_Example_Poses_and_Styles_3d.png and /dev/null differ diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo004_Heliostat_Names_xy.png b/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo004_Heliostat_Names_xy.png deleted file mode 100755 index cfd84064e..000000000 Binary files a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo004_Heliostat_Names_xy.png and /dev/null differ diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo005_Heliostat_Centroids_3d.png b/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo005_Heliostat_Centroids_3d.png deleted file mode 100755 index aa7d5eb9b..000000000 Binary files a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo005_Heliostat_Centroids_3d.png and /dev/null differ diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo006_Heliostat_Centroids_xy.png b/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo006_Heliostat_Centroids_xy.png deleted file mode 100755 index fbb4d1ed4..000000000 Binary files a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo006_Heliostat_Centroids_xy.png and /dev/null differ diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo007_Heliostat_Centroids_xz.png b/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo007_Heliostat_Centroids_xz.png deleted file mode 100755 index d9d293ba2..000000000 Binary files a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo007_Heliostat_Centroids_xz.png and /dev/null differ diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo008_Heliostat_Centroids_yz.png b/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo008_Heliostat_Centroids_yz.png deleted file mode 100755 index 91e3bda72..000000000 Binary files a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo008_Heliostat_Centroids_yz.png and /dev/null differ diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo009_Heliostat_Labelled_Centroids_xy.png b/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo009_Heliostat_Labelled_Centroids_xy.png deleted file mode 100755 index 6141dcb29..000000000 Binary files a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo009_Heliostat_Labelled_Centroids_xy.png and /dev/null differ diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo010_Heliostat_Outlines_3d.png b/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo010_Heliostat_Outlines_3d.png deleted file mode 100755 index fd6ac46c3..000000000 Binary files a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo010_Heliostat_Outlines_3d.png and /dev/null differ diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo011_Solar_Field_Situation_3d.png b/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo011_Solar_Field_Situation_3d.png deleted file mode 100755 index 793e7b169..000000000 Binary files a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo011_Solar_Field_Situation_3d.png and /dev/null differ diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo012_Selected_Heliostats_3d.png b/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo012_Selected_Heliostats_3d.png deleted file mode 100755 index 83d3ac8ce..000000000 Binary files a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo012_Selected_Heliostats_3d.png and /dev/null differ diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo013_Heliostat_Vector_Field_3d.png b/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo013_Heliostat_Vector_Field_3d.png deleted file mode 100755 index 06b53451b..000000000 Binary files a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo013_Heliostat_Vector_Field_3d.png and /dev/null differ diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo014_Heliostat_Vector_Field_xy.png b/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo014_Heliostat_Vector_Field_xy.png deleted file mode 100755 index c0d19d633..000000000 Binary files a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo014_Heliostat_Vector_Field_xy.png and /dev/null differ diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo015_Heliostat_Vector_Field_xz.png b/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo015_Heliostat_Vector_Field_xz.png deleted file mode 100755 index 94c66502b..000000000 Binary files a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo015_Heliostat_Vector_Field_xz.png and /dev/null differ diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo016_Heliostat_Vector_Field_yz.png b/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo016_Heliostat_Vector_Field_yz.png deleted file mode 100755 index 081eb8888..000000000 Binary files a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo016_Heliostat_Vector_Field_yz.png and /dev/null differ diff --git a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo017_Dense_Tracking_Vector_Field_xy.png b/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo017_Dense_Tracking_Vector_Field_xy.png deleted file mode 100755 index aa3103f5b..000000000 Binary files a/example/solarfield/data/input/ExampleSolarFieldOutput/tsfo017_Dense_Tracking_Vector_Field_xy.png and /dev/null differ diff --git a/example/solarfield/example_SolarFieldOutput.py b/example/solarfield/example_SolarFieldOutput.py index 551c88f63..937827ee7 100644 --- a/example/solarfield/example_SolarFieldOutput.py +++ b/example/solarfield/example_SolarFieldOutput.py @@ -3,12 +3,8 @@ """ -from datetime import datetime -import matplotlib.pyplot as plt import numpy as np -import os -from opencsp.common.lib.csp.HeliostatConfiguration import HeliostatConfiguration import opencsp.common.lib.csp.SolarField as sf from opencsp.common.lib.csp.SolarField import SolarField import opencsp.common.lib.csp.sun_track as sun_track # "st" is taken by string_tools. @@ -16,23 +12,14 @@ from opencsp.common.lib.geometry.Pxyz import Pxyz from opencsp.common.lib.geometry.Vxyz import Vxyz import opencsp.common.lib.opencsp_path.data_path_for_test as dpft -import opencsp.common.lib.opencsp_path.opencsp_root_path as orp import opencsp.common.lib.render.figure_management as fm import opencsp.common.lib.render.view_spec as vs -import opencsp.common.lib.render_control.RenderControlAxis as rca -from opencsp.common.lib.render_control.RenderControlAxis import RenderControlAxis -import opencsp.common.lib.render_control.RenderControlEnsemble as rce import opencsp.common.lib.render_control.RenderControlFacet as rcf -import opencsp.common.lib.render_control.RenderControlFigure as rcfg -from opencsp.common.lib.render_control.RenderControlFigure import RenderControlFigure -from opencsp.common.lib.render_control.RenderControlFigureRecord import RenderControlFigureRecord import opencsp.common.lib.render_control.RenderControlHeliostat as rch import opencsp.common.lib.render_control.RenderControlPointSeq as rcps import opencsp.common.lib.render_control.RenderControlSolarField as rcsf import opencsp.common.lib.render_control.RenderControlFacetEnsemble as rcfe -import opencsp.common.lib.test.support_test as stest import opencsp.common.lib.test.TestOutput as to -import opencsp.common.lib.tool.file_tools as ft import opencsp.common.lib.tool.log_tools as lt from opencsp.common.lib.csp.HeliostatAzEl import HeliostatAzEl @@ -46,12 +33,16 @@ class ExampleSolarFieldOutput(to.TestOutput): + """ + Example rendering of solar field objects under different configurations + and render settings. + """ @classmethod def setUpClass( self, source_file_body: str = 'ExampleSolarFieldOutput', # Set these here, because pytest calls - figure_prefix_root: str = 'tsfo', # setup_class() with no arguments. + figure_prefix_root: str = 'esfo', # setup_class() with no arguments. interactive: bool = False, verify: bool = True, ): @@ -888,15 +879,18 @@ def example_dense_vector_field(self) -> None: self.show_save_and_check_figure(fig_record) -def example_driver(): +def example_driver(verify=True): # Control flags. interactive = False # Set verify to False when you want to generate all figures and then copy # them into the expected_output directory. - # (Does not affect pytest, which uses default value.) + # Or, just run the pytest example, and then move the newly created + # output\ExampleSolarFieldOutput directory to the location + # input\ExampleSolarFieldOutput. + # Setup. example_object = ExampleSolarFieldOutput() - example_object.setUpClass(interactive=interactive, verify=False) + example_object.setUpClass(interactive=interactive, verify=verify) example_object.setUp() # Tests. @@ -920,4 +914,5 @@ def example_driver(): # MAIN EXECUTION if __name__ == "__main__": - example_driver() + # When running from the debugger, we typically do not want verify turned on. + example_driver(verify=False) diff --git a/opencsp/app/sofast/lib/DebugOpticsGeometry.py b/opencsp/app/sofast/lib/DebugOpticsGeometry.py index 94eb71085..8071ea4f2 100644 --- a/opencsp/app/sofast/lib/DebugOpticsGeometry.py +++ b/opencsp/app/sofast/lib/DebugOpticsGeometry.py @@ -9,3 +9,7 @@ def __init__(self): """To activate geometry debugging. Default False""" self.figures: list = [] """List to hold figure objects once created.""" + self.save_dir = None + """Where to save figure objects.""" + self.figure_idx = 0 + """Incrementing figure index, so figures appear in order created.""" diff --git a/opencsp/app/sofast/lib/DefinitionFacet.py b/opencsp/app/sofast/lib/DefinitionFacet.py index be893c9e5..0b434ecf3 100644 --- a/opencsp/app/sofast/lib/DefinitionFacet.py +++ b/opencsp/app/sofast/lib/DefinitionFacet.py @@ -15,7 +15,7 @@ def __init__(self, v_facet_corners: Vxyz, v_facet_centroid: Vxyz): ---------------------- v_facet_corners : Vxyz Corners of facet in facet coordinates - v_centroid_facet : Vxyz + v_facet_centroid : Vxyz Centroid of facet in facet coordinates NOTE: "facet" coordinates are defined as +x to right and +y up when diff --git a/opencsp/app/sofast/lib/process_optics_geometry.py b/opencsp/app/sofast/lib/process_optics_geometry.py index 1bfe76625..51bf5bdbc 100644 --- a/opencsp/app/sofast/lib/process_optics_geometry.py +++ b/opencsp/app/sofast/lib/process_optics_geometry.py @@ -1,6 +1,7 @@ """Library of functions used to process the geometry of a deflectometry setup.""" -from copy import copy +import copy +import os.path import matplotlib.pyplot as plt import numpy as np @@ -89,7 +90,7 @@ def process_singlefacet_geometry( data_error = cdc.CalculationError() # Make copy of orientation - ori = copy(orientation) + ori = copy.copy(orientation) # Get optic data v_facet_corners: Vxyz = facet_data.v_facet_corners # Corners of facet in facet coordinates @@ -102,13 +103,33 @@ def process_singlefacet_geometry( if debug.debug_active: fig = plt.figure() debug.figures.append(fig) + figure_title = "Raw Mask" + figure_file_body = figure_title.replace(' ', '_') + figure_dir_body_ext = os.path.join(debug.save_dir, f'{debug.figure_idx:02d}_geometry_{figure_file_body}.png') + debug.figure_idx += 1 plt.imshow(mask_raw, cmap="gray") - plt.title("Raw Mask") + plt.title(figure_title) + lt.info(f"In process_singlefacet_geometry(), saving figure '{figure_title}' to:\n {figure_dir_body_ext}") + fig.savefig(figure_dir_body_ext) # Find edges of mask v_edges_image = ip.edges_from_mask(mask_raw) data_image_processing_general.v_edges_image = v_edges_image + # Plot mask edges + if debug.debug_active: + fig = plt.figure() + debug.figures.append(fig) + figure_title = "Mask Edges" + figure_file_body = figure_title.replace(' ', '_') + figure_dir_body_ext = os.path.join(debug.save_dir, f'{debug.figure_idx:02d}_geometry_{figure_file_body}.png') + debug.figure_idx += 1 + plt.imshow(mask_raw, cmap="gray") + plt.scatter(*v_edges_image.data, marker=".", c='red', s=0.05) + plt.title(figure_title) + lt.info(f"In process_singlefacet_geometry(), saving figure '{figure_title}' to:\n {figure_dir_body_ext}") + fig.savefig(figure_dir_body_ext) + # Find centroid of processed mask v_mask_centroid_image = ip.centroid_mask(mask_raw) data_image_processing_general.v_mask_centroid_image = v_mask_centroid_image @@ -117,9 +138,15 @@ def process_singlefacet_geometry( if debug.debug_active: fig = plt.figure() debug.figures.append(fig) - plt.imshow(mask_raw) - plt.scatter(*v_mask_centroid_image.data, marker="x") - plt.title("Mask Centroid") + figure_title = "Mask Centroid" + figure_file_body = figure_title.replace(' ', '_') + figure_dir_body_ext = os.path.join(debug.save_dir, f'{debug.figure_idx:02d}_geometry_{figure_file_body}.png') + debug.figure_idx += 1 + plt.imshow(mask_raw, cmap="gray") + plt.scatter(*v_mask_centroid_image.data, marker="x", c='red') + plt.title(figure_title) + lt.info(f"In process_singlefacet_geometry(), saving figure '{figure_title}' to:\n {figure_dir_body_ext}") + fig.savefig(figure_dir_body_ext) # Find expected position of optic centroid v_cam_optic_centroid_cam_exp = sp.t_from_distance( @@ -131,11 +158,18 @@ def process_singlefacet_geometry( if debug.debug_active: fig = plt.figure() debug.figures.append(fig) - plt.imshow(mask_raw) - plt.scatter( - *camera.project(v_cam_optic_centroid_cam_exp, Rotation.identity(), Vxyz((0, 0, 0))).data, marker="." - ) - plt.title("Expected Optic Centroid") + figure_title = "Expected Optic Centroid" + figure_file_body = figure_title.replace(' ', '_') + figure_dir_body_ext = os.path.join(debug.save_dir, f'{debug.figure_idx:02d}_geometry_{figure_file_body}.png') + debug.figure_idx += 1 + plt.imshow(mask_raw, cmap="gray") + plt.scatter(*v_mask_centroid_image.data, marker="x", c='red', s=45, label='Mask Centroid') + expected_centroid = camera.project(v_cam_optic_centroid_cam_exp, Rotation.identity(), Vxyz((0, 0, 0))) + plt.scatter(*expected_centroid.data, marker=".", c='blue', s=35, label='Expected Centroid') + plt.title(figure_title) + plt.legend() + lt.info(f"In process_singlefacet_geometry(), saving figure '{figure_title}' to:\n {figure_dir_body_ext}") + fig.savefig(figure_dir_body_ext) # Find expected orientation of optic r_cam_optic_exp = sp.r_from_position(v_cam_optic_centroid_cam_exp, ori.v_cam_screen_cam) @@ -145,17 +179,34 @@ def process_singlefacet_geometry( v_cam_optic_cam_exp = v_cam_optic_centroid_cam_exp - v_centroid_facet.rotate(r_cam_optic_exp.inv()) data_geometry_general.v_cam_optic_cam_exp = v_cam_optic_cam_exp - # Find expected optic loop in pixels + # Find expected optic vertices v_optic_corners_image_exp = camera.project(v_facet_corners, r_cam_optic_exp.inv(), v_cam_optic_cam_exp) + + # Plot expected optic corners + if debug.debug_active: + fig = plt.figure() + debug.figures.append(fig) + figure_title = "Expected Optic Corners" + figure_file_body = figure_title.replace(' ', '_') + figure_dir_body_ext = os.path.join(debug.save_dir, f'{debug.figure_idx:02d}_geometry_{figure_file_body}.png') + debug.figure_idx += 1 + plt.imshow(mask_raw) + _plot_labeled_points(v_optic_corners_image_exp) + plt.title(figure_title) + lt.info(f"In process_singlefacet_geometry(), saving figure '{figure_title}' to:\n {figure_dir_body_ext}") + fig.savefig(figure_dir_body_ext) + + # Construct expected optic loop in pixels loop_optic_image_exp = LoopXY.from_vertices(v_optic_corners_image_exp) data_image_processing_general.loop_optic_image_exp = loop_optic_image_exp - # Plot expected optic corners + # Plot expected optic loop if debug.debug_active: fig = plt.figure() debug.figures.append(fig) plt.imshow(mask_raw) _plot_labeled_points(v_optic_corners_image_exp) + # *** ADD LOOP EDGES *** plt.title("Expected Optic Corners") # Refine locations of optic corners with mask diff --git a/opencsp/common/lib/csp/Facet.py b/opencsp/common/lib/csp/Facet.py index 19e6a831f..73d1538fb 100644 --- a/opencsp/common/lib/csp/Facet.py +++ b/opencsp/common/lib/csp/Facet.py @@ -6,7 +6,7 @@ from opencsp.common.lib.csp.RayTraceable import RayTraceable from opencsp.common.lib.csp.VisualizeOrthorectifiedSlopeAbstract import VisualizeOrthorectifiedSlopeAbstract from opencsp.common.lib.geometry.Pxyz import Pxyz -from opencsp.common.lib.geometry.RegionXY import Resolution +from opencsp.common.lib.geometry.Resolution import Resolution from opencsp.common.lib.geometry.Vxy import Vxy from opencsp.common.lib.geometry.Vxyz import Vxyz from opencsp.common.lib.geometry.TransformXYZ import TransformXYZ @@ -156,7 +156,7 @@ def draw(self, view: View3d, facet_style: RenderControlFacet = None, transform: view : View3d A view 3d object that holds the figure. mirror_styles : RenderControlMirror - Holds attibutes about the 3d graph. + Holds attributes about the 3d graph. transform : TransformXYZ 3d transform used to position points in the mirror's base coordinate reference frame in space. If None, defaults to position points @@ -220,4 +220,8 @@ def draw(self, view: View3d, facet_style: RenderControlFacet = None, transform: view.draw_xyz_text(origin.data.T[0], self.name, style=facet_style.name_style) if facet_style.draw_mirror_curvature: - self.mirror.draw(view, facet_style.mirror_styles, transform * self.mirror._self_to_parent_transform) + self.mirror.draw( + view=view, + mirror_style=facet_style.mirror_styles, + transform=transform * self.mirror._self_to_parent_transform, + ) diff --git a/opencsp/common/lib/csp/FacetEnsemble.py b/opencsp/common/lib/csp/FacetEnsemble.py index b12fa4269..0c9a51f19 100644 --- a/opencsp/common/lib/csp/FacetEnsemble.py +++ b/opencsp/common/lib/csp/FacetEnsemble.py @@ -9,7 +9,7 @@ from opencsp.common.lib.csp.RayTraceable import RayTraceable from opencsp.common.lib.geometry.Pxy import Pxy from opencsp.common.lib.geometry.Pxyz import Pxyz -from opencsp.common.lib.geometry.RegionXY import Resolution +from opencsp.common.lib.geometry.Resolution import Resolution from opencsp.common.lib.geometry.TransformXYZ import TransformXYZ from opencsp.common.lib.geometry.Vxyz import Vxyz from opencsp.common.lib.render.View3d import View3d diff --git a/opencsp/common/lib/csp/HeliostatAbstract.py b/opencsp/common/lib/csp/HeliostatAbstract.py index f4edd9162..5a3c1c2fc 100644 --- a/opencsp/common/lib/csp/HeliostatAbstract.py +++ b/opencsp/common/lib/csp/HeliostatAbstract.py @@ -15,7 +15,7 @@ from opencsp.common.lib.geometry.FunctionXYContinuous import FunctionXYContinuous from opencsp.common.lib.geometry.Pxy import Pxy from opencsp.common.lib.geometry.Pxyz import Pxyz -from opencsp.common.lib.geometry.RegionXY import Resolution +from opencsp.common.lib.geometry.Resolution import Resolution from opencsp.common.lib.geometry.TransformXYZ import TransformXYZ from opencsp.common.lib.geometry.Uxyz import Uxyz from opencsp.common.lib.geometry.Vxyz import Vxyz diff --git a/opencsp/common/lib/csp/MirrorAbstract.py b/opencsp/common/lib/csp/MirrorAbstract.py index 9367709ae..c67240c12 100644 --- a/opencsp/common/lib/csp/MirrorAbstract.py +++ b/opencsp/common/lib/csp/MirrorAbstract.py @@ -2,23 +2,30 @@ from abc import ABC, abstractmethod +from typing import Callable + from matplotlib.tri import Triangulation import numpy as np from scipy.spatial.transform import Rotation from opencsp.common.lib.csp.RayTraceable import RayTraceable -from opencsp.common.lib.geometry.RegionXY import Resolution +from opencsp.common.lib.geometry.Resolution import Resolution from opencsp.common.lib.csp.VisualizeOrthorectifiedSlopeAbstract import VisualizeOrthorectifiedSlopeAbstract from opencsp.common.lib.geometry.Pxy import Pxy from opencsp.common.lib.geometry.Pxyz import Pxyz from opencsp.common.lib.geometry.RegionXY import RegionXY from opencsp.common.lib.geometry.TransformXYZ import TransformXYZ -from opencsp.common.lib.geometry.Vxyz import Vxyz +from opencsp.common.lib.geometry.Vxy import Vxy +from opencsp.common.lib.geometry.Vxyz import Vxyz, connection_lines from opencsp.common.lib.render.View3d import View3d from opencsp.common.lib.render_control.RenderControlMirror import RenderControlMirror +import opencsp.common.lib.render_control.RenderControlMirrorProjected as rcmp +import opencsp.common.lib.render_control.RenderControlPointSeq as rcps from opencsp.common.lib.csp.OpticOrientationAbstract import OpticOrientationAbstract +import opencsp.common.lib.tool.log_tools as lt + class MirrorAbstract(RayTraceable, VisualizeOrthorectifiedSlopeAbstract, OpticOrientationAbstract): """ @@ -56,6 +63,10 @@ def children(self) -> list[OpticOrientationAbstract]: def _add_child_helper(self, new_child: OpticOrientationAbstract): raise ValueError("Mirror does not accept new children.") + # override function from RayTraceable + def most_basic_ray_tracable_objects(self) -> list[RayTraceable]: + return [self] # any mirror is in the set of most basic ray traceable objects + def in_bounds(self, p: Pxy) -> np.ndarray[bool]: """ Determines what points are valid points on the mirror. @@ -263,8 +274,170 @@ def orthorectified_slope_array(self, x_vec: np.ndarray, y_vec: np.ndarray) -> np slopes = -normals[:2] / normals[2:3] # normalize z coordinate return slopes.reshape((2, y_vec.size, x_vec.size)) # 2 x M x N + def lift_xy(self, projected_xy: Vxy) -> Vxyz: + """Given a set of points on the (x,y) plane, construct the + corresponding set of (x,y,z) points on the mirror surface. + + Parameters + ---------- + projected_xy : Vxy + Set of (x,y) points to lift. + If any points are outside the domain of the surface function, + their corresponding lifted z values will be zero. + + Returns + ------- + Vxyz + Set of (x,y,z) points, corresponding to the input (x,y) points lifted + onto the mirror surface. The order of points is preserved. + """ + lifted_z = self.surface_displacement_at(projected_xy) + # If any xy points aren't in range of the mirror's interpolation function, set to 0. + if np.any(np.isnan(lifted_z)): + lt.warn("In MirorParametric.lift_xy(), could not find z values for some input points; filling with zeros.") + lifted_z = np.nan_to_num(lifted_z, nan=0) + lifted_xyz = Vxyz((projected_xy.x, projected_xy.y, lifted_z)) + # Return + return lifted_xyz + + def on_surface_xyz(self, general_xyz: Vxyz) -> Vxyz: + """Given a set of points in (x,y,z) space, construct the + corresponding (x,y,z) points on the mirror surface. + + Parameters + ---------- + general_xyz : Vxyz + Set of (x,y) points to lift. + If any points are outside the domain of the surface function, + their corresponding z values will be zero. + + Returns + ------- + Vxyz + Set of (x,y,z) points, corresponding to the input (x,y,z) points + projected up or down onto the mirror surface. + The order of points is preserved. + """ + on_surface_z = self.surface_displacement_at(Pxy((general_xyz.x, general_xyz.y))) + # If any xy points aren't in range of the mirror's interpolation function, set to 0. + if np.any(np.isnan(on_surface_z)): + lt.warn( + "In MirorParametric.on_surface_xyz(), could not find z values for some input points; filling with zeros." + ) + on_surface_z = np.nan_to_num(on_surface_z, nan=0) + on_surface_xyz = Vxyz((general_xyz.x, general_xyz.y, on_surface_z)) + # Return + return on_surface_xyz + + def number_of_boundary_vertices(self) -> int: + """Returns the number of vertices in the region bounding the mirror. + + Returns + ------- + int + Number of vertices in the mirror boundary. + """ + return self.projected_boundary_xy().len() + + def projected_boundary_xy(self) -> Vxy: + """Returns a sequence of (x,y) points delineating the boundary + of the mirror, projected onto the (x,y) plane. + + Returns + ------- + Vxy + Boundary of the mirror, projected onto the (x,y) plane. + """ + return Vxy.merge([loop.vertices for loop in self.region.loops]) + + def projected_boundary_xyz(self) -> Vxyz: + """Returns a sequence of (x,y,z) points delineating the boundary + of the mirror, projected onto the (x,y) plane. + + Returns + ------- + Vxyz + Boundary of the mirror, projected onto the (x,y) plane. + z=0 for all points. + """ + projected_boundary_xy = self.projected_boundary_xy() + n_vertices = projected_boundary_xy.data.shape[1] + projected_boundary_z = np.zeros(n_vertices) + return Vxyz((projected_boundary_xy.x, projected_boundary_xy.y, projected_boundary_z)) + + def constant_x_slice(self, x: float, y_min: float, y_max: float, n_points: int) -> Vxyz: + """Returns a sequence of (x,y,z) points corresponding to a slice of constant x. + Returns two sets of points: On the surface, and projected onto the (x,y) plane. + + Parameters + ---------- + x : (float) + x value for this constant-x slice. + y_min : float + y lower bound for this slice. + y_max : float + y upper bound for this slice. + n_points : int + Number of points to sample along the slice. + + Returns + ------- + Vxyz + Slice points on the mirror surface. + Vxyz + Slice points projected onto the (x,y) plane. + """ + list_x = [] + list_y = [] + for y in np.linspace(y_min, y_max, n_points): + list_x.append(x) + list_y.append(y) + projected_xyz = Vxyz((list_x, list_y, [0] * n_points)) + # Lifted slice in xyz space. + lifted_xyz = self.on_surface_xyz(projected_xyz) + # Return + return lifted_xyz, projected_xyz + + def constant_y_slice(self, y: float, x_min: float, x_max: float, n_points: int) -> Vxyz: + """Returns a sequence of (x,y,z) points corresponding to a slice of constant y. + Returns two sets of points: On the surface, and projected onto the (x,y) plane. + + Parameters + ---------- + y : (float) + y value for this constant-y slice. + x_min : float + x lower bound for this slice. + x_max : float + x upper bound for this slice. + n_points : int + Number of points to sample along the slice. + + Returns + ------- + Vxyz + Slice points on the mirror surface. + Vxyz + Slice points projected onto the (x,y) plane. + """ + list_x = [] + list_y = [] + for x in np.linspace(x_min, x_max, n_points): + list_x.append(x) + list_y.append(y) + projected_xyz = Vxyz((list_x, list_y, [0] * n_points)) + # Lifted slice in xyz space. + lifted_xyz = self.on_surface_xyz(projected_xyz) + # Return + return lifted_xyz, projected_xyz + def draw( - self, view: View3d, mirror_style: RenderControlMirror = None, transform: TransformXYZ | None = None + self, + view: View3d, + mirror_style: RenderControlMirror = None, + draw_projection: bool = False, + projected_style: rcmp.RenderControlMirrorProjected = None, + transform: TransformXYZ | None = None, ) -> None: """ Draws a mirror onto a View3d object. @@ -273,18 +446,23 @@ def draw( ----------- view : View3d A view 3d object that holds the figure. - mirror_styles : RenderControlMirror - Holds attibutes about the 3d graph. + mirror_style : RenderControlMirror | None + Holds attributes defining how to draw features, etc. Default None. + draw_projection: bool, optional + Whether to draw the projection of the mirror onto the (x,y) plane. Default False. + projected_style: RenderControlMirrorProjected | None + Holds attributes defining how to draw projection features. Default None. transform : TransformXYZ 3d transform used to position points in the mirror's base coordinate reference frame in space. If None, defaults to position points in the mirror's parent coordinate reference frame. """ - if mirror_style is None: mirror_style = RenderControlMirror() resolution = mirror_style.resolution + + # Ensure that transform is defined. if transform is None: transform = self.self_to_global_tranformation @@ -303,10 +481,48 @@ def draw( tri = Triangulation(domain.x, domain.y) # create triangles view.draw_xyz_trisurface(*points_surf.data, surface_style=mirror_style.surface_style, triangles=tri.triangles) - # Draw surface boundary - if mirror_style.point_styles is not None: - mirror_style.point_styles.markersize = 0 - edge_values_lifted.draw_line(view, style=mirror_style.point_styles) + # # Draw surface boundary + # if mirror_style.point_styles is not None: + # mirror_style.point_styles.markersize = 0 + # edge_values_lifted.draw_line(view, style=mirror_style.point_styles) + + # Draw projection onto (x,y) plane. + if draw_projection: + if projected_style is None: + projected_style = rcmp.RenderControlMirrorProjected( + lifted_line_style=rcps.outline(color='red'), + lifted_vertex_style=rcps.marker(color='red', markersize=2), + projected_style=rcps.outline(color='blue'), + connection_style=rcps.outline(color='blue', linewidth=0.6), + ) + # Draw defining region. + # Projected boundary on xy plane. + projected_boundary_xyz = self.projected_boundary_xyz() + # Lifted boundary in xyz space. + lifted_boundary_xyz = self.on_surface_xyz(projected_boundary_xyz) + # Fine-resolution lifted boundary, showing edge curvature. + fine_projected_boundary_xy = Vxy.merge([loop.edge_sample(20) for loop in self.region.loops]) + fine_lifted_boundary_xyz = self.lift_xy(fine_projected_boundary_xy) + if projected_style.projected_style is not None: + # Draw projected boundary. + transform.apply(projected_boundary_xyz).draw_line( + view, close=True, style=projected_style.projected_style + ) + if projected_style.connection_style is not None: + # Draw lines connecting projected boundary vertices to lifted boundary vertices. + projected_to_lifted_boundary_lines_xyz = connection_lines(projected_boundary_xyz, lifted_boundary_xyz) + for line_xyz in projected_to_lifted_boundary_lines_xyz: + transform.apply(line_xyz).draw_line(view, close=False, style=projected_style.connection_style) + if projected_style.lifted_line_style is not None: + # Draw lifted boundary. + transform.apply(fine_lifted_boundary_xyz).draw_line( + view, close=True, style=projected_style.lifted_line_style + ) + if projected_style.lifted_vertex_style is not None: + # Draw lifted vertices last. + transform.apply(lifted_boundary_xyz).draw_line( + view, close=True, style=projected_style.lifted_vertex_style + ) # Draw surface normals if mirror_style.surface_normals: @@ -320,6 +536,397 @@ def draw( # Draw on plot view.draw_xyzdxyz_list(xyzdxyz, close=False, style=mirror_style.norm_base_style) - # override function from RayTraceable - def most_basic_ray_tracable_objects(self) -> list[RayTraceable]: - return [self] # any mirror is in the set of most basic ray traceable objects + def draw_slice_constant_x( + self, + view: View3d, + slice_x: float, + y_min: float, + y_max: float, + style: rcmp.RenderControlMirrorProjected = None, + transform: TransformXYZ | None = None, + ) -> None: + """ + Draws a constant-x slice of a mirror onto a View3d object. + + Parameters: + ----------- + view : View3d + A view 3d object that holds the figure. + slice_x: float + x value defining the slice. + y_min: float + Minimum y value defining the slice lower bound endpoint. + y_max: float + Maximum y value defining the slice upper bound endpoint. + style : RenderControlMirrorProjected + Holds attributes defining how to draw features, etc. + transform : TransformXYZ + 3d transform used to position points in the mirror's base coordinate + reference frame in space. If None, defaults to position points + in the mirror's parent coordinate reference frame. + """ + # Ensure that the number of vertices is set. + if style is None: + n_vertices = 9 + fine_n_vertices = 41 + else: + n_vertices = style.slice_n_vertices + fine_n_vertices = style.slice_fine_n_vertices + + # Ensure that transform is defined. + if transform is None: + transform = self.self_to_global_tranformation + + # Construct. + # Coarse-resolution lifted slice, with vertices to draw. + lifted_slice_xyz, _ = self.constant_x_slice(slice_x, y_min, y_max, n_vertices) + # Fine-resolution lifted slice, showing edge curvature. + fine_lifted_slice_xyz, _ = self.constant_x_slice(slice_x, y_min, y_max, fine_n_vertices) + + # Draw. + # Draw lifted slice. + if style.lifted_line_style is not None: + transform.apply(fine_lifted_slice_xyz).draw_line(view, close=False, style=style.lifted_line_style) + # Draw lifted slice vertices last. + if style.lifted_vertex_style is not None: + transform.apply(lifted_slice_xyz).draw_line(view, close=False, style=style.lifted_vertex_style) + + def draw_slice_constant_y( + self, + view: View3d, + slice_y: float, + x_min: float, + x_max: float, + style: rcmp.RenderControlMirrorProjected = None, + transform: TransformXYZ | None = None, + ) -> None: + """ + Draws a constant-y slice of a mirror onto a View3d object. + + Parameters: + ----------- + view : View3d + A view 3d object that holds the figure. + slice_y: float + y value defining the slice. + x_min: float + Minimum x value defining the slice lower bound endpoint. + x_max: float + Maximum x value defining the slice upper bound endpoint. + style : RenderControlMirrorProjected + Holds attributes defining how to draw features, etc. + transform : TransformXYZ + 3d transform used to position points in the mirror's base coordinate + reference frame in space. If None, defaults to position points + in the mirror's parent coordinate reference frame. + """ + # Ensure that the number of vertices is set. + if style is None: + n_vertices = 9 + fine_n_vertices = 41 + else: + n_vertices = style.slice_n_vertices + fine_n_vertices = style.slice_fine_n_vertices + + # Ensure that transform is defined. + if transform is None: + transform = self.self_to_global_tranformation + + # Construct. + # Coarse-resolution lifted slice, with vertices to draw. + lifted_slice_xyz, _ = self.constant_y_slice(slice_y, x_min, x_max, n_vertices) + # Fine-resolution lifted slice, showing edge curvature. + fine_lifted_slice_xyz, _ = self.constant_y_slice(slice_y, x_min, x_max, fine_n_vertices) + + # Draw. + # Draw lifted slice. + if style.lifted_line_style is not None: + transform.apply(fine_lifted_slice_xyz).draw_line(view, close=False, style=style.lifted_line_style) + # Draw lifted slice vertices last. + if style.lifted_vertex_style is not None: + transform.apply(lifted_slice_xyz).draw_line(view, close=False, style=style.lifted_vertex_style) + + def draw_projected_lifted_slice_constant_x( + self, + view: View3d, + slice_x: float, + y_min: float, + y_max: float, + style: rcmp.RenderControlMirrorProjected = None, + transform: TransformXYZ | None = None, + ) -> None: + """ + Draws a constant-x slice of a mirror onto a View3d object, showing both the slice + of the mirror surface, and the corresponding projected line on the (x,y) plane, + with correspondence lines drawn at the slice coarse vertices. + + Parameters: + ----------- + view : View3d + A view 3d object that holds the figure. + slice_x: float + x value defining the slice. + y_min: float + Minimum y value defining the slice lower bound endpoint. + y_max: float + Maximum y value defining the slice upper bound endpoint. + style : RenderControlMirrorProjected + Holds attributes defining how to draw features, etc. + transform : TransformXYZ + 3d transform used to position points in the mirror's base coordinate + reference frame in space. If None, defaults to position points + in the mirror's parent coordinate reference frame. + """ + # Ensure that the number of vertices is set. + if style is None: + n_vertices = 9 + fine_n_vertices = 41 + else: + n_vertices = style.slice_n_vertices + fine_n_vertices = style.slice_fine_n_vertices + + # Ensure that transform is defined. + if transform is None: + transform = self.self_to_global_tranformation + + # Construct. + # Coarse-resolution lifted slice, with vertices to draw. + lifted_slice_xyz, projected_slice_xyz = self.constant_x_slice(slice_x, y_min, y_max, n_vertices) + # Fine-resolution lifted slice, showing edge curvature. + fine_lifted_slice_xyz, _ = self.constant_x_slice(slice_x, y_min, y_max, fine_n_vertices) + + # Draw. + # Projected slice. + if style.projected_style is not None: + transform.apply(projected_slice_xyz).draw_line(view, close=False, style=style.projected_style) + # Connection lines. + if style.connection_style is not None: + # Construct and draw lines connecting projected slice vertices to lifted slice vertices. + projected_to_lifted_slice_lines_xyz = connection_lines(projected_slice_xyz, lifted_slice_xyz) + for line_xyz in projected_to_lifted_slice_lines_xyz: + transform.apply(line_xyz).draw_line(view, close=False, style=style.connection_style) + # Lifted slice. + if style.lifted_line_style is not None: + # Draw lifted slice. + transform.apply(fine_lifted_slice_xyz).draw_line(view, close=False, style=style.lifted_line_style) + if style.lifted_vertex_style is not None: + # Draw lifted slice vertices last. + transform.apply(lifted_slice_xyz).draw_line(view, close=False, style=style.lifted_vertex_style) + + def draw_projected_lifted_slice_constant_y( + self, + view: View3d, + slice_y: float, + x_min: float, + x_max: float, + style: rcmp.RenderControlMirrorProjected = None, + transform: TransformXYZ | None = None, + ) -> None: + """ + Draws a constant-y slice of a mirror onto a View3d object, showing both the slice + of the mirror surface, and the corresponding projected line on the (x,y) plane, + with correspondence lines drawn at the slice coarse vertices. + + Parameters: + ----------- + view : View3d + A view 3d object that holds the figure. + slice_y: float + y value defining the slice. + x_min: float + Minimum x value defining the slice lower bound endpoint. + x_max: float + Maximum x value defining the slice upper bound endpoint. + style : RenderControlMirrorProjected + Holds attributes defining how to draw features, etc. + transform : TransformXYZ + 3d transform used to position points in the mirror's base coordinate + reference frame in space. If None, defaults to position points + in the mirror's parent coordinate reference frame. + """ + # Ensure that the number of vertices is set. + if style is None: + n_vertices = 9 + fine_n_vertices = 41 + else: + n_vertices = style.slice_n_vertices + fine_n_vertices = style.slice_fine_n_vertices + + # Ensure that transform is defined. + if transform is None: + transform = self.self_to_global_tranformation + + # Construct. + # Coarse-resolution lifted slice, with vertices to draw. + lifted_slice_xyz, projected_slice_xyz = self.constant_y_slice(slice_y, x_min, x_max, n_vertices) + # Fine-resolution lifted slice, showing edge curvature. + fine_lifted_slice_xyz, _ = self.constant_y_slice(slice_y, x_min, x_max, fine_n_vertices) + + # Draw. + # Projected slice. + if style.projected_style is not None: + transform.apply(projected_slice_xyz).draw_line(view, close=False, style=style.projected_style) + # Connection lines. + if style.connection_style is not None: + # Construct and draw lines connecting projected slice vertices to lifted slice vertices. + projected_to_lifted_slice_lines_xyz = connection_lines(projected_slice_xyz, lifted_slice_xyz) + for line_xyz in projected_to_lifted_slice_lines_xyz: + transform.apply(line_xyz).draw_line(view, close=False, style=style.connection_style) + # Lifted slice. + if style.lifted_line_style is not None: + # Draw lifted slice. + transform.apply(fine_lifted_slice_xyz).draw_line(view, close=False, style=style.lifted_line_style) + if style.lifted_vertex_style is not None: + # Draw lifted slice vertices last. + transform.apply(lifted_slice_xyz).draw_line(view, close=False, style=style.lifted_vertex_style) + + def _draw_surfacemesh_aux_x( + self, + view: View3d, + x: float, + mirror_y_min: float, + mirror_y_max: float, + project: bool, + style: rcmp.RenderControlMirrorProjected, + transform: TransformXYZ | None = None, + ) -> None: + """Supports draw_surface_mesh() function by handling projected vs. non-projected + cases for constant-x slices.""" + if project: + self.draw_projected_lifted_slice_constant_x( + view, slice_x=x, y_min=mirror_y_min, y_max=mirror_y_max, transform=transform, style=style + ) + else: + self.draw_slice_constant_x( + view, slice_x=x, y_min=mirror_y_min, y_max=mirror_y_max, transform=transform, style=style + ) + + def _draw_surfacemesh_aux_y( + self, + view: View3d, + y: float, + mirror_x_min: float, + mirror_x_max: float, + project: bool, + style: rcmp.RenderControlMirrorProjected, + transform: TransformXYZ | None = None, + ) -> None: + """Supports draw_surface_mesh() function by handling projected vs. non-projected + cases for constant-y slices.""" + if project: + self.draw_projected_lifted_slice_constant_y( + view, slice_y=y, x_min=mirror_x_min, x_max=mirror_x_max, transform=transform, style=style + ) + else: + self.draw_slice_constant_y( + view, slice_y=y, x_min=mirror_x_min, x_max=mirror_x_max, transform=transform, style=style + ) + + def draw_surface_mesh( + self, + view: View3d, + n_slices_x: int = 11, + project_slices_x: bool = False, + draw_special_origin_slice_x: bool = True, + project_origin_slice_x: bool = True, + n_slices_y: int = 11, + project_slices_y: bool = False, + draw_special_origin_slice_y: bool = True, + project_origin_slice_y: bool = False, + slice_style: rcmp.RenderControlMirrorProjected | None = None, + origin_slice_style: rcmp.RenderControlMirrorProjected | None = None, + transform: TransformXYZ | None = None, + ) -> None: + """Draws a mesh on the mirror surface, optionally with projected slice correspondence. + + If any arguments that control projection rendering are true (for example, project_slices_x), + then the corresponding slices are drawn including their projection onto the (x,y) plane, + with correspondence lines for coarse vertices. + + Parameters + ---------- + view : View3d + A view 3d object that holds the figure. + n_slices_x : int + Number of constant-x slices to draw. + If you select an odd number and the mirror extent is balanced about x=0, + then an ordinary slice is drawn at the origin x=0. + Default 11. + project_slices_x : bool + Whether to draw projection of all constant-x slices. + draw_special_origin_slice_x : bool + Whether to draw a constant-x slice at x=0. Overwrites an ordinary slice there. + project_origin_slice_x : bool + Whether to draw projection of origin constant-x slice. + n_slices_y : int + Number of constant-y slices to draw. + If you select an odd number and the mirror extent is balanced about x=0, + then an ordinary slice is drawn at the origin x=0. + Default 11. + project_slices_y : bool + Whether to draw projection of all constant-y slices. + draw_special_origin_slice_y : bool + Whether to draw a constant-y slice at y=0. Overwrites an ordinary slice there. + project_origin_slice_y : bool + Whether to draw projection of origin constant-y slice. + slice_style : RenderControlMirrorProjected + Style to draw the ordinary slices. Holds attributes defining how to draw features. + If None, default style parameters are used. + origin_slice_style : RenderControlMirrorProjected + Style to draw the origin slices. Holds attributes defining how to draw features. + If None, default style parameters are used. + """ + # Ensure style control is set. + if slice_style is None: + slice_style = rcmp.mirror_contour() + if origin_slice_style is None: + origin_slice_style = rcmp.mirror_origin_contour() + + # Ensure that transform is defined. + if transform is None: + transform = self.self_to_global_tranformation + + # Get mirror extent. + mirror_x_min, mirror_x_max, mirror_y_min, mirror_y_max = self.axis_aligned_bounding_box + + # Draw ordinary constant-x slices. + if n_slices_x > 0: + if n_slices_x == 1: + # Linspace with n=1 returns the start point, not the middle, + # so we handle this case separately. + x_middle = (mirror_x_min, mirror_x_max) / 2.0 + self._draw_surfacemesh_aux_x( + view, x_middle, mirror_y_min, mirror_y_max, project_slices_x, slice_style, transform + ) + else: + for x in np.linspace(mirror_x_min, mirror_x_max, n_slices_x): + self._draw_surfacemesh_aux_x( + view, x, mirror_y_min, mirror_y_max, project_slices_x, slice_style, transform + ) + + # Draw ordinary constant-y slices. + if n_slices_y > 0: + if n_slices_y == 1: + # Linspace with n=1 returns the start point, not the middle, + # so we handle this case separately. + y_middle = (mirror_y_min, mirror_y_max) / 2.0 + self._draw_surfacemesh_aux_y( + view, y_middle, mirror_x_min, mirror_x_max, project_slices_y, slice_style, transform + ) + else: + for y in np.linspace(mirror_y_min, mirror_y_max, n_slices_y): + self._draw_surfacemesh_aux_y( + view, y, mirror_x_min, mirror_x_max, project_slices_y, slice_style, transform + ) + + # Draw origin constant-x slice. + if draw_special_origin_slice_x: + self._draw_surfacemesh_aux_x( + view, 0.0, mirror_y_min, mirror_y_max, project_origin_slice_x, origin_slice_style, transform + ) + + # Draw origin constant-y slice. + if draw_special_origin_slice_y: + self._draw_surfacemesh_aux_y( + view, 0.0, mirror_x_min, mirror_x_max, project_origin_slice_y, origin_slice_style, transform + ) diff --git a/opencsp/common/lib/csp/MirrorParametric.py b/opencsp/common/lib/csp/MirrorParametric.py index 255a736e6..4152e3ded 100644 --- a/opencsp/common/lib/csp/MirrorParametric.py +++ b/opencsp/common/lib/csp/MirrorParametric.py @@ -115,6 +115,10 @@ def _check_in_bounds(self, p_samp: Pxyz) -> None: if not all(self.in_bounds(p_samp)): raise ValueError("Not all points are within mirror perimeter.") + def surface_function(self) -> Callable: + """Returns the surface function, making this protected member accessible.""" + return self._surface_function + def surface_norm_at(self, p: Pxy) -> Vxyz: if not issubclass(type(p), Vxy): raise TypeError(f"Sample point must be type {Vxy}, not type {type(p)}") diff --git a/opencsp/common/lib/csp/MirrorParametricRectangular.py b/opencsp/common/lib/csp/MirrorParametricRectangular.py index f83414b37..87ff66605 100644 --- a/opencsp/common/lib/csp/MirrorParametricRectangular.py +++ b/opencsp/common/lib/csp/MirrorParametricRectangular.py @@ -2,11 +2,17 @@ representing a single reflective surface defined by an algebraic function. """ +import numpy as np + from typing import Callable from opencsp.common.lib.geometry.RegionXY import RegionXY from opencsp.common.lib.csp.MirrorParametric import MirrorParametric from opencsp.common.lib.geometry.FunctionXYContinuous import FunctionXYContinuous +from opencsp.common.lib.geometry.TransformXYZ import TransformXYZ +from opencsp.common.lib.render.View3d import View3d +import opencsp.common.lib.render_control.RenderControlMirrorProjected as rcmp +import opencsp.common.lib.render_control.RenderControlPointSeq as rcps class MirrorParametricRectangular(MirrorParametric): @@ -26,7 +32,7 @@ def __init__(self, surface_function: Callable[[float, float], float], size: tupl side lengths equal to size. If input length is 2, size is interpreted as size=(x, y) where x is the x side lengths and y is the y side lengths. """ - self.surface_function = surface_function + self._surface_function = surface_function # Use the XY size to make a rectangular region region = RegionXY.rectangle(size) diff --git a/opencsp/common/lib/csp/MirrorPoint.py b/opencsp/common/lib/csp/MirrorPoint.py index 7dcf0468b..6677b408e 100644 --- a/opencsp/common/lib/csp/MirrorPoint.py +++ b/opencsp/common/lib/csp/MirrorPoint.py @@ -1,4 +1,8 @@ -from typing import Literal +"""Point mirror representing a single reflective surface defined +by a collection of points. +""" + +from typing import Callable, Literal from warnings import warn import numpy as np @@ -15,6 +19,7 @@ from opencsp.common.lib.geometry.Vxyz import Vxyz from opencsp.common.lib.render.View3d import View3d from opencsp.common.lib.render_control.RenderControlMirror import RenderControlMirror +import opencsp.common.lib.tool.log_tools as lt # Interpolation types GIVEN_INTERPOLATION = "given" @@ -99,38 +104,38 @@ def _define_interpolation( # Z coordinate interpolation object points_xy = self.surface_points.projXY().data.T # Nx2 array Z = self.surface_points.z - self.surface_function = interp.LinearNDInterpolator(points_xy, Z, np.nan) + self._surface_function = interp.LinearNDInterpolator(points_xy, Z, np.nan) # Normal vector interpolation object Z_N = self.normal_vectors.data.T - self.normals_function = interp.LinearNDInterpolator(points_xy, Z_N, np.nan) + self._normals_function = interp.LinearNDInterpolator(points_xy, Z_N, np.nan) elif interpolation_type == CLOUGH_TOCHER_INTERPOLATION: # Z coordinate interpolation object points_xy = self.surface_points.projXY().data.T # Nx2 array Z = self.surface_points.z - self.surface_function = interp.CloughTocher2DInterpolator(points_xy, Z, np.nan) + self._surface_function = interp.CloughTocher2DInterpolator(points_xy, Z, np.nan) # Normal vector interpolation object Z_N = self.normal_vectors.data.T - self.normals_function = interp.CloughTocher2DInterpolator(points_xy, Z_N, np.nan) + self._normals_function = interp.CloughTocher2DInterpolator(points_xy, Z_N, np.nan) elif interpolation_type == NEAREST_INTERPOLATION: # Z coordinate interpolation object points_xy = self.surface_points.projXY().data.T # Nx2 array Z = self.surface_points.z - self.surface_function = interp.NearestNDInterpolator(points_xy, Z) + self._surface_function = interp.NearestNDInterpolator(points_xy, Z) # Normal vector interpolatin object Z_N = self.normal_vectors.data.T - self.normals_function = interp.NearestNDInterpolator(points_xy, Z_N) + self._normals_function = interp.NearestNDInterpolator(points_xy, Z_N) elif interpolation_type == GIVEN_INTERPOLATION: # Z coordinate lookup function points_lookup = { (x, y): z for x, y, z in zip(self.surface_points.x, self.surface_points.y, self.surface_points.z) } - self.surface_function = FXYD(points_lookup) + self._surface_function = FXYD(points_lookup) # Normal vector lookup function normals_lookup = { (x, y): normal for x, y, normal in zip(self.surface_points.x, self.surface_points.y, self.normal_vectors.data.T) } - self.normals_function = FXYD(normals_lookup) + self._normals_function = FXYD(normals_lookup) # Assert that there are no duplicate (x,y) pairs if len(points_lookup) != len(self.surface_points): raise ValueError("All (x,y) pairs must be unique.") @@ -166,7 +171,7 @@ def surface_norm_at(self, p: Pxy) -> Vxyz: """ # "ChatGPT 4o-mini" assisted with generating this docstring. self._check_in_bounds(p) - pts = self.normals_function(p.x, p.y) + pts = self._normals_function(p.x, p.y) return Vxyz(pts.T).normalize() def surface_displacement_at(self, p: Pxy) -> np.ndarray: @@ -190,7 +195,7 @@ def surface_displacement_at(self, p: Pxy) -> np.ndarray: """ # "ChatGPT 4o-mini" assisted with generating this docstring. self._check_in_bounds(p) - return self.surface_function(p.x, p.y) + return self._surface_function(p.x, p.y) def survey_of_points( self, resolution: int = 1, resolution_type: str = "pixelX", random_seed: int | None = None @@ -292,4 +297,4 @@ def draw(self, view: View3d, mirror_style: RenderControlMirror, transform: Trans # If surface is interpolated, draw mirror using MirrorAbstract method else: - super().draw(view, mirror_style, transform) + super().draw(view=view, mirror_style=mirror_style, transform=transform) diff --git a/opencsp/common/lib/csp/RayTrace.py b/opencsp/common/lib/csp/RayTrace.py index 7faddc44a..7344b8a74 100644 --- a/opencsp/common/lib/csp/RayTrace.py +++ b/opencsp/common/lib/csp/RayTrace.py @@ -16,7 +16,7 @@ from opencsp.common.lib.csp.LightPathEnsemble import LightPathEnsemble from opencsp.common.lib.csp.LightSource import LightSource from opencsp.common.lib.csp.RayTraceable import RayTraceable -from opencsp.common.lib.geometry.RegionXY import Resolution +from opencsp.common.lib.geometry.Resolution import Resolution import opencsp.common.lib.csp.Scene as scn from opencsp.common.lib.geometry.FunctionXYGrid import FunctionXYGrid from opencsp.common.lib.geometry.Pxyz import Pxyz diff --git a/opencsp/common/lib/csp/RayTraceable.py b/opencsp/common/lib/csp/RayTraceable.py index a159bab8a..1fc571c96 100644 --- a/opencsp/common/lib/csp/RayTraceable.py +++ b/opencsp/common/lib/csp/RayTraceable.py @@ -1,7 +1,6 @@ from abc import abstractmethod -from scipy.spatial.transform import Rotation -from opencsp.common.lib.geometry.RegionXY import Resolution +from opencsp.common.lib.geometry.Resolution import Resolution from opencsp.common.lib.geometry.Pxyz import Pxyz from opencsp.common.lib.geometry.Vxyz import Vxyz diff --git a/opencsp/common/lib/csp/SolarField.py b/opencsp/common/lib/csp/SolarField.py index b3e4cfca0..ad11ca99a 100644 --- a/opencsp/common/lib/csp/SolarField.py +++ b/opencsp/common/lib/csp/SolarField.py @@ -13,7 +13,7 @@ from opencsp.common.lib.csp.RayTraceable import RayTraceable from opencsp.common.lib.geometry.FunctionXYContinuous import FunctionXYContinuous from opencsp.common.lib.geometry.Pxyz import Pxyz -from opencsp.common.lib.geometry.RegionXY import Resolution +from opencsp.common.lib.geometry.Resolution import Resolution from opencsp.common.lib.geometry.TransformXYZ import TransformXYZ from opencsp.common.lib.geometry.Vxyz import Vxyz from opencsp.common.lib.render.View3d import View3d diff --git a/opencsp/common/lib/csp/StandardPlotOutput.py b/opencsp/common/lib/csp/StandardPlotOutput.py index 3c05f4559..9a55bf09c 100644 --- a/opencsp/common/lib/csp/StandardPlotOutput.py +++ b/opencsp/common/lib/csp/StandardPlotOutput.py @@ -11,7 +11,7 @@ import opencsp.common.lib.csp.RayTrace as rt from opencsp.common.lib.csp.RayTraceable import RayTraceable from opencsp.common.lib.csp.Scene import Scene -from opencsp.common.lib.geometry.RegionXY import Resolution +from opencsp.common.lib.geometry.Resolution import Resolution from opencsp.common.lib.geometry.Uxyz import Uxyz from opencsp.common.lib.geometry.Vxyz import Vxyz import opencsp.common.lib.render.figure_management as fm diff --git a/opencsp/common/lib/csp/embedding_mirror_surface.py b/opencsp/common/lib/csp/embedding_mirror_surface.py new file mode 100644 index 000000000..251d25806 --- /dev/null +++ b/opencsp/common/lib/csp/embedding_mirror_surface.py @@ -0,0 +1,305 @@ +"""Parametric mirror representing a single reflective surface defined +by an algebraic function. +""" + +import numpy as np + +import opencsp.common.lib.tool.log_tools as lt + +from opencsp.common.lib.csp.MirrorParametric import MirrorParametric +from opencsp.common.lib.csp.MirrorParametricRectangular import MirrorParametricRectangular +import opencsp.common.lib.render.figure_management as fm +from opencsp.common.lib.geometry.TransformXYZ import TransformXYZ, identity_transform +from opencsp.common.lib.render.View3d import View3d +import opencsp.common.lib.render.view_spec as vs +import opencsp.common.lib.render_control.RenderControlAxis as rca +import opencsp.common.lib.render_control.RenderControlFigureRecord as rcfr +import opencsp.common.lib.render_control.RenderControlMirror as rcm +import opencsp.common.lib.render_control.RenderControlMirrorEmbedded as rcme +import opencsp.common.lib.render_control.RenderControlMirrorProjected as rcmp +from opencsp.common.lib.render_control.RenderControlFigure import RenderControlFigure + + +def embedding_mirror_half_width( + parametric_mirror: MirrorParametric, margin: float = 0.1, round_to: float = 0.5 +) -> float: + """ + Computes the min/max extent of a square centered on the origin that encloses + the input mirror. This includes an input margin, rounded up to the nearest + increment indicated by the round_to parameter. + + Parameters + ---------- + parametric_mirror : MirrorParametric + Mirror to derive the embedding surface from. + margin : float, optional + Lower bound of the margin to leave all around the mirror. + Default 0.1. + round_to : float, optional + Increment to round the margin, so that it falls on an even plot axis tick mark. + Default 0.5. + + Returns + ------- + float + Half-width of the square enclosing the mirror, including the margin. + Example: + Mirror vertices: + [1.0, 2.0] + [1.5, 3.0] + [3.2, 2.9] + [4.0, 2.3] + + Mirror bounding box: + [x_min, x_max, y_min, y_max] = [1.0, 4.0, 2.0, 3.0]. + Bounding square centered at the origin: + [x_min, x_max, y_min, y_max] = [-4.0, 4.0, -3.0, 3.0]. + Adding margin=0.1: + [x_min, x_max, y_min, y_max] = [-4.1, 4.1, -3.1, 3.1]. + Rounding to nearest enclosing 0.5: + [x_min, x_max, y_min, y_max] = [-4.5, 4.5, -3.5, 3.5]. + Mirror extent: + 4.5 + """ + # Verify this is a parametric mirror. + if not isinstance(parametric_mirror, MirrorParametric): + lt.error( + f"In embedding_mirror_half_width(), non-parametric mirror encountered. Mirror type = {type(parametric_mirror).__name__}" + ) + + # Compute extent of embedding surface. + mirror_x_min, mirror_x_max, mirror_y_min, mirror_y_max = parametric_mirror.axis_aligned_bounding_box + mirror_half_width = max(abs(mirror_x_min), abs(mirror_x_max), abs(mirror_y_min), abs(mirror_y_max)) + return np.ceil((mirror_half_width + margin) / round_to) * round_to + + +def construct_embedding_mirror( + parametric_mirror: MirrorParametric, margin: float = 0.1, round_to: float = 0.5 +) -> MirrorParametricRectangular: + """ + Constructs a mirror with a square boundary with the same embedding surface + as the input parametric mirror. Useful for illustrating the geometric + construction of a specific mirror. + + Parameters + ---------- + parametric_mirror : MirrorParametric + Mirror to derive the embedding surface from. + margin : float, optional + Lower bound of the margin to leave all around the mirror. + Default 0.1. + round_to : float, optional + Increment to round the margin, so that it falls on an even plot axis tick mark. + Default 0.5. + + Returns + ------- + MirrorParametric + A mirror object with the same embedding surface as the input mirror, + but with a square boundary that is larger than the input mirror by + the given margin plus potentially more to meet an even plot tick mark. + """ + # Verify this is a parametric mirror. + if not isinstance(parametric_mirror, MirrorParametric): + lt.error( + f"In embedding_mirror_half_width(), non-parametric mirror encountered. Mirror type = {type(parametric_mirror).__name__}" + ) + + # Compute extent of embedding surface. + embedding_extent = embedding_mirror_half_width(parametric_mirror, margin, round_to) + # Construct embedding mirror. + len_xy = 2.0 * embedding_extent + rectangle_xy = (len_xy, len_xy) + return MirrorParametricRectangular(parametric_mirror.surface_function(), rectangle_xy) + + +def draw_mirror_and_embedding_mirror( + input_mirror: MirrorParametric, + view: View3d, + mirror_style: rcm.RenderControlMirror = None, + draw_projection: bool = True, + projected_style: rcmp.RenderControlMirrorProjected = None, + embedding_style: rcme.RenderControlMirrorEmbedded = None, + transform: TransformXYZ | None = None, +) -> None: + """ + Draws a mirror in the given view, and also a slightly larger embedding mirror. + There are options to draw slices and projections onto the (x,y) plane. + + Parameters + ---------- + input_mirror : MirrorParametric + Mirror to draw. + view : View3d + Vie to display the mirorr. + mirror_style : RenderControlMirror, optional + Attributes for drawing mirror features. Default None. + draw_projection : bool, optional + Whether to draw the projection of the mirror boundary onto the (x,y) plane. + Default True. + projected_style : RenderControlMirrorProjected, optional + Attributes for drawing the projected mirror boundary. Default None. + embedding_style : RenderControlMirrorEmbedded, optional + Attributes for drawing the embedding mirror surface. Default None. + transform : TransformXYZ | None, optional + Transform to position the miror in space. Default None. + """ + # Construct a second mirror, with larger boundary, enabling us to show the embedding surface in a plot. + embedding_mirror = construct_embedding_mirror( + input_mirror, margin=embedding_style.margin, round_to=embedding_style.round_to + ) + + # Set view axes to match the extent of the embedding mirror, which is square and larger than the input mirror. + # Also set equal axes to prevent z exaggeration. + embedding_x_min, embedding_x_max, embedding_y_min, embedding_y_max = embedding_mirror.axis_aligned_bounding_box + limit_xy = max(abs(embedding_x_min), abs(embedding_x_max), abs(embedding_y_min), abs(embedding_y_max)) + view.show(x_limits=[-limit_xy, limit_xy], y_limits=[-limit_xy, limit_xy], z_limits=[0, 2 * limit_xy]) + + # Draw second mirror showing embedding surface. + embedding_mirror.draw(view=view, mirror_style=mirror_style, draw_projection=False, transform=transform) + + # Draw slices of embedding surface. + embedding_mirror.draw_surface_mesh( + view, + n_slices_x=embedding_style.n_slices_x, + project_slices_x=embedding_style.project_slices_x, + draw_special_origin_slice_x=embedding_style.draw_special_origin_slice_x, + project_origin_slice_x=embedding_style.project_origin_slice_x, + n_slices_y=embedding_style.n_slices_y, + project_slices_y=embedding_style.project_slices_y, + draw_special_origin_slice_y=embedding_style.draw_special_origin_slice_y, + project_origin_slice_y=embedding_style.project_origin_slice_y, + slice_style=embedding_style.slice_style, + origin_slice_style=embedding_style.origin_slice_style, + transform=transform, + ) + + # Draw primary mirror. + input_mirror.draw( + view=view, + mirror_style=mirror_style, + draw_projection=draw_projection, + projected_style=projected_style, + transform=transform, + ) + + +def setup_and_draw_mirror_and_embedding_mirror( + # Required parameters. + figure_control: RenderControlFigure, + parametric_mirror: MirrorParametric, + title: str, + # Options. + axis_control: rca.RenderControlAxis = None, + view_spec: dict = None, + number_in_name: bool = False, + input_prefix: str = None, + caption: str = None, + comments: list[str] = [], + code_tag: str = None, + mirror_style: rcm.RenderControlMirror = rcm.RenderControlMirror(), + draw_projection: bool = True, + projected_style: rcmp.RenderControlMirrorProjected = rcmp.mirror_boundary(), + embedding_style: rcme.RenderControlMirrorEmbedded = rcme.standard_embedding_mirror(), + transform: TransformXYZ | None = None, +) -> rcfr.RenderControlFigureRecord: + """ + This function wraps function draw_mirror_and_embedding_mirror() above, + creating and drawing a figure for testing and other use. + It returns the figure so additional material can be added. + """ + # Ensure all parameters are set. + if axis_control is None: + axis_control = rca.meters(grid=False) # Drawing axis grid and surface grid is confusing. + if view_spec is None: + view_spec = vs.view_spec_3d() + if transform is None: + transform = identity_transform() + + # Setup figure. + fig_record = fm.setup_figure_for_3d_data( + figure_control=figure_control, + axis_control=axis_control, + view_spec=view_spec, + number_in_name=number_in_name, + input_prefix=input_prefix, + title=title, + caption=caption, + comments=comments, + code_tag=code_tag, + ) + + # Draw. + draw_mirror_and_embedding_mirror( + parametric_mirror, + view=fig_record.view, + mirror_style=mirror_style, + draw_projection=draw_projection, + projected_style=projected_style, + embedding_style=embedding_style, + transform=transform, + ) + + # Return figure so more can be added. + return fig_record + + +def setup_draw_and_save_mirror_and_embedding_mirror( + # Required parameters. + figure_control: RenderControlFigure, + parametric_mirror: MirrorParametric, + title: str, + output_dir: str, + # Options. + axis_control: rca.RenderControlAxis = None, + view_spec: dict = None, + number_in_name: bool = False, + input_prefix: str = None, + caption: str = None, + comments: list[str] = [], + code_tag: str = None, + mirror_style: rcm.RenderControlMirror = rcm.RenderControlMirror(), + draw_projection: bool = True, + projected_style: rcmp.RenderControlMirrorProjected = rcmp.mirror_boundary(), + embedding_style: rcme.RenderControlMirrorEmbedded = rcme.standard_embedding_mirror(), + transform: TransformXYZ | None = None, + # Save figure parameters. + dpi: int = 200, + output_format: str = 'png', + close_after_save: bool = True, + include_view_suffix: bool = True, + include_limit_suffix: bool = False, +) -> None: + """ + This function wraps function draw_mirror_and_embedding_mirror() above, + creating and saving a figure for testing and other use. + """ + + # Setup and draw. + fig_record = setup_and_draw_mirror_and_embedding_mirror( + figure_control=figure_control, + parametric_mirror=parametric_mirror, + title=title, + axis_control=axis_control, + view_spec=view_spec, + number_in_name=number_in_name, + input_prefix=input_prefix, + caption=caption, + comments=comments, + code_tag=code_tag, + mirror_style=mirror_style, + draw_projection=draw_projection, + projected_style=projected_style, + embedding_style=embedding_style, + transform=transform, + ) + + # Save. + fig_record.save( + output_dir=output_dir, + dpi=dpi, + format=output_format, + close_after_save=close_after_save, + include_view_suffix=include_view_suffix, + include_limit_suffix=include_limit_suffix, + ) diff --git a/opencsp/common/lib/csp/test/test_Intersection.py b/opencsp/common/lib/csp/test/test_Intersection.py index afe46d810..9fbe5b206 100644 --- a/opencsp/common/lib/csp/test/test_Intersection.py +++ b/opencsp/common/lib/csp/test/test_Intersection.py @@ -11,7 +11,7 @@ from opencsp.common.lib.csp.RayTrace import RayTrace from opencsp.common.lib.csp.Scene import Scene from opencsp.common.lib.geometry.Intersection import Intersection -from opencsp.common.lib.geometry.RegionXY import Resolution +from opencsp.common.lib.geometry.Resolution import Resolution from opencsp.common.lib.geometry.Pxyz import Pxyz from opencsp.common.lib.geometry.Uxyz import Uxyz from opencsp.common.lib.geometry.Vxyz import Vxyz diff --git a/opencsp/common/lib/csp/test/test_csp_optics_orientations.py b/opencsp/common/lib/csp/test/test_csp_optics_orientations.py index c0c64b30e..15ba34d58 100644 --- a/opencsp/common/lib/csp/test/test_csp_optics_orientations.py +++ b/opencsp/common/lib/csp/test/test_csp_optics_orientations.py @@ -8,7 +8,8 @@ from opencsp.common.lib.csp.MirrorAbstract import MirrorAbstract from opencsp.common.lib.csp.MirrorParametric import MirrorParametric from opencsp.common.lib.csp.Scene import Scene -from opencsp.common.lib.geometry.RegionXY import RegionXY, Resolution +from opencsp.common.lib.geometry.RegionXY import RegionXY +from opencsp.common.lib.geometry.Resolution import Resolution from opencsp.common.lib.geometry.TransformXYZ import TransformXYZ from opencsp.common.lib.geometry.Vxy import Vxy from opencsp.common.lib.geometry.Vxyz import Vxyz diff --git a/opencsp/common/lib/cv/__init__.py b/opencsp/common/lib/cv/__init__.py index bea115c1c..445793371 100644 --- a/opencsp/common/lib/cv/__init__.py +++ b/opencsp/common/lib/cv/__init__.py @@ -1,2 +1,5 @@ -# force the SpotAnalysisOperableAttributeParser to be registered with the AttributesManager -import opencsp.common.lib.cv.spot_analysis.SpotAnalysisOperableAttributeParser as saoap +# Commented out by Randy Brost on February 13, 2026, +# when confronted with excess imports leading to cyclic +# import problems for example_MirrorOutput.py. +# # force the SpotAnalysisOperableAttributeParser to be registered with the AttributesManager +# import opencsp.common.lib.cv.spot_analysis.SpotAnalysisOperableAttributeParser as saoap diff --git a/opencsp/common/lib/cv/fiducials/AbstractFiducials.py b/opencsp/common/lib/cv/fiducials/AbstractFiducials.py index 39aecf1f2..62fb157ef 100644 --- a/opencsp/common/lib/cv/fiducials/AbstractFiducials.py +++ b/opencsp/common/lib/cv/fiducials/AbstractFiducials.py @@ -8,7 +8,7 @@ import scipy.spatial import opencsp.common.lib.geometry.Pxy as p2 -import opencsp.common.lib.geometry.RegionXY as reg +from opencsp.common.lib.geometry.RegionXY import RegionXY import opencsp.common.lib.geometry.Vxyz as v3 import opencsp.common.lib.render.Color as color import opencsp.common.lib.render.figure_management as fm @@ -53,7 +53,7 @@ def __init__(self, style: rcps.RenderControlPointSeq = None, pixels_to_meters: C self.pixels_to_meters = pixels_to_meters @abstractmethod - def get_bounding_box(self, index=0) -> reg.RegionXY: + def get_bounding_box(self, index=0) -> RegionXY: """ Get the X/Y bounding box of this instance, in pixels. @@ -64,7 +64,7 @@ def get_bounding_box(self, index=0) -> reg.RegionXY: Returns ------- - reg.RegionXY + RegionXY The bounding box of the fiducial. """ diff --git a/opencsp/common/lib/deflectometry/SlopeSolverDataDebug.py b/opencsp/common/lib/deflectometry/SlopeSolverDataDebug.py index 718612d93..6b5f071b7 100644 --- a/opencsp/common/lib/deflectometry/SlopeSolverDataDebug.py +++ b/opencsp/common/lib/deflectometry/SlopeSolverDataDebug.py @@ -27,3 +27,7 @@ def __init__(self): self.slope_solver_single_plot: bool = False """Flag to plot all iterations of the slope solving algorithm on one plot (True) or create a separate plot for each iteration (False). Default False (new plot for each iteration)""" + self.save_dir = None + """Where to save figure objects.""" + self.figure_idx = 0 + """Incrementing figure index, so figures appear in order created.""" diff --git a/opencsp/common/lib/geometry/LoopXY.py b/opencsp/common/lib/geometry/LoopXY.py index b49100b1e..52a885a54 100644 --- a/opencsp/common/lib/geometry/LoopXY.py +++ b/opencsp/common/lib/geometry/LoopXY.py @@ -7,7 +7,7 @@ from opencsp.common.lib.geometry.EdgeXY import EdgeXY from opencsp.common.lib.geometry.LineXY import LineXY from opencsp.common.lib.geometry.Vxy import Vxy -import opencsp.common.lib.render.View3d as v3d +from opencsp.common.lib.render.View3d import View3d import opencsp.common.lib.render.view_spec as vs import opencsp.common.lib.render_control.RenderControlPointSeq as rcps import opencsp.common.lib.tool.log_tools as lt @@ -70,28 +70,48 @@ def _check_closed_loop(self) -> None: def _check_convex(self) -> None: """ - Checks that straight lines connecting each vertex makes convex loop. - + Checks that the sequence of straight lines connecting each vertex makes a convex loop. + Throws an error if not. """ vertex_angles = self._vertex_to_vertex_angles() vertex_positive = np.unique(vertex_angles > 0) + # If all corner angles are positive, then vertex_postiive will have one element: True. + # If all corner angles are negative, then vertex_postiive will have one element: False. + # Either way, the size of vertex_positive will be 1. + # If the size of vertex_positive is greater than 1, it indicates that the corner angles + # have differing sign; this reversal indicates non-convexity. + # Note that this works whether the corner angles are either all less than zero or + # all greater than zero. Thus it should work for vertex orders either clockwise + # or counter-clockwise. + # + # But corner angles equal to zero can lead to problematic behavior. Consider a + # convex region including a corner that has angle zero (that is, two collinear edges + # meeting at a corner). Further suppose that in this calculation, all corner angles + # are positive, except for the collinear vertex which has corner angle zero. + # The collinear vertex with corner angle zero does not have a corner angle > 0 m, + # so the resulting vertex_positive has elements [True, False] . This has length > 1, + # so the routine flags the region as non-convex. + # + # To prevent this, avoid input with vertices connecting collinear edges. if vertex_positive.size > 1: raise ValueError("Loop may not be convex or edges cross within loop.") def _vertex_to_vertex_angles(self): """ - Calculates the sin of the angle between the straight line drawn from + Calculates the sine of the angle between the straight line drawn from vertex to vertex. """ cross_prod_data = np.zeros(self.num_edges) for idx1 in range(self.num_edges): idx2 = np.mod(idx1 + 1, self.num_edges) - # Calcualte edge vectors + # Calculate edge vectors V_1 = (self._edges[idx1]._vertices[1] - self._edges[idx1]._vertices[0]).normalize() V_2 = (self._edges[idx2]._vertices[1] - self._edges[idx2]._vertices[0]).normalize() # Calculate cross product - cross_prod_data[idx2] = V_1.cross(V_2)[0] + cross_product = V_1.cross(V_2)[0] + cross_prod_data[idx2] = cross_product + # cross_prod_data[idx2] = V_1.cross(V_2)[0] return cross_prod_data @@ -331,7 +351,7 @@ def draw(self, ax: plt.Axes = None, style: rcps.RenderControlPointSeq = None) -> # Draw arrows first_vert_np = np.array([self.vertices.x[:1], self.vertices.y[:1]]) closed_loop_verts = Vxy(np.concatenate((self.vertices.data, first_vert_np), axis=1)) - view = v3d.View3d(ax.figure, ax, vs.view_spec_xy()) + view = View3d(ax.figure, ax, vs.view_spec_xy()) view.draw_pq((closed_loop_verts.x, closed_loop_verts.y), style) # Plot starting point as green dot diff --git a/opencsp/common/lib/geometry/RegionXY.py b/opencsp/common/lib/geometry/RegionXY.py index 6ea0ba054..19ba487f1 100644 --- a/opencsp/common/lib/geometry/RegionXY.py +++ b/opencsp/common/lib/geometry/RegionXY.py @@ -4,10 +4,7 @@ import matplotlib.pyplot as plt import numpy as np -# import opencsp.common.lib.geometry.Resolution as Resolution - from opencsp.common.lib.geometry.LoopXY import LoopXY -from opencsp.common.lib.geometry.TransformXYZ import TransformXYZ from opencsp.common.lib.geometry.Vxy import Vxy from opencsp.common.lib.geometry.Pxy import Pxy import opencsp.common.lib.render_control.RenderControlPointSeq as rcps @@ -224,13 +221,13 @@ def __add__(self, other: Vxy | numbers.Number) -> "RegionXY": lt.error_and_raise( TypeError, "Error in RegionXY.__add__(): " - + f"secondary value in addition must be of type Vxy or Number, " + + "secondary value in addition must be of type Vxy or Number, " + f"but is {type(other)}", ) if isinstance(other, Vxy) and len(other) != 1: lt.error_and_raise( ValueError, - "Error in RegionXY.__add__(): " + f"other value Vxy must have length 1, " + f"but {len(other)=}", + "Error in RegionXY.__add__(): " + "other value Vxy must have length 1, " + f"but {len(other)=}", ) ret = RegionXY(self.loops[0] + other) @@ -241,157 +238,3 @@ def __add__(self, other: Vxy | numbers.Number) -> "RegionXY": def __sub__(self, other: Vxy | numbers.Number) -> "RegionXY": return self + (-other) - - -class Resolution: - """ - Allows options for defining a set of points needed. To choose a type of - Resolution use a class method with keeps the type of unresolved resolution - stored until the bouning box containing the resolution is known. - - Attributes - ---------- - self.points: Pxy - The points that the resolution cares about. These are the xy points - that will be used in whatever the resolution is for. - self.unresolved: tuple[str, ...] - The description of the properties the resolution should have once - it is given a bounding box to axt on. - """ - - def __init__(self, points: Pxy) -> None: - self._points = points - self.unresolved: tuple[str, ...] = None - self.composite_transformation = TransformXYZ.identity() - - @classmethod - def separation(cls, separation: float) -> "Resolution": - """Separates the points along x and y by the separation.""" - res = Resolution(None) - res.unresolved = ("separation", separation) - return res - - @classmethod - def pixelX(cls, points_along_x: int) -> "Resolution": - """Will have `points_along_x` points along x and - equispaced points along y.""" - res = Resolution(None) - res.unresolved = ("pixelX", points_along_x) - return res - - @classmethod - def random(cls, number_of_points: int, seed: int = None) -> "Resolution": - """There will be `number_of_points` uniformly randomly in the region. - Can choose to add a seed.""" - res = Resolution(None) - res.unresolved = ("random", number_of_points, seed) - return res - - @classmethod - def center(cls) -> "Resolution": - """Gives the center point of a bounding box. - This resolution cannot be 'resolved' since there is not a set of points that can - represent what it is trying to do.""" - res = Resolution(None) - res.unresolved = ("center",) - return res - - @property - def points(self) -> Pxy: - if self._points is None: - RuntimeError("Resolution has no points, probably due to an unresolved tag.") - return self._points - - def is_resolved(self) -> bool: - return self.unresolved is None - - def is_unresolved(self) -> bool: - return self.unresolved is not None - - def change_frame_and_copy(self, frame_transform: TransformXYZ) -> "Resolution": - res = copy.deepcopy(self) - frame_translation = frame_transform.V.projXY() - if res.is_unresolved(): - return res - res._points = res.points + frame_translation - res.composite_transformation = frame_transform * res.composite_transformation - return res - - def resolve_in_place(self, bounding_box: tuple[float, float, float, float] | RegionXY): - """RegionXY - If the Resolution object is "unresolved" this is the function that resolves it to a - set of points in xy space (Pxy). If there is no unresolved tag, this function - just filters out points that do not fall in bounding box. Acts in place. - """ - # if a RegionXY is given: - region: RegionXY = None - if isinstance(bounding_box, RegionXY): - region = bounding_box - bounding_box = region.axis_aligned_bounding_box() - - left, right, bottom, top = bounding_box - - if self.is_resolved(): # add `and region is None` if this is too slow - self._points = Pxy.merge([p for p in self.points if left <= p.x[0] <= right and bottom <= p.y[0] <= top]) - elif self.is_unresolved(): # self is unresolved - width = right - left - height = top - bottom - - match self.unresolved[0]: - - case "separation": - separation = float(self.unresolved[1]) - - width -= separation / 1e10 - height -= separation / 1e10 - - x_shift = (width % separation) / 2 - x_start, x_end = (left + x_shift, right - x_shift) - y_shift = (height % separation) / 2 - y_start, y_end = (bottom + y_shift, top - y_shift) - - xs = np.arange(x_start, x_end, separation) - ys = np.arange(y_start, y_end, separation) - X = [x for x in xs for y in ys] - Y = [y for x in xs for y in ys] - self._points = Pxy([X, Y]) - self.unresolved = None - - case "pixelX": - points_along_x = int(self.unresolved[1]) - - separation = (right - left) / points_along_x - self.unresolved = ("separation", separation) - self.resolve_in_place(bounding_box) - - case "random": - number_of_points = int(self.unresolved[1]) - random_seed = int(self.unresolved[2]) if self.unresolved[2] is not None else None - - rng = np.random.default_rng(random_seed) - xs = rng.uniform(left, right, number_of_points) - ys = rng.uniform(bottom, top, number_of_points) - self._points = Pxy([xs, ys]) - self.unresolved = None - - case "center": - self._points = Pxy([left + width / 2, bottom + height / 2]) - # does not resolve - - case _: - ValueError(f"{self.unresolved[0]} is not a valid resolution type.") - - if region is not None: - self._points = region.filter_points(self.points) - - pass # end of resolve - - def resolve_and_copy(self, bounding_box: tuple[float, float, float, float] | RegionXY) -> "Resolution": - """ - If the Resolution object is "unresolved" this is the function that resolves it to a - set of points in xy space (Pxy). If there is no unresolved tag, this function - just filters out points that do not fall in bounding box. Produces a new Resolution object. - """ - new_res = copy.deepcopy(self) - new_res.resolve_in_place(bounding_box) - return new_res diff --git a/opencsp/common/lib/geometry/Resolution.py b/opencsp/common/lib/geometry/Resolution.py new file mode 100644 index 000000000..87115950e --- /dev/null +++ b/opencsp/common/lib/geometry/Resolution.py @@ -0,0 +1,161 @@ +import copy + +import numpy as np + +from opencsp.common.lib.geometry.TransformXYZ import TransformXYZ +from opencsp.common.lib.geometry.Pxy import Pxy +from opencsp.common.lib.geometry.RegionXY import RegionXY + + +class Resolution: + """ + Allows options for defining a set of points needed. To choose a type of + Resolution use a class method with keeps the type of unresolved resolution + stored until the bounding box containing the resolution is known. + + Attributes + ---------- + self.points: Pxy + The points that the resolution cares about. These are the xy points + that will be used in whatever the resolution is for. + self.unresolved: tuple[str, ...] + The description of the properties the resolution should have once + it is given a bounding box to act on. + """ + + def __init__(self, points: Pxy) -> None: + self._points = points + self.unresolved: tuple[str, ...] = None + self.composite_transformation = TransformXYZ.identity() + + @classmethod + def separation(cls, separation: float) -> "Resolution": + """Separates the points along x and y by the separation.""" + res = Resolution(None) + res.unresolved = ("separation", separation) + return res + + @classmethod + def pixelX(cls, points_along_x: int) -> "Resolution": + """Will have `points_along_x` points along x and + equispaced points along y.""" + res = Resolution(None) + res.unresolved = ("pixelX", points_along_x) + return res + + @classmethod + def random(cls, number_of_points: int, seed: int = None) -> "Resolution": + """There will be `number_of_points` uniformly randomly in the region. + Can choose to add a seed.""" + res = Resolution(None) + res.unresolved = ("random", number_of_points, seed) + return res + + @classmethod + def center(cls) -> "Resolution": + """Gives the center point of a bounding box. + This resolution cannot be 'resolved' since there is not a set of points that can + represent what it is trying to do.""" + res = Resolution(None) + res.unresolved = ("center",) + return res + + @property + def points(self) -> Pxy: + if self._points is None: + RuntimeError("Resolution has no points, probably due to an unresolved tag.") + return self._points + + def is_resolved(self) -> bool: + return self.unresolved is None + + def is_unresolved(self) -> bool: + return self.unresolved is not None + + def change_frame_and_copy(self, frame_transform: TransformXYZ) -> "Resolution": + res = copy.deepcopy(self) + frame_translation = frame_transform.V.projXY() + if res.is_unresolved(): + return res + res._points = res.points + frame_translation + res.composite_transformation = frame_transform * res.composite_transformation + return res + + def resolve_in_place(self, bounding_box: tuple[float, float, float, float] | RegionXY): + """RegionXY + If the Resolution object is "unresolved" this is the function that resolves it to a + set of points in xy space (Pxy). If there is no unresolved tag, this function + just filters out points that do not fall in bounding box. Acts in place. + """ + # if a RegionXY is given: + region: RegionXY = None + if isinstance(bounding_box, RegionXY): + region = bounding_box + bounding_box = region.axis_aligned_bounding_box() + + left, right, bottom, top = bounding_box + + if self.is_resolved(): # add `and region is None` if this is too slow + self._points = Pxy.merge([p for p in self.points if left <= p.x[0] <= right and bottom <= p.y[0] <= top]) + elif self.is_unresolved(): # self is unresolved + width = right - left + height = top - bottom + + match self.unresolved[0]: + + case "separation": + separation = float(self.unresolved[1]) + + width -= separation / 1e10 + height -= separation / 1e10 + + x_shift = (width % separation) / 2 + x_start, x_end = (left + x_shift, right - x_shift) + y_shift = (height % separation) / 2 + y_start, y_end = (bottom + y_shift, top - y_shift) + + xs = np.arange(x_start, x_end, separation) + ys = np.arange(y_start, y_end, separation) + X = [x for x in xs for y in ys] + Y = [y for x in xs for y in ys] + self._points = Pxy([X, Y]) + self.unresolved = None + + case "pixelX": + points_along_x = int(self.unresolved[1]) + + separation = (right - left) / points_along_x + self.unresolved = ("separation", separation) + self.resolve_in_place(bounding_box) + + case "random": + number_of_points = int(self.unresolved[1]) + random_seed = int(self.unresolved[2]) if self.unresolved[2] is not None else None + + rng = np.random.default_rng(random_seed) + xs = rng.uniform(left, right, number_of_points) + ys = rng.uniform(bottom, top, number_of_points) + self._points = Pxy([xs, ys]) + self.unresolved = None + + case "center": + self._points = Pxy([left + width / 2, bottom + height / 2]) + # does not resolve + + case _: + ValueError(f"{self.unresolved[0]} is not a valid resolution type.") + + if region is not None: + self._points = region.filter_points(self.points) + + pass # end of resolve + + def resolve_and_copy(self, bounding_box: tuple[float, float, float, float] | RegionXY) -> "Resolution": + """ + If the Resolution object is "unresolved" this is the function that resolves it to a + set of points in xy space (Pxy). If there is no unresolved tag, this function + just filters out points that do not fall in bounding box. Produces a new Resolution object. + """ + new_res = copy.deepcopy(self) + new_res.resolve_in_place(bounding_box) + return new_res diff --git a/opencsp/common/lib/geometry/TransformXYZ.py b/opencsp/common/lib/geometry/TransformXYZ.py index 245706e6b..459cbfe08 100644 --- a/opencsp/common/lib/geometry/TransformXYZ.py +++ b/opencsp/common/lib/geometry/TransformXYZ.py @@ -248,3 +248,15 @@ def inv(self) -> "TransformXYZ": def copy(self) -> "TransformXYZ": """Returns a copy of the transform""" return TransformXYZ(self.matrix.copy()) + + +# Common transforms + + +def identity_transform() -> TransformXYZ: + """Return a transform that does not change position or orientation.""" + # There is probably a batter way to do this, but I don't have time + # to figure it out right now. -RCB + rotation = Rotation.from_euler('x', 0, True) + translation = Vxyz([0, 0, 0]) + return TransformXYZ.from_R_V(rotation, translation) diff --git a/opencsp/common/lib/geometry/Vxy.py b/opencsp/common/lib/geometry/Vxy.py index e855bcaca..7f1ea3d82 100644 --- a/opencsp/common/lib/geometry/Vxy.py +++ b/opencsp/common/lib/geometry/Vxy.py @@ -225,6 +225,16 @@ def _magnitude_with_zero_check(self) -> np.ndarray: return mag + def len(self) -> int: + """Return the number of points in the Vxy. + + Returns + ------- + int + Number of points in the Vxy. + """ + return self.__len__() + def normalize(self): """ Returns copy of normalized vector. diff --git a/opencsp/common/lib/geometry/Vxyz.py b/opencsp/common/lib/geometry/Vxyz.py index b46a26997..3845c8348 100644 --- a/opencsp/common/lib/geometry/Vxyz.py +++ b/opencsp/common/lib/geometry/Vxyz.py @@ -223,6 +223,16 @@ def __len__(self): def __neg__(self): return self._from_data(-self._data, dtype=self.dtype) + def len(self) -> int: + """Return the number of points in the Vxy. + + Returns + ------- + int + Number of points in the Vxy. + """ + return self.__len__() + def _magnitude_with_zero_check(self) -> np.ndarray: """ Returns magnitude of each vector as a new array. @@ -650,3 +660,36 @@ def draw_points( view = figure if isinstance(figure, View3d) else figure.view for x, y, z, label in zip(self.x, self.y, self.z, labels): view.draw_xyz((x, y, z), style, label) + + +def connection_lines(xyz_sequence_1: Vxyz, xyz_sequence_2: Vxyz) -> [Vxyz]: + """Given two sequences of (x,y,z) points, return a list + of line segments connecting them. + + Throws an error if point sequences are not the same length. + + Parameters + ---------- + xyz_sequence_1 : Vxyz + Sequence of (x,y,z) points. + xyz_sequence_2 : Vxyz + Sequence of (x,y,z) points. + + Returns + ------- + [Vxyz] + List of line segments connecting corresponding points. + """ + n_points = xyz_sequence_1.len() + if xyz_sequence_2.len() != n_points: + raise ValueError("xyz_1 and xyz_2 are not the same length.") + + list_of_line_segments = [] + for idx in range(n_points): + xyz_point_1 = Vxyz(xyz_sequence_1.data[:, idx]) + xyz_point_2 = Vxyz(xyz_sequence_2.data[:, idx]) + line_segment_xyz = xyz_point_1.copy() + line_segment_xyz = line_segment_xyz.concatenate(xyz_point_2) + list_of_line_segments.append(line_segment_xyz) + + return list_of_line_segments diff --git a/opencsp/common/lib/render/View3d.py b/opencsp/common/lib/render/View3d.py index e5c7504c6..ef990e19b 100644 --- a/opencsp/common/lib/render/View3d.py +++ b/opencsp/common/lib/render/View3d.py @@ -409,7 +409,9 @@ def show_and_save( # Save all figures, including this one. self.save(output_dir, output_figure_body, format=format, dpi=dpi) - def save(self, output_dir, output_figure_body, format="png", dpi=300, include_view_suffix=True) -> str: + def save( + self, output_dir, output_figure_body, format="png", dpi=300, include_view_suffix=True, include_limit_suffix=True + ) -> str: """ Saves this view to an image file. @@ -436,7 +438,8 @@ def save(self, output_dir, output_figure_body, format="png", dpi=300, include_vi if include_view_suffix: output_figure_body += "_" + self.view_spec["type"] # Add axis limit suffix. - output_figure_body += self.limit_suffix() + if include_limit_suffix: + output_figure_body += self.limit_suffix() # Join with output directory. output_figure_dir_body = os.path.join(output_dir, output_figure_body) # Save the figure. diff --git a/opencsp/common/lib/render/__init__.py b/opencsp/common/lib/render/__init__.py index 46aa2c8c8..3af974c36 100644 --- a/opencsp/common/lib/render/__init__.py +++ b/opencsp/common/lib/render/__init__.py @@ -1,5 +1,9 @@ -# import the cv package to work around the circular imports issue -import opencsp.common.lib.cv +# Commented out by Randy Brost on February 13, 2026, +# when confronted with excess imports leading to cyclic +# import problems for example_MirrorOutput.py. -# force the ImageAttributeParser to be registered with the AttributesManager -import opencsp.common.lib.render.ImageAttributeParser as iap +# # import the cv package to work around the circular imports issue +# import opencsp.common.lib.cv + +# # force the ImageAttributeParser to be registered with the AttributesManager +# import opencsp.common.lib.render.ImageAttributeParser as iap diff --git a/opencsp/common/lib/render_control/RenderControlFigureRecord.py b/opencsp/common/lib/render_control/RenderControlFigureRecord.py index aa22ca4f2..d79e5c3e5 100644 --- a/opencsp/common/lib/render_control/RenderControlFigureRecord.py +++ b/opencsp/common/lib/render_control/RenderControlFigureRecord.py @@ -245,8 +245,9 @@ def save( output_file_body: str = None, format: str = None, dpi=600, - close_after_save=True, - include_view_suffix=True, + close_after_save: bool = True, + include_view_suffix: bool = True, + include_limit_suffix: bool = True, ): """ Saves this figure record to an image file. @@ -263,6 +264,10 @@ def save( Dots per inch used to format the figure. Defaults to 600. close_after_save : bool, optional If True, closes the plot after saving. Defaults to True. + include_view_suffix : bool, optional + If True, adds view type (xy, 3-d, etc) to filename. Defaults to True. + include_limit_suffix : bool, optional + If True, adds plot limits to filename. Defaults to True. Returns ------- @@ -296,7 +301,12 @@ def save( # If this is a 3-d plot, add the projection choice. if self.view != None: output_figure_dir_body_ext = self.view.save( - output_dir, output_figure_body, format=format, dpi=dpi, include_view_suffix=include_view_suffix + output_dir, + output_figure_body, + format=format, + dpi=dpi, + include_view_suffix=include_view_suffix, + include_limit_suffix=include_limit_suffix, ) else: # Make the figure current. diff --git a/opencsp/common/lib/render_control/RenderControlMirror.py b/opencsp/common/lib/render_control/RenderControlMirror.py index bfa34ab03..b4ca07275 100644 --- a/opencsp/common/lib/render_control/RenderControlMirror.py +++ b/opencsp/common/lib/render_control/RenderControlMirror.py @@ -1,7 +1,7 @@ import opencsp.common.lib.render_control.RenderControlPointSeq as rcps from opencsp.common.lib.render_control.RenderControlPointSeq import RenderControlPointSeq from opencsp.common.lib.render_control.RenderControlSurface import RenderControlSurface -from opencsp.common.lib.geometry.RegionXY import Resolution +from opencsp.common.lib.geometry.Resolution import Resolution class RenderControlMirror: diff --git a/opencsp/common/lib/render_control/RenderControlMirrorEmbedded.py b/opencsp/common/lib/render_control/RenderControlMirrorEmbedded.py new file mode 100644 index 000000000..fbdc4f333 --- /dev/null +++ b/opencsp/common/lib/render_control/RenderControlMirrorEmbedded.py @@ -0,0 +1,94 @@ +import opencsp.common.lib.render_control.RenderControlMirrorProjected as rcmp + + +class RenderControlMirrorEmbedded: + """ + A class for controlling the construction and rendering of a mirror representing + the embedding surface of a parametric mirror. + """ + + def __init__( + self, + margin: float = 0.1, + round_to: float = 0.25, + n_slices_x: int = 11, + project_slices_x: bool = False, + draw_special_origin_slice_x: bool = True, + project_origin_slice_x: bool = True, + n_slices_y: int = 11, + project_slices_y: bool = False, + draw_special_origin_slice_y: bool = True, + project_origin_slice_y: bool = True, + slice_style: rcmp.RenderControlMirrorProjected = None, + origin_slice_style: rcmp.RenderControlMirrorProjected = None, + ) -> None: + """ + Initializes a RenderControlMirrorEmbedded object with the specified parameters. + + Parameters + ---------- + margin : float, optional + Minimum amount embedding surface should extend beyond mirror boundary, Default 0.1 + round_to : float, optional + Even increment to extend margin to match plot axis tick mark. Default 0.25 + n_slices_x : int, optional + Number of constant-x contour slides to draw. Default 11. + project_slices_x : bool, optional + Whether to show projection of constant-x slices to the (x,y) plane. Default False. + draw_special_origin_slice_x : bool, optional + Whether to draw a special constant-x slice through x=0. Default True. + project_origin_slice_x : bool, optional + Whether to show projection for the special constant-x slice at x=0. Default True. + n_slices_y : int, optional + Number of constant-y contour slides to draw. Default 11. + project_slices_y : bool, optional + Whether to show projection of constant-y slices to the (x,y) plane. Default False. + draw_special_origin_slice_y : bool, optional + Whether to draw a special constant-y slice through y=0. Default True. + project_origin_slice_y : bool, optional + Whether to show projection for the special constant-x slice at x=0. Default True. + slice_style : RenderControlMirrorProjected, optional + Drawing attribute options for the contour slices. + None implies use default contour style. + origin_slice_style : RenderControlMirrorProjected, optional + Drawing attribute options for the special origin slices. + None implies use default origin contour style. + """ + self.round_to = round_to + self.margin = margin + self.n_slices_x = n_slices_x + self.project_slices_x = project_slices_x + self.draw_special_origin_slice_x = draw_special_origin_slice_x + self.project_origin_slice_x = project_origin_slice_x + self.n_slices_y = n_slices_y + self.project_slices_y = project_slices_y + self.draw_special_origin_slice_y = draw_special_origin_slice_y + self.project_origin_slice_y = project_origin_slice_y + if slice_style is None: + self.slice_style = slice_style + else: + self.slice_style = rcmp.mirror_contour() + if origin_slice_style is None: + self.origin_slice_style = origin_slice_style + else: + self.origin_slice_style = rcmp.mirror_origin_contour() + + +# Common Configurations + + +def standard_embedding_mirror() -> RenderControlMirrorEmbedded: + return RenderControlMirrorEmbedded( + margin=0.1, + round_to=0.25, + n_slices_x=9, + project_slices_x=False, + draw_special_origin_slice_x=True, + project_origin_slice_x=True, + n_slices_y=9, + project_slices_y=False, + draw_special_origin_slice_y=True, + project_origin_slice_y=True, + slice_style=rcmp.mirror_contour(), + origin_slice_style=rcmp.mirror_origin_contour(), + ) diff --git a/opencsp/common/lib/render_control/RenderControlMirrorProjected.py b/opencsp/common/lib/render_control/RenderControlMirrorProjected.py new file mode 100644 index 000000000..d51ba0738 --- /dev/null +++ b/opencsp/common/lib/render_control/RenderControlMirrorProjected.py @@ -0,0 +1,84 @@ +import opencsp.common.lib.render_control.RenderControlPointSeq as rcps +from opencsp.common.lib.render_control.RenderControlPointSeq import RenderControlPointSeq +from opencsp.common.lib.render_control.RenderControlSurface import RenderControlSurface + +# from opencsp.common.lib.geometry.Resolution import Resolution + + +class RenderControlMirrorProjected: + """ + A class for controlling the rendering of a mirror projection onto the (x,y) plane + in a graphical environment. + + This class allows for the configuration of various visual aspects of a projection, + including its lifted, projected, and connection line features. + """ + + def __init__( + self, + lifted_line_style: RenderControlPointSeq = None, + lifted_vertex_style: RenderControlPointSeq = None, + projected_style: RenderControlPointSeq = None, + connection_style: RenderControlPointSeq = None, + slice_n_vertices: int = 9, + slice_fine_n_vertices: int = 41, + ) -> None: + """ + Initializes a RenderControlMirrorProjected object with the specified parameters. + + Parameters + ---------- + lifted_line_style : RenderControlPointSeq | None, optional + Style to draw the contour of the lifted slice. + Default None. + lifted_vertex_style : RenderControlPointSeq | None, optional + Style to draw the coarse vertices of the lifted slice. + Default None. + projected_style: RenderControlPointSeq | None, optional + Style to draw the projected slice. + Default None. + connection_style: RenderControlPointSeq | None, optional + Style to draw the connection line between the projected and lifted slices. + Default None. + slice_n_vertices : int, optional + Default 9. + slice_fine_n_vertices:int, optional + Default 41. + """ + self.lifted_line_style = lifted_line_style + self.lifted_vertex_style = lifted_vertex_style + self.projected_style = projected_style + self.connection_style = connection_style + self.slice_n_vertices = slice_n_vertices + self.slice_fine_n_vertices = slice_fine_n_vertices + + +# Common Configurations + + +def mirror_contour(slice_n_vertices: int = 5) -> RenderControlMirrorProjected: + """Style for drawing a contour illustrating a mirror surface""" + return RenderControlMirrorProjected( + lifted_line_style=rcps.outline(color='grey', linewidth=0.5), slice_n_vertices=slice_n_vertices + ) + + +def mirror_origin_contour(slice_n_vertices: int = 5) -> RenderControlMirrorProjected: + """Style for drawing a contour illustrating a mirror surface slice passing through the (0,0) origin.""" + return RenderControlMirrorProjected( + lifted_line_style=rcps.outline(color='grey', linewidth=1.0), + lifted_vertex_style=rcps.marker(color='grey', markersize=1.3), + projected_style=rcps.outline(color='grey', linewidth=0.75), + connection_style=rcps.outline(color='grey', linewidth=0.75), + slice_n_vertices=slice_n_vertices, + ) + + +def mirror_boundary() -> RenderControlMirrorProjected: + """Style for drawing the projection of a mirror XyRegion up to the embedding surface.""" + return RenderControlMirrorProjected( + lifted_line_style=rcps.outline(color='red'), + lifted_vertex_style=rcps.marker(color='red', markersize=2), + projected_style=rcps.outline(color='blue'), + connection_style=rcps.outline(color='blue', linewidth=0.6), + ) diff --git a/opencsp/common/lib/target/TargetAbstract.py b/opencsp/common/lib/target/TargetAbstract.py index 01c3a1818..602b02935 100755 --- a/opencsp/common/lib/target/TargetAbstract.py +++ b/opencsp/common/lib/target/TargetAbstract.py @@ -158,7 +158,7 @@ def set_pattern_description(self, description: str) -> None: # Parameters: # ----------- # view: A view 3d object that holds the figure. - # mirror_styles: A RenderControlMirror object that holds attibutes about the graph. + # mirror_styles: A RenderControlMirror object that holds attributes about the graph. # """ # resolution = mirror_style.resolution diff --git a/opencsp/common/lib/test/TstMotionBasedCanting.py b/opencsp/common/lib/test/TstMotionBasedCanting.py index df3c27658..ba9095d98 100755 --- a/opencsp/common/lib/test/TstMotionBasedCanting.py +++ b/opencsp/common/lib/test/TstMotionBasedCanting.py @@ -86,7 +86,7 @@ from opencsp.common.lib.geometry.FunctionXYContinuous import FunctionXYContinuous from opencsp.common.lib.geometry.Intersection import Intersection from opencsp.common.lib.geometry.Pxyz import Pxyz -from opencsp.common.lib.geometry.RegionXY import Resolution +from opencsp.common.lib.geometry.Resolution import Resolution from opencsp.common.lib.geometry.TransformXYZ import TransformXYZ from opencsp.common.lib.geometry.Uxyz import Uxyz from opencsp.common.lib.geometry.Vxyz import Vxyz diff --git a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo001_Mirror_pentagon_f_eq_1.0m_Elevation_60_Degrees_Embedding_Surface_3d.png b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo001_Mirror_pentagon_f_eq_1.0m_Elevation_60_Degrees_Embedding_Surface_3d.png new file mode 100644 index 000000000..2820670da Binary files /dev/null and b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo001_Mirror_pentagon_f_eq_1.0m_Elevation_60_Degrees_Embedding_Surface_3d.png differ diff --git a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo001_Mirror_pentagon_f_eq_1.0m_Elevation_60_Degrees_Embedding_Surface_3d.txt b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo001_Mirror_pentagon_f_eq_1.0m_Elevation_60_Degrees_Embedding_Surface_3d.txt new file mode 100644 index 000000000..c2e5d6cba --- /dev/null +++ b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo001_Mirror_pentagon_f_eq_1.0m_Elevation_60_Degrees_Embedding_Surface_3d.txt @@ -0,0 +1,16 @@ +Metadata: +Figure number: 1 +Name: tmo001_Mirror (pentagon, f=1.0m), Elevation 60 Degrees, Embedding Surface +Title: Mirror (pentagon, f=1.0m), Elevation 60 Degrees, Embedding Surface +Code tag: TestMirrorOutput.test_deep_pentagon_elevation_60deg_embedding() +View spec: 3d + +Title: +Mirror (pentagon, f=1.0m), Elevation 60 Degrees, Embedding Surface + +Caption: +A single mirror of shape (pentagon), analytically defined with focal length f=1.0m, facing 60 degrees above the horizon. + +Comments: +Oriented face 60 deg up from level. + diff --git a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo002_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_yz.png b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo002_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_yz.png new file mode 100644 index 000000000..fa503b938 Binary files /dev/null and b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo002_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_yz.png differ diff --git a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo002_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_yz.txt b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo002_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_yz.txt new file mode 100644 index 000000000..fe61c77cf --- /dev/null +++ b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo002_Mirror_pentagon_f_eq_1.0m_Face_Up_Embedding_Surface_yz.txt @@ -0,0 +1,16 @@ +Metadata: +Figure number: 1 +Name: tmo002_Mirror (pentagon, f=1.0m), Face Up, Embedding Surface +Title: Mirror (pentagon, f=1.0m), Face Up, Embedding Surface +Code tag: TestMirrorOutput.test_deep_pentagon_elevation_face_up_embedding() +View spec: yz + +Title: +Mirror (pentagon, f=1.0m), Face Up, Embedding Surface + +Caption: +A single mirror of shape (pentagon), analytically defined with focal length f=1.0m, facing up, with embedding suraface and origin slices. + +Comments: +Oriented face up. + diff --git a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo002_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_Face_Horizon_3d.png b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo002_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_Face_Horizon_3d.png deleted file mode 100644 index bf218c406..000000000 Binary files a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo002_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_Face_Horizon_3d.png and /dev/null differ diff --git a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo002_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_Face_Horizon_3d.txt b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo002_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_Face_Horizon_3d.txt deleted file mode 100644 index 49879c14b..000000000 --- a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo002_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_Face_Horizon_3d.txt +++ /dev/null @@ -1,17 +0,0 @@ -Metadata: -Figure number: 1 -Name: tmo002_Mirror (rectangle 2.0m x 3.0m, f=2.0m), Face Up, Face Horizon -Title: Mirror (rectangle 2.0m x 3.0m, f=2.0m), Face Up, Face Horizon -Code tag: TestMirrorOutput.test_mirror_halfpi_rotation() -View spec: 3d - -Title: -Mirror (rectangle 2.0m x 3.0m, f=2.0m), Face Up, Face Horizon - -Caption: -A single mirror of shape (rectangle 2.0m x 3.0m), analytically defined with focal length f=2.0m, facing the horizon. - -Comments: -Oriented face 45 deg up from level. -Render surface only. - diff --git a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo003_Facet_from_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_3d.png b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo003_Facet_from_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_3d.png new file mode 100644 index 000000000..e282f1fda Binary files /dev/null and b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo003_Facet_from_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_3d.png differ diff --git a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo004_Facet_from_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_3d.txt b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo003_Facet_from_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_3d.txt similarity index 87% rename from opencsp/common/lib/test/data/input/TestMirrorOutput/tmo004_Facet_from_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_3d.txt rename to opencsp/common/lib/test/data/input/TestMirrorOutput/tmo003_Facet_from_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_3d.txt index c129522f4..7418023a4 100644 --- a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo004_Facet_from_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_3d.txt +++ b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo003_Facet_from_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_3d.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 1 -Name: tmo004_Facet, from Mirror (rectangle 2.0m x 3.0m, f=2.0m), Face Up +Name: tmo003_Facet, from Mirror (rectangle 2.0m x 3.0m, f=2.0m), Face Up Title: Facet, from Mirror (rectangle 2.0m x 3.0m, f=2.0m), Face Up Code tag: TestMirrorOutput.test_facet() View spec: 3d diff --git a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo004_Facet_from_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_3d.png b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo004_Facet_from_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_3d.png deleted file mode 100644 index d8a6b3f64..000000000 Binary files a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo004_Facet_from_Mirror_rectangle_2.0m_x_3.0m_f_eq_2.0m_Face_Up_3d.png and /dev/null differ diff --git a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo004_Two_Heliostats_3d.png b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo004_Two_Heliostats_3d.png new file mode 100644 index 000000000..fa0219693 Binary files /dev/null and b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo004_Two_Heliostats_3d.png differ diff --git a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo007_Two_Heliostats_3d.txt b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo004_Two_Heliostats_3d.txt similarity index 93% rename from opencsp/common/lib/test/data/input/TestMirrorOutput/tmo007_Two_Heliostats_3d.txt rename to opencsp/common/lib/test/data/input/TestMirrorOutput/tmo004_Two_Heliostats_3d.txt index 44e8e1022..f913b59b8 100644 --- a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo007_Two_Heliostats_3d.txt +++ b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo004_Two_Heliostats_3d.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 1 -Name: tmo007_Two Heliostats +Name: tmo004_Two Heliostats Title: Two Heliostats Code tag: TestMirrorOutput.test_solar_field() View spec: 3d diff --git a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo007_Two_Heliostats_3d.png b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo007_Two_Heliostats_3d.png deleted file mode 100644 index cad8c6924..000000000 Binary files a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo007_Two_Heliostats_3d.png and /dev/null differ diff --git a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo010_NSTTF_Heliostat_5W01_long_normals__xy.png b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo010_NSTTF_Heliostat_5W01_long_normals__xy.png new file mode 100644 index 000000000..2170cf443 Binary files /dev/null and b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo010_NSTTF_Heliostat_5W01_long_normals__xy.png differ diff --git a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo017_NSTTF_Heliostat_5W01_long_normals__xy.txt b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo010_NSTTF_Heliostat_5W01_long_normals__xy.txt similarity index 87% rename from opencsp/common/lib/test/data/input/TestMirrorOutput/tmo017_NSTTF_Heliostat_5W01_long_normals__xy.txt rename to opencsp/common/lib/test/data/input/TestMirrorOutput/tmo010_NSTTF_Heliostat_5W01_long_normals__xy.txt index 5c7a22c9a..3e46a9a65 100644 --- a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo017_NSTTF_Heliostat_5W01_long_normals__xy.txt +++ b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo010_NSTTF_Heliostat_5W01_long_normals__xy.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 1 -Name: tmo017_NSTTF Heliostat 5W01 (long normals) +Name: tmo010_NSTTF Heliostat 5W01 (long normals) Title: NSTTF Heliostat 5W01 (long normals) Code tag: TestMirrorOutput.test_heliostat_05W01_and_14W01() View spec: xy diff --git a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo011_NSTTF_Heliostat_14W01_long_normals__xy.png b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo011_NSTTF_Heliostat_14W01_long_normals__xy.png new file mode 100644 index 000000000..92925af22 Binary files /dev/null and b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo011_NSTTF_Heliostat_14W01_long_normals__xy.png differ diff --git a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo018_NSTTF_Heliostat_14W01_long_normals__xy.txt b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo011_NSTTF_Heliostat_14W01_long_normals__xy.txt similarity index 87% rename from opencsp/common/lib/test/data/input/TestMirrorOutput/tmo018_NSTTF_Heliostat_14W01_long_normals__xy.txt rename to opencsp/common/lib/test/data/input/TestMirrorOutput/tmo011_NSTTF_Heliostat_14W01_long_normals__xy.txt index de372b26a..d4e1397f5 100644 --- a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo018_NSTTF_Heliostat_14W01_long_normals__xy.txt +++ b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo011_NSTTF_Heliostat_14W01_long_normals__xy.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 2 -Name: tmo018_NSTTF Heliostat 14W01 (long normals) +Name: tmo011_NSTTF Heliostat 14W01 (long normals) Title: NSTTF Heliostat 14W01 (long normals) Code tag: TestMirrorOutput.test_heliostat_05W01_and_14W01() View spec: xy diff --git a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo017_NSTTF_Heliostat_5W01_long_normals__xy.png b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo017_NSTTF_Heliostat_5W01_long_normals__xy.png deleted file mode 100644 index d24d01f5a..000000000 Binary files a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo017_NSTTF_Heliostat_5W01_long_normals__xy.png and /dev/null differ diff --git a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo018_NSTTF_Heliostat_14W01_long_normals__xy.png b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo018_NSTTF_Heliostat_14W01_long_normals__xy.png deleted file mode 100644 index 54aa86386..000000000 Binary files a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo018_NSTTF_Heliostat_14W01_long_normals__xy.png and /dev/null differ diff --git a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo019_Two_NSTTF_Heliostats_5W01_and_14W01_very_long_normals__yz.png b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo019_Two_NSTTF_Heliostats_5W01_and_14W01_very_long_normals__yz.png deleted file mode 100644 index 4a2197930..000000000 Binary files a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo019_Two_NSTTF_Heliostats_5W01_and_14W01_very_long_normals__yz.png and /dev/null differ diff --git a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo020_Two_NSTTF_Heliostats_5W01_and_14W01_very_long_normals__yz.png b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo020_Two_NSTTF_Heliostats_5W01_and_14W01_very_long_normals__yz.png new file mode 100644 index 000000000..568c61101 Binary files /dev/null and b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo020_Two_NSTTF_Heliostats_5W01_and_14W01_very_long_normals__yz.png differ diff --git a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo019_Two_NSTTF_Heliostats_5W01_and_14W01_very_long_normals__yz.txt b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo020_Two_NSTTF_Heliostats_5W01_and_14W01_very_long_normals__yz.txt similarity index 89% rename from opencsp/common/lib/test/data/input/TestMirrorOutput/tmo019_Two_NSTTF_Heliostats_5W01_and_14W01_very_long_normals__yz.txt rename to opencsp/common/lib/test/data/input/TestMirrorOutput/tmo020_Two_NSTTF_Heliostats_5W01_and_14W01_very_long_normals__yz.txt index 4ed835a8d..a87466561 100644 --- a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo019_Two_NSTTF_Heliostats_5W01_and_14W01_very_long_normals__yz.txt +++ b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo020_Two_NSTTF_Heliostats_5W01_and_14W01_very_long_normals__yz.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 3 -Name: tmo019_Two NSTTF Heliostats: 5W01 and 14W01 (very long normals) +Name: tmo020_Two NSTTF Heliostats: 5W01 and 14W01 (very long normals) Title: Two NSTTF Heliostats: 5W01 and 14W01 (very long normals) Code tag: TestMirrorOutput.test_heliostat_05W01_and_14W01() View spec: yz diff --git a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo021_NSTTF_Heliostat_14W01_exaggerated_z__3d_4.36z5.07.png b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo021_NSTTF_Heliostat_14W01_exaggerated_z__3d_4.36z5.07.png new file mode 100644 index 000000000..a0187278c Binary files /dev/null and b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo021_NSTTF_Heliostat_14W01_exaggerated_z__3d_4.36z5.07.png differ diff --git a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo023_NSTTF_Heliostat_14W01_exaggerated_z__yz_4.36z5.07.txt b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo021_NSTTF_Heliostat_14W01_exaggerated_z__3d_4.36z5.07.txt similarity index 79% rename from opencsp/common/lib/test/data/input/TestMirrorOutput/tmo023_NSTTF_Heliostat_14W01_exaggerated_z__yz_4.36z5.07.txt rename to opencsp/common/lib/test/data/input/TestMirrorOutput/tmo021_NSTTF_Heliostat_14W01_exaggerated_z__3d_4.36z5.07.txt index d95db44ed..c33172335 100644 --- a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo023_NSTTF_Heliostat_14W01_exaggerated_z__yz_4.36z5.07.txt +++ b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo021_NSTTF_Heliostat_14W01_exaggerated_z__3d_4.36z5.07.txt @@ -1,9 +1,9 @@ Metadata: -Figure number: 5 -Name: tmo023_NSTTF Heliostat 14W01 (exaggerated z) +Figure number: 4 +Name: tmo021_NSTTF Heliostat 14W01 (exaggerated z) Title: NSTTF Heliostat 14W01 (exaggerated z) Code tag: TestMirrorOutput.test_heliostat_05W01_and_14W01() -View spec: yz +View spec: 3d Title: NSTTF Heliostat 14W01 (exaggerated z) diff --git a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo022_NSTTF_Heliostat_14W01_exaggerated_z__3d_4.36z5.07.png b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo022_NSTTF_Heliostat_14W01_exaggerated_z__3d_4.36z5.07.png deleted file mode 100644 index a08f5c1dd..000000000 Binary files a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo022_NSTTF_Heliostat_14W01_exaggerated_z__3d_4.36z5.07.png and /dev/null differ diff --git a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo022_NSTTF_Heliostat_14W01_exaggerated_z__yz_4.36z5.07.png b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo022_NSTTF_Heliostat_14W01_exaggerated_z__yz_4.36z5.07.png new file mode 100644 index 000000000..e56e2e6ab Binary files /dev/null and b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo022_NSTTF_Heliostat_14W01_exaggerated_z__yz_4.36z5.07.png differ diff --git a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo022_NSTTF_Heliostat_14W01_exaggerated_z__3d_4.36z5.07.txt b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo022_NSTTF_Heliostat_14W01_exaggerated_z__yz_4.36z5.07.txt similarity index 92% rename from opencsp/common/lib/test/data/input/TestMirrorOutput/tmo022_NSTTF_Heliostat_14W01_exaggerated_z__3d_4.36z5.07.txt rename to opencsp/common/lib/test/data/input/TestMirrorOutput/tmo022_NSTTF_Heliostat_14W01_exaggerated_z__yz_4.36z5.07.txt index bb137439e..b63b3dfd6 100644 --- a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo022_NSTTF_Heliostat_14W01_exaggerated_z__3d_4.36z5.07.txt +++ b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo022_NSTTF_Heliostat_14W01_exaggerated_z__yz_4.36z5.07.txt @@ -1,9 +1,9 @@ Metadata: -Figure number: 4 +Figure number: 5 Name: tmo022_NSTTF Heliostat 14W01 (exaggerated z) Title: NSTTF Heliostat 14W01 (exaggerated z) Code tag: TestMirrorOutput.test_heliostat_05W01_and_14W01() -View spec: 3d +View spec: yz Title: NSTTF Heliostat 14W01 (exaggerated z) diff --git a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo023_NSTTF_Heliostat_14W01_exaggerated_z__yz_4.36z5.07.png b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo023_NSTTF_Heliostat_14W01_exaggerated_z__yz_4.36z5.07.png deleted file mode 100755 index 7c6a358ee..000000000 Binary files a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo023_NSTTF_Heliostat_14W01_exaggerated_z__yz_4.36z5.07.png and /dev/null differ diff --git a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo023_NSTTF_Heliostat_Short_Focal_Length_Canted_and_Lifted_3d.png b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo023_NSTTF_Heliostat_Short_Focal_Length_Canted_and_Lifted_3d.png new file mode 100644 index 000000000..767b44dc2 Binary files /dev/null and b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo023_NSTTF_Heliostat_Short_Focal_Length_Canted_and_Lifted_3d.png differ diff --git a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo025_NSTTF_Heliostat_Short_Focal_Length_Canted_and_Lifted_3d.txt b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo023_NSTTF_Heliostat_Short_Focal_Length_Canted_and_Lifted_3d.txt similarity index 85% rename from opencsp/common/lib/test/data/input/TestMirrorOutput/tmo025_NSTTF_Heliostat_Short_Focal_Length_Canted_and_Lifted_3d.txt rename to opencsp/common/lib/test/data/input/TestMirrorOutput/tmo023_NSTTF_Heliostat_Short_Focal_Length_Canted_and_Lifted_3d.txt index 9d7f0c8fc..42eed9306 100644 --- a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo025_NSTTF_Heliostat_Short_Focal_Length_Canted_and_Lifted_3d.txt +++ b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo023_NSTTF_Heliostat_Short_Focal_Length_Canted_and_Lifted_3d.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 1 -Name: tmo025_NSTTF Heliostat Short Focal Length, Canted and Lifted +Name: tmo023_NSTTF Heliostat Short Focal Length, Canted and Lifted Title: NSTTF Heliostat Short Focal Length, Canted and Lifted Code tag: TestMirrorOutput.test_heliostat_stages() View spec: 3d diff --git a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo024_NSTTF_Heliostat_Short_Focal_Length_With_Canting_and_Tracking_3d.png b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo024_NSTTF_Heliostat_Short_Focal_Length_With_Canting_and_Tracking_3d.png new file mode 100644 index 000000000..a128dcd39 Binary files /dev/null and b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo024_NSTTF_Heliostat_Short_Focal_Length_With_Canting_and_Tracking_3d.png differ diff --git a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo027_NSTTF_Heliostat_Short_Focal_Length_With_Canting_and_Tracking_3d.txt b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo024_NSTTF_Heliostat_Short_Focal_Length_With_Canting_and_Tracking_3d.txt similarity index 89% rename from opencsp/common/lib/test/data/input/TestMirrorOutput/tmo027_NSTTF_Heliostat_Short_Focal_Length_With_Canting_and_Tracking_3d.txt rename to opencsp/common/lib/test/data/input/TestMirrorOutput/tmo024_NSTTF_Heliostat_Short_Focal_Length_With_Canting_and_Tracking_3d.txt index 37ab5805e..9048950cd 100644 --- a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo027_NSTTF_Heliostat_Short_Focal_Length_With_Canting_and_Tracking_3d.txt +++ b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo024_NSTTF_Heliostat_Short_Focal_Length_With_Canting_and_Tracking_3d.txt @@ -1,6 +1,6 @@ Metadata: Figure number: 2 -Name: tmo027_NSTTF Heliostat Short Focal Length, With Canting and Tracking +Name: tmo024_NSTTF Heliostat Short Focal Length, With Canting and Tracking Title: NSTTF Heliostat Short Focal Length, With Canting and Tracking Code tag: TestMirrorOutput.test_heliostat_stages() View spec: 3d diff --git a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo025_NSTTF_Heliostat_Short_Focal_Length_Canted_and_Lifted_3d.png b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo025_NSTTF_Heliostat_Short_Focal_Length_Canted_and_Lifted_3d.png deleted file mode 100644 index 2d3effd95..000000000 Binary files a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo025_NSTTF_Heliostat_Short_Focal_Length_Canted_and_Lifted_3d.png and /dev/null differ diff --git a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo027_NSTTF_Heliostat_Short_Focal_Length_With_Canting_and_Tracking_3d.png b/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo027_NSTTF_Heliostat_Short_Focal_Length_With_Canting_and_Tracking_3d.png deleted file mode 100644 index 9be4f877a..000000000 Binary files a/opencsp/common/lib/test/data/input/TestMirrorOutput/tmo027_NSTTF_Heliostat_Short_Focal_Length_With_Canting_and_Tracking_3d.png and /dev/null differ diff --git a/opencsp/common/lib/test/test_FluxMaps.py b/opencsp/common/lib/test/test_FluxMaps.py index 04a404866..cc720bd42 100644 --- a/opencsp/common/lib/test/test_FluxMaps.py +++ b/opencsp/common/lib/test/test_FluxMaps.py @@ -41,7 +41,7 @@ from opencsp.common.lib.csp.SolarField import SolarField from opencsp.common.lib.geometry.Intersection import Intersection from opencsp.common.lib.geometry.Pxyz import Pxyz -from opencsp.common.lib.geometry.RegionXY import Resolution +from opencsp.common.lib.geometry.Resolution import Resolution from opencsp.common.lib.geometry.Uxyz import Uxyz from opencsp.common.lib.geometry.Vxyz import Vxyz from opencsp.common.lib.render_control.RenderControlAxis import RenderControlAxis @@ -172,7 +172,7 @@ def square(z: float): code_tag=self.code_tag, ) mirror_style = rcm.RenderControlMirror() - mirror.draw(fig_record.view, mirror_style) + mirror.draw(view=fig_record.view, mirror_style=mirror_style) trace_style = rcrt.init_current_lengths(current_len=6) trace.draw(fig_record.view, trace_style) square(4).draw_line(fig_record.view, close=True, style=rcps.RenderControlPointSeq(color="b", marker=",")) diff --git a/opencsp/common/lib/test/test_MirrorOutput.py b/opencsp/common/lib/test/test_MirrorOutput.py index e18ff12ad..b4ef9e6be 100644 --- a/opencsp/common/lib/test/test_MirrorOutput.py +++ b/opencsp/common/lib/test/test_MirrorOutput.py @@ -10,23 +10,27 @@ import numpy as np import pytz from scipy.spatial.transform import Rotation +import opencsp.common.lib.csp.embedding_mirror_surface as ems from opencsp.common.lib.csp.FacetEnsemble import FacetEnsemble from opencsp.common.lib.csp.LightSourceSun import LightSourceSun from opencsp.common.lib.csp.Scene import Scene from opencsp.common.lib.geometry.Pxyz import Pxyz from opencsp.common.lib.geometry.RegionXY import RegionXY from opencsp.common.lib.geometry.Pxy import Pxy - from opencsp.common.lib.geometry.TransformXYZ import TransformXYZ from opencsp.common.lib.geometry.Vxyz import Vxyz import opencsp.common.lib.opencsp_path.data_path_for_test as dpft import opencsp.common.lib.render.figure_management as fm import opencsp.common.lib.render.view_spec as vs +import opencsp.common.lib.render_control.RenderControlAxis as rca import opencsp.common.lib.render_control.RenderControlFacet as rcf +import opencsp.common.lib.render_control.RenderControlFacetEnsemble as rcfe import opencsp.common.lib.render_control.RenderControlHeliostat as rch +import opencsp.common.lib.render_control.RenderControlLightPath as rclp import opencsp.common.lib.render_control.RenderControlMirror as rcm +import opencsp.common.lib.render_control.RenderControlMirrorEmbedded as rcme +import opencsp.common.lib.render_control.RenderControlMirrorProjected as rcmp import opencsp.common.lib.render_control.RenderControlSolarField as rcsf -import opencsp.common.lib.render_control.RenderControlLightPath as rclp import opencsp.common.lib.test.TestOutput as to import opencsp.common.lib.tool.log_tools as lt import opencsp.common.lib.tool.string_tools as st @@ -35,7 +39,6 @@ from opencsp.common.lib.csp.MirrorParametricRectangular import MirrorParametricRectangular from opencsp.common.lib.csp.MirrorParametric import MirrorParametric from opencsp.common.lib.csp.SolarField import SolarField -import opencsp.common.lib.render_control.RenderControlFacetEnsemble as rcfe import opencsp.common.lib.geo.lon_lat_nsttf as lln @@ -45,6 +48,9 @@ class TestMirrorOutput(to.TestOutput): + """ + Test generation and rendering of mirror surfaces, their surface normals, etc. + """ @classmethod def setUpClass( @@ -63,7 +69,7 @@ def setUpClass( ) def setUp(self): - # create a scnene for placing optics + # create a scene for placing optics self.scene = Scene() # Mirror, based on a parameteric model. @@ -86,7 +92,9 @@ def setUp(self): ) self.m1_comments = [] - # Pentagonal mirror, based on a parametric model. + # Deep pentagonal mirror, based on a parametric model. + self.m_deep_focal_length = 1.0 # meters + self.m_deep_fxn = self.lambda_symmetric_paraboloid(self.m_deep_focal_length) pentagon_vertices = Pxy( [ [0.0, -0.95105652, -0.58778525, 0.58778525, 0.95105652], @@ -94,7 +102,19 @@ def setUp(self): ] ) pentagon_region = RegionXY.from_vertices(pentagon_vertices) - self.m_pentagon = MirrorParametric(self.m1_fxn, pentagon_region) + self.m_deep_pentagon = MirrorParametric(self.m_deep_fxn, pentagon_region) + self.m_pentagon_shape_description = 'pentagon' + self.m_deep_pentagon_title = ( + 'Mirror (' + self.m_pentagon_shape_description + ', f=' + str(self.m_deep_focal_length) + 'm)' + ) + self.m_deep_pentagon_caption = ( + 'A single mirror of shape (' + + self.m_pentagon_shape_description + + '), analytically defined with focal length f=' + + str(self.m_deep_focal_length) + + 'm.' + ) + self.m_deep_pentagon_comments = [] # Facet, based on a parameteric mirror. self.f1 = Facet(self.m1) @@ -170,41 +190,103 @@ def lambda_symmetric_paraboloid(self, focal_length: float) -> Callable[[float, f a = 1.0 / (4 * focal_length) return lambda x, y: a * (x**2 + y**2) - def test_mirror_halfpi_rotation(self) -> None: + def test_deep_pentagon_elevation_60deg_embedding(self) -> None: """ - Draws a pentagonal mirror that is rotated 90 deg in space. Should look like a mirror with its normal parallel in the xy plane. + Draws a deep pentagonal mirror that is rotated 60 deg in space. + Should look like a mirror with its normal pointing 60 degrees + above the xy plane. + Also demonstrates embedding surface and slice drawing, all + including transform. """ # Initialize test. self.start_test() - local_comments = self.m1_comments.copy() + local_comments = self.m_deep_pentagon_comments.copy() # Position/Rotation in space. - tran = Vxyz([0, 0, 0]) - rot = Rotation.from_euler("x", 45, True) + tran = Vxyz([0, 0, 0.6]) + # Rotation about x rotates face-up surface normal down from zenith, + # so we rotate by (90-30) degrees. + desired_elevation_deg = 60.0 + rot = Rotation.from_euler('x', (90.0 - desired_elevation_deg), True) transform = TransformXYZ.from_R_V(rot, tran) + # Copy the mirror because we will want to use it again later without the rotation. + m_deep_pentagon_copy = copy.deepcopy(self.m_deep_pentagon) - local_comments.append("Oriented face 45 deg up from level.") - self.scene.add_object(self.m_pentagon) - self.scene.set_position_in_space(self.m_pentagon, transform) + local_comments.append('Oriented face 60 deg up from level.') + self.scene.add_object(m_deep_pentagon_copy) + self.scene.set_position_in_space(m_deep_pentagon_copy, transform) # Setup render control. mirror_control = rcm.RenderControlMirror() - local_comments.append("Render surface only.") + # See below for multi-part projection and slice control settings. # Draw. fig_record = fm.setup_figure_for_3d_data( - self.figure_control, - self.axis_control_m, - vs.view_spec_3d(), + figure_control=self.figure_control, + axis_control=rca.meters(grid=False), # Drawing axis grid and surface grid is confusing. + view_spec=vs.view_spec_3d(), + # Figure numbers needed because titles may be identical. Hard-code number because test order is unpredictable. + number_in_name=False, + input_prefix=self.figure_prefix(1), + title=self.m_deep_pentagon_title + ', Elevation 60 Degrees, Embedding Surface', + caption=st.add_to_last_sentence(self.m_deep_pentagon_caption, ', facing 60 degrees above the horizon'), + comments=local_comments, + code_tag=self.code_tag, + ) + m_deep_pentagon_copy.draw(view=fig_record.view, mirror_style=mirror_control) + ems.draw_mirror_and_embedding_mirror( + m_deep_pentagon_copy, + view=fig_record.view, + mirror_style=rcm.RenderControlMirror(), + draw_projection=True, + projected_style=rcmp.mirror_boundary(), + embedding_style=rcme.standard_embedding_mirror(), + transform=transform, + ) + + # Output. + self.show_save_and_check_figure(fig_record) + + def test_deep_pentagon_elevation_face_up_embedding(self) -> None: + """ + Draws a deep pentagonal mirror that is face up, with embedding + surface and origin slices. + """ + # Initialize test. + self.start_test() + local_comments = self.m_deep_pentagon_comments.copy() + + # Position/Rotation in space. + local_comments.append('Oriented face up.') + + # Setup render control. + mirror_control = rcm.RenderControlMirror() + # See below for multi-part projection and slice control settings. + + # Draw. + fig_record = fm.setup_figure_for_3d_data( + figure_control=self.figure_control, + axis_control=rca.meters(grid=False), # Drawing axis grid and surface grid is confusing. + view_spec=vs.view_spec_yz(), # Figure numbers needed because titles may be identical. Hard-code number because test order is unpredictable. number_in_name=False, input_prefix=self.figure_prefix(2), - title=self.m1_title + ", Face Horizon", - caption=st.add_to_last_sentence(self.m1_caption, ", facing the horizon"), + title=self.m_deep_pentagon_title + ', Face Up, Embedding Surface', + caption=st.add_to_last_sentence( + self.m_deep_pentagon_caption, ', facing up, with embedding suraface and origin slices' + ), comments=local_comments, code_tag=self.code_tag, ) - self.m_pentagon.draw(fig_record.view, mirror_control) + self.m_deep_pentagon.draw(view=fig_record.view, mirror_style=mirror_control) + ems.draw_mirror_and_embedding_mirror( + self.m_deep_pentagon, + view=fig_record.view, + mirror_style=rcm.RenderControlMirror(), + draw_projection=True, + projected_style=rcmp.mirror_boundary(), + embedding_style=rcme.standard_embedding_mirror(), + ) # Output. self.show_save_and_check_figure(fig_record) @@ -245,7 +327,7 @@ def test_facet(self) -> None: vs.view_spec_3d(), # Figure numbers needed because titles may be identical. Hard-code number because test order is unpredictable. number_in_name=False, - input_prefix=self.figure_prefix(4), + input_prefix=self.figure_prefix(3), title=self.f1_title, caption=self.f1_caption, comments=local_comments, @@ -304,7 +386,7 @@ def test_solar_field(self) -> None: vs.view_spec_3d(), # Figure numbers needed because titles may be identical. Hard-code number because test order is unpredictable. number_in_name=False, - input_prefix=self.figure_prefix(7), + input_prefix=self.figure_prefix(4), title=self.sf2x2_title, caption=self.sf2x2_caption, comments=local_comments, @@ -476,7 +558,7 @@ def fn_14W01(x, y): vs.view_spec_xy(), # Figure numbers needed because titles may be identical. Hard-code number because test order is unpredictable. number_in_name=False, - input_prefix=self.figure_prefix(17), + input_prefix=self.figure_prefix(10), title=title_5W01 + " (long normals)", caption=caption_5W01, comments=comments, @@ -492,7 +574,7 @@ def fn_14W01(x, y): vs.view_spec_xy(), # Figure numbers needed because titles may be identical. Hard-code number because test order is unpredictable. number_in_name=False, - input_prefix=self.figure_prefix(18), + input_prefix=self.figure_prefix(11), title=title_14W01 + " (long normals)", caption=caption_14W01, comments=comments, @@ -531,7 +613,7 @@ def fn_14W01(x, y): vs.view_spec_yz(), # Figure numbers needed because titles may be identical. Hard-code number because test order is unpredictable. number_in_name=False, - input_prefix=self.figure_prefix(19), + input_prefix=self.figure_prefix(20), title=title_sf + " (very long normals)", caption=caption_sf, comments=comments, @@ -599,7 +681,7 @@ def fn_14W01(x, y): vs.view_spec_3d(), # Figure numbers needed because titles may be identical. Hard-code number because test order is unpredictable. number_in_name=False, - input_prefix=self.figure_prefix(22), + input_prefix=self.figure_prefix(21), title=title_14W01 + " (exaggerated z)", caption=caption_14W01, comments=comments, @@ -616,7 +698,7 @@ def fn_14W01(x, y): vs.view_spec_yz(), # Figure numbers needed because titles may be identical. Hard-code number because test order is unpredictable. number_in_name=False, - input_prefix=self.figure_prefix(23), + input_prefix=self.figure_prefix(22), title=title_14W01 + " (exaggerated z)", caption=caption_14W01, comments=comments, @@ -718,7 +800,7 @@ def fn(x: float, y: float): vs.view_spec_3d(), # Figure numbers needed because titles may be identical. Hard-code number because test order is unpredictable. number_in_name=False, - input_prefix=self.figure_prefix(25), + input_prefix=self.figure_prefix(23), title=title + ", Canted and Lifted", caption=st.add_to_last_sentence(caption, " with canting angle and lifted"), comments=comments, @@ -747,7 +829,7 @@ def fn(x: float, y: float): vs.view_spec_3d(), # Figure numbers needed because titles may be identical. Hard-code number because test order is unpredictable. number_in_name=False, - input_prefix=self.figure_prefix(27), + input_prefix=self.figure_prefix(24), title=title + ", With Canting and Tracking", caption=st.add_to_last_sentence(caption, " with canting and tracking"), comments=comments, diff --git a/opencsp/common/lib/test/test_RayTraceOutput.py b/opencsp/common/lib/test/test_RayTraceOutput.py index 6974cc2be..e1bd05736 100644 --- a/opencsp/common/lib/test/test_RayTraceOutput.py +++ b/opencsp/common/lib/test/test_RayTraceOutput.py @@ -44,7 +44,7 @@ from opencsp.common.lib.csp.Scene import Scene from opencsp.common.lib.csp.SolarField import SolarField from opencsp.common.lib.geometry.Pxyz import Pxyz -from opencsp.common.lib.geometry.RegionXY import Resolution +from opencsp.common.lib.geometry.Resolution import Resolution from opencsp.common.lib.geometry.TransformXYZ import TransformXYZ from opencsp.common.lib.geometry.Uxyz import Uxyz from opencsp.common.lib.geometry.Vxyz import Vxyz @@ -245,7 +245,7 @@ def test_mirror_trace(self) -> None: view1_yz = fig_record.view trace1.draw(view1_yz, RenderControlRayTrace(light_path_control=light_path_control)) - m1.draw(view1_yz, mirror_control) + m1.draw(view=view1_yz, mirror_style=mirror_control) # Output. self.show_save_and_check_figure(fig_record) diff --git a/opencsp/test/test_DocStringsExist.py b/opencsp/test/test_DocStringsExist.py index 20e2d5fe4..7ae9f235b 100644 --- a/opencsp/test/test_DocStringsExist.py +++ b/opencsp/test/test_DocStringsExist.py @@ -688,7 +688,7 @@ def test_docstrings_exist_for_methods(self): n_undocumented_methods = sum([len(v) for v in undocumented_methods.values()]) if n_undocumented_methods > 0: - print(f"\nFound {n_undocumented_methods} total undocumented metshods!\n") + print(f"\nFound {n_undocumented_methods} total undocumented methods!\n") for class_module_name, class_ums in undocumented_methods.items(): print(f"Undocumented methods in {class_module_name} ({len(class_ums)}):") for class_um in class_ums: