private double FitCurve() { if (m_Group == null || m_Group.Count < 5) return 0; Vect2 uv = new Vect2(); Vect3 xyz = new Vect3(), xprev = new Vect3(); List<IFitPoint> fit = new List<IFitPoint>(m_Group.Count); //get target point on starting yarn //yar0.xVal(m_sPos, ref uv, ref xyz); double s1 = m_sPos, d = 0; //fit.Add(new FixedPoint(uv)); double length = 0, h=0; Vect2 v; List<Vect2> combs = new List<Vect2>(m_Group.Count); for (int i = 0; i < m_Group.Count; i++) { m_Group[i].xVal(s1, ref uv, ref xprev); fit.Add(new FixedPoint(uv[0], uv[1])); //find closest point on yar1 to the target point on yar0; if (i < m_Group.Count - 1) { xyz.Set(xprev); //find the spacing to the next yarn if (!CurveTools.xClosest(m_Group[i + 1], ref s1, ref uv, ref xyz, ref d, 1e-6, true)) Logger.logger.Instance.Log("xClosest failed in DensityComb"); //throw new Exception("xClosest failed in DensityComb"); h = xyz.Distance(xprev); //store the spacing and x-distance v = new Vect2(); v[0] = length; v[1] = m_Group.InverseSpacing(h); combs.Add(v); length += h;//accumulate length } } Length = length; //convert x-distance to s-spacing for (int i = 0; i < combs.Count; i++) fit[i][0] = combs[i][0] /= length; combs.Add(new Vect2(1, m_Group.InverseSpacing(h)));//add endpoint with spacing to previous curve //fit to the intersection points SurfaceCurve.SimpleFit(this, fit.ToArray()); FitComb(combs.ToArray()); return DPI = m_Group.YarnDenier * .0254 * (m_Group.Count - 1) / length; }
public virtual List<Entity> CreateEntities(bool bFitPoints, double TolAngle, out double[] sPos) { if (!AllFitPointsValid()) { sPos = null; return new List<Entity>(); } List<double> spos = new List<double>(); const int TEST = 8; int FitLength = FitPoints.Length; double[] stest = new double[(FitLength - 1) * TEST]; Vect3[] xtest = new Vect3[(FitLength - 1) * TEST]; Vect2 uv = new Vect2(); Vect3 xyz = new Vect3(); Vect3 dxp = new Vect3(), dxm = new Vect3(); //initial 8 subdivisions per segment int nFit, nTest = 0; for (nFit = 1; nFit < FitLength; nFit++) { for (int i = 0; i < TEST; i++, nTest++) { stest[nTest] = BLAS.interpolate(i, TEST, FitPoints[nFit].S, FitPoints[nFit - 1].S); xtest[nTest] = new Vect3(); xVal(stest[nTest], ref uv, ref xtest[nTest]); } } //test the midpoint of each subsegment to determine required # of points int[] nAdd = new int[stest.Length]; double cosA; double smid; int nTotal = FitLength; for (nTest = 1; nTest < stest.Length; nTest++) { //midpoint position smid = (stest[nTest] + stest[nTest - 1]) / 2.0; xVal(smid, ref uv, ref xyz); //forward and backward tangents dxp = xtest[nTest] - xyz; dxm = xtest[nTest - 1] - xyz; //change in angle between for and aft tans cosA = -(dxp.Dot(dxm)) / (dxp.Magnitude * dxm.Magnitude); Utilities.LimitRange(-1, ref cosA, 1); cosA = Math.Acos(cosA); //determine additional points and sum total nTotal += nAdd[nTest] = (int)(cosA / TolAngle + 1); } m_Length = 0; Vect3 xprev = new Vect3(); Vect3 dx = new Vect3(); List<Point3D> pnts = new List<Point3D>(); List<Vect3> tans = new List<Vect3>(); xVal(stest[0], ref uv, ref xprev); pnts.Add(new Point3D(xprev.ToArray())); spos.Add(stest[0]); for (nTest = 1; nTest < stest.Length; nTest++) { for (int i = 1; i <= nAdd[nTest]; i++) { smid = ((nAdd[nTest] - i) * stest[nTest - 1] + i * stest[nTest]) / nAdd[nTest]; xVec(smid, ref uv, ref xyz, ref dx); spos.Add(smid); pnts.Add(new Point3D(xyz.ToArray())); tans.Add(new Vect3(dx)); m_Length += xyz.Distance(xprev); xprev.Set(xyz); } } if (EXTENDENTITY) { //add for-cast/back-cast points for (int i = 0; i < 2; i++) { for (nTest = 0; nTest < 10; nTest++) { smid = BLAS.interpolant(nTest, 10) * 0.05;//scale down to .1 cast if (i == 0) smid = -smid; else smid += 1.0; xVal(smid, ref uv, ref xyz); if (i == 0) pnts.Insert(0, new Point3D(xyz.ToArray())); else pnts.Add(new Point3D(xyz.ToArray())); } } } LinearPath lp = new LinearPath(pnts); lp.EntityData = this; //lp.LineWeight = 3.0f; //lp.LineWeightMethod = colorMethodType.byEntity; List<Entity> tanpaths = new List<Entity>(); tanpaths.Add(lp); if (bFitPoints) { //LinearPath path; //int npnt = 0; //foreach (Vect3 pnt in tans) //{ // pnt.Magnitude = 2; // xyz = new Vect3(pnts[npnt].ToArray()); // xyz += pnt; // path = new LinearPath(pnts[npnt], new Point3D(xyz.ToArray())); // path.EntityData = this; // tanpaths.Add(path); // npnt++; // //xVal(pnt.UV, ref xyz); // //pnts.Add(new Point3D(xyz.ToArray())); //} pnts = new List<Point3D>(); foreach (IFitPoint pnt in FitPoints) { xVal(pnt.UV, ref xyz); pnts.Add(new Point3D(xyz.ToArray())); } PointCloud pc = new PointCloud(pnts, 8f); pc.EntityData = this; tanpaths.Add(pc); } sPos = spos.ToArray(); return tanpaths; }
/// <summary> /// fit a curve to the specified points /// requires S parameter specified for each point /// requires at least 5 points /// </summary> /// <param name="points">points to fit to, minimum 5</param> internal static void SimpleFit(MouldCurve c, IFitPoint[] points) { Vect2 uv = new Vect2(); Vect3 x0 = new Vect3(); Vect3 x1 = new Vect3(); double[][] uFits = new double[2][]; double[] sFits = new double[points.Length]; uFits[0] = new double[points.Length]; uFits[1] = new double[points.Length]; //complile fitpoints to fitting arrays sFits[0] = 0; points[0][0] = 0; c.xVal(points[0].UV, ref x0);//initialize starting x point for (int nFit = 0; nFit < points.Length; nFit++) { //sFits[nFit] = fits[nFit][0]; uFits[0][nFit] = points[nFit][1]; uFits[1][nFit] = points[nFit][2]; if (nFit > 0) { c.xVal(points[nFit].UV, ref x1); points[nFit][0] = points[nFit - 1][0] + x1.Distance(x0); x0.Set(x1);//store previous x point } } for (int nFit = 0; nFit < points.Length; nFit++) sFits[nFit] = points[nFit][0] /= points.Last()[0];//convert length to position //sFits[sFits.Length-1] = fits.Last()[0] = 1;//enforce unit length c.FitPoints = points; c.ReSpline(sFits, uFits); }
/// <summary> /// Interpolates intermediate points in uv and fits a curve /// </summary> /// <param name="c">the curve to fit</param> /// <param name="points">points to fit to, minimum 2</param> internal static void InterpoFit(MouldCurve c, IFitPoint[] points) { if (points.Length <= 1 || points.Length >= 5)//need at least 2 points to fit a curve, can't interpolate more than 4 return; //recalculate s-positions based on xyz-values //if (RePos) //{ // Vect2 uv = new Vect2(); // Vect3 x0 = new Vect3(); // Vect3 x1 = new Vect3(); // fits[0][0] = 0;//initialize s paramter // Surface.xVal(fits[0].UV, ref x0);//initialize starting x point // for (int nFit = 1; nFit < fits.Length; nFit++) // { // Surface.xVal(fits[nFit].UV, ref x1); // fits[nFit][0] = fits[nFit - 1][0] + x1.Distance(x0); // x1.Set(x0);//store previous x point // } // for (int nFit = 0; nFit < fits.Length; nFit++) // fits[nFit][0] /= fits.Last()[0];//convert length to position // fits.Last()[0] = 1;//enforce unit length //} //linear uv interpolation to match minimum 5 points required double[][] uFits = new double[2][]; double[] sFits = new double[5]; uFits[0] = new double[5]; uFits[1] = new double[5]; double p; int i, nint = 0; Vect3 x2 = new Vect3(), x1 = new Vect3(); Vect2 umid = new Vect2(); Dictionary<int, int> FitstoSFits = new Dictionary<int, int>(); if (points.Length == 4) { //store fitpoints sFits[nint] = points[nint][0] = 0; uFits[0][nint] = points[nint][1]; uFits[1][nint] = points[nint][2]; c.xVal(points[nint].UV, ref x1); FitstoSFits[nint] = nint; nint++; //store fitpoints //sFits[nint] = fits[nint][0]; uFits[0][nint] = points[nint][1]; uFits[1][nint] = points[nint][2]; c.xVal(points[nint].UV, ref x2); sFits[nint] = x2.Distance(x1) + sFits[nint - 1]; FitstoSFits[nint] = nint; nint++; //insert midpoint //sFits[nint] = (fits[nint][0] + fits[nint - 1][0]) / 2.0; umid = points[nint].UV + points[nint - 1].UV; umid /= 2; uFits[0][nint] = umid[0]; uFits[1][nint] = umid[1]; c.xVal(umid, ref x1); sFits[nint] = x2.Distance(x1) + sFits[nint - 1]; nint++; //store fitpoints //sFits[nint] = fits[nint-1][0]; uFits[0][nint] = points[nint - 1][1]; uFits[1][nint] = points[nint - 1][2]; c.xVal(points[nint - 1].UV, ref x2); sFits[nint] = x2.Distance(x1) + sFits[nint - 1]; FitstoSFits[nint - 1] = nint; nint++; //store fitpoints //sFits[nint] = fits[nint-1][0]; uFits[0][nint] = points[nint - 1][1]; uFits[1][nint] = points[nint - 1][2]; c.xVal(points[nint - 1].UV, ref x1); sFits[nint] = x2.Distance(x1) + sFits[nint - 1]; FitstoSFits[nint - 1] = nint; nint++; } else { int num = (5 - points.Length) / (points.Length - 1);//insertion points num = num < 1 ? 1 : num; for (i = 0; i < points.Length - 1; i++) { //store fitpoints //sFits[nint] = fits[i][0]; uFits[0][nint] = points[i][1]; uFits[1][nint] = points[i][2]; FitstoSFits[i] = nint; c.xVal(points[i].UV, ref x1); if (i == 0) { sFits[nint] = 0; } else { sFits[nint] = x2.Distance(x1) + sFits[nint - 1]; } x2.Set(x1);//store xprev nint++; for (int j = 1; j <= num; j++) { //interpolate insertion points and store p = BLAS.interpolant(j, num + 2); //sFits[nint] = BLAS.interpolate(p, fits[i + 1][0], fits[i][0]); umid[0] = uFits[0][nint] = BLAS.interpolate(p, points[i + 1][1], points[i][1]); umid[1] = uFits[1][nint] = BLAS.interpolate(p, points[i + 1][2], points[i][2]); c.xVal(umid, ref x1); sFits[nint] = x2.Distance(x1) + sFits[nint - 1]; x2.Set(x1);//store xprev nint++; } } //endpoint //sFits[nint] = 1; uFits[0][nint] = points[i][1]; uFits[1][nint] = points[i][2]; c.xVal(points[i].UV, ref x1); sFits[nint] = x2.Distance(x1) + sFits[nint - 1]; System.Diagnostics.Debug.Assert(nint == 4); FitstoSFits[i] = nint; } for (i = 0; i < sFits.Length; i++) sFits[i] /= sFits.Last(); //sFits[sFits.Length - 1] = 1; foreach (int key in FitstoSFits.Keys) points[key][0] = sFits[FitstoSFits[key]]; c.FitPoints = points; c.ReSpline(sFits, uFits); }
/// <summary> /// Fits a multi-segement geodesic between the specified fitpoints optionally specifying which segments to girth /// </summary> /// <param name="points">the array of fitpoints, must be more than 2</param> /// <param name="bGirths">an array specifying which segments to girth and which to spline /// count is 1 less than the fitpoints count /// can be null which defaults to first and last segment girths</param> /// <returns>true if successful, false otherwise</returns> internal static bool Geo(MouldCurve g, IFitPoint[] points) { if (points == null || points.Length < 2) return false; else if (points.Length == 2 && g.IsGirth(0)) return Geo(g, points[0], points[1]); //compiled piecewise values List<double> S = new List<double>(); List<Vect2> U = new List<Vect2>(); //segment values double[] spos = null; Vect2[] upos = null; Vect3 xyz = new Vect3(), xyp = new Vect3(); //initialize S and U points[0].S = 0; S.Add(0); U.Add(points[0].UV); for (int i = 1; i < points.Length; i++) { //span a geo between the fitpoints //if (i % 2 == 1) if( g.IsGirth(i-1) ) { if (!GeoSegment(g, points[i - 1], points[i], ref spos, ref upos)) return false; for (int nS = 1; nS < spos.Length; nS++) { //scale the spos by length to get distance S.Add(spos[nS] * g.Length + points[i - 1].S); //copy the upos U.Add(upos[nS]); } } else// if (i % 2 == 0) { g.xVal(points[i - 1].UV, ref xyp); g.xVal(points[i].UV, ref xyz); S.Add(xyz.Distance(xyp) + points[i-1].S); U.Add(points[i].UV); } points[i].S = S.Last();//store the curent length for paramterization } //reparamaterize g.Length = S.Last(); for (int i = 0; i < S.Count; i++) S[i] /= g.Length; for (int i = 0; i < points.Length; i++) points[i].S /= g.Length; //spline the combined points g.ReSpline(S.ToArray(), U.ToArray()); g.FitPoints = points; return true; }