예제 #1
0
        /// <summary>
        /// Returns true if the ray hits the other ray before the parameter
        /// value contained in the supplied hit. Detailed information about
        /// the hit is returned in the supplied hit.
        /// </summary>
        public bool HitsRay(
            Ray3d ray,
            double tmin, double tmax,
            ref RayHit3d hit
            )
        {
            V3d d = Origin - ray.Origin;
            V3d u = Direction;
            V3d v = ray.Direction;
            V3d n = u.Cross(v);

            if (Fun.IsTiny(d.Length))
            {
                return(true);
            }
            else if (Fun.IsTiny(u.Cross(v).Length))
            {
                return(false);
            }
            else
            {
                //-t0*u + t1*v + t2*n == d
                //M = {-u,v,n}
                //M*{t0,t1,t2}T == d
                //{t0,t1,t2}T == M^-1 * d

                M33d M = new M33d();
                M.C0 = -u;
                M.C1 = v;
                M.C2 = n;

                if (M.Invertible)
                {
                    V3d t = M.Inverse * d;
                    if (Fun.IsTiny(t.Z))
                    {
                        ProcessHits(t.X, double.MaxValue, tmin, tmax, ref hit);
                        return(true);
                    }
                    else
                    {
                        return(false);
                    }
                }
                else
                {
                    return(false);
                }
            }
        }
예제 #2
0
        public static double ComputeUnscaledFormFactor(
            this Polygon3d polygon,
            V3d p, V3d n,
            double eps = 1e-6)
        {
            var vc = polygon.PointCount;

            V3d[] cpa = new V3d[vc + 1];

            var cc = 0;
            var pb = polygon[0] - p;
            var hb = V3d.Dot(pb, n); bool hbp = hb > eps, hbn = hb < -eps;

            if (hb >= -eps)
            {
                cpa[cc++] = pb;
            }
            var p0 = pb; var h0 = hb; var h0p = hbp; var h0n = hbn;

            for (int vi = 1; vi < vc; vi++)
            {
                var  p1 = polygon[vi] - p; var h1 = V3d.Dot(p1, n);
                bool h1p = h1 > eps, h1n = h1 < -eps;
                if (h0p && h1n || h0n && h1p)
                {
                    cpa[cc++] = p0 + (p1 - p0) * (h0 / (h0 - h1));
                }
                if (h1 >= -eps)
                {
                    cpa[cc++] = p1;
                }
                p0 = p1; h0 = h1; h0p = h1p; h0n = h1n;
            }
            if (h0p && hbn || h0n && hbp)
            {
                cpa[cc++] = p0 + (pb - p0) * (h0 / (h0 - hb));
            }

            var cpr = cpa.Map(cc, v => v.Length);

            var    cv = V3d.Cross(cpa[0], cpa[cc - 1]);
            double ff = V3d.Dot(n, cv)
                        * Fun.AcosC(V3d.Dot(cpa[0], cpa[cc - 1])
                                    / (cpr[0] * cpr[cc - 1]))
                        / cv.Length;

            for (int ci = 0; ci < cc - 1; ci++)
            {
                cv  = V3d.Cross(cpa[ci + 1], cpa[ci]);
                ff += V3d.Dot(n, cv)
                      * Fun.AcosC(V3d.Dot(cpa[ci + 1], cpa[ci])
                                  / (cpr[ci + 1] * cpr[ci]))
                      / cv.Length;
            }
            return(ff);
        }
예제 #3
0
        /// <summary>
        /// The geometric center of a 3-dimensional, flat polygon.
        /// WARNING: UNTESTED!
        /// </summary>
        public static V3d ComputeCentroid(this Polygon3d polygon)
        {
            var pc = polygon.PointCount;

            if (pc < 3)
            {
                return(V3d.Zero);
            }
            V3d p0 = polygon[0], p1 = polygon[1];
            V3d e0       = p1 - p0;
            var p2       = polygon[2];
            var e1       = p2 - p0;
            var normal   = e0.Cross(e1);
            var area2    = normal.Length;
            var centroid = area2 * (p0 + p1 + p2);

            p1 = p2; e0 = e1;
            for (int pi = 3; pi < pc; pi++)
            {
                p2 = polygon[pi]; e1 = p2 - p0;
                var n  = e0.Cross(e1);
                var a2 = Fun.Sign(normal.Dot(n)) * n.Length;
                area2    += a2;
                centroid += a2 * (p0 + p1 + p2);
                p1        = p2; e0 = e1;
            }
            if (area2 > Constant <double> .PositiveTinyValue)
            {
                return(centroid * (Constant.OneThird / area2));
            }
            else if (area2 < Constant <double> .NegativeTinyValue)
            {
                return(centroid * (-Constant.OneThird / area2));
            }
            else
            {
                return(V3d.Zero);
            }
        }
