/// <summary> /// Intersects two lines. /// </summary> /// <param name="lineA">First line for intersection.</param> /// <param name="lineB">Second line for intersection.</param> /// <param name="a"> /// Parameter on lineA that is closest to LineB. /// The shortest distance between the lines is the chord from lineA.PointAt(a) to lineB.PointAt(b) /// </param> /// <param name="b"> /// Parameter on lineB that is closest to LineA. /// The shortest distance between the lines is the chord from lineA.PointAt(a) to lineB.PointAt(b) /// </param> /// <param name="tolerance"> /// If tolerance > 0.0, then an intersection is reported only if the distance between the points is <= tolerance. /// If tolerance <= 0.0, then the closest point between the lines is reported. /// </param> /// <param name="finiteSegments"> /// If true, the input lines are treated as finite segments. /// If false, the input lines are treated as infinite lines. /// </param> /// <returns> /// true if a closest point can be calculated and the result passes the tolerance parameter test; otherwise false. /// </returns> /// <remarks> /// If the lines are exactly parallel, meaning the system of equations used to find a and b /// has no numerical solution, then false is returned. If the lines are nearly parallel, which /// is often numerically true even if you think the lines look exactly parallel, then the /// closest points are found and true is returned. So, if you care about weeding out "parallel" /// lines, then you need to do something like the following: /// <code lang="cs"> /// bool rc = Intersect.LineLine(lineA, lineB, out a, out b, tolerance, segments); /// if (rc) /// { /// double angle_tol = RhinoMath.ToRadians(1.0); // or whatever /// double parallel_tol = Math.Cos(angle_tol); /// if ( Math.Abs(lineA.UnitTangent * lineB.UnitTangent) >= parallel_tol ) /// { /// ... do whatever you think is appropriate /// } /// } /// </code> /// <code lang="vb"> /// Dim rc As Boolean = Intersect.LineLine(lineA, lineB, a, b, tolerance, segments) /// If (rc) Then /// Dim angle_tol As Double = RhinoMath.ToRadians(1.0) 'or whatever /// Dim parallel_tolerance As Double = Math.Cos(angle_tol) /// If (Math.Abs(lineA.UnitTangent * lineB.UnitTangent) >= parallel_tolerance) Then /// ... do whatever you think is appropriate /// End If /// End If /// </code> /// </remarks> public static bool LineLine(Line lineA, Line lineB, out double a, out double b, double tolerance, bool finiteSegments) { bool rc = LineLine(lineA, lineB, out a, out b); if (rc) { if (finiteSegments) { if (a < 0.0) a = 0.0; else if (a > 1.0) a = 1.0; if (b < 0.0) b = 0.0; else if (b > 1.0) b = 1.0; } if (tolerance > 0.0) { rc = (lineA.PointAt(a).DistanceTo(lineB.PointAt(b)) <= tolerance); } } return rc; }
/// <summary> /// Gets the parameter along the polyline which is closest to a test-point. /// </summary> /// <param name="testPoint">Point to approximate.</param> /// <returns>The parameter along the polyline closest to testPoint.</returns> public double ClosestParameter(Point3d testPoint) { int count = Count; if (count < 2) { return 0.0; } int s_min = 0; double t_min = 0.0; double d_min = double.MaxValue; for (int i = 0; i < count - 1; i++) { Line seg = new Line(this[i], this[i + 1]); double d; double t; if (seg.Direction.IsTiny(1e-32)) { t = 0.0; d = this[i].DistanceTo(testPoint); } else { t = seg.ClosestParameter(testPoint); if (t <= 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } d = seg.PointAt(t).DistanceTo(testPoint); } if (d < d_min) { d_min = d; t_min = t; s_min = i; } } return s_min + t_min; }
public Polyline QuadFaceOffset(Point3d p1, Point3d p2, Point3d p3, Point3d p4, Vector3d N, double distance) { Point3d cen = (p1 + p2 + p3 + p4) / 4; Line lcen = new Line(cen, cen + N); double u, v; Line l1 = new Line(p1, p2); Rhino.Geometry.Intersect.Intersection.LineLine(lcen, l1, out u, out v); Vector3d v1 = lcen.PointAt(u) - l1.PointAt(v); v1.Unitize(); v1 *= distance; l1.Transform(Transform.Translation(v1)); Line l2 = new Line(p2, p3); Rhino.Geometry.Intersect.Intersection.LineLine(lcen, l2, out u, out v); v1 = lcen.PointAt(u) - l2.PointAt(v); v1.Unitize(); v1 *= distance; l2.Transform(Transform.Translation(v1)); Line l3 = new Line(p3, p4); Rhino.Geometry.Intersect.Intersection.LineLine(lcen, l3, out u, out v); v1 = lcen.PointAt(u) - l3.PointAt(v); v1.Unitize(); v1 *= distance; l3.Transform(Transform.Translation(v1)); Line l4 = new Line(p4, p1); Rhino.Geometry.Intersect.Intersection.LineLine(lcen, l4, out u, out v); v1 = lcen.PointAt(u) - l4.PointAt(v); v1.Unitize(); v1 *= distance; l4.Transform(Transform.Translation(v1)); Polyline output = new Polyline(); Rhino.Geometry.Intersect.Intersection.LineLine(l1, l4, out u, out v); output.Add((l1.PointAt(u) + l4.PointAt(v)) / 2); Rhino.Geometry.Intersect.Intersection.LineLine(l2, l1, out u, out v); output.Add((l2.PointAt(u) + l1.PointAt(v)) / 2); Rhino.Geometry.Intersect.Intersection.LineLine(l3, l2, out u, out v); output.Add((l3.PointAt(u) + l2.PointAt(v)) / 2); Rhino.Geometry.Intersect.Intersection.LineLine(l4, l3, out u, out v); output.Add((l4.PointAt(u) + l3.PointAt(v)) / 2); return output; }
///// MeshCreation public Mesh MeshWindow(Mesh mesh, double t) { Mesh output = new Mesh(); mesh.FaceNormals.ComputeFaceNormals(); for (int i = 0; i < mesh.Faces.Count; i++) { MeshFace mf = mesh.Faces[i]; if (mf.IsTriangle) { Point3d p1 = mesh.Vertices[mf.A]; Point3d p2 = mesh.Vertices[mf.B]; Point3d p3 = mesh.Vertices[mf.C]; Line l1 = new Line(p1, p2); Line l2 = new Line(p2, p3); Line l3 = new Line(p3, p1); Vector3d v1 = Vector3d.CrossProduct(p2 - p1, mesh.FaceNormals[i]); v1.Unitize(); v1 *= -t; Vector3d v2 = Vector3d.CrossProduct(p3 - p2, mesh.FaceNormals[i]); v2.Unitize(); v2 *= -t; Vector3d v3 = Vector3d.CrossProduct(p1 - p3, mesh.FaceNormals[i]); v3.Unitize(); v3 *= -t; l1.Transform(Transform.Translation(v1)); l2.Transform(Transform.Translation(v2)); l3.Transform(Transform.Translation(v3)); double t1, t2, t3; Rhino.Geometry.Intersect.Intersection.LineLine(l1, l2, out t1, out t2); p2 = (l1.PointAt(t1) + l2.PointAt(t2)) / 2; Rhino.Geometry.Intersect.Intersection.LineLine(l2, l3, out t2, out t3); p3 = (l3.PointAt(t3) + l2.PointAt(t2)) / 2; Rhino.Geometry.Intersect.Intersection.LineLine(l3, l1, out t3, out t1); p1 = (l1.PointAt(t1) + l3.PointAt(t3)) / 2; int index1 = output.Vertices.Count; output.Vertices.Add(p1); output.Vertices.Add(p2); output.Vertices.Add(p3); output.Faces.AddFace(index1, index1 + 1, index1 + 2); } if (mf.IsQuad) { Point3d p1 = mesh.Vertices[mesh.Faces[i].A]; Point3d p2 = mesh.Vertices[mesh.Faces[i].B]; Point3d p3 = mesh.Vertices[mesh.Faces[i].C]; Point3d p4 = mesh.Vertices[mesh.Faces[i].D]; Line l1 = new Line(p1, p2); Line l2 = new Line(p2, p3); Line l3 = new Line(p3, p4); Line l4 = new Line(p4, p1); Vector3d v1 = Vector3d.CrossProduct(p2 - p1, mesh.FaceNormals[i]); v1.Unitize(); v1 *= -t; Vector3d v2 = Vector3d.CrossProduct(p3 - p2, mesh.FaceNormals[i]); v2.Unitize(); v2 *= -t; Vector3d v3 = Vector3d.CrossProduct(p4 - p3, mesh.FaceNormals[i]); v3.Unitize(); v3 *= -t; Vector3d v4 = Vector3d.CrossProduct(p1 - p4, mesh.FaceNormals[i]); v4.Unitize(); v4 *= -t; l1.Transform(Transform.Translation(v1)); l2.Transform(Transform.Translation(v2)); l3.Transform(Transform.Translation(v3)); l4.Transform(Transform.Translation(v4)); double t1, t2, t3, t4; Rhino.Geometry.Intersect.Intersection.LineLine(l1, l2, out t1, out t2); p2 = (l1.PointAt(t1) + l2.PointAt(t2)) / 2; Rhino.Geometry.Intersect.Intersection.LineLine(l2, l3, out t2, out t3); p3 = (l3.PointAt(t3) + l2.PointAt(t2)) / 2; Rhino.Geometry.Intersect.Intersection.LineLine(l3, l4, out t3, out t4); p4 = (l4.PointAt(t4) + l3.PointAt(t3)) / 2; Rhino.Geometry.Intersect.Intersection.LineLine(l4, l1, out t4, out t1); p1 = (l1.PointAt(t1) + l4.PointAt(t4)) / 2; int index1 = output.Vertices.Count; output.Vertices.Add(p1); output.Vertices.Add(p2); output.Vertices.Add(p3); output.Vertices.Add(p4); output.Faces.AddFace(index1, index1 + 1, index1 + 2, index1 + 3); } } output.UnifyNormals(); return output; }
/// <summary> /// Morphs cell topology to UVWI node map (morphed struts). /// </summary> public void MorphMapping(UnitCell cell, DataTree<GeometryBase> spaceTree, float[] N) { for (int u = 0; u <= N[0]; u++) { for (int v = 0; v <= N[1]; v++) { for (int w = 0; w <= N[2]; w++) { // We're inside a unit cell // Loop through all pairs of nodes that make up struts foreach (IndexPair nodePair in cell.NodePairs) { // Prepare the path of the nodes (path in tree) // First, get relative paths of nodes (with respect to current unit cell) int[] IRel = cell.NodePaths[nodePair.I]; int[] JRel = cell.NodePaths[nodePair.J]; // Next, compute absolute paths GH_Path IPath = new GH_Path(u + IRel[0], v + IRel[1], w + IRel[2]); GH_Path JPath = new GH_Path(u + JRel[0], v + JRel[1], w + JRel[2]); // Make sure the cell exists // No cells exist beyond the boundary + 1 if (Nodes.PathExists(IPath) && Nodes.PathExists(JPath)) { LatticeNode node1 = Nodes[IPath, IRel[3]]; LatticeNode node2 = Nodes[JPath, JRel[3]]; // Make sure both nodes exist: // Null nodes either belong to other cells, or are beyond the upper uvw boundary. if (node1 != null && node2 != null) { GH_Path spacePath; // If strut is along boundary, we must use the previous morph space // Since one does not exist beyond the boundary) if (u == N[0] && v == N[1]) { spacePath = new GH_Path(u - 1, v - 1); } else if (u == N[0]) { spacePath = new GH_Path(u - 1, v); } else if (v == N[1]) { spacePath = new GH_Path(u, v - 1); } else { spacePath = new GH_Path(u, v); } // Retrieve uv cell space (will be casted in the tempPt loop) GeometryBase ss1 = spaceTree[spacePath, 0]; GeometryBase ss2 = spaceTree[spacePath, 1]; // Discretize the unit cell line for morph mapping int ptCount = 16; // Template points are unitized cell points (x,y of these points are u,v of sub-surface) var templatePts = new List<Point3d>(); Line templateLine = new Line(cell.Nodes[nodePair.I], cell.Nodes[nodePair.J]); for (int ptIndex = 0; ptIndex <= ptCount; ptIndex++) { templatePts.Add(templateLine.PointAt(ptIndex / (double)ptCount)); } // We will map the lines' points to its uvw cell-space // Control points are the interpolation points in space var controlPoints = new List<Point3d>(); foreach (Point3d tempPt in templatePts) { Point3d surfPt; Vector3d[] surfDerivs; // UV params on unitized sub-surface are simply the xy coordinate of the template point double uParam = tempPt.X; double vParam = tempPt.Y; // If at boundary, we're using a previous morph space, so reverse the parameter(s) if (u == N[0]) { uParam = 1 - uParam; } if (v == N[1]) { vParam = 1 - vParam; } // Now, we will map the template point to the uvw-space ((Surface)ss1).Evaluate(uParam, vParam, 0, out surfPt, out surfDerivs); Vector3d wVect = Vector3d.Unset; switch (ss2.ObjectType) { case ObjectType.Point: wVect = ((Point)ss2).Location - surfPt; ; break; case ObjectType.Curve: wVect = ((Curve)ss2).PointAt(uParam) - surfPt; break; case ObjectType.Surface: Point3d surfPt2; Vector3d[] surfDerivs2; ((Surface)ss2).Evaluate(uParam, vParam, 0, out surfPt2, out surfDerivs2); wVect = surfPt2 - surfPt; break; } // The mapped point Point3d uvwPt = surfPt + wVect * (w + tempPt.Z) / N[2]; controlPoints.Add(uvwPt); } // Now create interpolated curve based on control points Curve curve = Curve.CreateInterpolatedCurve(controlPoints, 3); if (curve != null && curve.IsValid) { Struts.Add(curve); } } } } } } } }
public void intersect(Plane p) { for (int i = 0; i < pts.Count; i++) { double db = p.DistanceTo(pts[i].pos); if (Math.Abs(db) < RhinoDoc.ActiveDoc.ModelAbsoluteTolerance) { pts[i].condition = 1; } else if (db > 0) { pts[i].condition = 2; } else if (db < 0) { pts[i].condition = 0; } } /////////////////////// int ii = 0; while (ii < edges.Count) { if (edges[ii].p1.condition == 0 && edges[ii].p2.condition == 0) { edges.RemoveAt(ii); } else if (edges[ii].p1.condition == 1 && edges[ii].p2.condition == 0) { edges.RemoveAt(ii); } else if (edges[ii].p1.condition == 1 && edges[ii].p2.condition == 1) { edges.RemoveAt(ii); } else if (edges[ii].p1.condition == 0 && edges[ii].p2.condition == 1) { edges.RemoveAt(ii); } else if (edges[ii].p1.condition == 0 && edges[ii].p2.condition == 2) { double u; Line line = new Line(edges[ii].p1.pos, edges[ii].p2.pos); Rhino.Geometry.Intersect.Intersection.LinePlane(line, p, out u); pts.Add(new vertex(line.PointAt(u), this.center.DistanceTo(line.PointAt(u)))); edges[ii].p1 = pts[pts.Count - 1]; ii++; } else if (edges[ii].p1.condition == 2 && edges[ii].p2.condition == 0) { double u; Line line = new Line(edges[ii].p1.pos, edges[ii].p2.pos); Rhino.Geometry.Intersect.Intersection.LinePlane(line, p, out u); pts.Add(new vertex(line.PointAt(u), this.center.DistanceTo(line.PointAt(u)))); edges[ii].p2 = pts[pts.Count - 1]; ii++; } else { ii++; } } clearnull(); ////////////////////////////////// Transform w2p = Transform.PlaneToPlane(Plane.WorldXY, p); Transform p2w = Transform.PlaneToPlane(p, Plane.WorldXY); Grasshopper.Kernel.Geometry.Node2List ls = new Grasshopper.Kernel.Geometry.Node2List(); List<int> count = new List<int>(); for (int i = 0; i < pts.Count; i++) { if (pts[i].condition == 1 || pts[i].condition == -1) { pts[i].pos.Transform(w2p); ls.Append(new Grasshopper.Kernel.Geometry.Node2(pts[i].pos.X, pts[i].pos.Y)); pts[i].pos.Transform(p2w); count.Add(i); } } if (count.Count == 2) edges.Add(new edge(pts[count[0]], pts[count[1]])); else if (count.Count > 2) { List<int> count2 = new List<int>(); Grasshopper.Kernel.Geometry.ConvexHull.Solver.Compute(ls, count2); for (int i = 0; i < count2.Count; i++) { int c = i + 1; if (c == count2.Count) c = 0; edges.Add(new edge(pts[count[count2[i]]], pts[count[count2[c]]])); } } }