Exemple #1
0
 /// <summary>
 /// Creates a view tranformation from the given vectors.
 /// Transformation from world- into view-space.
 /// </summary>
 /// <param name="location">Origin of the view</param>
 /// <param name="right">Right vector of the view-plane</param>
 /// <param name="up">Up vector of the view-plane</param>
 /// <param name="normal">Normal vector of the view-plane. This vector is suppsoed to point in view-direction for a left-handed view transformation and in opposit direction in the right-handed case.</param>
 /// <returns>The view transformation</returns>
 public static M44d ViewTrafo(V3d location, V3d right, V3d up, V3d normal)
 {
     return(new M44d(
                right.X, right.Y, right.Z, -location.Dot(right),
                up.X, up.Y, up.Z, -location.Dot(up),
                normal.X, normal.Y, normal.Z, -location.Dot(normal),
                0, 0, 0, 1
                ));
 }
Exemple #2
0
        /// <summary>
        /// Returns true if the ray hits the sphere given by center and
        /// radius within the supplied parameter interval and before the
        /// parameter value contained in the supplied hit. Note that a
        /// hit is only registered if the front or the backsurface is
        /// encountered within the interval.
        /// </summary>
        public bool HitsSphere(
            V3d center, double radius,
            double tmin, double tmax,
            ref RayHit3d hit)
        {
            V3d    originSubCenter = Origin - center;
            double a = Direction.LengthSquared;
            double b = Direction.Dot(originSubCenter);
            double c = originSubCenter.LengthSquared - radius * radius;

            // --------------------- quadric equation : a t^2  + 2b t + c = 0
            double d = b * b - a * c;                     // factor 2 was eliminated

            if (d < Constant <double> .PositiveTinyValue) // no root ?
            {
                return(false);                            // then exit
            }
            if (b > 0.0)                                  // stable way to calculate
            {
                d = -Fun.Sqrt(d) - b;                     // the roots of a quadratic
            }
            else                                          // equation
            {
                d = Fun.Sqrt(d) - b;
            }

            double t1 = d / a;
            double t2 = c / d;  // Vieta : t1 * t2 == c/a

            return(t1 < t2
                    ? ProcessHits(t1, t2, tmin, tmax, ref hit)
                    : ProcessHits(t2, t1, tmin, tmax, ref hit));
        }
Exemple #3
0
        /// <summary>
        /// Enumerates all vertex indexes at which
        /// both outgoing edges meet at an angle that
        /// is less than the given threshold.
        /// </summary>
        public static IEnumerable <int> GetSpikes(
            this Polygon3d self, double toleranceInDegrees = 0.1)
        {
            if (toleranceInDegrees < 0.0)
            {
                throw new ArgumentOutOfRangeException();
            }
            var threshold = Conversion.RadiansFromDegrees(toleranceInDegrees).Cos();
            var edges     = self.GetEdgeArray();

            edges.Apply(e => e.Normalized);
            var ec = edges.Length;

            if (V3d.Dot(-edges[ec - 1], edges[0]) > threshold)
            {
                yield return(0);
            }
            for (int i = 1; i < ec; i++)
            {
                if (V3d.Dot(-edges[i - 1], edges[i]) > threshold)
                {
                    yield return(i);
                }
            }
        }
Exemple #4
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);
        }
Exemple #5
0
 public static Trafo3d ViewTrafo(V3d location, V3d u, V3d v, V3d z)
 {
     return(new Trafo3d(
                new M44d(
                    u.X, u.Y, u.Z, -V3d.Dot(u, location),
                    v.X, v.Y, v.Z, -V3d.Dot(v, location),
                    z.X, z.Y, z.Z, -V3d.Dot(z, location),
                    0, 0, 0, 1
                    ),
                new M44d(
                    u.X, v.X, z.X, location.X,
                    u.Y, v.Y, z.Y, location.Y,
                    u.Z, v.Z, z.Z, location.Z,
                    0, 0, 0, 1
                    )));
 }
