/// <summary> /// 単調増加ベジエの場合にのみ使用可。X座標からY座標を得る /// </summary> /// <param name="X"></param> /// <returns></returns> public float GetYFromX(float X) { float ret = 0; PointF p1 = BCPS[0].Second, p2 = BCPS[0].Second, p3 = BCPS[1].Second, p4 = BCPS[1].Second; if (BCPS[0].ValidThird) { p2 = BCPS[0].Third; } if (BCPS[1].ValidFirst) { p3 = BCPS[1].First; } float s = 0, e = 1; for (int i = 0; i < 20; i++) { float m = (s + e) / 2; var bp = BezierCaliculate.GetBezeirPoint(ref p1, ref p2, ref p3, ref p4, ref m); if (bp.X < X) { e = m; } else { s = m; } ret = bp.Y; } return(ret); }
/// <summary> /// 指定された割合分割されたベジエを得るメソッド /// </summary> /// <param name="num">最大、最小はMaxRatio,MinRatioから</param> /// <param name="bcps1">分割1</param> /// <param name="bcps2">分割2</param> public void GetDevidedBeziers(float num, out BezierControlPoint[] bcps1, out BezierControlPoint[] bcps2) { bcps1 = null; bcps2 = null; if (bcps == null || bcps.Length == 0) { return; } if (num < MinRatio) { num = MinRatio; } else if (num > MaxRatio) { num = MaxRatio; } //find where float sumnum = 0; float rest = 0; BezierControlPoint previous = null, next = null; int foundindex = -1; for (int i = 0; i < bcps.Length; i++) { BezierControlPoint bcp = bcps[i]; if (previous != null) { float ratio = eachlength[i - 1] / length * MaxRatio; if (sumnum + ratio >= num || (sumnum + ratio) >= MaxRatio - 0.0009765625) { next = bcp; rest = num - sumnum; foundindex = i; break; } sumnum += ratio; } previous = bcp; } if (foundindex != -1) { float targetratio = 1 - rest / MaxRatio * length / eachlength[foundindex - 1]; BezierCaliculate.GetDevidedBeziers(previous, next, targetratio, out BezierControlPoint bcp1, out BezierControlPoint bcp2, out BezierControlPoint bcp3); bcps1 = new BezierControlPoint[foundindex + 1]; bcps2 = new BezierControlPoint[BCPS.Length - foundindex + 1]; for (int i = 0; i < foundindex - 1; i++) { bcps1[i] = BCPS[i].Clone(); } bcps1[foundindex - 1] = bcp1; bcps1[foundindex] = bcp2.Clone(); bcps2[0] = bcp2; bcps2[1] = bcp3; for (int i = foundindex + 1; i < BCPS.Length; i++) { bcps2[i - foundindex + 1] = BCPS[i].Clone(); } return; } }
/// <summary> /// ベジエ曲線状に乗っているか調べる /// </summary> /// <param name="p1">頂点1</param> /// <param name="p2">頂点2</param> /// <param name="p3">頂点3</param> /// <param name="p4">頂点4</param> /// <param name="target">調べる対象</param> /// <param name="outt">乗っていた時の割合(0~1)</param> /// <returns></returns> public static bool OnBezeier(PointF p1, PointF p2, PointF p3, PointF p4, PointF target, out float outt) { PointF lastbezierpoint, bezierpoint; lastbezierpoint = p1; outt = -1; float best = float.MaxValue; var count = BezierCaliculate.AboutBezeirCount(ref p1, ref p2, ref p3, ref p4); for (int i = count; i >= 0; i--) { float t = (float)i / count; bezierpoint = BezierCaliculate.GetBezeirPoint(ref p1, ref p2, ref p3, ref p4, ref t); var temp = GetLength(new PointF(bezierpoint.X - target.X, bezierpoint.Y - target.Y)); if (temp < best) { best = temp; outt = t; } lastbezierpoint = bezierpoint; } if (best <= 2) { return(true); } return(false); }
/// <summary> /// 4頂点からベジエ曲線上の位置を得る /// </summary> /// <param name="p1">頂点1</param> /// <param name="p2">頂点2</param> /// <param name="p3">頂点3</param> /// <param name="p4">頂点4</param> /// <returns></returns> public static IEnumerable <PointF> GetPoints(PointF p1, PointF p2, PointF p3, PointF p4) { var count = BezierCaliculate.AboutBezeirCount(ref p1, ref p2, ref p3, ref p4); for (int i = count; i >= 0; i--) { float t = (float)i / count; yield return(BezierCaliculate.GetBezeirPoint(ref p1, ref p2, ref p3, ref p4, ref t)); } }
private void Analyze() { eachlength = new float[bcps.Length - 1]; BezierControlPoint previous = null; for (int i = 0; i < bcps.Length; i++) { BezierControlPoint bcp = bcps[i]; if (previous != null) { eachlength[i - 1] += BezierCaliculate.GetBezeierLength(previous, bcp); length += eachlength[i - 1]; } previous = bcp; } }
/// <summary> /// 連結ベジエから特定の割合の場所を得るメソッド /// </summary> /// <param name="num">最大、最小はMaxRatio,MinRatioから</param> /// <param name="direction">位置</param> /// <param name="pos">向き</param> /// <returns></returns> public void GetPoint(float num, out PointF pos, out PointF direction) { pos = PointF.Empty; direction = new PointF(1, 0); if (bcps == null || bcps.Length == 0) { return; } if (num < MinRatio) { num = MinRatio; } else if (num > MaxRatio) { num = MaxRatio; } //find where float sumnum = 0; float rest = 0; BezierControlPoint previous = null, next = null; int foundindex = -1; for (int i = 0; i < bcps.Length; i++) { BezierControlPoint bcp = bcps[i]; if (previous != null) { float ratio = eachlength[i - 1] / length * MaxRatio; if (sumnum + ratio >= num || (sumnum + ratio) >= MaxRatio - 0.0009765625) { next = bcp; rest = num - sumnum; foundindex = i; break; } sumnum += ratio; } previous = bcp; } if (foundindex != -1) { float targetlength = length * rest / MaxRatio; BezierCaliculate.GetBezeirSplitPoint(previous, next, targetlength, out pos, out direction); return; } }
private static float GetBezeierLength(PointF p1, PointF p2, PointF p3, PointF p4) { PointF lastbezierpoint, bezierpoint; lastbezierpoint = p1; float sum = 0; var count = BezierCaliculate.AboutBezeirCount(ref p1, ref p2, ref p3, ref p4); if (count == 0) { return(0); } for (int i = count; i >= 0; i--) { float t = (float)i / count; bezierpoint = BezierCaliculate.GetBezeirPoint(ref p1, ref p2, ref p3, ref p4, ref t); sum += GetLength(new PointF(bezierpoint.X - lastbezierpoint.X, bezierpoint.Y - lastbezierpoint.Y)); lastbezierpoint = bezierpoint; } return(sum); }
private static void GetBezeirSplitPoint(PointF p1, PointF p2, PointF p3, PointF p4, float length, out PointF pos, out PointF direction) { PointF lastbezierpoint, bezierpoint; lastbezierpoint = p1; pos = p1; direction = new PointF(1, 0); float sum = 0; var count = BezierCaliculate.AboutBezeirCount(ref p1, ref p2, ref p3, ref p4); for (int i = count; i >= 0; i--) { float t = (float)i / count; bezierpoint = BezierCaliculate.GetBezeirPoint(ref p1, ref p2, ref p3, ref p4, ref t); sum += GetLength(new PointF(bezierpoint.X - lastbezierpoint.X, bezierpoint.Y - lastbezierpoint.Y)); if (sum >= length) { pos = bezierpoint; direction = GetNormalizePoint(new PointF(bezierpoint.X - lastbezierpoint.X, bezierpoint.Y - lastbezierpoint.Y)); if (direction.X == 0 && direction.Y == 0) { t = (float)(i - 1) / count; lastbezierpoint = bezierpoint; bezierpoint = BezierCaliculate.GetBezeirPoint(ref p1, ref p2, ref p3, ref p4, ref t); direction = GetNormalizePoint(new PointF(bezierpoint.X - lastbezierpoint.X, bezierpoint.Y - lastbezierpoint.Y)); } return; } lastbezierpoint = bezierpoint; } pos = p4; direction = GetNormalizePoint(new PointF(p4.X - lastbezierpoint.X, p4.Y - lastbezierpoint.Y)); if (direction.X == 0 && direction.Y == 0) { float t = (float)1 / count; bezierpoint = BezierCaliculate.GetBezeirPoint(ref p1, ref p2, ref p3, ref p4, ref t); direction = GetNormalizePoint(new PointF(lastbezierpoint.X - bezierpoint.X, lastbezierpoint.Y - bezierpoint.Y)); } }