Пример #1
0
        /// <summary>
        /// Does this ray intersect with the provided face?
        /// </summary>
        /// <param name="face">The Face to intersect with.</param>
        /// <param name="result">The intersection result.</param>
        /// <returns>True if an intersection occurs, otherwise false. If true, check the intersection result for the location of the intersection.</returns>
        internal bool Intersects(Face face, out Vector3 result)
        {
            var plane = face.Plane();

            if (Intersects(plane, out Vector3 intersection))
            {
                var boundaryPolygon      = face.Outer.ToPolygon();
                var voids                = face.Inner?.Select(v => v.ToPolygon())?.ToList();
                var transformToPolygon   = new Transform(plane.Origin, plane.Normal);
                var transformFromPolygon = new Transform(transformToPolygon);
                transformFromPolygon.Invert();
                var transformedIntersection = transformFromPolygon.OfPoint(intersection);
                IEnumerable <(Vector3 from, Vector3 to)> curveList = boundaryPolygon.Edges();
                if (voids != null)
                {
                    curveList = curveList.Union(voids.SelectMany(v => v.Edges()));
                }
                curveList = curveList.Select(l => (transformFromPolygon.OfPoint(l.from), transformFromPolygon.OfPoint(l.to)));

                if (Polygon.Contains(curveList, transformedIntersection, out _))
                {
                    result = intersection;
                    return(true);
                }
            }
            result = default(Vector3);
            return(false);
        }
Пример #2
0
        /// <summary>
        /// Transform a specified segment of this polyline in place.
        /// </summary>
        /// <param name="t">The transform. If it is not within the polygon plane, then an exception will be thrown.</param>
        /// <param name="i">The segment to transform. If it does not exist, then no work will be done.</param>
        /// <param name="isClosed">If set to true, the segment between the start end end point will be considered a valid target.</param>
        /// <param name="isPlanar">If set to true, an exception will be thrown if the resultant shape is no longer planar.</param>
        public void TransformSegment(Transform t, int i, bool isClosed = false, bool isPlanar = false)
        {
            var v = this.Vertices;

            if (i < 0 || i > v.Count)
            {
                // Segment index is out of range, do no work.
                return;
            }

            var candidates = new List <Vector3>(this.Vertices);

            var endIndex = (i + 1) % v.Count;

            candidates[i]        = t.OfPoint(v[i]);
            candidates[endIndex] = t.OfPoint(v[endIndex]);

            // All motion for a triangle results in a planar shape, skip this case.
            var enforcePlanar = v.Count != 3 && isPlanar;

            if (enforcePlanar && !candidates.AreCoplanar())
            {
                throw new Exception("Segment transformation must be within the polygon's plane.");
            }

            this.Vertices = candidates;
        }
Пример #3
0
        /// <summary>
        /// Construct a transformed copy of this Line.
        /// </summary>
        /// <param name="transform">The transform to apply.</param>
        public Line TransformedLine(Transform transform)
        {
            if (transform == null)
            {
                return(this);
            }

            return(new Line(transform.OfPoint(this.Start), transform.OfPoint(this.End)));
        }
Пример #4
0
 /// <summary>
 /// Transform this polygon in place.
 /// </summary>
 /// <param name="t">The transform.</param>
 public void Transform(Transform t)
 {
     for (var i = 0; i < this.Vertices.Count; i++)
     {
         this.Vertices[i] = t.OfPoint(this.Vertices[i]);
     }
 }
Пример #5
0
        /// <summary>
        /// Does this ray intersect with the provided GeometricElement? Only GeometricElements with Solid Representations are currently supported, and voids will be ignored.
        /// </summary>
        /// <param name="element">The element to intersect with.</param>
        /// <param name="result">The list of intersection results.</param>
        /// <returns></returns>
        public bool Intersects(GeometricElement element, out List <Vector3> result)
        {
            if (element.Representation == null || element.Representation.SolidOperations == null || element.Representation.SolidOperations.Count == 0)
            {
                element.UpdateRepresentations();
            }
            List <Vector3> resultsOut           = new List <Vector3>();
            var            transformFromElement = new Transform(element.Transform);

            transformFromElement.Invert();
            var transformToElement = new Transform(element.Transform);
            var transformedRay     = new Ray(transformFromElement.OfPoint(Origin), transformFromElement.OfVector(Direction));
            //TODO: extend to handle voids when void solids in Representations are supported generally
            var intersects = false;

            foreach (var solidOp in element.Representation.SolidOperations.Where(e => !e.IsVoid))
            {
                if (transformedRay.Intersects(solidOp, out List <Vector3> tempResults))
                {
                    intersects = true;
                    resultsOut.AddRange(tempResults.Select(t => transformToElement.OfPoint(t)));
                }
                ;
            }
            result = resultsOut;
            return(intersects);
        }
