/// <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(); }
public virtual double ClosestParameter(Point3 pt) { return(Analyze.Curve.ClosestParameter(this, pt)); }
/// <summary> /// Recursively search to find the horizon or lit set. /// </summary> private void SearchHorizon(List <Point3> points, Point3 point, int prevFaceIndex, int faceCount, Face face) { Assert(prevFaceIndex >= 0); Assert(_litFaces.Contains(prevFaceIndex)); Assert(!_litFaces.Contains(faceCount)); Assert(_faces[faceCount].Equals(face)); _litFaces.Add(faceCount); // Use prevFaceIndex to determine what the next face to search will // be, and what edges we need to cross to get there. It's important // that the search proceeds in counter-clockwise order from the // previous face. int nextFaceIndex0; int nextFaceIndex1; int edge0; int edge1; int edge2; if (prevFaceIndex == face.Opposite0) { nextFaceIndex0 = face.Opposite1; nextFaceIndex1 = face.Opposite2; edge0 = face.Vertex2; edge1 = face.Vertex0; edge2 = face.Vertex1; } else if (prevFaceIndex == face.Opposite1) { nextFaceIndex0 = face.Opposite2; nextFaceIndex1 = face.Opposite0; edge0 = face.Vertex0; edge1 = face.Vertex1; edge2 = face.Vertex2; } else { Assert(prevFaceIndex == face.Opposite2); nextFaceIndex0 = face.Opposite0; nextFaceIndex1 = face.Opposite1; edge0 = face.Vertex1; edge1 = face.Vertex2; edge2 = face.Vertex0; } if (!_litFaces.Contains(nextFaceIndex0)) { Face oppositeFace = _faces[nextFaceIndex0]; double dist = PointFaceDistance( point, points[oppositeFace.Vertex0], oppositeFace); if (dist <= 0.0f) { _horizon.Add(new HorizonEdge { Face = nextFaceIndex0, Edge0 = edge0, Edge1 = edge1, }); } else { SearchHorizon(points, point, faceCount, nextFaceIndex0, oppositeFace); } } if (!_litFaces.Contains(nextFaceIndex1)) { Face oppositeFace = _faces[nextFaceIndex1]; double dist = PointFaceDistance( point, points[oppositeFace.Vertex0], oppositeFace); if (dist <= 0.0f) { _horizon.Add(new HorizonEdge { Face = nextFaceIndex1, Edge0 = edge1, Edge1 = edge2, }); } else { SearchHorizon(points, point, faceCount, nextFaceIndex1, oppositeFace); } } }
/// <summary> /// Start the search for the horizon. /// /// The search is a DFS search that searches neighboring triangles in /// a counter-clockwise fashion. When it find a neighbor which is not /// lit, that edge will be a line on the horizon. If the search always /// proceeds counter-clockwise, the edges of the horizon will be found /// in counter-clockwise order. /// /// The heart of the search can be found in the recursive /// SearchHorizon() method, but the the first iteration of the search /// is special, because it has to visit three neighbors (all the /// neighbors of the initial triangle), while the rest of the search /// only has to visit two (because one of them has already been /// visited, the one you came from). /// </summary> private void FindHorizon(List <Point3> points, Point3 point, int fi, Face face) { // TODO should I use epsilon in the PointFaceDistance comparisons? _litFaces.Clear(); _horizon.Clear(); _litFaces.Add(fi); Assert(PointFaceDistance(point, points[face.Vertex0], face) > 0.0f); // For the rest of the recursive search calls, we first check if the // triangle has already been visited and is part of litFaces. // However, in this first call we can skip that because we know it // can't possibly have been visited yet, since the only thing in // litFaces is the current triangle. { Face oppositeFace = _faces[face.Opposite0]; double dist = PointFaceDistance( point, points[oppositeFace.Vertex0], oppositeFace); if (dist <= 0.0f) { _horizon.Add(new HorizonEdge { Face = face.Opposite0, Edge0 = face.Vertex1, Edge1 = face.Vertex2, }); } else { SearchHorizon(points, point, fi, face.Opposite0, oppositeFace); } } if (!_litFaces.Contains(face.Opposite1)) { Face oppositeFace = _faces[face.Opposite1]; double dist = PointFaceDistance( point, points[oppositeFace.Vertex0], oppositeFace); if (dist <= 0.0f) { _horizon.Add(new HorizonEdge { Face = face.Opposite1, Edge0 = face.Vertex2, Edge1 = face.Vertex0, }); } else { SearchHorizon(points, point, fi, face.Opposite1, oppositeFace); } } if (!_litFaces.Contains(face.Opposite2)) { Face oppositeFace = _faces[face.Opposite2]; double dist = PointFaceDistance( point, points[oppositeFace.Vertex0], oppositeFace); if (dist <= 0.0f) { _horizon.Add(new HorizonEdge { Face = face.Opposite2, Edge0 = face.Vertex0, Edge1 = face.Vertex1, }); } else { SearchHorizon(points, point, fi, face.Opposite2, oppositeFace); } } }
private Vector3 Normal(Point3 v0, Point3 v1, Point3 v2) { return(Vector3.CrossProduct(v1 - v0, v2 - v0).Unitize()); }
private double PointFaceDistance(Point3 point, Point3 pointOnFace, Face face) { return(Vector3.DotProduct(face.Normal, point - pointOnFace)); }