示例#1
0
        public virtual Point3 ClosestPoint(Point3 point)
        {
            double t       = Analyze.Curve.ClosestParameter(this, point);
            Point3 pointAt = Evaluate.Curve.PointAt(this, t);

            return(Point4.PointDehomogenizer(pointAt));
        }
示例#2
0
        protected NurbsBase(int degree, KnotVector knots, List <Point4> controlPoints)
        {
            if (controlPoints is null)
            {
                throw new ArgumentNullException(nameof(controlPoints));
            }

            if (knots is null)
            {
                throw new ArgumentNullException(nameof(knots));
            }

            if (degree < 1)
            {
                throw new ArgumentException("Degree must be greater than 1!");
            }

            if (knots.Count != controlPoints.Count + degree + 1)
            {
                throw new ArgumentException("Number of controlPoints + degree + 1 must equal knots length!");
            }

            if (!knots.IsValid(degree, controlPoints.Count))
            {
                throw new ArgumentException("Invalid knot format! Should begin with degree + 1 repeats and end with degree + 1 repeats!");
            }

            Weights = Point4.GetWeights(controlPoints);
            Degree  = degree;
            Knots   = knots;
            ControlPointLocations = Point4.PointDehomogenizer1d(controlPoints);
            ControlPoints         = controlPoints;
        }
示例#3
0
        /// <summary>
        /// Initializes a new point by copying coordinates from a four-dimensional point.
        /// The first three coordinates are divided by the last one.
        /// If the W (fourth) dimension of the input point is zero, then it will be discarded.
        /// </summary>
        /// <param name="point">A point.</param>
        public Point3(Point4 point)
        {
            double w = (Math.Abs(point.W - 1.0) > GSharkMath.Epsilon && point.W != 0.0) ? 1.0 / point.W : 1.0;

            X = point.X * w;
            Y = point.Y * w;
            Z = point.Z * w;
        }
示例#4
0
        /// <summary>
        /// Internal constructor used to validate the NURBS surface.
        /// </summary>
        /// <param name="degreeU">The degree in the U direction.</param>
        /// <param name="degreeV">The degree in the V direction.</param>
        /// <param name="knotsU">The knotVector in the U direction.</param>
        /// <param name="knotsV">The knotVector in the V direction.</param>
        /// <param name="controlPts">Two dimensional array of points.</param>
        internal NurbsSurface(int degreeU, int degreeV, KnotVector knotsU, KnotVector knotsV, List <List <Point4> > controlPts)
        {
            if (controlPts == null)
            {
                throw new ArgumentNullException("Control points array connot be null!");
            }
            if (degreeU < 1)
            {
                throw new ArgumentException("DegreeU must be greater than 1!");
            }
            if (degreeV < 1)
            {
                throw new ArgumentException("DegreeV must be greater than 1!");
            }
            if (knotsU == null)
            {
                throw new ArgumentNullException("KnotU cannot be null!");
            }
            if (knotsV == null)
            {
                throw new ArgumentNullException("KnotV cannot be null!");
            }
            if (knotsU.Count != controlPts.Count() + degreeU + 1)
            {
                throw new ArgumentException("Points count + degreeU + 1 must equal knotsU count!");
            }
            if (knotsV.Count != controlPts.First().Count() + degreeV + 1)
            {
                throw new ArgumentException("Points count + degreeV + 1 must equal knotsV count!");
            }
            if (!knotsU.IsValid(degreeU, controlPts.Count()))
            {
                throw new ArgumentException("Invalid knotsU!");
            }
            if (!knotsV.IsValid(degreeV, controlPts.First().Count()))
            {
                throw new ArgumentException("Invalid knotsV!");
            }

            DegreeU = degreeU;
            DegreeV = degreeV;
            KnotsU  = (Math.Abs(knotsU.GetDomain(degreeU).Length - 1.0) > GSharkMath.Epsilon) ? knotsU.Normalize() : knotsU;
            KnotsV  = (Math.Abs(knotsV.GetDomain(degreeV).Length - 1.0) > GSharkMath.Epsilon) ? knotsV.Normalize() : knotsV;
            Weights = Point4.GetWeights2d(controlPts);
            ControlPointLocations = Point4.PointDehomogenizer2d(controlPts);
            ControlPoints         = controlPts;
            DomainU = new Interval(KnotsU.First(), KnotsU.Last());
            DomainV = new Interval(KnotsV.First(), KnotsV.Last());
        }