Пример #6
0
        /// <summary>
        /// Does this ray intersect with the provided GeometricElement? Only GeometricElements with Solid Representations are currently supported, and voids will be ignored.
        /// </summary>
        /// <param name="element">The element to intersect with.</param>
        /// <param name="result">The list of intersection results.</param>
        /// <returns></returns>
        public bool Intersects(GeometricElement element, out List <Vector3> result)
        {
            List <Vector3> resultsOut           = new List <Vector3>();
            var            transformFromElement = new Transform(element.Transform);

            transformFromElement.Invert();
            var transformToElement        = new Transform(element.Transform);
            var transformMinusTranslation = new Transform(transformFromElement);

            // This transform ignores position so it can be used to transform the ray direction vector
            transformMinusTranslation.Move(transformMinusTranslation.Origin.Negate());

            var transformedRay = new Ray(transformFromElement.OfPoint(Origin), transformMinusTranslation.OfVector(Direction));
            //TODO: extend to handle voids when void solids in Representations are supported generally
            var intersects = false;

            foreach (var solidOp in element.Representation.SolidOperations.Where(e => !e.IsVoid))
            {
                if (transformedRay.Intersects(solidOp, out List <Vector3> tempResults))
                {
                    intersects = true;
                    resultsOut.AddRange(tempResults.Select(t => transformToElement.OfPoint(t)));
                }
                ;
            }
            result = resultsOut;
            return(intersects);
        }
Пример #7
0
        internal static Mesh ToMesh(this Tess tess,
                                    Transform transform = null,
                                    Color color         = default,
                                    Vector3 normal      = default)
        {
            var faceMesh = new Mesh();

            (Vector3 U, Vector3 V)basis = (default(Vector3), default(Vector3));

            for (var i = 0; i < tess.ElementCount; i++)
            {
                var a = tess.Vertices[tess.Elements[i * 3]].Position.ToVector3();
                var b = tess.Vertices[tess.Elements[i * 3 + 1]].Position.ToVector3();
                var c = tess.Vertices[tess.Elements[i * 3 + 2]].Position.ToVector3();

                if (transform != null)
                {
                    a = transform.OfPoint(a);
                    b = transform.OfPoint(b);
                    c = transform.OfPoint(c);
                }

                if (i == 0)
                {
                    // Calculate the texture space basis vectors
                    // from the first triangle. This is acceptable
                    // for planar faces.
                    // TODO: Update this when we support non-planar faces.
                    // https://gamedev.stackexchange.com/questions/172352/finding-texture-coordinates-for-plane
                    basis = Tessellation.Tessellation.ComputeBasisAndNormalForTriangle(a, b, c, out Vector3 naturalNormal);
                    if (normal == default)
                    {
                        normal = naturalNormal;
                    }
                }

                var v1 = faceMesh.AddVertex(a, new UV(basis.U.Dot(a), basis.V.Dot(a)), normal, color: color);
                var v2 = faceMesh.AddVertex(b, new UV(basis.U.Dot(b), basis.V.Dot(b)), normal, color: color);
                var v3 = faceMesh.AddVertex(c, new UV(basis.U.Dot(c), basis.V.Dot(c)), normal, color: color);

                faceMesh.AddTriangle(v1, v2, v3);
            }

            return(faceMesh);
        }
Пример #8
0
        /// <summary>
        /// Construct a transformed copy of this Bezier.
        /// </summary>
        /// <param name="transform">The transform to apply.</param>
        public Bezier TransformedBezier(Transform transform)
        {
            var newCtrlPoints = new List <Vector3>();

            foreach (var vp in ControlPoints)
            {
                newCtrlPoints.Add(transform.OfPoint(vp));
            }
            return(new Bezier(newCtrlPoints, this.FrameType));
        }
Пример #9
0
        /// <summary>
        /// Construct a transformed copy of this Polygon.
        /// </summary>
        /// <param name="transform">The transform to apply.</param>
        public Polygon TransformedPolygon(Transform transform)
        {
            var transformed = new Vector3[this.Vertices.Count];

            for (var i = 0; i < transformed.Length; i++)
            {
                transformed[i] = transform.OfPoint(this.Vertices[i]);
            }
            var p = new Polygon(transformed);

            return(p);
        }
