コード例 #1
0
        /// <summary>
        ///   Reassign points based on the new faces added by ConstructCone().
        ///
        ///   Only points that were previous assigned to a removed face need to
        ///   be updated, so check litFaces while looping through the open set.
        ///
        ///   There is a potential optimization here: there's no reason to loop
        ///   through the entire openSet here. If each face had it's own
        ///   openSet, we could just loop through the openSets in the removed
        ///   faces. That would make the loop here shorter.
        ///
        ///   However, to do that, we would have to juggle A LOT more List<CurveParameter>'s,
        ///   and we would need an object pool to manage them all without
        ///   generating a whole bunch of garbage. I don't think it's worth
        ///   doing that to make this loop shorter, a straight for-loop through
        ///   a list is pretty darn fast. Still, it might be worth trying
        /// </summary>
        private void ReassignPoints(List <Point3> points)
        {
            for (int i = 0; i <= _openSetTail; i++)
            {
                PointFace fp = _openSet[i];

                if (_litFaces.Contains(fp.Face))
                {
                    bool    assigned = false;
                    Vector3 point    = points[fp.Point];

                    foreach (KeyValuePair <int, Face> kvp in _faces)
                    {
                        int  fi   = kvp.Key;
                        Face face = kvp.Value;

                        double dist = PointFaceDistance(
                            point,
                            points[face.Vertex0],
                            face);

                        if (dist > EPSILON)
                        {
                            assigned = true;

                            fp.Face     = fi;
                            fp.Distance = dist;

                            _openSet[i] = fp;
                            break;
                        }
                    }

                    if (!assigned)
                    {
                        // If point hasn't been assigned, then it's inside the
                        // convex hull. Swap it with openSetTail, and decrement
                        // openSetTail. We also have to decrement i, because
                        // there's now a new thing in openSet[i], so we need i
                        // to remain the same the next iteration of the loop.
                        fp.Face     = INSIDE;
                        fp.Distance = double.NaN;

                        _openSet[i]            = _openSet[_openSetTail];
                        _openSet[_openSetTail] = fp;

                        i--;
                        _openSetTail--;
                    }
                }
            }
        }
コード例 #2
0
ファイル: ConvexHull.cs プロジェクト: HaiwenLi/Genuage
            void ReassignPoints()
            {
                for (int i = 0; i <= openSetTail; i++)
                {
                    PointFace pf = openSet[i];
                    if (litFaces.Contains(pf.Face))
                    {
                        bool    assigned = false;
                        Vector3 point    = positionList[pf.Point];

                        foreach (var kvp in faces)
                        {
                            var fi   = kvp.Key;
                            var face = kvp.Value;

                            float dist = PointFaceDistance(point, positionList[face.Vertex0], face);

                            if (dist > EPSILON)
                            {
                                assigned    = true;
                                pf.Face     = fi;
                                pf.Distance = dist;
                                openSet[i]  = pf;
                                break;
                            }
                        }

                        if (!assigned)
                        {
                            pf.Face     = INSIDE;
                            pf.Distance = float.NaN;

                            openSet[i]           = openSet[openSetTail];
                            openSet[openSetTail] = pf;

                            i--;
                            openSetTail--;
                        }
                    }
                }
            }
コード例 #3
0
ファイル: ConvexHull.cs プロジェクト: HaiwenLi/Genuage
            public Mesh CreateMesh()
            {
                Assert.IsTrue(pointList.Count >= 4);
                if (pointList.Count == 4)
                {
                    initializeHull();
                    //assign each point to a specific face, unless they are inside the hull.
                    for (int i = 0; i < openSet.Count; i++)
                    {
                        PointFace pf = openSet[i];

                        bool assigned = false;
                        for (int j = 0; j < 4; j++)
                        {
                            Face  face = faces[j];
                            float dist = PointFaceDistance(positionList[pf.Point], positionList[face.Vertex0], face);

                            if (dist > 0)
                            {
                                pf.Face     = j;
                                pf.Distance = dist;
                                openSet[i]  = pf;
                                assigned    = true;
                                break;
                            }
                        }
                        if (!assigned)
                        {
                            pf.Face     = INSIDE;
                            pf.Distance = float.NaN;
                        }
                    }
                }

                if (pointList.Count > 4)
                {
                    initializeHull();

                    openSetTail = openSet.Count - 5;
                    Assert.IsTrue(openSet.Count == pointList.Count);

                    for (int k = 0; k <= openSetTail; k++)
                    {
                        bool      assigned = false;
                        PointFace pf       = openSet[k];
                        for (int i = 0; i < faces.Count; i++)
                        {
                            Face face     = faces[i];
                            var  distance = PointFaceDistance(positionList[pf.Point], positionList[face.Vertex0], face);
                            if (distance > EPSILON)
                            {
                                pf.Face     = i;
                                pf.Distance = distance;
                                openSet[k]  = pf;
                                assigned    = true;
                                break;
                            }
                        }

                        if (!assigned)
                        {
                            pf.Face     = INSIDE;
                            pf.Distance = float.NaN;

                            openSet[k]           = openSet[openSetTail];
                            openSet[openSetTail] = pf;

                            openSetTail -= 1;
                            k--;
                        }
                    }
                    while (openSetTail >= 0)
                    {
                        int   farthestPoint = 0;
                        float dist          = openSet[0].Distance;

                        for (int l = 1; l <= openSetTail; l++)
                        {
                            if (openSet[l].Distance > dist)
                            {
                                farthestPoint = l;
                                dist          = openSet[l].Distance;
                            }
                        }

                        FindHorizon(positionList, positionList[openSet[farthestPoint].Point], openSet[farthestPoint].Face, faces[openSet[farthestPoint].Face]);

                        ConstructCone(openSet[farthestPoint].Point);

                        ReassignPoints();
                    }
                }

                Mesh mesh = ExportMesh();

                return(mesh);
            }
