Beispiel #1
0
        /// <summary>
        /// Try to fit a circle to two curves using tangent relationships.
        /// </summary>
        /// <param name="c1">First curve to touch.</param>
        /// <param name="c2">Second curve to touch.</param>
        /// <param name="t1">Parameter on first curve close to desired solution.</param>
        /// <param name="t2">Parameter on second curve closet to desired solution.</param>
        /// <returns>Valid circle on success, Circle.Unset on failure.</returns>
        /// <since>5.0</since>
        public static Circle TryFitCircleTT(Curve c1, Curve c2, double t1, double t2)
        {
            if (c1 == null)
            {
                throw new ArgumentNullException("c1");
            }
            if (c2 == null)
            {
                throw new ArgumentNullException("c2");
            }
            if (!RhinoMath.IsValidDouble(t1))
            {
                throw new ArgumentNullException("t1");
            }
            if (!RhinoMath.IsValidDouble(t2))
            {
                throw new ArgumentNullException("t2");
            }

            Circle rc = Circle.Unset;

            if (!UnsafeNativeMethods.ON_Circle_TryFitTT(c1.ConstPointer(), c2.ConstPointer(), t1, t2, ref rc))
            {
                rc = Circle.Unset;
            }

            Runtime.CommonObject.GcProtect(c1, c2);
            return(rc);
        }
Beispiel #2
0
        /// <summary>
        /// This is the method that actually does the work.
        /// </summary>
        protected override void SolveInstance(IGH_DataAccess data)
        {
            var x = 0.0;

            if (!data.GetData(0, ref x))
            {
                return;
            }

            if (!RhinoMath.IsValidDouble(x))
            {
                AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "X Value is invalid");
                return;
            }

            var y = 0.0;

            if (!data.GetData(1, ref y))
            {
                return;
            }

            if (!RhinoMath.IsValidDouble(y))
            {
                AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Y Value is invalid");
                return;
            }

            var sum = MooseCommon.Utility.Sum(x, y);

            data.SetData(0, sum);
        }
Beispiel #3
0
        private bool CalculatePlaneAngle(Point3d point)
        {
            if (System.Math.Abs(m_plane.ValueAt(point)) > 0.000001)
            {
                return(false);
            }

            if (m_base_point.DistanceTo(point) <= RhinoMath.ZeroTolerance)
            {
                return(false);
            }

            Vector3d v = point - m_base_point;

            v.Unitize();

            Vector3d zerov = m_ref_point - m_base_point;
            double   r     = zerov.Length;

            zerov.Unitize();

            double dot = zerov * v;

            if (!RhinoMath.IsValidDouble(dot))
            {
                dot = 1.0;
            }
            else if (dot > 1.0)
            {
                dot = 1.0;
            }
            else if (dot < -1.0)
            {
                dot = -1.0;
            }

            double   test_angle = Math.Acos(dot);
            Vector3d zaxis      = Vector3d.CrossProduct(m_plane.XAxis, m_plane.YAxis);

            zaxis.Unitize();

            v = Vector3d.CrossProduct(zaxis, zerov);
            v.Unitize();

            Plane yplane = new Plane(m_base_point, v);

            if (yplane.ValueAt(point) < 0.0)
            {
                test_angle = 2.0 * Math.PI - test_angle;
            }

            m_angle = test_angle;

            Plane arc_plane = new Plane(m_plane.Origin, zerov, v);

            m_arc = new Arc(arc_plane, r, m_angle);

            return(m_arc.IsValid);
        }
Beispiel #4
0
 private void OnFormClosing(object sender, FormClosingEventArgs e)
 {
     if (OnlyNumbers && (e.CloseReason == CloseReason.UserClosing || e.CloseReason == CloseReason.None) && DialogResult == System.Windows.Forms.DialogResult.OK)
     {
         string text = GetText();
         if (!string.IsNullOrEmpty(text))
         {
             double d;
             if (!double.TryParse(text, out d))
             {
                 e.Cancel = true;
                 return;
             }
             if ((RhinoMath.IsValidDouble(MinimumNumberValue) && d < MinimumNumberValue) ||
                 (RhinoMath.IsValidDouble(MaximumNumberValue) && d > MaximumNumberValue))
             {
                 e.Cancel = true;
             }
         }
     }
 }
        private static void ComputeDeviation(Rectangle3d rec, Rhino.Collections.Point3dList pts, out double dev, out double angdev)
        {
            dev = double.MaxValue;
            for (int i = 0; i < 4; i++)
            {
                dev = Math.Min(dev, rec.Corner(i).DistanceTo(pts[i]));
            }

            angdev = double.MaxValue;
            for (int i = 0; i < 4; i++)
            {
                int      j  = (i == 3) ? 0 : i + 1;
                Vector3d re = rec.Corner(i) - rec.Corner(j);
                Vector3d pe = pts[i] - pts[j];
                double   ad = Vector3d.VectorAngle(re, pe);
                if (RhinoMath.IsValidDouble(ad))
                {
                    angdev = Math.Min(angdev, ad);
                }
            }
        }