示例#5
0
        /// <summary>
        /// Defines the NURBS form of the polyline.
        /// </summary>
        private void ToNurbsForm()
        {
            if (_segments.Count == 1)
            {
                Weights = Point4.GetWeights(_segments[0].ControlPoints);
                Degree  = _segments[0].Degree;
                Knots   = _segments[0].Knots;
                ControlPointLocations = Point4.PointDehomogenizer1d(_segments[0].ControlPoints);
                ControlPoints         = _segments[0].ControlPoints;
                return;
            }

            // Extract the biggest degree between the curves.
            int finalDegree = _segments.Max(c => c.Degree);

            // Homogenized degree curves.
            IEnumerable <NurbsBase> homogenizedCurves = _segments.Select(curve => curve.Degree != finalDegree ? Modify.Curve.ElevateDegree(curve, finalDegree) : curve);

            // Join curves.
            List <double> joinedKnots      = new List <double>();
            List <Point4> joinedControlPts = new List <Point4>();

            joinedKnots.AddRange(homogenizedCurves.First().Knots.Take(homogenizedCurves.First().Knots.Count - 1));
            joinedControlPts.AddRange(homogenizedCurves.First().ControlPoints);

            foreach (NurbsBase curve in homogenizedCurves.Skip(1))
            {
                joinedKnots.AddRange(curve.Knots.Take(curve.Knots.Count - 1).Skip(finalDegree + 1).Select(k => k + joinedKnots.Last()).ToList());
                joinedControlPts.AddRange(curve.ControlPoints.Skip(1));
            }

            // Appending the last knot to the end.
            joinedKnots.Add(joinedKnots.Last());

            Weights = Point4.GetWeights(joinedControlPts);
            Degree  = finalDegree;
            Knots   = joinedKnots.ToKnot().Normalize();
            ControlPointLocations = Point4.PointDehomogenizer1d(joinedControlPts);
            ControlPoints         = joinedControlPts;
        }
