Example #1
0
        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);
        }
Example #3
0
        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);
                }
            }
        }
Example #4
0
        // [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);
        }
Example #5
0
        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");
            }
        }
Example #6
0
        /// <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();
        }
Example #7
0
 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");
            }
        }