예제 #4
0
        /// <summary>
        /// Returns true if the ray hits the triangle within the supplied
        /// parameter interval and before the parameter value contained
        /// in the supplied hit. Detailed information about the hit is
        /// returned in the supplied hit. In order to obtain all potential
        /// hits, the supplied hit can be initialized with RayHit3d.MaxRange.
        /// </summary>
        public bool HitsTriangle(
            V3d p0, V3d p1, V3d p2,
            double tmin, double tmax,
            ref RayHit3d hit
            )
        {
            V3d    edge01 = p1 - p0;
            V3d    edge02 = p2 - p0;
            V3d    plane  = V3d.Cross(Direction, edge02);
            double det    = V3d.Dot(edge01, plane);

            if (det > -0.0000001 && det < 0.0000001)
            {
                return(false);
            }
            // ray ~= paralell / Triangle
            V3d tv = Origin - p0;

            det = 1.0 / det;  // det is now inverse det
            double u = V3d.Dot(tv, plane) * det;

            if (u < 0.0 || u > 1.0)
            {
                return(false);
            }
            plane = V3d.Cross(tv, edge01); // plane is now qv
            double v = V3d.Dot(Direction, plane) * det;

            if (v < 0.0 || u + v > 1.0)
            {
                return(false);
            }
            double t = V3d.Dot(edge02, plane) * det;

            if (t < tmin || t >= tmax || t >= hit.T)
            {
                return(false);
            }
            hit.T        = t;
            hit.Point    = Origin + t * Direction;
            hit.Coord.X  = u; hit.Coord.Y = v;
            hit.BackSide = (det < 0.0);
            return(true);
        }
예제 #5
0
        internal static void AddTriangle(
            BspTreeBuilder builder, int tiMul3, ref BspNode node)
        {
            Triangle3d tr;

            builder.GetTriangleVertexPositions(tiMul3, out tr.P0, out tr.P1, out tr.P2);

            V3d    e0   = tr.P1 - tr.P0;
            V3d    e1   = tr.P2 - tr.P0;
            V3d    n    = V3d.Cross(e0, e1);
            double len2 = n.LengthSquared;

            if (len2 > 0.0)
            {
                AddTriangle(builder, tiMul3, ref tr,
                            n * (1.0 / Math.Sqrt(len2)),
                            ref node);
            }
        }
예제 #6
0
        public void ObjectHitInfo(
            ObjectRayHit hit,
            ref ObjectHitInfo info
            )
        {
            List <V3d> pl = Position3dList;
            int        pi = hit.SetObject.Index * 3;

            info.Points = new V3d[3] {
                pl[pi], pl[pi + 1], pl[pi + 2]
            };
            V3d e01 = info.Points[1] - info.Points[0];
            V3d e02 = info.Points[2] - info.Points[0];

            info.Edges = new V3d[2] {
                e01, e02
            };
            info.Normal = V3d.Cross(e01, e02).Normalized;
        }
예제 #7
0
        /// <summary>
        /// Computes the normal with the length of twice the polygon area as
        /// the sum of  the simple triangulation cross-product normals.
        /// NOTE: This has been tested to be slightly faster and slightly more
        /// accurate than the computation via the 3d Newell normal
        /// (see Math.Tests/GeometryTests, rft 2013-05-04).
        /// </summary>
        public static V3d ComputeDoubleAreaNormal(this Polygon3d polygon)
        {
            var pc = polygon.PointCount;

            if (pc < 3)
            {
                return(V3d.Zero);
            }
            V3d p0     = polygon[0];
            V3d e0     = polygon[1] - p0;
            V3d normal = V3d.Zero;

            for (int pi = 2; pi < pc; pi++)
            {
                var e1 = polygon[pi] - p0;
                normal += e0.Cross(e1);
                e0      = e1;
            }
            return(normal);
        }
예제 #8
0
        public static bool IsLinearCombinationOf(this V3d x, V3d u, V3d v, out double t0, out double t1)
        {
            //x == t2*u + t1*v
            V3d n = u.Cross(v);

            double[,] mat = new double[3, 3]
            {
                { u.X, v.X, n.X },
                { u.Y, v.Y, n.Y },
                { u.Z, v.Z, n.Z }
            };

            double[] result = new double[3] {
                x.X, x.Y, x.Z
            };

            int[] perm = mat.LuFactorize();
            V3d   t    = new V3d(mat.LuSolve(perm, result));

            if (Fun.IsTiny(t.Z))
            {
                t0 = t.X;
                t1 = t.Y;

                return(true);
            }
            else
            {
                t0 = double.NaN;
                t1 = double.NaN;

                return(false);
            }

            //x ==
        }
예제 #9
0
 /// <summary>
 /// Creates a left-handed view trafo, where z-positive points into the scene.
 /// </summary>
 public static Trafo3d ViewTrafoLH(V3d location, V3d up, V3d forward)
 {
     return(Trafo3d.ViewTrafo(location, up.Cross(forward), up, forward));
 }
