diff --git a/src/PRo3D.Core/SequencedBookmarks/BookmarkAnimations.fs b/src/PRo3D.Core/SequencedBookmarks/BookmarkAnimations.fs index 42b513bd..74eb9bf2 100644 --- a/src/PRo3D.Core/SequencedBookmarks/BookmarkAnimations.fs +++ b/src/PRo3D.Core/SequencedBookmarks/BookmarkAnimations.fs @@ -31,11 +31,11 @@ module BookmarkAnimations = //let appearance = getName "appearance" module Primitives = - let frustum_ = ViewConfigModel.frustumModel_ >-> FrustumModel.frustum_ - let focal_ = ViewConfigModel.frustumModel_ >-> FrustumModel.focal_ >-> NumericInput.value_ + let frustum_ = SceneStateViewConfig.frustumModel_ >-> FrustumModel.frustum_ + let focal_ = SceneStateViewConfig.frustumModel_ >-> FrustumModel.focal_ >-> NumericInput.value_ - let interpVcm (src : ViewConfigModel) (dst : ViewConfigModel) - : IAnimation<'Model, ViewConfigModel> = + let interpVcm (src : SceneStateViewConfig) (dst : SceneStateViewConfig) + : IAnimation<'Model, SceneStateViewConfig> = //let animFocal = Primitives.lerp src.frustumModel.focal.value src.frustumModel.focal.value let animFocal = Animation.create (lerp src.frustumModel.focal.value dst.frustumModel.focal.value) |> Animation.seconds 1 @@ -44,8 +44,8 @@ module BookmarkAnimations = let newFrustum = FrustumUtils.calculateFrustum focal - dst.nearPlane.value - dst.farPlane.value + dst.nearPlane + dst.farPlane dst |> Optic.set frustum_ newFrustum diff --git a/src/PRo3D.Core/SequencedBookmarks/SequencedBookmarks-Model.fs b/src/PRo3D.Core/SequencedBookmarks/SequencedBookmarks-Model.fs index 08b35aef..23d395d2 100644 --- a/src/PRo3D.Core/SequencedBookmarks/SequencedBookmarks-Model.fs +++ b/src/PRo3D.Core/SequencedBookmarks/SequencedBookmarks-Model.fs @@ -74,9 +74,110 @@ type SequencedBookmarksAction = | ToggleUpdateJsonBeforeRendering | SaveAnimation + +/// a reduced version of SceneConfigModel that is saved and restore with sequenced bookmarks +type SceneStateViewConfig = + { + nearPlane : float + farPlane : float + frustumModel : FrustumModel + arrowLength : float + arrowThickness : float + dnsPlaneSize : float + lodColoring : bool + drawOrientationCube : bool + } with + static member frustumModel_ = + (fun c -> c.frustumModel), + (fun (value : FrustumModel) (c : SceneStateViewConfig) -> + { c with frustumModel = value }) + static member fromViewConfigModel (config : ViewConfigModel) = + { + nearPlane = config.nearPlane.value + farPlane = config.farPlane.value + frustumModel = config.frustumModel + arrowLength = config.arrowLength.value + arrowThickness = config.arrowThickness.value + dnsPlaneSize = config.dnsPlaneSize.value + lodColoring = config.lodColoring + drawOrientationCube = config.drawOrientationCube + } + + static member FromJson(_ : SceneStateViewConfig) = + json { + let! nearPlane = Json.read "nearPlane" + let! farPlane = Json.read "farPlane" + let! frustumModel = Json.read "frustumModel" + let! arrowLength = Json.read "arrowLength" + let! arrowThickness = Json.read "arrowThickness" + let! dnsPlaneSize = Json.read "dnsPlaneSize" + let! lodColoring = Json.read "lodColoring" + let! drawOrientationCube = Json.read "drawOrientationCube" + + return { + nearPlane = nearPlane + farPlane = farPlane + frustumModel = frustumModel + arrowLength = arrowLength + arrowThickness = arrowThickness + dnsPlaneSize = dnsPlaneSize + lodColoring = lodColoring + drawOrientationCube = drawOrientationCube + } + } + static member ToJson (x : SceneStateViewConfig) = + json { + do! Json.write "nearPlane" x.nearPlane + do! Json.write "farPlane" x.farPlane + do! Json.write "frustumModel" x.frustumModel + do! Json.write "arrowLength" x.arrowLength + do! Json.write "arrowThickness" x.arrowThickness + do! Json.write "dnsPlaneSize" x.dnsPlaneSize + do! Json.write "lodColoring" x.lodColoring + do! Json.write "drawOrientationCube" x.drawOrientationCube + } + +type SceneStateReferenceSystem = + { + origin : V3d + isVisible : bool + size : float + selectedScale : string + } with + static member fromReferenceSystem (refSystem : ReferenceSystem) + : SceneStateReferenceSystem = + { + origin = refSystem.origin + isVisible = refSystem.isVisible + size = refSystem.size.value + selectedScale = refSystem.selectedScale + } + static member FromJson(_ : SceneStateReferenceSystem) = + json { + let! origin = Json.read "origin" + let! isVisible = Json.read "isVisible" + let! size = Json.read "size" + let! selectedScale = Json.read "selectedScale" + + return { + origin = origin |> V3d.Parse + isVisible = isVisible + size = size + selectedScale = selectedScale + } + } + static member ToJson(x : SceneStateReferenceSystem) = + json { + do! Json.write "origin" (string x.origin) + do! Json.write "isVisible" x.isVisible + do! Json.write "size" x.size + do! Json.write "selectedScale" x.selectedScale + } + /// state of various scene elements for use with animations type SceneState = { + version : int isValid : bool timestamp : DateTime stateAnnoatations : GroupsModel @@ -84,8 +185,8 @@ type SceneState = stateSceneObjects : SceneObjectsModel stateScaleBars : ScaleBarsModel stateGeologicSurfaces : GeologicSurfacesModel - stateConfig : ViewConfigModel - stateReferenceSystem : ReferenceSystem + stateConfig : SceneStateViewConfig + stateReferenceSystem : SceneStateReferenceSystem stateTraverses : option } with static member stateConfig_ = @@ -95,14 +196,52 @@ type SceneState = ) static member frustum_ = SceneState.stateConfig_ - >-> ViewConfigModel.frustumModel_ + >-> SceneStateViewConfig.frustumModel_ >-> FrustumModel.frustum_ static member focalLength_ = SceneState.stateConfig_ - >-> ViewConfigModel.frustumModel_ + >-> SceneStateViewConfig.frustumModel_ >-> FrustumModel.focal_ >-> NumericInput.value_ - static member FromJson( _ : SceneState) = + +[] +module SceneState = + let currentVersion = 1 + let read0 = + json { + let isValid = true + let! timestamp = Json.tryRead "timestamp" + let timestamp = + match timestamp with + | Some timestamp -> timestamp + | None -> DateTime.Now + let! stateAnnoatations = Json.read "stateAnnoatations" + let! stateSurfaces = Json.read "stateSurfaces" + let! stateSceneObjects = Json.read "stateSceneObjects" + let! stateScaleBars = Json.read "stateScaleBars" + let! stateGeologicSurfaces = Json.read "stateGeologicSurfaces" + let! stateConfig = Json.read "stateConfig" + let! stateReferenceSystem = Json.read "stateReferenceSystem" + let! stateTraverse = Json.tryRead "stateTraverse" + + return { + version = currentVersion + isValid = isValid + timestamp = timestamp + stateAnnoatations = stateAnnoatations + stateSurfaces = stateSurfaces + stateSceneObjects = stateSceneObjects + stateScaleBars = stateScaleBars + stateGeologicSurfaces = stateGeologicSurfaces + stateConfig = + SceneStateViewConfig.fromViewConfigModel stateConfig + stateReferenceSystem = + SceneStateReferenceSystem.fromReferenceSystem stateReferenceSystem + stateTraverses = stateTraverse + } + } + + let read1 = json { let isValid = true let! timestamp = Json.tryRead "timestamp" @@ -120,6 +259,7 @@ type SceneState = let! stateTraverse = Json.tryRead "stateTraverse" return { + version = currentVersion isValid = isValid timestamp = timestamp stateAnnoatations = stateAnnoatations @@ -133,8 +273,24 @@ type SceneState = } } +type SceneState with + static member FromJson( _ : SceneState) = + json { + let! version = Json.tryRead "version" + match version with + | None -> + return! SceneState.read0 + | Some v when v = 1 -> + return! SceneState.read1 + | _ -> + return! version + |> sprintf "don't know version %A of SceneState" + |> Json.error + } + static member ToJson(x : SceneState) = json { + do! Json.write "version" SceneState.currentVersion do! Json.write "timestamp" x.timestamp do! Json.write "stateAnnoatations" x.stateAnnoatations do! Json.write "stateSurfaces" x.stateSurfaces @@ -247,7 +403,7 @@ type SequencedBookmarkModel = { this.filename ] | None -> - Log.warn "[SequencedBookmarks] Bookmark has no basePath." + //Log.warn "[SequencedBookmarks] Bookmark has no basePath." //debugging this.filename member this.filename = diff --git a/src/PRo3D.SimulatedViews/Snapshots/SnapshotAnimation.fs b/src/PRo3D.SimulatedViews/Snapshots/SnapshotAnimation.fs index d62dbb41..709f556e 100644 --- a/src/PRo3D.SimulatedViews/Snapshots/SnapshotAnimation.fs +++ b/src/PRo3D.SimulatedViews/Snapshots/SnapshotAnimation.fs @@ -168,16 +168,14 @@ module SnapshotAnimation = lerpFrames fromState.stateConfig.frustumModel.focal.value toState.stateConfig.frustumModel.focal.value (nrOfFrames |> round |> int) - Log.line "%s" (lerped |> List.map (sprintf "%f ") |> List.reduce (+)) let lerpedFrustra = lerped |> List.map (fun focal -> FrustumUtils.calculateFrustum' focal - toState.stateConfig.nearPlane.value - toState.stateConfig.farPlane.value + toState.stateConfig.nearPlane + toState.stateConfig.farPlane (bm.resolutionX.value / bm.resolutionY.value)) - Log.line "%s" (lerpedFrustra |> List.map string |> List.reduce (+)) lerpedFrustra | _ -> @@ -228,8 +226,8 @@ module SnapshotAnimation = let frustum = FrustumUtils.calculateFrustum' state.stateConfig.frustumModel.focal.value - state.stateConfig.nearPlane.value - state.stateConfig.farPlane.value + state.stateConfig.nearPlane + state.stateConfig.farPlane (bm.resolutionX.value / bm.resolutionY.value) Some (Optic.set SequencedBookmarkModel._frustum frustum firstBm) | None -> diff --git a/src/PRo3D.Viewer/Viewer/ViewerLenses.fs b/src/PRo3D.Viewer/Viewer/ViewerLenses.fs index 45a976b8..23c8a64f 100644 --- a/src/PRo3D.Viewer/Viewer/ViewerLenses.fs +++ b/src/PRo3D.Viewer/Viewer/ViewerLenses.fs @@ -66,6 +66,7 @@ module ViewerLenses = // sequenced bookmarks let _sequencedBookmarks = Model.scene_ >-> Scene.sequencedBookmarks_ + // scene state for saving the state of the scene with sequenced bookmarks let _sceneState : ((Model -> SceneState) * (SceneState -> Model -> Model)) = let inline haveSameKeys (a : HashMap<'a, 'b>) (b : HashMap<'a, 'c>) = if a.Count <> b.Count then false @@ -74,6 +75,7 @@ module ViewerLenses = (fun m -> { + version = SceneState.currentVersion isValid = true timestamp = System.DateTime.Now stateAnnoatations = m.drawing.annotations @@ -81,8 +83,10 @@ module ViewerLenses = stateSceneObjects = m.scene.sceneObjectsModel stateScaleBars = m.scene.scaleBars stateGeologicSurfaces = m.scene.geologicSurfacesModel - stateConfig = m.scene.config - stateReferenceSystem = m.scene.referenceSystem + stateConfig = SceneStateViewConfig.fromViewConfigModel + m.scene.config + stateReferenceSystem = SceneStateReferenceSystem.fromReferenceSystem + m.scene.referenceSystem stateTraverses = Some m.scene.traverses } ), @@ -126,12 +130,10 @@ module ViewerLenses = | false -> FrustumUtils.calculateFrustum state.stateConfig.frustumModel.focal.value - state.stateConfig.nearPlane.value - state.stateConfig.farPlane.value + state.stateConfig.nearPlane + state.stateConfig.farPlane | true -> state.stateConfig.frustumModel.frustum - - {m with drawing = {m.drawing with annotations = state.stateAnnoatations} scene = @@ -140,8 +142,31 @@ module ViewerLenses = sceneObjectsModel = state.stateSceneObjects scaleBars = scaleBars geologicSurfacesModel = state.stateGeologicSurfaces - config = state.stateConfig - referenceSystem = state.stateReferenceSystem + config = + {m.scene.config with + nearPlane = + {m.scene.config.nearPlane with value = state.stateConfig.nearPlane} + farPlane = + {m.scene.config.farPlane with value = state.stateConfig.farPlane} + frustumModel = state.stateConfig.frustumModel + arrowLength = + {m.scene.config.arrowLength with value = state.stateConfig.arrowLength} + arrowThickness = + {m.scene.config.arrowLength with value = state.stateConfig.arrowThickness} + dnsPlaneSize = + {m.scene.config.dnsPlaneSize with value = state.stateConfig.dnsPlaneSize} + lodColoring = state.stateConfig.lodColoring + drawOrientationCube = state.stateConfig.drawOrientationCube + } + referenceSystem = + {m.scene.referenceSystem with + origin = state.stateReferenceSystem.origin + isVisible = state.stateReferenceSystem.isVisible + size = + {m.scene.referenceSystem.size with + value = state.stateReferenceSystem.size} + selectedScale = state.stateReferenceSystem.selectedScale + } traverses = traverses }