Beispiel #6
0
        /// <summary>
        /// Try to fit a circle to three curves using tangent relationships.
        /// </summary>
        /// <param name="c1">First curve to touch.</param>
        /// <param name="c2">Second curve to touch.</param>
        /// <param name="c3">Third curve to touch.</param>
        /// <param name="t1">Parameter on first curve close to desired solution.</param>
        /// <param name="t2">Parameter on second curve closet to desired solution.</param>
        /// <param name="t3">Parameter on third curve close to desired solution.</param>
        /// <returns>Valid circle on success, Circle.Unset on failure.</returns>
        public static Circle TryFitCircleTTT(Curve c1, Curve c2, Curve c3, double t1, double t2, double t3)
        {
            if (c1 == null)
            {
                throw new ArgumentNullException("c1");
            }
            if (c2 == null)
            {
                throw new ArgumentNullException("c2");
            }
            if (c3 == null)
            {
                throw new ArgumentNullException("c3");
            }
            if (!RhinoMath.IsValidDouble(t1))
            {
                throw new ArgumentNullException("t1");
            }
            if (!RhinoMath.IsValidDouble(t2))
            {
                throw new ArgumentNullException("t2");
            }
            if (!RhinoMath.IsValidDouble(t3))
            {
                throw new ArgumentNullException("t3");
            }

            Circle rc = Circle.Unset;

            if (!UnsafeNativeMethods.ON_Circle_TryFitTTT(c1.ConstPointer(), c2.ConstPointer(), c3.ConstPointer(), t1, t2, t3, ref rc))
            {
                rc = Circle.Unset;
            }

            return(rc);
        }
Beispiel #7
0
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            if (DA.Iteration > 1)
            {
                AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "超出数据已被忽视");
                return;
            }

            Mesh tm = new Mesh();

            if (!DA.GetData(0, ref tm) && !tm.IsValid)
            {
                return;
            }
            List <Mesh> o = new List <Mesh>(3);

            DA.GetDataList(1, o);
            List <Point3d> pl = new List <Point3d>();

            if (!DA.GetDataList(2, pl))
            {
                return;
            }

            int a = 0;

            if (!DA.GetData(3, ref a))
            {
                return;
            }

            #region 制作网格上用于测量的点阵

            BoundingBox mb = new BoundingBox();
            foreach (Point3f p3f in tm.Vertices)
            {
                mb.Union(new Point3d(p3f));
            }
            double         px   = mb.Min.X;
            double         py   = mb.Min.Y;
            int            rx   = (int)Math.Ceiling((mb.Max.X - px) / a);
            int            ry   = (int)Math.Ceiling((mb.Max.Y - py) / a);
            List <Point3d> grid = new List <Point3d>(rx * ry);
            for (int ix = 0; ix < rx; ix++)
            {
                for (int iy = 0; iy < ry; iy++)
                {
                    Ray3d  ray = new Ray3d(new Point3d(px, py, mb.Min.Z), Vector3d.ZAxis);
                    double pmd = Intersection.MeshRay(tm, ray);
                    if (RhinoMath.IsValidDouble(pmd) && pmd > 0.0)
                    {
                        grid.Add(ray.PointAt(pmd));
                    }
                    py += a;
                }

                px += a;
                py  = mb.Min.Y;
            } //获取网格上点阵制作栅格点阵z射线,与网格相交,交点加入grid

            #endregion

            List <Point3d> pt = new List <Point3d>(pl.Count);

            #region 将观测点投影到地形网格上,并增加眼高

            foreach (Point3d p0 in pl)
            {
                Point3d p = p0;

                Ray3d  rayp = new Ray3d(new Point3d(p.X, p.Y, mb.Min.Z), Vector3d.ZAxis);
                double pmdp = Intersection.MeshRay(tm, rayp);
                if (RhinoMath.IsValidDouble(pmdp) && pmdp > 0.0)
                {
                    p = rayp.PointAt(pmdp);
                }
                else
                {
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Error, $"观测点{p}无法被Z向投影至地形网格上");
                    return;
                }

                p.Z += 1.5; //增加眼高
                pt.Add(p);
            } //采样点

            #endregion

            foreach (Mesh m in o) //将障碍物附加入网格
            {
                tm.Append(m);
            }

            bool[] grib = new bool[grid.Count]; //采样点布尔数组

            foreach (Point3d p in pt)
            {
                if (Environment.ProcessorCount > 2)
                {
                    Parallel.For(0, grid.Count, j => //多线程处理每个采样点
                    {
                        if (!grib[j])                //grib为否(尚未可见)时 判定当前是否为可见点,与网格上的点阵交点仅为1的即可见点
                        {
                            grib[j] = Intersection.MeshLine(tm, new Line(p, grid[j]), out _).Length == 1;
                        }
                    });
                }
                else
                {
                    for (int j = 0; j < grid.Count; j++)
                    {
                        if (!grib[j]) //grib为否(尚未可见)时 判定当前是否为可见点,与网格上的点阵交点仅为1的即可见点
                        {
                            grib[j] = Intersection.MeshLine(tm, new Line(p, grid[j]), out _).Length == 1;
                        }
                    }
                }
            }


            for (int i = grid.Count - 1; i >= 0; i--) //剔除不可见点
            {
                if (!grib[i])
                {
                    grid.RemoveAt(i);
                }
            }


            DA.SetDataList(0, pt);
            DA.SetDataList(1, grid);
        }