Exemple #6
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);
        }
        /// <summary>
        /// Note, that the parallel implementation of this method could be
        /// optimized, by providing separate node types for parallel and non
        /// parallel execution.
        /// </summary>
        internal void SortBackToFront(
            BspTree t, TargetArrays target,
            int ti, V3d eye, bool mainTask, Action <Action> runChild)
        {
            int    nti    = ti;
            double height = V3d.Dot(m_normal, eye - m_point);

            if (height >= 0.0)
            {
                ti += m_negativeCount;
                var ti3 = ti * 3;
                foreach (int oti in m_zeroList)
                {
                    t.GetTriangleVertexIndices(oti * 3,
                                               out target.Via[ti3],
                                               out target.Via[ti3 + 1],
                                               out target.Via[ti3 + 2]);
                    ti3           += 3;
                    target.Aia[ti] = (t.m_triangleAttributeIndexArray != null) ? t.m_triangleAttributeIndexArray[oti] : 0;
                    ti++;
                }
            }
            else
            {
                nti += m_positiveCount;
                var nti3 = nti * 3;
                foreach (int oti in m_zeroList)
                {
                    t.GetTriangleVertexIndices(oti * 3,
                                               out target.Via[nti3],
                                               out target.Via[nti3 + 1],
                                               out target.Via[nti3 + 2]);
                    nti3           += 3;
                    target.Aia[nti] = (t.m_triangleAttributeIndexArray != null) ? t.m_triangleAttributeIndexArray[oti] : 0;
                    nti++;
                }
            }
            if (m_negativeTree != null)
            {
                if (mainTask && m_negativeCount < c_taskChunkSize)
                {
                    target.Finished.AddCount(1);
                    runChild(() =>
                    {
                        m_negativeTree.SortBackToFront(
                            t, target, nti, eye, false, runChild);
                        target.Finished.Signal();
                    });
                }
                else
                {
                    m_negativeTree.SortBackToFront(
                        t, target, nti, eye, mainTask, runChild);
                }
            }
            if (m_positiveTree != null)
            {
                if (mainTask && m_positiveCount < c_taskChunkSize)
                {
                    target.Finished.AddCount(1);
                    runChild(() =>
                    {
                        m_positiveTree.SortBackToFront(
                            t, target, ti, eye, false, runChild);
                        target.Finished.Signal();
                    });
                }
                else
                {
                    m_positiveTree.SortBackToFront(
                        t, target, ti, eye, mainTask, runChild);
                }
            }
        }
Exemple #8
0
 /// <summary>
 /// The signed height of the supplied point over the plane.
 /// </summary>
 public double Height(V3d p)
 {
     return(V3d.Dot(Normal, p) - Distance);
 }
        // 3-Dimensional

        #region V3d - V3d

        public static bool IsOrthogonalTo(this V3d u, V3d v) => Fun.IsTiny(u.Dot(v));
Exemple #10
0
 /// <summary>
 /// The signed height of the supplied point over the plane.
 /// </summary>
 public double Height(V3d p)
 {
     return(V3d.Dot(Normal, p - Point));
 }
Exemple #11
0
        public NormalsClustering(V3d[] normalArray, double delta)
        {
            var count = normalArray.Length;

            Alloc(count);
            var ca     = m_indexArray;
            var sa     = new int[count].Set(1);
            var suma   = SumArray;
            var kdTree = normalArray.CreateRkdTreeDistDotProduct(0);
            var query  = kdTree.CreateClosestToPointQuery(delta, 0);

            for (int i = 0; i < count; i++)
            {
                int ci = ca[i]; if (ca[ci] != ci)
                {
                    do
                    {
                        ci = ca[ci];
                    } while (ca[ci] != ci); ca[i] = ci;
                }
                int si         = sa[ci];
                V3d avgNormali = suma[ci].Normalized;

                kdTree.GetClosest(query, avgNormali);
                kdTree.GetClosest(query, avgNormali.Negated);

                foreach (var id in query.List)
                {
                    int j  = (int)id.Index;
                    int cj = ca[j]; if (ca[cj] != cj)
                    {
                        do
                        {
                            cj = ca[cj];
                        } while (ca[cj] != cj); ca[j] = cj;
                    }
                    if (ci == cj)
                    {
                        continue;
                    }

                    int    sj         = sa[cj];
                    V3d    avgNormalj = suma[cj].Normalized;
                    double avgDot     = avgNormali.Dot(avgNormalj);
                    if (avgDot.Abs() < 1.0 - 2.0 * delta)
                    {
                        continue;
                    }

                    V3d sum = suma[ci] + (avgDot > 0 ? suma[cj] : suma[cj].Negated);
                    if (si < sj)
                    {
                        ca[ci] = cj; ca[i] = cj; ci = cj;
                    }
                    else
                    {
                        ca[cj] = ci; ca[j] = ci;
                    }
                    si += sj; sa[ci] = si; suma[ci] = sum;
                }
                query.Clear();
            }
            Init();
        }
