protected override void OnPointUpdated(ControlPoint pt, Frame3f prevFrameS, bool isFirst)
        {
            Vector3f basePt  = GetPointPosition(BasePointID, CoordSpace.SceneCoords).Origin;
            Vector3f frontPt = GetPointPosition(FrontPointID, CoordSpace.SceneCoords).Origin;
            Vector3f topPt   = GetPointPosition(TopPointID, CoordSpace.SceneCoords).Origin;

            lastTargetFrameS = TargetSO.GetLocalFrame(CoordSpace.SceneCoords);

            Frame3f previewFrameS = lastTargetFrameS;

            // position next to original object
            previewFrameS = previewFrameS.Translated(1.1f * (float)meshBounds.Width * Vector3f.AxisX);

            Vector3f upAxis = (topPt - basePt).Normalized;

            // construct a frame perp to upAxis at midpoint, and project original and current fw points
            Frame3f  upFrame = new Frame3f((topPt + basePt) * 0.5f, upAxis);
            Vector3f origFW  = upFrame.ProjectToPlane(initialFrontPt, 2);

            origFW = (origFW - upFrame.Origin).Normalized;
            Vector3f curFW = upFrame.ProjectToPlane(frontPt, 2);

            curFW = (curFW - upFrame.Origin).Normalized;
            //float angle = MathUtil.PlaneAngleSignedD(origFW, curFW, upAxis);

            start_forward_pt_S   = upFrame.FromFrameP(origFW);
            current_forward_pt_S = upFrame.FromFrameP(curFW);

            // construct rotation that aligns up axis with y-up
            Quaternionf upRotate = Quaternionf.FromTo(upAxis, Vector3f.AxisY);

            previewFrameS.Rotate(upRotate);

            // now rotate so that forward dir points along -Z
            //Quaternionf fwRotate = Quaternionf.AxisAngleD(Vector3f.AxisY, angle);
            //curFW = upRotate * curFW;
            Quaternionf fwRotate = Quaternionf.FromToConstrained(curFW, -Vector3f.AxisZ, Vector3f.AxisY);

            previewFrameS.Rotate(fwRotate);

            previewSO.SetLocalFrame(previewFrameS, CoordSpace.SceneCoords);
            lastPreviewFrameS = previewFrameS;
        }
        override public void Apply()
        {
            float VerticalSpaceFudge = 10.0f;

            DMeshSO TargetMeshSO = TargetSO as DMeshSO;

            Frame3f           curFrameS = TargetSO.GetLocalFrame(CoordSpace.SceneCoords);
            TransformSOChange change    = new TransformSOChange(TargetSO,
                                                                curFrameS, lastPreviewFrameS, CoordSpace.SceneCoords);

            Scene.History.PushChange(change, false);

            Frame3f newFrameS = new Frame3f(SceneTransforms.ObjectToSceneP(TargetSO, meshBounds.Center));
            RepositionPivotChangeOp pivot1 = new RepositionPivotChangeOp(newFrameS, TargetMeshSO);

            Scene.History.PushChange(pivot1, false);

            newFrameS = TargetSO.GetLocalFrame(CoordSpace.SceneCoords);
            AxisAlignedBox3d bounds         = TargetMeshSO.Mesh.CachedBounds;
            float            h              = (float)bounds.Height;
            Vector3f         o              = newFrameS.Origin;
            Vector3f         translate      = new Vector3f(-o.x, h * 0.5f - o.y + VerticalSpaceFudge, -o.z);
            Frame3f          centeredFrameS = newFrameS.Translated(translate);

            TransformSOChange centerChange = new TransformSOChange(TargetSO,
                                                                   newFrameS, centeredFrameS, CoordSpace.SceneCoords);

            Scene.History.PushChange(centerChange, false);

            newFrameS        = TargetSO.GetLocalFrame(CoordSpace.SceneCoords);
            o                = newFrameS.Origin;
            o.y              = 0;
            newFrameS.Origin = o;

            RepositionPivotChangeOp pivot2 = new RepositionPivotChangeOp(newFrameS, TargetMeshSO);

            Scene.History.PushChange(pivot2, false);


            Scene.History.PushInteractionCheckpoint();
        }
        public override void PreRender()
        {
            base.PreRender();

            // for fixed preview orientation, we keep preview "on the right" of scan.
            if (FixedPreviewOrientation && previewSO != null)
            {
                fCamera  cam       = previewSO.GetScene().ActiveCamera;
                Vector3f camRightW = cam.Right();
                Vector3f camRightS = previewSO.GetScene().ToSceneN(camRightW);

                Frame3f  previewF = lastPreviewFrameS;
                Frame3f  targetF  = TargetSO.GetLocalFrame(CoordSpace.SceneCoords);
                Vector3f dv       = previewF.Origin - targetF.Origin;
                dv.y = 0;
                float dist = dv.Length;

                Frame3f rightF = targetF.Translated(dist * camRightS);
                rightF.Rotation = previewF.Rotation;
                previewSO.SetLocalFrame(rightF, CoordSpace.SceneCoords);
            }
        }
        public override void Setup()
        {
            StartPointID = AppendSurfacePoint("StartPoint", Colorf.Blue);
            EndPointID   = AppendSurfacePoint("EndPoint", Colorf.Green);

            //LineIndicator line = new LineIndicator() {
            //    LineWidth = fDimension.Scene(1.0f),
            //    SceneStartF = () => { return GizmoPoints[StartPointID].currentFrameS.Origin; },
            //    SceneEndF = () => { return GizmoPoints[EndPointID].currentFrameS.Origin; },
            //};
            //indicators.AddIndicator(line);
            //indicators.SetLayer(line, FPlatform.HUDOverlay);   // has to be hud overlay or it will be clipped by depth render

            Frame3f TargetFrameS = TargetSO.GetLocalFrame(CoordSpace.SceneCoords);

            TargetAxis = new Line3d(TargetFrameS.Origin, Vector3d.AxisY);

            SectionPlaneIndicator startPlane = IndicatorBuilder.MakeSectionPlaneIndicator(
                100, "startPlane",
                fDimension.Scene(plane_indicator_width),
                () => { return(new Frame3f(TargetAxis.ClosestPoint(GizmoPoints[StartPointID].currentFrameS.Origin))); },
                () => { return(new Colorf(Colorf.LightGreen, 0.5f)); },
                () => { return(true); }
                );

            Indicators.AddIndicator(startPlane);

            SectionPlaneIndicator endPlane = IndicatorBuilder.MakeSectionPlaneIndicator(
                101, "endPlane",
                fDimension.Scene(plane_indicator_width),
                () => { return(new Frame3f(TargetAxis.ClosestPoint(GizmoPoints[EndPointID].currentFrameS.Origin))); },
                () => { return(new Colorf(Colorf.LightGreen, 0.5f)); },
                () => { return(true); }
                );

            Indicators.AddIndicator(endPlane);
        }