예제 #10
0
 /// <summary>
 /// Creates a right-handed view trafo, where z-negative points into the scene.
 /// </summary>
 public static Trafo3d ViewTrafoRH(V3d location, V3d up, V3d forward)
 {
     return(Trafo3d.ViewTrafo(location, forward.Cross(up), up, -forward));
 }
예제 #11
0
        // 3-Dimensional

        #region V3d - V3d

        public static bool IsParallelTo(this V3d u, V3d v)
        => Fun.IsTiny(u.Cross(v).Norm1);
예제 #12
0
        public static bool IsLinearCombinationOf(this V3d x, V3d u, V3d v)
        {
            V3d n = u.Cross(v);

            return(n.IsOrthogonalTo(x));
        }
예제 #13
0
 /// <summary>
 /// Creates a right-handed view trafo, where z-negative points into the scene.
 /// </summary>
 public static Trafo3d ViewTrafoRH(V3d location, V3d up, V3d forward)
 => ViewTrafo(location, forward.Cross(up), up, -forward);
예제 #14
0
        public bool HitsCylinder(Cylinder3d cylinder,
                                 double tmin, double tmax,
                                 ref RayHit3d hit)
        {
            var axisDir = cylinder.Axis.Direction.Normalized;

            // Vector Cyl.P0 -> Ray.Origin
            var op = Origin - cylinder.P0;

            // normal RayDirection - CylinderAxis
            var normal     = Direction.Cross(axisDir);
            var unitNormal = normal.Normalized;

            // normal (Vec Cyl.P0 -> Ray.Origin) - CylinderAxis
            var normal2 = op.Cross(axisDir);
            var t       = -normal2.Dot(unitNormal) / normal.Length;

            var radius = cylinder.Radius;

            if (cylinder.DistanceScale != 0)
            {   // cylinder gets bigger, the further away it is
                var pnt = GetPointOnRay(t);

                var dis = V3d.Distance(pnt, this.Origin);
                radius = ((cylinder.Radius / cylinder.DistanceScale) * dis) * 2;
            }

            // between enitre rays (caps are ignored)
            var shortestDistance = Fun.Abs(op.Dot(unitNormal));

            if (shortestDistance <= radius)
            {
                var s = Fun.Abs(Fun.Sqrt(radius.Square() - shortestDistance.Square()) / Direction.Length);

                var t1 = t - s; // first hit of Cylinder shell
                var t2 = t + s; // second hit of Cylinder shell

                if (t1 > tmin && t1 < tmax)
                {
                    tmin = t1;
                }
                if (t2 < tmax && t2 > tmin)
                {
                    tmax = t2;
                }

                hit.T     = t1;
                hit.Point = GetPointOnRay(t1);

                // check if found point is outside of Cylinder Caps
                var bottomPlane  = new Plane3d(cylinder.Circle0.Normal, cylinder.Circle0.Center);
                var topPlane     = new Plane3d(cylinder.Circle1.Normal, cylinder.Circle1.Center);
                var heightBottom = bottomPlane.Height(hit.Point);
                var heightTop    = topPlane.Height(hit.Point);
                // t1 lies outside of caps => find closest cap hit
                if (heightBottom > 0 || heightTop > 0)
                {
                    hit.T = tmax;
                    // intersect with bottom Cylinder Cap
                    var bottomHit = HitsPlane(bottomPlane, tmin, tmax, ref hit);
                    // intersect with top Cylinder Cap
                    var topHit = HitsPlane(topPlane, tmin, tmax, ref hit);

                    // hit still close enough to cylinder axis?
                    var distance = cylinder.Axis.Ray3d.GetMinimalDistanceTo(hit.Point);

                    if (distance <= radius && (bottomHit || topHit))
                    {
                        return(true);
                    }
                }
                else
                {
                    return(true);
                }
            }

            hit.T     = tmax;
            hit.Point = V3d.NaN;
            return(false);
        }
예제 #15
0
        // 3-Dimensional

        #region V3d - V3d

        public static bool IsParallelTo(this V3d u, V3d v)
        {
            return(Fun.IsTiny(u.Cross(v).Norm1));
        }
예제 #16
0
 /// <summary>
 /// Creates a left-handed view trafo, where z-positive points into the scene.
 /// </summary>
 public static Trafo3d ViewTrafoLH(V3d location, V3d up, V3d forward)
 => ViewTrafo(location, up.Cross(forward), up, forward);
예제 #17
0
 /// <summary>
 /// Creates a plane from 3 independent points. A normalized normal
 /// vector is computed and stored.
 /// </summary>
 public Plane3d(V3d p0, V3d p1, V3d p2)
 {
     Normal   = V3d.Cross(p1 - p0, p2 - p0).Normalized;
     Distance = V3d.Dot(Normal, p0);
 }