Exemple #12
0
        /// <summary>
        /// Projets the given point x perpendicular on the plane
        /// and returns the nearest point on the plane.
        /// </summary>
        public V3d NearestPoint(V3d x)
        {
            var p = Point;

            return(x - Normal.Dot(x - p) * Normal);
        }
Exemple #13
0
 /// <summary>
 /// The signed height of the supplied point over the plane.
 /// </summary>
 public double Height(V3d p) => V3d.Dot(Normal, p - Point);
Exemple #14
0
 /// <summary>
 /// Creates plane from point and normal vector. IMPORTANT: The
 /// supplied vector has to be normalized in order for all methods
 /// to work correctly, however if only relative height computations
 /// using the <see cref="Height"/> method are necessary, the normal
 /// vector need not be normalized.
 /// </summary>
 public Plane3d(V3d normalizedNormal, V3d point)
 {
     Normal   = normalizedNormal;
     Distance = V3d.Dot(normalizedNormal, point);
 }
        internal void SortFrontToBack(
            BspTree t, TargetArray via,
            int ti3, V3d eye, bool mainTask, Action <Action> runChild)
        {
            int    nti3   = ti3;
            double height = V3d.Dot(m_normal, eye - m_point);

            if (height < 0.0)
            {
                ti3 += m_negativeCount;
                foreach (int tiMul3 in m_zeroList)
                {
                    t.GetTriangleVertexIndices(tiMul3,
                                               out via.Via[ti3],
                                               out via.Via[ti3 + 1],
                                               out via.Via[ti3 + 2]);
                    ti3 += 3;
                }
            }
            else
            {
                nti3 += m_positiveCount;
                foreach (int tiMul3 in m_zeroList)
                {
                    t.GetTriangleVertexIndices(tiMul3,
                                               out via.Via[nti3],
                                               out via.Via[nti3 + 1],
                                               out via.Via[nti3 + 2]);
                    nti3 += 3;
                }
            }
            if (m_positiveTree != null)
            {
                if (mainTask && m_positiveCount < c_taskChunkSize)
                {
                    via.Finished.AddCount(1);
                    runChild(() =>
                    {
                        m_positiveTree.SortFrontToBack(
                            t, via, ti3, eye, false, runChild);
                        via.Finished.Signal();
                    });
                }
                else
                {
                    m_positiveTree.SortFrontToBack(
                        t, via, ti3, eye, mainTask, runChild);
                }
            }
            if (m_negativeTree != null)
            {
                if (mainTask && m_negativeCount < c_taskChunkSize)
                {
                    via.Finished.AddCount(1);
                    runChild(() =>
                    {
                        m_negativeTree.SortFrontToBack(
                            t, via, nti3, eye, false, runChild);
                        via.Finished.Signal();
                    });
                }
                else
                {
                    m_negativeTree.SortFrontToBack(
                        t, via, nti3, eye, mainTask, runChild);
                }
            }
        }
        internal void AddTriangle(
            BspTreeBuilder builder, int tiMul3, ref Triangle3d tr, V3d normal)
        {
            var htr = (V3d.Dot(m_normal, tr.P0 - m_point),
                       V3d.Dot(m_normal, tr.P1 - m_point),
                       V3d.Dot(m_normal, tr.P2 - m_point));
            var signs = new[] { htr.Item1, htr.Item2, htr.Item3 }.AggregateSigns(builder.m_absoluteEpsilon);

            if (signs == Signs.Zero)
            {
                m_zeroList.Add(tiMul3);
            }
            else if ((signs & Signs.Negative) == Signs.None)
            {
                AddTriangle(builder, tiMul3, ref tr, normal, ref m_positiveTree);
            }
            else if ((signs & Signs.Positive) == Signs.None)
            {
                AddTriangle(builder, tiMul3, ref tr, normal, ref m_negativeTree);
            }
            else
            {
                // the triangle straddles the separating plane

                var    positivePoints = new List <BspSplitPoint>(4);
                var    negativePoints = new List <BspSplitPoint>(4);
                V3d    firstPoint     = tr.P0;
                double firstHeight    = htr.Item1;
                bool   firstPositive  = firstHeight > 0.0;

                if (firstPositive)
                {
                    positivePoints.Add(new BspSplitPoint(firstPoint, 0, 0.0));
                }
                else
                {
                    negativePoints.Add(new BspSplitPoint(firstPoint, 0, 0.0));
                }

                V3d    startPoint    = firstPoint;
                double startHeight   = firstHeight;
                bool   startPositive = firstPositive;

                int start = 0;
                int end   = 1;

                while (end < 3)
                {
                    V3d    endPoint    = tr[end];
                    double endHeight   = htr.Get(end);
                    bool   endPositive = endHeight > 0.0;

                    if (startPositive != endPositive)
                    {
                        V3d    direction = endPoint - startPoint;
                        double t         = -startHeight / V3d.Dot(m_normal,
                                                                  direction);
                        V3d newPoint = startPoint + t * direction;

                        // note, that the same split point (reference!) is
                        // added to both lists!

                        var sp = new BspSplitPoint(newPoint, start, t);
                        positivePoints.Add(sp);
                        negativePoints.Add(sp);
                    }

                    if (endPositive)
                    {
                        positivePoints.Add(new BspSplitPoint(endPoint, end, 0.0));
                    }
                    else
                    {
                        negativePoints.Add(new BspSplitPoint(endPoint, end, 0.0));
                    }

                    start         = end;
                    startPoint    = endPoint;
                    startHeight   = endHeight;
                    startPositive = endPositive;
                    end++;
                }
                if (startPositive != firstPositive)
                {
                    V3d    direction = firstPoint - startPoint;
                    double t         = -startHeight / V3d.Dot(m_normal,
                                                              direction);
                    V3d newPoint = startPoint + t * direction;

                    var sp = new BspSplitPoint(newPoint, start, t);
                    positivePoints.Add(sp);
                    negativePoints.Add(sp);
                }

                // in order to ensure that all fragments of a triangle are
                // consecutively stored, we walk through the two point lists
                // twice. for this we need a store of the triangle indices

                int[] positiveIndices = new int[2];
                int[] negativeIndices = new int[2];

                // first pass: generate the cloned triangles (fragments) and
                // the resulting triangle indices

                if (positivePoints.Count > 2)
                {
                    for (int i = 1; i < positivePoints.Count - 1; i++)
                    {
                        positiveIndices[i - 1] = builder.AddClonedTriangle(tiMul3,
                                                                           positivePoints[0],
                                                                           positivePoints[i],
                                                                           positivePoints[i + 1]);
                    }
                }
                if (negativePoints.Count > 2)
                {
                    for (int i = 1; i < negativePoints.Count - 1; i++)
                    {
                        negativeIndices[i - 1] = builder.AddClonedTriangle(tiMul3,
                                                                           negativePoints[0],
                                                                           negativePoints[i],
                                                                           negativePoints[i + 1]);
                    }
                }

                // second pass: add the fragments (with the triangle
                // indices) to the BSP-tree

                if (positivePoints.Count > 2)
                {
                    for (int i = 0; i < positivePoints.Count - 2; i++)
                    {
                        AddTriangle(builder, positiveIndices[i], ref m_positiveTree);
                    }
                }
                if (negativePoints.Count > 2)
                {
                    for (int i = 0; i < negativePoints.Count - 2; i++)
                    {
                        AddTriangle(builder, negativeIndices[i], ref m_negativeTree);
                    }
                }
            }
        }
Exemple #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);
 }
Exemple #18
0
        // 3-Dimensional

        #region V3d - V3d

        public static bool IsOrthogonalTo(this V3d u, V3d v)
        {
            return(Fun.IsTiny(u.Dot(v)));
        }
Exemple #19
0
 /// <summary>
 /// The signed height of the supplied point over the plane.
 /// </summary>
 public double Height(V3d p) => V3d.Dot(Normal, p) - Distance;