コード例 #4
0
        /// <summary>
        ///   Create initial seed hull.
        /// </summary>
        private void GenerateInitialHull(List <Point3> points)
        {
            // Find points suitable for use as the seed hull. Some varieties of
            // this algorithm pick extreme points here, but I'm not convinced
            // you gain all that much from that. Currently what it does is just
            // find the first four points that are not coplanar.
            FindInitialHullIndices(points, out int b0, out int b1, out int b2, out int b3);

            Vector3 v0 = points[b0];
            Vector3 v1 = points[b1];
            Vector3 v2 = points[b2];
            Vector3 v3 = points[b3];

            bool above = Vector3.DotProduct(v3 - v1, Vector3.CrossProduct(v1 - v0, v2 - v0)) > 0.0f;

            // Create the faces of the seed hull. You need to draw a diagram
            // here, otherwise it's impossible to know what's going on :)

            // Basically: there are two different possible start-tetrahedrons,
            // depending on whether the fourth point is above or below the base
            // triangle. If you draw a tetrahedron with these coordinates (in a
            // right-handed coordinate-system):

            //   b0 = (0,0,0)
            //   b1 = (1,0,0)
            //   b2 = (0,1,0)
            //   b3 = (0,0,1)

            // you can see the first case (set b3 = (0,0,-1) for the second
            // case). The faces are added with the proper references to the
            // faces opposite each vertex

            _faceCount = 0;
            if (above)
            {
                _faces[_faceCount++] = new Face(b0, b2, b1, 3, 1, 2, Normal(points[b0], points[b2], points[b1]));
                _faces[_faceCount++] = new Face(b0, b1, b3, 3, 2, 0, Normal(points[b0], points[b1], points[b3]));
                _faces[_faceCount++] = new Face(b0, b3, b2, 3, 0, 1, Normal(points[b0], points[b3], points[b2]));
                _faces[_faceCount++] = new Face(b1, b2, b3, 2, 1, 0, Normal(points[b1], points[b2], points[b3]));
            }
            else
            {
                _faces[_faceCount++] = new Face(b0, b1, b2, 3, 2, 1, Normal(points[b0], points[b1], points[b2]));
                _faces[_faceCount++] = new Face(b0, b3, b1, 3, 0, 2, Normal(points[b0], points[b3], points[b1]));
                _faces[_faceCount++] = new Face(b0, b2, b3, 3, 1, 0, Normal(points[b0], points[b2], points[b3]));
                _faces[_faceCount++] = new Face(b1, b3, b2, 2, 0, 1, Normal(points[b1], points[b3], points[b2]));
            }

            VerifyFaces(points);

            // Create the openSet. Add all points except the points of the seed
            // hull.
            for (int i = 0; i < points.Count; i++)
            {
                if (i == b0 || i == b1 || i == b2 || i == b3)
                {
                    continue;
                }

                _openSet.Add(new PointFace(i, UNASSIGNED, 0.0f));
            }

            // Add the seed hull verts to the tail of the list.
            _openSet.Add(new PointFace(b0, INSIDE, double.NaN));
            _openSet.Add(new PointFace(b1, INSIDE, double.NaN));
            _openSet.Add(new PointFace(b2, INSIDE, double.NaN));
            _openSet.Add(new PointFace(b3, INSIDE, double.NaN));

            // Set the openSetTail value. Last item in the array is
            // openSet.Count - 1, but four of the points (the verts of the seed
            // hull) are part of the closed set, so move openSetTail to just
            // before those.
            _openSetTail = _openSet.Count - 5;

            Assert(_openSet.Count == points.Count);

            // Assign all points of the open set. This does basically the same
            // thing as ReassignPoints()
            for (int i = 0; i <= _openSetTail; i++)
            {
                Assert(_openSet[i].Face == UNASSIGNED);
                Assert(_openSet[_openSetTail].Face == UNASSIGNED);
                Assert(_openSet[_openSetTail + 1].Face == INSIDE);

                bool      assigned = false;
                PointFace fp       = _openSet[i];

                Assert(_faces.Count == 4);
                Assert(_faces.Count == _faceCount);
                for (int j = 0; j < 4; j++)
                {
                    Assert(_faces.ContainsKey(j));

                    Face face = _faces[j];

                    double dist = PointFaceDistance(points[fp.Point], points[face.Vertex0], face);

                    if (dist > 0)
                    {
                        fp.Face     = j;
                        fp.Distance = dist;
                        _openSet[i] = fp;

                        assigned = true;
                        break;
                    }
                }

                if (!assigned)
                {
                    // Point is inside
                    fp.Face     = INSIDE;
                    fp.Distance = double.NaN;

                    // Point is inside seed hull: swap point with tail, and move
                    // openSetTail back. We also have to decrement i, because
                    // there's a new item at openSet[i], and we need to process
                    // it next iteration
                    _openSet[i]            = _openSet[_openSetTail];
                    _openSet[_openSetTail] = fp;

                    _openSetTail -= 1;
                    i            -= 1;
                }
            }

            VerifyOpenSet(points);
        }