Beispiel #8
0
        public Point3d ClosestPoint(Point3d testPoint)
        {
            double t = ClosestParameter(testPoint);

            return(RhinoMath.IsValidDouble(t) ? PointAt(t) : Point3d.Unset);
        }
Beispiel #9
0
        /// <summary>
        /// Test for a curve that is a polyline (or looks like a polyline).
        /// </summary>
        bool IsPolyline(Curve curve, ref int point_count, ref bool bClosed, ref bool bPlanar, ref bool bLength, ref bool bAngle, ref bool bIntersect)
        {
            if (null == curve)
            {
                return(false);
            }

            List <Point3d> points = new List <Point3d>();

            // Is the curve a polyline curve?
            PolylineCurve polyline_curve = curve as PolylineCurve;

            if (null != polyline_curve)
            {
                if (polyline_curve.PointCount <= 2)
                {
                    return(false);
                }

                for (int i = 0; i < polyline_curve.PointCount; i++)
                {
                    points.Add(polyline_curve.Point(i));
                }
            }

            // Is the curve a polycurve that looks like an polyline?
            PolyCurve poly_curve = curve as PolyCurve;

            if (null != poly_curve)
            {
                Polyline polyline;
                if (poly_curve.TryGetPolyline(out polyline))
                {
                    if (polyline.Count <= 2)
                    {
                        return(false);
                    }

                    for (int i = 0; i < polyline.Count; i++)
                    {
                        points.Add(polyline[i]);
                    }
                }
            }

            // Is the curve a NURBS curve that looks like an polyline?
            NurbsCurve nurbs_curve = curve as NurbsCurve;

            if (null != nurbs_curve)
            {
                Polyline polyline;
                if (nurbs_curve.TryGetPolyline(out polyline))
                {
                    if (polyline.Count <= 2)
                    {
                        return(false);
                    }

                    for (int i = 0; i < polyline.Count; i++)
                    {
                        points.Add(polyline[i]);
                    }
                }
            }

            if (0 == points.Count)
            {
                return(false);
            }

            // Is the curve closed?
            bClosed = curve.IsClosed;

            // Is the curve planar?
            bPlanar = curve.IsPlanar();

            // Get the point (vertex) count.
            point_count = (bClosed ? points.Count - 1 : points.Count);

            // Test for self-intersection.
            CurveIntersections intesections = Intersection.CurveSelf(curve, m_tolerance);

            bIntersect = (intesections.Count > 0) ? true : false;

            // If the curve is not closed, no reason to continue...
            if (!bClosed)
            {
                return(true);
            }

            // Test if the distance between each point is identical.
            double distance = 0.0;

            for (int i = 1; i < points.Count; i++)
            {
                Point3d  p0 = points[i - 1];
                Point3d  p1 = points[i];
                Vector3d v  = p0 - p1;

                double d = v.Length;
                if (i == 1)
                {
                    distance = d;
                    continue;
                }
                else if (Math.Abs(distance - d) < m_tolerance)
                {
                    continue;
                }
                else
                {
                    distance = RhinoMath.UnsetValue;
                    break;
                }
            }

            // Set return value.
            bLength = RhinoMath.IsValidDouble(distance);

            // Test if the angle between each point is identical.
            double angle = 0.0;

            for (int i = 1; i < points.Count - 1; i++)
            {
                Point3d p0 = points[i - 1];
                Point3d p1 = points[i];
                Point3d p2 = points[i + 1];

                Vector3d v0 = p1 - p0;
                Vector3d v1 = p1 - p2;

                v0.Unitize();
                v1.Unitize();

                double a = Vector3d.VectorAngle(v0, v1);
                if (i == 1)
                {
                    angle = a;
                    continue;
                }
                else if (Math.Abs(angle - a) < m_angle_tolerance)
                {
                    continue;
                }
                else
                {
                    angle = RhinoMath.UnsetValue;
                    break;
                }
            }

            // Set return value.
            bAngle = RhinoMath.IsValidDouble(angle);

            return(true);
        }