示例#6
0
        /// <summary>
        /// Creates a surface of revolution through an arbitrary angle, and axis.
        /// <em>Corresponds the algorithm A8.1 of The NURBS Book by Piegl and Tiller.</em>
        /// </summary>
        /// <param name="curveProfile">Profile curve.</param>
        /// <param name="axis">Revolution axis.</param>
        /// <param name="rotationAngle">Angle in radiance.</param>
        /// <returns>The revolution surface.</returns>
        public static NurbsSurface Revolved(NurbsBase curveProfile, Ray axis, double rotationAngle)
        {
            // if angle is less than 90.
            int        arcCount = 1;
            KnotVector knotsU   = Vector.Zero1d(6).ToKnot();

            if (rotationAngle <= Math.PI && rotationAngle > (Math.PI / 2))
            {
                arcCount  = 2;
                knotsU[3] = knotsU[4] = 0.5;
            }

            if (rotationAngle <= (3 * Math.PI / 2) && rotationAngle > Math.PI)
            {
                arcCount  = 3;
                knotsU    = Vector.Zero1d(6 + 2 * (arcCount - 1)).ToKnot();
                knotsU[3] = knotsU[4] = (double)1 / 3;
                knotsU[5] = knotsU[6] = (double)2 / 3;
            }

            if (rotationAngle <= (4 * Math.PI) && rotationAngle > (3 * Math.PI / 2))
            {
                arcCount  = 4;
                knotsU    = Vector.Zero1d(6 + 2 * (arcCount - 1)).ToKnot();
                knotsU[3] = knotsU[4] = (double)1 / 4;
                knotsU[5] = knotsU[6] = (double)1 / 2;
                knotsU[7] = knotsU[8] = (double)3 / 4;
            }

            // load start and end knots.
            int t = 3 + 2 * (arcCount - 1);

            for (int i = 0; i < 3; i++, t++)
            {
                knotsU[i] = 0.0;
                knotsU[t] = 1.0;
            }

            // some initialization.
            double divideAngle = rotationAngle / arcCount;
            int    n           = 2 * arcCount;
            double wm          = divideAngle / 2; // is the base angle.

            // initialize the sines and cosines only once.
            double angle = 0.0;

            double[] sines   = new double[arcCount + 1];
            double[] cosines = new double[arcCount + 1];
            for (int i = 1; i <= arcCount; i++)
            {
                angle     += divideAngle;
                sines[i]   = Math.Sin(angle);
                cosines[i] = Math.Cos(angle);
            }

            // loop and compute each u row of control points and weights.
            List <List <Point4> > controlPts = new List <List <Point4> >();

            for (int r = 0; r < 2 * arcCount + 1; r++)
            {
                List <Point4> temp = CollectionHelpers.RepeatData(Point4.Zero, curveProfile.ControlPoints.Count);
                controlPts.Add(temp);
            }

            for (int j = 0; j < curveProfile.ControlPointLocations.Count; j++)
            {
                Point3  ptO     = axis.ClosestPoint(curveProfile.ControlPointLocations[j]);
                Vector3 vectorX = curveProfile.ControlPointLocations[j] - ptO;
                double  radius  = vectorX.Length; // the radius at that length.
                Vector3 vectorY = Vector3.CrossProduct(axis.Direction, vectorX);

                if (radius > GSharkMath.Epsilon)
                {
                    vectorX *= (1 / radius);
                    vectorY *= (1 / radius);
                }

                // initialize the first control points and weights.
                Point3 pt0 = curveProfile.ControlPointLocations[j];
                controlPts[0][j] = new Point4(pt0, curveProfile.Weights[j]);

                Vector3 tangent0 = vectorY;
                int     index    = 0;

                for (int i = 1; i <= arcCount; i++)
                {
                    // rotated generatrix point.
                    Point3 pt2 = (Math.Abs(radius) < GSharkMath.Epsilon)
                        ? ptO
                        : ptO + (vectorX * (cosines[i] * radius) + vectorY * (sines[i] * radius));

                    controlPts[index + 2][j] = new Point4(pt2, curveProfile.Weights[j]);

                    // construct the vector tangent to the rotation.
                    Vector3 rotationTangent = vectorX * (-1 * sines[i]) + vectorY * cosines[i];

                    // construct the next control point.
                    if (Math.Abs(radius) < GSharkMath.Epsilon)
                    {
                        controlPts[index + 1][j] = ptO;
                    }
                    else
                    {
                        Line ln0 = new Line(pt0, tangent0, tangent0.Length);
                        Line ln1 = new Line(pt2, rotationTangent, rotationTangent.Length);
                        Intersection.Intersect.LineLine(ln0, ln1, out Point3 intersectionPt, out _, out _, out _);
                        controlPts[index + 1][j] = new Point4(intersectionPt, wm * curveProfile.Weights[j]);
                    }

                    index += 2;
                    if (i >= arcCount)
                    {
                        continue;
                    }
                    pt0      = pt2;
                    tangent0 = rotationTangent;
                }
            }

            return(new NurbsSurface(2, curveProfile.Degree, knotsU, curveProfile.Knots, controlPts.Select(pts => pts.ToList()).ToList()));
        }
