public static void ToFrame(IDeformableMesh mesh, Frame3f f) { int NV = mesh.MaxVertexID; bool bHasNormals = mesh.HasVertexNormals; for (int vid = 0; vid < NV; ++vid) { if (mesh.IsVertex(vid)) { Vector3D v = mesh.GetVertex(vid); Vector3D vf = f.ToFrameP((Vector3F)v); mesh.SetVertex(vid, vf); if (bHasNormals) { Vector3F n = mesh.GetVertexNormal(vid); Vector3F nf = f.ToFrameV(n); mesh.SetVertexNormal(vid, nf); } } } }
virtual public Vector2f To2DCoords(Vector3f pos) { Vector3f posF = Frame.ToFrameP(pos); return(posF.xy); }
public override void Generate() { int nRings = Curve.Length; int nRingSize = (NoSharedVertices) ? Slices + 1 : Slices; int nCapVertices = (NoSharedVertices) ? Slices + 1 : 1; if (Capped == false) { nCapVertices = 0; } vertices = new VectorArray3d(nRingSize * nRings + 2 * nCapVertices); uv = new VectorArray2f(vertices.Count); normals = new VectorArray3f(vertices.Count); int nSpanTris = (nRings - 1) * (2 * Slices); int nCapTris = (Capped) ? 2 * Slices : 0; triangles = new IndexArray3i(nSpanTris + nCapTris); float fDelta = (float)((Math.PI * 2.0) / Slices); Frame3f f = Axis; // generate tube for (int ri = 0; ri < nRings; ++ri) { Vector3D v_along = Curve[ri]; Vector3F v_frame = f.ToFrameP((Vector3F)v_along); float uv_along = (float)ri / (float)(nRings - 1); // generate vertices int nStartR = ri * nRingSize; for (int j = 0; j < nRingSize; ++j) { float angle = (float)j * fDelta; // [TODO] this is not efficient...use Matrix3f? Vector3F v_rot = Quaternionf.AxisAngleR(Vector3F.AxisY, angle) * v_frame; Vector3D v_new = f.FromFrameP(v_rot); int k = nStartR + j; vertices[k] = v_new; float uv_around = (float)j / (float)(nRingSize); uv[k] = new Vector2F(uv_along, uv_around); // [TODO] proper normal Vector3F n = (Vector3F)(v_new - f.Origin).Normalized; normals[k] = n; } } // generate triangles int ti = 0; for (int ri = 0; ri < nRings - 1; ++ri) { int r0 = ri * nRingSize; int r1 = r0 + nRingSize; for (int k = 0; k < nRingSize - 1; ++k) { triangles.Set(ti++, r0 + k, r0 + k + 1, r1 + k + 1, Clockwise); triangles.Set(ti++, r0 + k, r1 + k + 1, r1 + k, Clockwise); } if (NoSharedVertices == false) // close disc if we went all the way { triangles.Set(ti++, r1 - 1, r0, r1, Clockwise); triangles.Set(ti++, r1 - 1, r1, r1 + nRingSize - 1, Clockwise); } } if (Capped) { // find avg start loop size Vector3D vAvgStart = Vector3D.Zero, vAvgEnd = Vector3D.Zero; for (int k = 0; k < Slices; ++k) { vAvgStart += vertices[k]; vAvgEnd += vertices[(nRings - 1) * nRingSize + k]; } vAvgStart /= (double)Slices; vAvgEnd /= (double)Slices; Frame3f fStart = f; fStart.Origin = (Vector3F)vAvgStart; Frame3f fEnd = f; fEnd.Origin = (Vector3F)vAvgEnd; // add endcap verts int nBottomC = nRings * nRingSize; vertices[nBottomC] = fStart.Origin; uv[nBottomC] = new Vector2F(0.5f, 0.5f); normals[nBottomC] = -fStart.Z; startCapCenterIndex = nBottomC; int nTopC = nBottomC + 1; vertices[nTopC] = fEnd.Origin; uv[nTopC] = new Vector2F(0.5f, 0.5f); normals[nTopC] = fEnd.Z; endCapCenterIndex = nTopC; if (NoSharedVertices) { // duplicate first loop and make a fan w/ bottom-center int nExistingB = 0; int nStartB = nTopC + 1; for (int k = 0; k < Slices; ++k) { vertices[nStartB + k] = vertices[nExistingB + k]; //uv[nStartB + k] = (Vector2f)Polygon.Vertices[k].Normalized; float angle = (float)k * fDelta; double cosa = Math.Cos(angle), sina = Math.Sin(angle); uv[nStartB + k] = new Vector2F(0.5f * (1.0f + cosa), 0.5f * (1 + sina)); normals[nStartB + k] = normals[nBottomC]; } append_disc(Slices, nBottomC, nStartB, true, Clockwise, ref ti); // duplicate second loop and make fan int nExistingT = nRingSize * (nRings - 1); int nStartT = nStartB + Slices; for (int k = 0; k < Slices; ++k) { vertices[nStartT + k] = vertices[nExistingT + k]; //uv[nStartT + k] = (Vector2f)Polygon.Vertices[k].Normalized; float angle = (float)k * fDelta; double cosa = Math.Cos(angle), sina = Math.Sin(angle); uv[nStartT + k] = new Vector2F(0.5f * (1.0f + cosa), 0.5f * (1 + sina)); normals[nStartT + k] = normals[nTopC]; } append_disc(Slices, nTopC, nStartT, true, !Clockwise, ref ti); } else { append_disc(Slices, nBottomC, 0, true, Clockwise, ref ti); append_disc(Slices, nTopC, nRingSize * (nRings - 1), true, !Clockwise, ref ti); } } }
// [TODO] projection pass // - only project vertices modified by smooth pass? // - and/or verts in set of modified edges? protected virtual void TrackedFaceProjectionPass() { IOrientedProjectionTarget normalTarget = ProjectionTarget as IOrientedProjectionTarget; if (normalTarget == null) { throw new Exception("RemesherPro.TrackedFaceProjectionPass: projection target does not have normals!"); } InitializeBuffersForFacePass(); SpinLock buffer_lock = new SpinLock(); // this function computes rotated position of triangle, such that it // aligns with face normal on target surface. We accumulate weighted-average // of vertex positions, which we will then use further down where possible. Action <int> process_triangle = (tid) => { Vector3d normal; double area; Vector3d centroid; mesh.GetTriInfo(tid, out normal, out area, out centroid); Vector3d projNormal; Vector3d projPos = normalTarget.Project(centroid, out projNormal); Index3i tv = mesh.GetTriangle(tid); Vector3d v0 = mesh.GetVertex(tv.a), v1 = mesh.GetVertex(tv.b), v2 = mesh.GetVertex(tv.c); // ugh could probably do this more efficiently... Frame3f triF = new Frame3f(centroid, normal); v0 = triF.ToFrameP(ref v0); v1 = triF.ToFrameP(ref v1); v2 = triF.ToFrameP(ref v2); triF.AlignAxis(2, (Vector3f)projNormal); triF.Origin = (Vector3f)projPos; v0 = triF.FromFrameP(ref v0); v1 = triF.FromFrameP(ref v1); v2 = triF.FromFrameP(ref v2); double dot = normal.Dot(projNormal); dot = MathUtil.Clamp(dot, 0, 1.0); double w = area * (dot * dot * dot); bool taken = false; buffer_lock.Enter(ref taken); vBufferV[tv.a] += w * v0; vBufferVWeights[tv.a] += w; vBufferV[tv.b] += w * v1; vBufferVWeights[tv.b] += w; vBufferV[tv.c] += w * v2; vBufferVWeights[tv.c] += w; buffer_lock.Exit(); }; // compute face-aligned vertex positions gParallel.ForEach(mesh.TriangleIndices(), process_triangle); // ok now we filter out all the positions we can't change, as well as vertices that // did not actually move. We also queue any edges that moved far enough to fall // under min/max edge length thresholds gParallel.ForEach(mesh.VertexIndices(), (vID) => { vModifiedV[vID] = false; if (vBufferVWeights[vID] < MathUtil.ZeroTolerance) { return; } if (vertex_is_constrained(vID)) { return; } if (VertexControlF != null && (VertexControlF(vID) & VertexControl.NoProject) != 0) { return; } Vector3d curpos = mesh.GetVertex(vID); Vector3d projPos = vBufferV[vID] / vBufferVWeights[vID]; if (curpos.EpsilonEqual(projPos, MathUtil.ZeroTolerancef)) { return; } vModifiedV[vID] = true; vBufferV[vID] = projPos; foreach (int eid in mesh.VtxEdgesItr(vID)) { Index2i ev = Mesh.GetEdgeV(eid); int othervid = (ev.a == vID) ? ev.b : ev.a; Vector3d otherv = mesh.GetVertex(othervid); double old_len = curpos.Distance(otherv); double new_len = projPos.Distance(otherv); if (new_len < MinEdgeLength || new_len > MaxEdgeLength) { queue_edge_safe(eid); } } }); // update vertices ApplyVertexBuffer(true); }
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); // step 1: find radius in plane 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); } 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); 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("DrawPrimitivesTool.UpdateDraw_Ray - type not supported"); } }
/// <summary> /// This is the action we give to the trim-scan tool, to run on accept /// </summary> public static void CropScanFromSelection(DMeshSO so, MeshFaceSelection selection, object tool) { DMesh3 beforeMesh = new DMesh3(so.Mesh); DMesh3 mesh = so.Mesh; // [RMS] if we are using the two-point tool, then we can use the user input points to // try to figure out an up axis, by assuming the first point is on the base of the scan. Steps are: // 1) guess a midpoint. Currently centroid of upper-half of geodesic selection. // 2) construct up axis as (midpoint-basepoint). this axis to Y-up. Vector3f upAxisS = Vector3f.AxisY; TwoPointFaceSelectionTool ptool = tool as TwoPointFaceSelectionTool; if (ptool != null) { var cache = ptool.SelectionCache; Interval1d range = new Interval1d(cache.CurrentScalarThreshold / 2, cache.CurrentScalarThreshold); List <int> triangles = new List <int>(selection.Count); cache.FindTrianglesInScalarInterval(range, triangles); Vector3d c = MeshMeasurements.Centroid(triangles, mesh.GetTriCentroid); Vector3d cS = SceneTransforms.ObjectToSceneP(so, c); Vector3d basePosS = ptool.SourcePositionS.Origin; upAxisS = (Vector3f)(cS - basePosS).Normalized; } // crop scan and fill top hole List <int> borderTris = selection.FindBorderTris(); MeshEditor editor = new MeshEditor(mesh); editor.RemoveTriangles((tid) => { return(selection.IsSelected(tid) == false); }, true); if (OGActions.FillHoleInScan) { SmoothedHoleFill fill = new SmoothedHoleFill(mesh) { TargetEdgeLength = 2.5f, SmoothAlpha = 0.5f, BorderHintTris = borderTris, OffsetDirection = SceneTransforms.SceneToObjectN(so, upAxisS), OffsetDistance = (ptool != null) ? 25.0 : 0.0 }; fill.Apply(); } so.NotifyMeshEdited(); DMesh3 afterMesh = new DMesh3(so.Mesh); so.GetScene().History.PushChange(new ReplaceEntireMeshChange(so, beforeMesh, afterMesh), true); mesh = so.Mesh; // Now we auto-align the scan so it points upwards, and then // recenter pivot and shift to above ground plane if (ptool != null) { Vector3d basePosS = ptool.SourcePositionS.Origin; Quaternionf alignUp = Quaternionf.FromTo(upAxisS, Vector3f.AxisY); // rotate part so that axis points up Frame3f curF = so.GetLocalFrame(CoordSpace.SceneCoords); Frame3f newF = curF.Rotated(alignUp); TransformSOChange alignUpChange = new TransformSOChange(so, curF, newF, CoordSpace.SceneCoords); basePosS = newF.FromFrameP(curF.ToFrameP(basePosS)); // map to new frame so.GetScene().History.PushChange(alignUpChange, false); // recenter pivot at bbox center // [RMS] previously was using vertex centroid, but this is then affected by mesh density // (maybe tri centroid? but bbox makes more sense...and below we assume box center) Vector3d centerL = mesh.CachedBounds.Center; Vector3d centerO = newF.FromFrameP(centerL); Frame3f newPivotO = new Frame3f(centerO); so.GetScene().History.PushChange(new RepositionPivotChangeOp(newPivotO, so), false); // position above ground plane AxisAlignedBox3d bounds = so.Mesh.CachedBounds; float h = (float)bounds.Height; Vector3f o = newPivotO.Origin; Vector3f translateO = new Vector3f(-o.x, h * 0.5f - o.y + BaseHeightAboveGroundPlaneMM, -o.z); //Vector3f translateO = new Vector3f(0, h * 0.5f - o.y + BaseHeightAboveGroundPlaneMM, 0); newPivotO.Translate(translateO); so.GetScene().History.PushChange(new TransformSOChange(so, newPivotO, CoordSpace.ObjectCoords), false); // save base point in frame of scan basePosS += translateO; Vector3d basePosL = SceneTransforms.SceneToObjectP(so, basePosS); OG.Scan.UserBasePoint = basePosL; } so.GetScene().History.PushInteractionCheckpoint(); }
public void BeginDraw_Spatial(AnyRayHit rayHit, Frame3f handFrame) { BeginDraw_Ray(rayHit); startHandF = handFrame; handHitVec = startHandF.ToFrameP(rayHit.hitPos); }
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); // 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 // step 2: find height from plane float fY = MinDimension; 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); } } else 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 { 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("SnapDrawPrimitivesTool.UpdateDraw_Ray - type not supported"); } }