Beispiel #10
0
        SolveResults Compute(Curve crv, List <double> pattern)
        {
            var rc = new SolveResults();

            if (pattern.Count == 0)
            {
                return(null);
            }

            var pattern_length = 0.0;

            for (var i = 0; i < pattern.Count; i++)
            {
                if (pattern[i] < 0.0)
                {
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Dash patterns cannot have negative length segments");
                    pattern[i] = 0.0;
                }
                pattern_length += pattern[i];
            }

            if (pattern_length <= 1e-12)
            {
                AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Total pattern length is too short.");
                return(rc);
            }

            crv = crv.DuplicateCurve();

            var dashes = new List <Curve>();
            var gaps   = new List <Curve>();

            var index = -1;
            var dash  = false;

            while (true)
            {
                //toggle gap/dash flag
                dash = !dash;

                //increment
                index++;

                //limit
                if (index >= pattern.Count)
                {
                    index = 0;
                }

                //get pattern length
                if (Math.Abs(pattern[index]) < 1e-32)
                {
                    if (dash)
                    {
                        dashes.Add(null);
                    }
                    else
                    {
                        gaps.Add(null);
                    }
                }
                else
                {
                    //measure length
                    double length = crv.GetLength();
                    if (!RhinoMath.IsValidDouble(length))
                    {
                        break;
                    }

                    //cut short if we're at the end of the curve
                    if (length <= pattern[index])
                    {
                        if (dash)
                        {
                            dashes.Add(crv);
                        }
                        else
                        {
                            gaps.Add(crv);
                        }
                        break;
                    }

                    //compute normalised arc-length parameter.
                    if (!crv.LengthParameter(pattern[index], out var t))
                    {
                        break;
                    }

                    var segment = crv.Trim(crv.Domain.Min, t);
                    if (segment != null && segment.IsValid)
                    {
                        if (dash)
                        {
                            dashes.Add(segment);
                        }
                        else
                        {
                            gaps.Add(segment);
                        }
                    }

                    crv = crv.Trim(t, crv.Domain.Max);
                    if (crv == null)
                    {
                        break;
                    }
                }
            }

            rc.Dashes = dashes;
            rc.Gaps   = gaps;

            return(rc);
        }
