/// <summary> /// Needs to calculate Length of the curve. If you have it - create this class passing 'length' parameter. /// </summary> /// <param name="t"></param> /// <returns></returns> public Percent PercentAt(double t) { var subLength = Crv.GetLength(new Interval(Domain.T0, t)); Percent p = subLength / Length; return(p); }
/// <summary> /// This is the method that actually does the work. /// </summary> /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param> protected override void SolveInstance(IGH_DataAccess DA) { //字典立面的Key必须唯一,如何保证TempDict的Key值唯一? //调换Curve和Dict的顺序 //这里存在的一个bug Point3d Pt = default(Point3d); List <Curve> Crvs = new List <Curve>(); int Num = 1; Dictionary <Curve, double> _TempDict = new Dictionary <Curve, double>(); if (!DA.GetDataList <Curve>(0, Crvs)) { return; } if (!DA.GetData(1, ref Pt)) { return; } if (!DA.GetData(2, ref Num)) { return; } if (Num == 0) { this.AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Num为0"); } double Param = 0; foreach (var Crv in Crvs) { if (Crv.ClosestPoint(Pt, out Param)) { Point3d TempPt = Crv.PointAt(Param); double Dist = Pt.DistanceTo(TempPt); _TempDict.Add(Crv, Dist); } } var ResultDict = _TempDict.OrderByDescending(item => - item.Value).ToDictionary(item => item.Key, item => item.Value); List <Curve> TempCrvs = ResultDict.Keys.ToList(); List <Curve> ResultCrvs = new List <Curve>(); if (TempCrvs.Count < Math.Abs(Num)) { this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Num 数值过大"); return; } if (this.FindType == 0) { ResultCrvs = TempCrvs.GetRange(0, Math.Abs(Num)); } else { ResultCrvs = TempCrvs.GetRange(TempCrvs.Count - Num - 1, TempCrvs.Count); } DA.SetDataList(0, ResultCrvs); }
/// <summary> /// Needs to calculate Length of the curve. If you have it - create this class passing 'length' parameter. /// </summary> /// <param name="point"></param> /// <returns></returns> public Percent PercentAt(Point3d point) { double t; if (!Crv.ClosestPoint(point, out t)) { throw new Exception("CurveNormalized.P(Point3d point) failed to get T from 3d point!"); } return(PercentAt(t)); }
// same as 'T' but use sinlge method call to optimize perfromance public double[] T(Percent[] ps) { foreach (var p in ps) { p.MustBeInScope01(); } double[] s = ps.Select(o => (double)o).ToArray(); double[] t = Crv.NormalizedLengthParameters(s, 1E-08); // single method call to Rhinocommon if (t != null) { return(t); } return(ps.Select(o => T(o)).ToArray()); }
void OnSceneGUI() { Handles.color = Col.black; List <Vector3> lis = Crv.CatmullRomSpline(hand.points, hand.smooth, hand.spacing); for (int i = 1; i < lis.Count; i++) { Handles.DrawLine(hand.TfPnt(lis[i - 1]), hand.TfPnt(lis[i])); } Handles.color = Col.red; for (int i = 0; i < hand.points.Count; i++) { hand.points[i] = hand.TfInvPnt( Handles.FreeMoveHandle( hand.TfPnt(hand.points[i]), Q.O, 25, V3.O, Handles.CylinderHandleCap ) ); } }
public double T(Percent p) { p.MustBeInScope01(); double t; if (Crv.NormalizedLengthParameter(p, out t, 1E-08)) { return(t); } // very small curves are really hard to get some middle point - so dont bother - show a warning only for normal curves var len = Crv.PointAtStart._DistanceTo(Crv.PointAtEnd); if (len > 0.0001) { log.wrong("CurveNormalized.T(Percent p) cannot get value from method 'NormalizedLengthParameter'"); } // at least we can return approximated value return(Crv.Domain.T0 + Crv.Domain.Length * p); }
/// <summary> /// Remove portions of the curve outside the specified interval. /// </summary> /// <param name="p0"></param> /// <param name="p1"></param> /// <param name="failReason"></param> /// <returns></returns> public CurveNormalized Trim(Percent p0, Percent p1, out string failReason) { failReason = ""; Curve res = null; if (p0.is0percent() && p1.is100percent()) { res = Crv; } else { var t0 = T(p0); var t1 = T(p1); res = Crv.DuplicateCurve().Trim(t0, t1); } if (res == null) { failReason = "failed to trim crv"; return(null); } return(new CurveNormalized(res)); }
/// <summary> /// This is the method that actually does the work. /// </summary> /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param> protected override void SolveInstance(IGH_DataAccess DA) { List <Curve> Crvs = new List <Curve>(); double ThreadHold = 0.1; string SortSign = "x"; GH_Structure <GH_Curve> OutputTree = new GH_Structure <GH_Curve>(); if (!DA.GetDataList(0, Crvs)) { return; } if (!DA.GetData(1, ref ThreadHold)) { return; } if (!DA.GetData(2, ref SortSign)) { return; } int SortIndex = SortSign.ToLower() == "x" ? 0 : SortSign.ToLower() == "y" ? 1 : SortSign.ToLower() == "z" ? 2 : 0; var GroupData = Crvs.GroupBy(Crv => { double Pt_Seg = Crv.PointAtNormalizedLength(0.5)[SortIndex]; return(Pt_Seg * (1 / ThreadHold)); }).ToList(); for (int Index = 0; Index < GroupData.Count; Index++) { var TempGroup = GroupData[Index]; var TreeBranch = TempGroup.Select(Crv => new GH_Curve(Crv)).ToList(); OutputTree.AppendRange(TreeBranch, new GH_Path(Index)); } DA.SetDataTree(0, OutputTree); }
void Start() { lis = Crv.CatmullRomSpline(points, smooth, spacing); }
/// <summary> /// Generate conter-clockwise ordered CurveArray representing enclosed areas based on a bunch of intersected lines /// </summary> /// <param name="C"></param> /// <returns></returns> public static List <CurveArray> RegionCluster(List <Curve> C) // , Plane P, ref object CN { List <Curve> Crvs = new List <Curve>(); for (int CStart = 0; CStart <= C.Count - 1; CStart++) { List <double> breakParams = new List <double>(); for (int CCut = 0; CCut <= C.Count - 1; CCut++) { if (CStart != CCut) { // ExtendCrv(C[CCut], 0.005) SetComparisonResult result = C[CStart].Intersect(C[CCut], out IntersectionResultArray results); if (result != SetComparisonResult.Disjoint) { double breakParam = results.get_Item(0).UVPoint.U; breakParams.Add(breakParam); //Debug.Print("Projection parameter is: " + breakParam.ToString()); } } } Crvs.AddRange(SplitCrv(C[CStart], breakParams)); } List <XYZ> Vtc = new List <XYZ>(); // all unique vertices List <Curve> HC = new List <Curve>(); // list of all shattered half-curves List <int> HCI = new List <int>(); // half curve indices List <int> HCO = new List <int>(); // half curve reversed List <int> HCN = new List <int>(); // next index for each half-curve (conter-clockwise) List <int> HCV = new List <int>(); // vertex representing this half-curve List <int> HCF = new List <int>(); // half-curve face List <bool> HCK = new List <bool>(); // mark if a half-curve needs to be killed // (if it either starts or ends hanging, but does not exclude redundant curves that not exclosing a room) Dictionary <int, List <Curve> > F = new Dictionary <int, List <Curve> >(); // data tree for faces Dictionary <int, List <int> > VOut = new Dictionary <int, List <int> >(); // data tree of outgoing half-curves from each vertex foreach (Curve Crv in Crvs) // cycle through each curve { for (int CRun = 0; CRun <= 2; CRun += 2) // create two half-curves: first in one direction, and then the other... { XYZ testedPt = new XYZ(); if (CRun == 0) { HC.Add(Crv); testedPt = Crv.GetEndPoint(0); } else { HC.Add(Crv.CreateReversed()); testedPt = Crv.GetEndPoint(1); } HCI.Add(HCI.Count); // count this iteration HCO.Add(HCI.Count - CRun); // a little index trick HCN.Add(-1); HCF.Add(-1); HCK.Add(false); int VtcSet = -1; for (int VtxCheck = 0; VtxCheck <= Vtc.Count - 1; VtxCheck++) { if (Vtc[VtxCheck].DistanceTo(testedPt) < 0.0000001) { VtcSet = VtxCheck; // get the vertex index, if it already exists break; } } if (VtcSet > -1) { HCV.Add(VtcSet); // If the vertex already exists, set the half-curve vertex VOut[VtcSet].Add(HCI.Last()); } else { HCV.Add(Vtc.Count); // if the vertex doesn't already exist, add a new vertex index VOut.Add(Vtc.Count, new List <int>() { HCI.Last() }); // add the new half-curve index to the list of outgoing half-curves associated with the vertex Vtc.Add(testedPt); // add the new vertex to the vertex list } Crv.CreateReversed(); // reverse the curve for creating the opposite half-curve in the second part of the loop //Debug.Print("Tested point is (" + testedPt.X.ToString() + ", " + testedPt.Y.ToString() + ")"); } } // For each Vertex that has only one outgoing half-curve, kill the half-curve and its opposite foreach (KeyValuePair <int, List <int> > path in VOut) { //Debug.Print("This point has been connected to " + path.Value.Count.ToString() + " curves"); if (path.Value.Count == 1) { HCK[path.Value[0]] = true; HCK[HCO[path.Value[0]]] = true; } } Debug.Print("Elements inside Crvs are " + Crvs.Count.ToString()); Debug.Print("Elements inside HC are " + HC.Count.ToString()); Debug.Print("Elements inside VOut are " + VOut.Count.ToString()); Debug.Print("Elements inside HCK are " + HCK.Count.ToString()); //Debug.Print(printb(HCK)); // Find the "next" half-curve for each starting half curve by identifying the outgoing half-curve from the end vertex // that presents the smallest angle by calculating its plane's x-axis angle from x-axis of the starting half-curve's opposite plane foreach (int HCIdx in HCI) { int minIdx = -1; double minAngle = 2 * Math.PI; //Debug.Print(VOut[HCV[HCO[HCIdx]]].Count().ToString()); foreach (int HCOut in VOut[HCV[HCO[HCIdx]]]) { if (HCOut != HCO[HCIdx] & HCK[HCIdx] == false & HCK[HCOut] == false) { double testAngle = AngleBetweenCrv(HC[HCOut], HC[HCO[HCIdx]], new XYZ(0, 0, 1)); // The comparing order is important to ensure a right-hand angle under z-axis if (testAngle < minAngle) { minIdx = HCOut; minAngle = testAngle; } } } HCN[HCIdx] = minIdx; } Debug.Print("Elements inside HCI are " + HCI.Count.ToString()); Debug.Print("Elements inside HCN are " + HCN.Count.ToString()); Debug.Print("Elements in HCN: " + printo(HCN)); // Sequence half-curves into faces by running along "next" half-curves in order until the starting half-curve is returned to List <int> FaceEdges = new List <int>(); List <int> DeleteEdges = new List <int>(); // cycle through each half-curve foreach (int HCIdx in HCI) { int EmExit = 0; if (HCF[HCIdx] == -1) { int EdgeCounter = 1; int FaceIdx = F.Count(); int CurrentIdx = HCIdx; F.Add(FaceIdx, new List <Curve>() { HC[CurrentIdx] }); HCF[CurrentIdx] = FaceIdx; do { if (HCN[CurrentIdx] == -1) { DeleteEdges.Add(FaceIdx); break; } CurrentIdx = HCN[CurrentIdx]; F[FaceIdx].Add(HC[CurrentIdx]); EdgeCounter += 1; HCF[CurrentIdx] = FaceIdx; if (HCN[CurrentIdx] == HCIdx) { break; } EmExit += 1; if (EmExit == Crvs.Count - 1) { break; } }while (true); // exit once the starting half-curve is reached again // emergency exit prevents infinite loops FaceEdges.Add(EdgeCounter); } } //Debug.Print("Elements in FaceEdges: " + printo(FaceEdges)); //Debug.Print("Elements in DeleteEdges: " + printo(DeleteEdges)); //Debug.Print("Elements in F dict: " + printd(F)); // Find the perimeter by counting edges of a region int Perim = -1; int PerimCount = -1; for (int FE = 0; FE <= FaceEdges.Count - 1; FE++) { if (FaceEdges[FE] > PerimCount) { Perim = FE; PerimCount = FaceEdges[FE]; } } DeleteEdges.Add(Perim); int NewPath = 0; List <CurveArray> OutputFaces = new List <CurveArray>(); // only output those faces that haven't been identified as either the perimeter or open foreach (KeyValuePair <int, List <Curve> > kvp in F) { if (DeleteEdges.Contains(kvp.Key) == false) { CurveArray tempLoop = new CurveArray(); foreach (Curve element in kvp.Value) { tempLoop.Append(element); } OutputFaces.Add(tempLoop); NewPath += 1; } } // Debug.Print("Elements in OutputFaces dict: " + printd(OutputFaces)); return(OutputFaces); }
public Vector3d TangentAt(Percent p) { return(Crv.TangentAt(T(p))); }
public Point3d PointAt(CurveEnd end) { return(Crv.PointAt(T(end))); }
public Point3d[] PointsAt(Percent[] ps) { double[] ts = T(ps); return(ts.Select(o => Crv.PointAt(o)).ToArray()); }
public Point3d PointAt(Percent p) { return(Crv.PointAt(T(p))); }