示例#7
0
        /// <summary>
        /// Constructs a nurbs curve representation of this arc.<br/>
        /// <em>Implementation of Algorithm A7.1 from The NURBS Book by Piegl and Tiller.</em>
        /// </summary>
        /// <returns>A nurbs curve shaped like this arc.</returns>
        internal void ToNurbs()
        {
            Vector3 axisX      = Plane.XAxis;
            Vector3 axisY      = Plane.YAxis;
            double  curveAngle = _domain.Length;
            int     numberOfArc;

            Point3[] pts;
            Point4[] ctrPts;
            double[] weights;

            // Number of arcs.
            double piNum = 0.5 * Math.PI;

            if ((curveAngle - piNum) <= GSharkMath.Epsilon)
            {
                numberOfArc = 1;
                pts         = new Point3[3];
                ctrPts      = new Point4[3];
                weights     = new double[3];
            }
            else if ((curveAngle - piNum * 2) <= GSharkMath.Epsilon)
            {
                numberOfArc = 2;
                pts         = new Point3[5];
                ctrPts      = new Point4[5];
                weights     = new double[5];
            }
            else if ((curveAngle - piNum * 3) <= GSharkMath.Epsilon)
            {
                numberOfArc = 3;
                pts         = new Point3[7];
                ctrPts      = new Point4[7];
                weights     = new double[7];
            }
            else
            {
                numberOfArc = 4;
                pts         = new Point3[9];
                ctrPts      = new Point4[9];
                weights     = new double[9];
            }

            double  detTheta = curveAngle / numberOfArc;
            double  weight   = Math.Cos(detTheta / 2);
            Point3  p0       = Center + (axisX * (Radius * Math.Cos(_domain.T0)) + axisY * (Radius * Math.Sin(_domain.T0)));
            Vector3 t0       = axisY * Math.Cos(_domain.T0) - axisX * Math.Sin(_domain.T0);

            KnotVector knots = new KnotVector(CollectionHelpers.RepeatData(0.0, ctrPts.Length + 3));
            int        index = 0;
            double     angle = _domain.T0;

            pts[0]     = p0;
            ctrPts[0]  = new Point4(p0);
            weights[0] = weight;

            for (int i = 1; i < numberOfArc + 1; i++)
            {
                angle += detTheta;
                Point3 p2 = Center + (axisX * (Radius * Math.Cos(angle)) + axisY * (Radius * Math.Sin(angle)));

                ctrPts[index + 2]  = new Point4(p2);
                pts[index + 2]     = p2;
                weights[index + 2] = 1.0;

                Vector3 t2  = (axisY * Math.Cos(angle)) - (axisX * Math.Sin(angle));
                Line    ln0 = new Line(p0, t0.Unitize() + p0);
                Line    ln1 = new Line(p2, t2.Unitize() + p2);
                Intersect.LineLine(ln0, ln1, out _, out _, out double u0, out _);
                Point3 p1 = p0 + (t0 * u0);

                ctrPts[index + 1]  = new Point4(p1, weight);
                pts[index + 1]     = p1;
                weights[index + 1] = weight;
                index += 2;

                if (i >= numberOfArc)
                {
                    continue;
                }

                p0 = p2;
                t0 = t2;
            }

            int j = 2 * numberOfArc + 1;

            for (int i = 0; i < 3; i++)
            {
                knots[i]     = 0.0;
                knots[i + j] = 1.0;
            }

            switch (numberOfArc)
            {
            case 2:
                knots[3] = knots[4] = 0.5;
                break;

            case 3:
                knots[3] = knots[4] = (double)1 / 3;
                knots[5] = knots[6] = (double)2 / 3;
                break;

            case 4:
                knots[3] = knots[4] = 0.25;
                knots[5] = knots[6] = 0.5;
                knots[7] = knots[8] = 0.75;
                break;
            }

            Weights               = weights.ToList();
            Degree                = 2;
            Knots                 = knots;
            ControlPoints         = ctrPts.ToList();
            ControlPointLocations = pts.ToList();
        }