Beispiel #11
0
        public Curve[] AfterOffset(Curve destination, double naN, Plane unset, int num2)
        {
            if (!RhinoMath.IsValidDouble(naN))
            {
                this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "不是有效的数字");
                return(new Curve[] {});
            }
            else if (!unset.IsValid)
            {
                this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "不是有效的平面");
                return(new Curve[] { });
            }
            else
            {
                double num3      = Math.Abs(naN);
                double tolerance = Math.Min(GH_Component.DocumentTolerance(), 0.1 * num3);
                GH_Component.DocumentAngleTolerance();
                num2 = Math.Max(Math.Min(num2, 4), 0);
                if (naN == 0.0)
                {
                    return(new Curve[] { destination });
                }
                else
                {
                    CurveOffsetCornerStyle none = CurveOffsetCornerStyle.None;
                    switch (num2)
                    {
                    case 0:
                        none = CurveOffsetCornerStyle.None;
                        break;

                    case 1:
                        none = CurveOffsetCornerStyle.Sharp;
                        break;

                    case 2:
                        none = CurveOffsetCornerStyle.Round;
                        break;

                    case 3:
                        none = CurveOffsetCornerStyle.Smooth;
                        break;

                    case 4:
                        none = CurveOffsetCornerStyle.Chamfer;
                        break;
                    }
                    Curve[] inputCurves = null;
                    inputCurves = destination.Offset(unset, naN, tolerance, none);
                    if (inputCurves == null)
                    {
                        this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "不能偏移该曲线");
                        return(new Curve[] { });
                    }
                    else
                    {
                        Curve[] data = Curve.JoinCurves(inputCurves);
                        if (data == null)
                        {
                            return(inputCurves);
                        }
                        else
                        {
                            return(data);
                        }
                    }
                }
            }
        }
