/// <summary> /// /// </summary> /// <param name="x"></param> /// <param name="y"></param> internal bool ValueChange(float x, float y) { if (CurrentIndex.IsValid()) { var m_path = Paths[CurrentIndex.BlockIndex]; var item = m_path[CurrentIndex.ItemIndex]; item.ValueChange(CurrentIndex.PartIndex, x, y); if (item.IsC() && CurrentIndex.PartIndex == 2) { int nextindex = CurrentIndex.ItemIndex + 1; if (nextindex >= m_path.Count) { nextindex = 0; } SvgPathItem next = m_path[nextindex]; if (next.IsZ()) { next = m_path[0]; if (next.IsM()) { next.ValueChange(0, x, y); nextindex = 1; next = m_path[nextindex]; } } if (next.IsC()) { next.ValueChange(0, x, y); } } return(true); } return(false); }
int PathCount(ref SvgPathItem last) { // 先頭を探す var top = FindTop(); // アイテム数を数えるのと最後を見つける last = top; int count = 1; for (; ;) { if (last.Next == null || last.Next.IsZ()) { break; } last = last.Next; count++; } if (last.Next != null) { if (top.GetPoint() == last.GetPoint()) { count--; } } return(count); }
/// <summary> /// 現在の座標を指定されたいテムを指定した角度回転した値にセット。 /// </summary> /// <param name="item0"></param> /// <param name="partIndex"></param> /// <param name="center"></param> /// <param name="da"></param> internal void ApplyOtherValue2(SvgPathItem item0, int partIndex, Vector2 center, float da) { switch (Command) { case 'C': case 'c': { if (item0.IsC()) { if (partIndex == 2 || partIndex == 1) { Vector2 p = item0.GetPoint(); Vector2 ps = GetPoint(); p = CalcRotatePosition(p, center, da); points[2] = p; // コントロールポイント2も同様に、 var cp2 = item0.GetControlPoint(true); cp2 = CalcRotatePosition(cp2, center, da); points[1] = cp2; // 隣のコントロールポイント1も同様に var nexti = FindNext(); if (nexti.IsC()) { nexti.ControlRotate(0, center, ps, p); } } else if (partIndex == 0) { /* * SvgPathItem item = item0.FindBefor(); * Vector2 p = item.GetPoint(); * * p = CalcRotatePosition(p, center, da); * var itemb = FindBefor(); * itemb.SetPoint(p); * * // コントロールポイント * var cp1 = item0.GetControlPoint(false); * cp1 = CalcRotatePosition(p, center, da); * points[0] = cp1; */ var p = item0.GetControlPoint(false); p = CalcRotatePosition(p, center, da); points[0] = p; } } break; } case 'M': case 'l': case 'L': { Vector2 p = item0.GetPoint(); p = CalcRotatePosition(p, center, da); points[0] = p; break; } } }
public SvgPathData(SvgEditData item, PolygonUnit polygonUnitValue) { CurrentIndex = new SvgPathIndex(); var m_path = item?.GetPathData(); Paths = new List <List <SvgPathItem> >(); List <SvgPathItem> path = null; if (m_path != null) { SvgPathItem top = null; SvgPathItem befor = null; foreach (var p in m_path) { if (p.Command == 'm' || p.Command == 'M') { befor = null; top = p; path = new List <SvgPathItem>(); path.Add(p); Paths.Add(path); } else if (path != null) { path.Add(p); } if (befor != null) { befor.Next = p; } befor = p; } } }
internal static void SetPreviusPoint(List <SvgPathItem> path, int index, Vector2 p1) { SvgPathItem pre = null; Vector2? pm = null; index--; if (index < 0) { index = path.Count - 1; } pre = path[index]; if (pre.IsM()) { pm = pre.GetPoint(); pre.SetPoint(p1); } if (pre.IsZ()) { index--; pre = path[index]; } if (pm == null) { pre.SetPoint(p1); } else { var p = pre.GetPoint(); if (p == pm) { pre.SetPoint(p1); } } }
public SvgPathItem(char command, SvgPathItem befor) { this.befor = befor; Command = command; index = 0; points = new List <Vector2>(); beforPoint = befor == null ? new Vector2(0, 0) : befor.GetPoint(); }
internal void AdjustSymmetric(SvgPathItem item) { if (!IsC() || !item.IsC()) { return; } var c = item.GetControlPoint(true); var p = item.GetPoint(); c.X = p.X + (p.X - c.X); c.Y = p.Y + (p.Y - c.Y); points[0] = c; }
internal void RulerShow(Vector2 startPoint, Vector2 endPoint) { if (!RulerEnabled) { List <SvgPathItem> path = new List <SvgPathItem>(); SvgPathItem p1 = new SvgPathItem('M', null); p1.SetPoint(startPoint); SvgPathItem p2 = new SvgPathItem('L', p1); p2.SetPoint(endPoint); p1.Next = p2; path.Add(p1); path.Add(p2); Paths.Add(path); } RulerEnabled = true; RulerVisible = true; }
private SvgPathItem FindBefor() { var item = befor; if (item == null || item.IsM()) { SvgPathItem last = null; PathCount(ref last); if (item == null) { return(last); } if (item.GetPoint() == last.GetPoint()) { return(last); } } return(item); }
/// <summary> /// 中心を返す、循環してなかったらnullを返す /// </summary> /// <returns></returns> private Vector2?CalcCenter() { // 先頭を探す var top = FindTop(); SvgPathItem last = null; int count = PathCount(ref last); int offset = last.IsC() ? 1 : 0; var item0 = top; var n1 = count / 2; var item1 = top;// = m_path[n1]; int index = 0; for (; ;) { if (item1.Next == null) { return(null); } if (index == n1) { break; } item1 = item1.Next; index++; } var p0 = item0.GetPoint(); var p1 = item1.GetPoint(); float x = MathF.Round((float)(p0.X + p1.X) / 2); float y = MathF.Round((float)(p0.Y + p1.Y) / 2); System.Diagnostics.Debug.WriteLine("中心 {0:0.00},{1:0.00}", x, y); return(new Vector2(x, y)); }
/// <summary> /// 直線と直線の交わりにベジェを挿入し角丸めにする。 /// </summary> /// <returns></returns> internal bool InsRoundCorner() { if (!CurrentIndex.IsValid()) { return(false); } var path = Paths[CurrentIndex.BlockIndex]; if (path.Count <= CurrentIndex.ItemIndex + 1) { return(false); } var item = path[CurrentIndex.ItemIndex]; // M の時は未対応 var next = path[CurrentIndex.ItemIndex + 1]; if (!item.IsL() || !(next.IsL() || next.IsZ())) { return(false); } if (next.IsZ()) { next = path[0]; // M のはず! } var pn = next.GetPoint(); SvgPathItem cp = item.CreateRoundCorner(pn); path.Insert(CurrentIndex.ItemIndex + 1, cp); next.SetBefor(cp); cp.SetBefor(item); return(true); }
/// <summary> /// /// </summary> /// <param name="path"></param> /// <param name="index">自分のindex</param> /// <param name="step"></param> /// <returns></returns> internal bool RoundCorner(List <SvgPathItem> path, int index, float step) { SvgPathItem b1 = path[index - 1]; // 自分はCなので最低Mは存在する。 var p1 = b1.GetPoint(); var p3 = GetPoint(); SvgPathItem b2 = null; if (index >= 2) { b2 = path[index - 2]; } else { var item = path[path.Count - 1]; if (item.IsZ()) { b2 = path[path.Count - 2]; var p = b2.GetPoint(); if (p == p1) { if (b2.IsL()) { b2 = null; } } } } if (b2 == null) { return(false); } var p2 = b2.GetPoint(); SvgPathItem n1 = null; if (index <= path.Count - 2) { n1 = path[index + 1]; if (n1.IsZ()) { n1 = path[0]; var p = n1.GetPoint(); if (p == p3) { n1 = path[1]; if (!n1.IsL()) { return(false); } } } } else { return(false); } // 交点求める公式より var p4 = n1.GetPoint(); float dev = (p2.Y - p1.Y) * (p4.X - p3.X) - (p2.X - p1.X) * (p4.Y - p3.Y); if (dev == 0) { return(false); } float d1 = p3.Y * p4.X - p3.X * p4.Y; float d2 = p1.Y * p2.X - p1.X * p2.Y; float x = d1 * (p2.X - p1.X) - d2 * (p4.X - p3.X); x /= dev; float y = d1 * (p2.Y - p1.Y) - d2 * (p4.Y - p3.Y); y /= dev; if (RoundSub(new Vector2(x, y), p2, p4, ref p1, ref p3, step)) { SvgPathData.SetPreviusPoint(path, index, p1); SvgPathData.SetSameNextPoint(path, index); return(true); } return(false); }
/// <summary> /// item の線対称の値をセット /// </summary> /// <param name="item"></param> /// <param name="partIndex"></param> /// <param name="start"></param> /// <param name="end"></param> internal void ApplyOtherValue(SvgPathItem item, int partIndex, Vector2 start, Vector2 end) { if (item.IsC() || IsC()) { switch (Command) { case 'L': case 'l': case 'M': case 'm': { if (item.IsC()) { // 自分の次はCで無いとつじつまが合わない var next = this.Next; if (next == null || !next.IsC()) { return; } if (partIndex == 2) { points[0] = CalcSymmetricPoint(item.GetPoint(partIndex), start, end); } if (partIndex == 2 || partIndex == 1) { var v = CalcSymmetricPoint(item.GetPoint(1), start, end); next.SetPoint(v, 0); } if (partIndex == 0) { var v = CalcSymmetricPoint(item.GetPoint(1), start, end); next.SetPoint(v, 1); } } break; } case 'c': case 'C': // 自分が C if (item.IsC()) { if (partIndex == 2) //終点 この場合は全体を移動 { { var v = CalcSymmetricPoint(item.GetPoint(), start, end); SetPoint(v, 2); } // 制御点をitemの制御点にあわせる { // item の終点の制御点を next の始点の制御点に var next = this.Next; if (next != null && next.IsC()) { var v = CalcSymmetricPoint(item.GetPoint(1), start, end); next.SetPoint(v, 0); } } { // item の 次の始点の制御点を this の終点の制御点に var next = item.Next; if (next != null && next.IsC()) { var v = CalcSymmetricPoint(next.GetPoint(0), start, end); SetPoint(v, 1); } } } else if (partIndex == 0) { // 相手側の始点制御点の変更 なので、相手側の対象点を自分の次のアイテムの終点制御点へ var next = this.Next; if (next != null && next.IsC()) { var v = CalcSymmetricPoint(item.GetPoint(0), start, end); next.SetPoint(v, 1); } } } else if (item.IsL() || item.IsM()) { // itemの次はCで無いとつじつまが合わない var next = item.Next; if (next == null || !next.IsC()) { return; } { var v = CalcSymmetricPoint(item.GetPoint(), start, end); SetPoint(v, 2); } { var v = CalcSymmetricPoint(next.GetPoint(0), start, end); SetPoint(v, 1); } } break; } } else if (item.IsL() || item.IsM()) { switch (Command) { case 'L': case 'l': case 'M': case 'm': { points[0] = CalcSymmetricPoint(item.GetPoint(), start, end); } break; } } }
internal void SetBefor(SvgPathItem cp) { befor = cp; beforPoint = befor.GetPoint(); }
int sweep_flag; //円弧の方向 1: 時計回りを採用,0:半時計回りを採用 public static SvgPathItem Create(char command, SvgPathItem item) { return(new SvgPathItem(command, item)); }
/// <summary> /// /// </summary> /// <param name="pn"></param> /// <returns></returns> internal SvgPathItem CreateRoundCorner(Vector2 pn) { var pc = GetPoint(); var pb = befor.GetPoint(); var a1 = MathF.Atan2(pc.Y - pb.Y, pc.X - pb.X); //傾き var a2 = MathF.Atan2(pn.Y - pc.Y, pn.X - pc.X); //次の線の傾き var a = (a1 + a2) / 2; a = MathF.Abs(a); if (a > MathF.PI) { a -= MathF.PI; } float r = 2; float v = 0; v = r / MathF.Tan(a); // 半径r円の接点の頂点からの距離 float l1 = CmUtils.Length(pb, pc); // 自分の線の長さ float l2 = CmUtils.Length(pc, pn); // 次の線の長さ if (l1 < v || l2 < v) { return(null); } var citem = new SvgPathItem('C', this); var x = MathF.Cos(a1) * v; var y = MathF.Sin(a1) * v; var p1 = new Vector2(pc.X - x, pc.Y - y); x = MathF.Cos(a2) * v; y = MathF.Sin(a2) * v; var p2 = new Vector2(pc.X + x, pc.Y + y); var c = r * 0.5522847f; // 半径rの円弧に近似するためのコントロールポイントの長さ x = MathF.Cos(a1) * c; y = MathF.Sin(a1) * c; var c1 = new Vector2(p1.X + x, p1.Y + y); x = MathF.Cos(a2) * c; y = MathF.Sin(a2) * c; var c2 = new Vector2(p2.X - x, p2.Y - y); var points = new List <Vector2>(); points.Add(c1); points.Add(c2); points.Add(p2); citem.SetPoints(points); this.points[0] = p1; CmUtils.DebugWriteLine(string.Format("a1:{0:0.00},a2:{1:0.00},vl:{2:0.00},cl:{3:0.00}", CmUtils.ToAngle(a1), CmUtils.ToAngle(a2), v, c)); return(citem); }
/// <summary> /// 位置変更メイン /// </summary> /// <param name="polygonUnit"></param> /// <param name="partIndex"></param> /// <param name="dx"></param> /// <param name="dy"></param> /// <param name="da"></param> /// <param name="dr"></param> /// <param name="center"></param> /// <returns></returns> internal bool PointChange(MainPage.PolygonUnit polygonUnit, int partIndex, float dx, float dy, float da, float dr, Vector2 center) { int unit = (int)polygonUnit; bool rot = true; if (dx != 0 || dy != 0) { rot = false; } if (rot) { if (IsC() && partIndex != 2) { if (partIndex == 1) { center = points[2]; } else { center = befor.GetPoint(); // C の場合最低前にMが存在。 } } ValueRotate(partIndex, center, da, dr); } else { // 移動 ValueChange(partIndex, dx, dy); } //---------------------------------------------------------- if (polygonUnit == MainPage.PolygonUnit.Symmetry) { } else if (unit > 0 && polygonUnit != MainPage.PolygonUnit.RulerOrigin) { if (IsC() && partIndex != 2) { var v = CalcCenter(); if (v == null) { return(false); } center = v.Value; } SvgPathItem last = null; var top = FindTop(); int count = PathCount(ref last); var item = this; for (int cx = 1; cx < count / unit; cx++) { for (int ix = 0; ix < unit; ix++) { item = item.FindNext(true); } if (item == this) { break; } item.ApplyOtherValue2(this, partIndex, center, (360.0f / count * unit) * cx); } } return(true); }