Пример #10
0
        /// <summary>
        /// Construct a transformed copy of this Polyline.
        /// </summary>
        /// <param name="transform">The transform to apply.</param>
        public Polyline TransformedPolyline(Transform transform)
        {
            if (transform == null)
            {
                return(this);
            }

            var transformed = new Vector3[this.Vertices.Count];

            for (var i = 0; i < transformed.Length; i++)
            {
                transformed[i] = transform.OfPoint(this.Vertices[i]);
            }
            var p = new Polyline(transformed);

            return(p);
        }
Пример #11
0
        /// <summary>
        /// Does this ray intersect the provided polygon area?
        /// </summary>
        /// <param name="polygon">The Polygon to intersect with.</param>
        /// <param name="result">The intersection result.</param>
        /// <returns>True if an intersection occurs, otherwise false. If true, check the intersection result for the location of the intersection.</returns>
        public bool Intersects(Polygon polygon, out Vector3 result)
        {
            var plane = new Plane(polygon.Vertices.First(), polygon.Vertices);

            if (Intersects(plane, out Vector3 intersection))
            {
                var transformToPolygon   = new Transform(plane.Origin, plane.Normal);
                var transformFromPolygon = new Transform(transformToPolygon);
                transformFromPolygon.Invert();
                var transformedIntersection  = transformFromPolygon.OfPoint(intersection);
                IEnumerable <Line> curveList = polygon.Segments();
                curveList = curveList.Select(l => l.TransformedLine(transformFromPolygon));

                if (Polygon.Contains(curveList, transformedIntersection, out _))
                {
                    result = intersection;
                    return(true);
                }
            }
            result = default(Vector3);
            return(false);
        }
Пример #12
0
 /// <summary>
 /// Construct a transformed copy of this Arc.
 /// </summary>
 /// <param name="transform">The transform to apply.</param>
 public Arc TransformedArc(Transform transform)
 {
     return(new Arc(transform.OfPoint(Center), Radius, StartAngle, EndAngle));
 }
Пример #13
0
        /// <summary>
        /// A mesh sphere.
        /// </summary>
        /// <param name="radius">The radius of the sphere.</param>
        /// <param name="divisions">The number of tessellations of the sphere.</param>
        /// <returns>A mesh.</returns>
        public static Mesh Sphere(double radius, int divisions = 10)
        {
            if (divisions < 2)
            {
                throw new ArgumentException(nameof(divisions), "The number of divisions must be greater than 2.");
            }

            var arc      = new Arc(Vector3.Origin, radius, 0, 180).ToPolyline(divisions);
            var t        = new Transform();
            var vertices = new Vertex[divisions + 1, divisions + 1];
            var mesh     = new Mesh();
            var div      = 360.0 / divisions;

            for (var u = 0; u <= divisions; u++)
            {
                if (u > 0)
                {
                    t.Rotate(Vector3.XAxis, div);
                }

                for (var v = 1; v < divisions; v++)
                {
                    var pt = t.OfPoint(arc.Vertices[v]);

                    var vx = new Vertex(pt)
                    {
                        UV = new UV((double)v / (double)divisions, (double)u / (double)divisions)
                    };
                    vertices[u, v] = vx;
                    mesh.AddVertex(vx);

                    if (u > 0 && v > 1)
                    {
                        var a = vertices[u, v];
                        var b = vertices[u, v - 1];
                        var c = vertices[u - 1, v - 1];
                        var d = vertices[u - 1, v];

                        mesh.AddTriangle(a, b, c);
                        mesh.AddTriangle(a, c, d);
                    }
                }
            }

            var p1 = new Vertex(arc.Start)
            {
                UV = new UV(0, 0)
            };

            var p2 = new Vertex(arc.End)
            {
                UV = new UV(1, 1)
            };

            mesh.AddVertex(p1);
            mesh.AddVertex(p2);

            // Make the end caps separately to manage the singularity
            // at the poles. Attempting to do this in the algorithm above
            // will result in duplicate vertices for every arc section, which
            // is currently illegal in meshes.
            // TODO: This causes spiraling of the UV coordinates at the poles.
            for (var u = 1; u <= divisions; u++)
            {
                mesh.AddTriangle(p1, vertices[u - 1, 1], vertices[u, 1]);
                mesh.AddTriangle(p2, vertices[u, divisions - 1], vertices[u - 1, divisions - 1]);
            }

            mesh.ComputeNormals();

            return(mesh);
        }