Beispiel #12
0
 public void SetAsNumberInput(double minimum, double maximum)
 {
     OnlyNumbers        = true;
     MinimumNumberValue = RhinoMath.IsValidDouble(minimum) ? minimum : RhinoMath.UnsetValue;
     MaximumNumberValue = RhinoMath.IsValidDouble(maximum) ? maximum : RhinoMath.UnsetValue;
 }
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            var plane = Plane.Unset;
            var x     = RhinoMath.UnsetValue;
            var y     = RhinoMath.UnsetValue;
            var r     = RhinoMath.UnsetValue;

            if (!DA.GetData(0, ref plane))
            {
                return;
            }
            if (!DA.GetData(1, ref x))
            {
                return;
            }
            if (!DA.GetData(2, ref y))
            {
                return;
            }
            if (!DA.GetData(3, ref r))
            {
                return;
            }

            if (!plane.IsValid)
            {
                return;
            }
            if (!RhinoMath.IsValidDouble(x))
            {
                return;
            }
            if (!RhinoMath.IsValidDouble(y))
            {
                return;
            }
            if (!RhinoMath.IsValidDouble(r))
            {
                return;
            }

            if ((Math.Abs(x) < 1e-12) || (Math.Abs(y) < 1e-12))
            {
                AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Rectangle diagonal cannot be zero length.");
                return;
            }

            var min = Math.Min(x, y);

            r = Math.Min(r, 0.5 * min);

            if (r <= 0.0)
            {
                var dx     = x * 0.5;
                var dy     = y * 0.5;
                var width  = new Interval(-dx, dx);
                var height = new Interval(-dy, dy);
                var rect   = new Rectangle3d(plane, width, height);
                DA.SetData(0, new GH_Rectangle(rect));
                DA.SetData(1, rect.Circumference);
                return;
            }

            if ((x == y) && (r == (0.5 * x)))
            {
                var circle = new Circle(plane, r);
                DA.SetData(0, new GH_Circle(circle));
                DA.SetData(1, circle.Circumference);
                return;
            }

            var curve = RoundedRectangle(plane, x, y, r);

            if (null == curve)
            {
                AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Rectangle construction failed.");
                return;
            }

            DA.SetData(0, curve);
            DA.SetData(1, curve.GetLength());
        }
        protected override Result RunCommand(RhinoDoc doc, RunMode mode)
        {
            // Select cutting surface
            var gc = new GetObject();

            gc.SetCommandPrompt("Select cutting surface");
            gc.GeometryFilter  = ObjectType.Surface;
            gc.SubObjectSelect = false;
            gc.Get();
            if (gc.CommandResult() != Result.Success)
            {
                return(gc.CommandResult());
            }

            var splitter = gc.Object(0).Brep();

            if (null == splitter)
            {
                return(Result.Failure);
            }

            // Select surface to trim
            var gs = new GetObject();

            gs.SetCommandPrompt("Select surface to trim");
            gs.GeometryFilter  = ObjectType.Surface;
            gs.SubObjectSelect = false;
            gs.EnablePreSelect(false, true);
            gs.DeselectAllBeforePostSelect = false;
            gs.Get();
            if (gs.CommandResult() != Result.Success)
            {
                return(gs.CommandResult());
            }

            var brep_ref = gs.Object(0);
            var brep     = brep_ref.Brep();

            if (null == brep)
            {
                return(Result.Failure);
            }

            var pick_pt = brep_ref.SelectionPoint();

            if (!pick_pt.IsValid)
            {
                // The user didn't "pick" the object, but rather
                // selected the object using the SelID command.
                // So, make up some pick location.
                var dom_u = brep.Faces[0].Domain(0);
                var dom_v = brep.Faces[0].Domain(1);
                pick_pt = brep.Faces[0].PointAt(dom_u.Min, dom_v.Min);
            }

            // Do the splitting
            var trims = brep.Split(splitter, doc.ModelAbsoluteTolerance);

            if (null == trims || 1 == trims.Length)
            {
                RhinoApp.WriteLine("Unable to trim surface.");
                return(Result.Failure);
            }

            // Figure out which piece the user wanted trimmed away
            var dist         = RhinoMath.UnsetValue;
            int picked_index = -1;

            for (int i = 0; i < trims.Length; i++)
            {
                var pt = trims[i].ClosestPoint(pick_pt);
                if (pt.IsValid)
                {
                    double d = pt.DistanceTo(pick_pt);
                    if (!RhinoMath.IsValidDouble(dist) || d < dist)
                    {
                        dist         = d;
                        picked_index = i;
                    }
                }
            }

            // Add the new pieces
            for (int i = 0; i < trims.Length; i++)
            {
                if (i != picked_index)
                {
                    doc.Objects.AddBrep(trims[i]);
                }
            }

            // Delete the original
            doc.Objects.Delete(brep_ref, false);

            doc.Views.Redraw();

            return(Result.Success);
        }
        /// <summary>
        /// Calculates the u, v, n directions of a NURBS curve control point
        /// similar to the method used by the MoveUVN command.
        /// </summary>
        /// <param name="nurb">The NURBS curve to evaluate.</param>
        /// <param name="cvIndex">The index of the control point to evaluate.</param>
        /// <param name="uDir">The u direction.</param>
        /// <param name="vDir">The v direction.</param>
        /// <param name="nDir">The n direction.</param>
        /// <returns>true if successful, false otherwise</returns>
        public static bool GetNurbsCurveControlPointDirections(
            NurbsCurve nurb,
            int cvIndex,
            out Vector3d uDir,
            out Vector3d vDir,
            out Vector3d nDir
            )
        {
            uDir = vDir = nDir = Vector3d.Unset;
            var rc = false;

            if (null != nurb && cvIndex >= 0 && cvIndex < nurb.Points.Count)
            {
                var t = nurb.GrevilleParameter(cvIndex);
                if (RhinoMath.IsValidDouble(t))
                {
                    if (t < nurb.Domain.Min)
                    {
                        t += nurb.Domain.Length;
                    }

                    uDir = nurb.TangentAt(t);

                    var kappa = nurb.CurvatureAt(t);
                    if (nurb.TryGetPlane(out Plane plane))
                    {
                        nDir = plane.ZAxis;
                        vDir = Vector3d.CrossProduct(nDir, uDir);
                        vDir.Unitize();
                    }
                    else if (kappa.Unitize())
                    {
                        vDir = kappa;
                        nDir = Vector3d.CrossProduct(uDir, vDir);
                        nDir.Unitize();
                    }
                    else
                    {
                        vDir.PerpendicularTo(uDir);
                        vDir.Unitize();
                        nDir = Vector3d.CrossProduct(uDir, vDir);
                        nDir.Unitize();
                    }

                    const double tol = 1E-15;

                    if (Math.Abs(uDir.X) <= tol)
                    {
                        uDir.X = 0.0;
                    }
                    if (Math.Abs(uDir.Y) <= tol)
                    {
                        uDir.Y = 0.0;
                    }
                    if (Math.Abs(uDir.Z) <= tol)
                    {
                        uDir.Z = 0.0;
                    }

                    if (Math.Abs(vDir.X) <= tol)
                    {
                        vDir.X = 0.0;
                    }
                    if (Math.Abs(vDir.Y) <= tol)
                    {
                        vDir.Y = 0.0;
                    }
                    if (Math.Abs(vDir.Z) <= tol)
                    {
                        vDir.Z = 0.0;
                    }

                    if (Math.Abs(nDir.X) <= tol)
                    {
                        nDir.X = 0.0;
                    }
                    if (Math.Abs(nDir.Y) <= tol)
                    {
                        nDir.Y = 0.0;
                    }
                    if (Math.Abs(nDir.Z) <= tol)
                    {
                        nDir.Z = 0.0;
                    }

                    rc = true;
                }
            }

            return(rc);
        }