public override ITransformGizmo Build(FScene scene, List <SceneObject> targets) { if (targets.Count != 1) { return(null); } LengthenPivotSO pivotSO = targets[0] as LengthenPivotSO; if (pivotSO == null) { return(null); } // [TODO] lost this functionality when we removed OriginalFrameS. // //Frame3f frameS = pivotSO.OriginalFrameS; Frame3f frameS = pivotSO.GetLocalFrame(CoordSpace.SceneCoords); MoveLengthenPivotGizmo gizmo = new MoveLengthenPivotGizmo(); gizmo.ScenePositionF = (ray) => { DistLine3Ray3 dist = new DistLine3Ray3(ray, new Line3d(frameS.Origin, -frameS.Y)); dist.Compute(); // [RMS] disabling clamp here because we don't know original "start" point now //if (dist.LineParameter < 0) // return dist.Line.Origin; //else return(dist.LineClosest); }; gizmo.WidgetScale = WidgetScale; gizmo.Create(scene, targets); return(gizmo); }
// try to compute a stable ray/plane intersection. when origin is at < +/- an altitude threshold, // use ray/line distance with view-perp line, instead of actual intersection public static Vector3f SafeRayPlaneIntersection(Ray3f ray, Vector3f forwardDir, Vector3f planeOrigin, Vector3f planeNormal, float fAngleThresh = 10.0f) { // determine if we are in unstable condition float fOriginAngleDeg = (float)Math.Abs( planeNormal.AngleD((planeOrigin - ray.Origin).Normalized)); bool bOriginUnstable = Math.Abs(fOriginAngleDeg - 90.0f) < fAngleThresh; // we use ray/plane intersect if stable Frame3f planeF = new Frame3f(planeOrigin, planeNormal); Vector3f planeHit = planeF.RayPlaneIntersection(ray.Origin, ray.Direction, 2); if (bOriginUnstable == false) { return(planeHit); } // if unstable, find "right" direction in plane (ie perp to forward dir, which // may just be ray dir), then intersection is ray/axis closest point Vector3f fwDirInPlane = (forwardDir - planeNormal.Dot(forwardDir)).Normalized; Vector3f perpDirInPlane = Quaternionf.AxisAngleD(planeNormal, 90.0f) * fwDirInPlane; float fAxisDist = (float)DistLine3Ray3.MinDistanceLineParam(ray, new Line3d(planeOrigin, perpDirInPlane)); return(planeOrigin + fAxisDist * perpDirInPlane); }
public void UpdateDraw_Ray(Ray3f ray, int nStep) { // scene xform may have changed during steps (eg view rotation), so we // need to reconstruct our local frame Frame3f primCurW = scene.ToWorldFrame(primStartS); // step 1: find radius in plane // step 2: find height from plane float fY = MinDimension; if (nStep == 0) { Vector3f forwardDir = ray.Direction; Vector3f plane_hit = VRUtil.SafeRayPlaneIntersection(ray, forwardDir, primCurW.Origin, primCurW.Y); plane_hit_local = primCurW.ToFrameP(plane_hit); } else if (nStep == 1) { Vector3f plane_hit = primCurW.FromFrameP(plane_hit_local); Line3d l = new Line3d(plane_hit, primCurW.Y); fY = (float)DistLine3Ray3.MinDistanceLineParam(ray, l); } // figure out possible dimensions, clamp to ranges float planeX = MathUtil.SignedClamp(plane_hit_local[0], MinDimension, MaxDimension); float planeZ = MathUtil.SignedClamp(plane_hit_local[2], MinDimension, MaxDimension); float fR_plane = MathUtil.Clamp(plane_hit_local.Length, MinDimension / 2, MaxDimension / 2); fY = MathUtil.SignedClamp(fY, MinDimension, MaxDimension); // update frame primitive.Frame = primCurW; // update dimensions bool bIsCorner = (primitive.Center == CenterModes.Corner); float fScale = 1.0f; // object is not in scene coordinates! if (primitive.Type == MeshPrimitivePreview.PrimType.Cylinder) { primitive.Width = (bIsCorner) ? fR_plane * fScale : 2 * fR_plane * fScale; primitive.Depth = primitive.Width; primitive.Height = fY * fScale; } else if (primitive.Type == MeshPrimitivePreview.PrimType.Box) { primitive.Width = (bIsCorner) ? planeX * fScale : 2 * planeX * fScale; primitive.Depth = (bIsCorner) ? planeZ * fScale : 2 * planeZ * fScale; primitive.Height = fY * fScale; } else if (primitive.Type == MeshPrimitivePreview.PrimType.Sphere) { primitive.Width = (bIsCorner) ? fR_plane * fScale : 2 * fR_plane * fScale; primitive.Depth = primitive.Width; primitive.Height = Mathf.Sign(fY) * primitive.Width; } else { throw new NotImplementedException("DrawPrimitivesTool.UpdateDraw_Ray - type not supported"); } }
public void UpdateDraw_Spatial(Ray3f ray, Frame3f handFrame, int nStep) { // scene xform may have changed during steps (eg view rotation), so we // need to reconstruct our local frame Frame3f primCurW = scene.ToWorldFrame(primStartS); // try snap points SnapResult snap = Snaps.FindHitSnapPoint(ray); bool bHaveSnap = (snap != null); Frame3f snapF = (bHaveSnap) ? scene.ToWorldFrame(snap.FrameS) : Frame3f.Identity; // step 1: find radius in plane if (nStep == 0) { if (bHaveSnap) { plane_hit_local = primCurW.ToFrameP( primCurW.ProjectToPlane(snapF.Origin, 1)); } else { Vector3f forwardDir = ray.Direction; Vector3f plane_hit = VRUtil.SafeRayPlaneIntersection(ray, forwardDir, primCurW.Origin, primCurW.Y); plane_hit_local = primCurW.ToFrameP(plane_hit); } } float fX = MathUtil.SignedClamp(plane_hit_local[0], MinDimension, MaxDimension); float fY = MinDimension; float fZ = MathUtil.SignedClamp(plane_hit_local[2], MinDimension, MaxDimension); float fR_plane = MathUtil.Clamp(plane_hit_local.Length, MinDimension / 2, MaxDimension / 2); // step 2: find height from plane if (nStep == 1) { Vector3f plane_hit = primCurW.FromFrameP(plane_hit_local); Line3d l = new Line3d(plane_hit, primCurW.Y); if (bHaveSnap) { fY = (float)l.Project(snapF.Origin); } else { Vector3f handTip = handFrame.Origin + SceneGraphConfig.HandTipOffset * handFrame.Z; float fHandDist = (float)l.DistanceSquared(handTip); if (fHandDist < fR_plane * 1.5f) { fY = (float)l.Project(handTip); } else { fY = (float)DistLine3Ray3.MinDistanceLineParam(ray, l); } } } // figure out possible dimensions, clamp to ranges fY = MathUtil.SignedClamp(fY, MinDimension, MaxDimension); // update frame primitive.Frame = primCurW; // update dimensions bool bIsCorner = (primitive.Center == CenterModes.Corner); float fScale = 1.0f; // object is not in scene coordinates! if (primitive.Type == MeshPrimitivePreview.PrimType.Cylinder) { primitive.Width = (bIsCorner) ? fR_plane * fScale : 2 * fR_plane * fScale; primitive.Depth = primitive.Width; //primitive.Depth = Mathf.Sign(fZ) * primitive.Width; //primitive.Width = Mathf.Sign(fX) * primitive.Width; primitive.Height = fY * fScale; } else if (primitive.Type == MeshPrimitivePreview.PrimType.Box) { primitive.Width = (bIsCorner) ? fX : 2 * fX * fScale; primitive.Depth = (bIsCorner) ? fZ : 2 * fZ * fScale; primitive.Height = fY * fScale; } else if (primitive.Type == MeshPrimitivePreview.PrimType.Sphere) { primitive.Width = (bIsCorner) ? fR_plane * fScale : 2 * fR_plane * fScale; primitive.Depth = primitive.Height = primitive.Width; //primitive.Depth = Mathf.Sign(fZ) * primitive.Width; //primitive.Width = Mathf.Sign(fX) * primitive.Width; //primitive.Height = Mathf.Sign(fY) * primitive.Width; } else { throw new NotImplementedException("SnapDrawPrimitivesTool.UpdateDraw_Ray - type not supported"); } }