/// <summary> /// 指定したコントロールカーブにベジエ曲線を追加します。 /// </summary> /// <param name="curve_type"></param> /// <param name="chain"></param> public void addBezierChain(CurveType curve_type, BezierChain chain, int chain_id) { BezierChain add = (BezierChain)chain.clone(); add.id = chain_id; this.get(curve_type).Add(add); }
/// <summary> /// 与えられたBezierChainがx軸について陰かどうかを判定する /// </summary> /// <param name="chain"></param> /// <returns></returns> public static bool isBezierImplicit(BezierChain chain) { int size = chain.points.Count; if (size < 2) { return(true); } BezierPoint last_point = chain.points[0]; for (int i = 1; i < size; i++) { BezierPoint point = chain.points[i]; double pt1 = last_point.getBase().getX(); double pt2 = (last_point.getControlRightType() == BezierControlType.None) ? pt1 : last_point.getControlRight().getX(); double pt4 = point.getBase().getX(); double pt3 = (point.getControlLeftType() == BezierControlType.None) ? pt4 : point.getControlLeft().getX(); if (!isUnitBezierImplicit(pt1, pt2, pt3, pt4)) { return(false); } last_point = point; } return(true); }
public Object clone() { BezierChain result = new BezierChain(this.mColor); foreach (var bp in points) { result.points.Add((BezierPoint)bp.clone()); } result.Default = this.Default; result.id = id; return(result); }
public void setBezierChain(CurveType curve_type, int chain_id, BezierChain item) { List <BezierChain> list = this.get(curve_type); int count = list.Count; for (int i = 0; i < count; i++) { if (list[i].id == chain_id) { list[i] = item; break; } } }
public void handleMoveButtonClick(bool backward) { // イベントの送り主によって動作を変える int delta = 1; if (backward) { delta = -1; } // 選択中のデータ点を検索し,次に選択するデータ点を決める BezierChain target = AppManager.getVsqFile().AttachedCurves.get(m_track - 1).getBezierChain(m_curve_type, m_chain_id); int index = -2; int size = target.size(); for (int i = 0; i < size; i++) { if (target.points[i].getID() == m_point_id) { index = i + delta; break; } } // 次に選択するデータ点のインデックスが有効範囲なら,選択を実行 if (0 <= index && index < size) { // 選択を実行 m_point_id = target.points[index].getID(); m_point = target.points[index]; updateStatus(); m_parent.mEditingPointID = m_point_id; m_parent.doInvalidate(); // スクリーン上でデータ点が見えるようにする FormMain main = m_parent.getMainForm(); if (main != null) { main.ensureVisible((int)m_point.getBase().getX()); } } }
public BezierChain extractPartialBezier(double t_start, double t_end) { if (this.size() <= 1) { throw new Exception("chain must has two or more bezier points"); } double start = this.points[0].getBase().getX(); double end = this.points[this.size() - 1].getBase().getX(); // [from, to]が、このベジエ曲線の範囲内にあるかどうかを検査 if (start > t_start || t_end > end) { throw new Exception("no bezier point appeared in the range of \"from\" to \"to\""); } // t_start, t_endが既存のベジエデータ点位置を被っていないかどうか検査しながらコピー bool t_start_added = false; // 最初の区間が追加された直後だけ立つフラグ BezierChain edited = new BezierChain(mColor); int count = 0; for (int i = 0; i < this.points.Count - 1; i++) { if (this.points[i].getBase().getX() < t_start && t_start < this.points[i + 1].getBase().getX()) { if (this.points[i].getBase().getX() < t_end && t_end < this.points[i + 1].getBase().getX()) { #if DEBUG AppManager.debugWriteLine("points[i].Base.X < t_start < t_end < points[i + 1].Base.X"); #endif PointD x0 = this.points[i].getBase(); PointD x1 = this.points[i + 1].getBase(); PointD c0 = (this.points[i].getControlRightType() == BezierControlType.None) ? x0 : this.points[i].getControlRight(); PointD c1 = (this.points[i + 1].getControlLeftType() == BezierControlType.None) ? x1 : this.points[i + 1].getControlLeft(); PointD[] res = cutUnitBezier(x0, c0, c1, x1, t_start); x0 = res[3]; c0 = res[4]; c1 = res[5]; x1 = res[6]; res = cutUnitBezier(x0, c0, c1, x1, t_end); BezierPoint left = new BezierPoint(res[0]); BezierPoint right = new BezierPoint(res[3]); left.setControlRight(res[1]); right.setControlLeft(res[2]); left.setControlRightType(this.points[i].getControlRightType()); right.setControlLeftType(this.points[i + 1].getControlLeftType()); edited.add(left); edited.add(right); t_start_added = true; break; } else { #if DEBUG AppManager.debugWriteLine("points[i].Base.X < t_start < points[i + 1].Base.X"); #endif PointD x0 = this.points[i].getBase(); PointD x1 = this.points[i + 1].getBase(); PointD c0 = (this.points[i].getControlRightType() == BezierControlType.None) ? x0 : this.points[i].getControlRight(); PointD c1 = (this.points[i + 1].getControlLeftType() == BezierControlType.None) ? x1 : this.points[i + 1].getControlLeft(); PointD[] res = cutUnitBezier(x0, c0, c1, x1, t_start); BezierPoint left = new BezierPoint(res[3]); BezierPoint right = new BezierPoint(res[6]); left.setControlRight(res[4]); left.setControlRightType(this.points[i].getControlRightType()); right.setControlLeft(res[5]); right.setControlRight(this.points[i + 1].getControlRight()); right.setControlRightType(this.points[i + 1].getControlRightType()); right.setControlLeftType(this.points[i + 1].getControlLeftType()); edited.points.Add(left); count++; edited.points.Add(right); count++; t_start_added = true; } } if (t_start <= this.points[i].getBase().getX() && this.points[i].getBase().getX() <= t_end) { if (!t_start_added) { edited.points.Add((BezierPoint)this.points[i].clone()); count++; } else { t_start_added = false; } } if (this.points[i].getBase().getX() < t_end && t_end < this.points[i + 1].getBase().getX()) { PointD x0 = this.points[i].getBase(); PointD x1 = this.points[i + 1].getBase(); PointD c0 = (this.points[i].getControlRightType() == BezierControlType.None) ? x0 : this.points[i].getControlRight(); PointD c1 = (this.points[i + 1].getControlLeftType() == BezierControlType.None) ? x1 : this.points[i + 1].getControlLeft(); PointD[] res = cutUnitBezier(x0, c0, c1, x1, t_end); edited.points[count - 1].setControlRight(res[1]); BezierPoint right = new BezierPoint(res[3]); right.setControlLeft(res[2]); right.setControlLeftType(this.points[i + 1].getControlLeftType()); edited.add(right); count++; break; } } if (this.points[this.points.Count - 1].getBase().getX() == t_end && !t_start_added) { edited.add((BezierPoint)this.points[this.points.Count - 1].clone()); count++; } for (int i = 0; i < edited.size(); i++) { edited.points[i].setID(i); } return(edited); }
/// <summary> /// 指定したカーブ種類のベジエ曲線の,指定した範囲を削除します. /// 削除はclock_startからclock_endの範囲について行われ,clock_end以降のシフト操作は行われません. /// つまり,操作後にclock_end以降のイベントが(clock_end - clock_start)だけ前方にシフトしてくることはありません. /// </summary> /// <param name="target_curve"></param> /// <param name="clock_start"></param> /// <param name="clock_end"></param> /// <returns></returns> public bool deleteBeziers( List <CurveType> target_curve, int clock_start, int clock_end ) { bool edited = false; foreach (var curve in target_curve) { if (curve.isScalar() || curve.isAttachNote()) { continue; } List <BezierChain> tmp = new List <BezierChain>(); foreach (var bc in this.get(curve)) { int len = bc.points.Count; if (len < 1) { continue; } int chain_start = (int)bc.points[0].getBase().getX(); int chain_end; if (len < 2) { chain_end = chain_start; } else { chain_end = (int)bc.points[len - 1].getBase().getX(); } if (clock_start < chain_start && chain_start < clock_end && clock_end < chain_end) { // end ~ chain_endを残す try { BezierChain chain = bc.extractPartialBezier(clock_end, chain_end); chain.id = bc.id; tmp.Add(chain); edited = true; } catch (Exception ex) { Logger.write(typeof(BezierCurves) + ".deleteBeziers; ex=" + ex + "\n"); } } else if (chain_start <= clock_start && clock_end <= chain_end) { // chain_start ~ startとend ~ chain_endを残す try { BezierChain chain1 = bc.extractPartialBezier(chain_start, clock_start); chain1.id = bc.id; BezierChain chain2 = bc.extractPartialBezier(clock_end, chain_end); chain2.id = -1; // 後で番号をつける tmp.Add(chain1); tmp.Add(chain2); edited = true; } catch (Exception ex) { Logger.write(typeof(BezierCurves) + ".deleteBeziers; ex=" + ex + "\n"); } } else if (chain_start < clock_start && clock_start < chain_end && chain_end < clock_end) { // chain_start ~ startを残す try { BezierChain chain = bc.extractPartialBezier(chain_start, clock_start); chain.id = bc.id; tmp.Add(chain); edited = true; } catch (Exception ex) { Logger.write(typeof(BezierCurves) + ".deleteBeiers; ex=" + ex + "\n"); } } else if (clock_start <= chain_start && chain_end <= clock_end) { // 全体を削除 edited = true; } else { // 全体を残す tmp.Add((BezierChain)bc.clone()); } } this.get(curve).Clear(); foreach (var bc in tmp) { if (bc.id >= 0) { addBezierChain(curve, bc, bc.id); } } foreach (var bc in tmp) { if (bc.id < 0) { bc.id = this.getNextId(curve); addBezierChain(curve, bc, bc.id); } } } return(edited); }
/// <summary> /// 指定した種類のコントロールカーブにベジエ曲線を追加します。 /// AddBezierChainとの違い、オーバーラップする部分があれば自動的に結合されます。 /// chainには2個以上のデータ点が含まれている必要がある /// </summary> /// <param name="curve"></param> /// <param name="chain"></param> public void mergeBezierChain(CurveType curve, BezierChain chain) { if (chain.points.Count <= 1) { return; } int chain_start = (int)chain.getStart(); int chain_end = (int)chain.getEnd(); // まず、全削除する必要のあるBezierChainを検索 List <int> delete_list = new List <int>(); List <BezierChain> src = this.get(curve); //foreach ( int id in this[curve].Keys ) { for (int j = 0; j < src.Count; j++) { //BezierChain bc = this[curve][id]; BezierChain bc = src[j]; if (bc.points.Count <= 0) { continue; } int bc_start = (int)bc.getStart(); int bc_end = (int)bc.getEnd(); if (chain_start <= bc_start && bc_end <= chain_end) { delete_list.Add(bc.id); } } // 削除を実行 foreach (var id in delete_list) { remove(curve, id); //this[curve].Remove( id ); } // マージする必要があるかどうかを検査。 bool processed = true; while (processed) { processed = false; List <BezierChain> list = this.get(curve); //foreach ( int id in this[curve].Keys ) { for (int j = 0; j < list.Count; j++) { //BezierChain bc = this[curve][id]; BezierChain bc = list[j]; int id = bc.id; int start = (int)bc.getStart(); int end = (int)bc.getEnd(); // 被っている箇所が2箇所以上ある可能性があるので、ifでヒットしてもbreakしない if (start < chain_start && chain_start <= end && end < chain_end) { // bcのchain_start ~ endを削除し、chain_startで結合 BezierChain bc_edit = null; try { bc_edit = bc.extractPartialBezier(start, chain_start); } catch (Exception ex) { Logger.write(typeof(BezierCurves) + ".mergeBezierChain; ex=" + ex + "\n"); continue; } bc_edit.id = bc.id; int last = bc_edit.size() - 1; // 接合部分では、制御点無しでステップ変化する bc_edit.points[last].setControlRightType(BezierControlType.None); chain.points[0].setControlLeftType(BezierControlType.None); int copy_start = 0; if (bc_edit.points[last].getBase().getY() == chain.points[0].getBase().getY()) { // bcの終点とchainの始点の座標が一致している場合 if (bc_edit.points[last].getControlLeftType() != BezierControlType.None) { bc_edit.points[last].setControlLeftType(BezierControlType.Master); } bc_edit.points[last].setControlRight(chain.points[0].controlLeft); if (chain.points[0].getControlRightType() != BezierControlType.None) { bc_edit.points[last].setControlLeftType(BezierControlType.Master); } copy_start = 1; } for (int i = copy_start; i < chain.points.Count; i++) { chain.points[i].setID(bc_edit.getNextId()); bc_edit.add(chain.points[i]); } //this[curve].Remove( id ); remove(curve, id); chain = bc_edit; chain_start = (int)chain.getStart(); chain_end = (int)chain.getEnd(); processed = true; break; } else if (chain_start < start && start <= chain_end && chain_end < end) { // bcのstart ~ chain_endを削除し、chain_endで結合 BezierChain bc_edit = null; try { bc_edit = bc.extractPartialBezier(chain_end, end); } catch (Exception ex) { Logger.write(typeof(BezierCurves) + ".mergeBezierChain; ex=" + ex + "\n"); continue; } bc_edit.id = bc.id; int last = chain.size() - 1; // 接合部分では、制御点無しでステップ変化する bc_edit.points[0].setControlLeftType(BezierControlType.None); chain.points[last].setControlRightType(BezierControlType.None); int copy_end = last; if (chain.points[last].getBase().getY() == bc_edit.points[0].getBase().getY()) { // bcの終点とchainの始点の座標が一致している場合 if (chain.points[last].getControlLeftType() != BezierControlType.None) { chain.points[last].setControlLeftType(BezierControlType.Master); } chain.points[last].setControlRight(bc_edit.points[0].controlLeft); if (bc_edit.points[0].getControlRightType() != BezierControlType.None) { chain.points[last].setControlLeftType(BezierControlType.Master); } copy_end = last - 1; } for (int i = 0; i <= copy_end; i++) { chain.points[i].setID(bc_edit.getNextId()); bc_edit.add(chain.points[i]); } //this[curve].Remove( id ); remove(curve, id); chain = bc_edit; chain_start = (int)chain.getStart(); chain_end = (int)chain.getEnd(); processed = true; break; } else if (start < chain_start && chain_end < end) { // bcのchain_start ~ chain_endをchainで置き換え // left + chain + right BezierChain left = null; try { left = bc.extractPartialBezier(start, chain_start); } catch (Exception ex) { Logger.write(typeof(BezierCurves) + ".mergeBezierChain; ex=" + ex + "\n"); continue; } BezierChain right = null; try { right = bc.extractPartialBezier(chain_end, end); } catch (Exception ex) { Logger.write(typeof(BezierCurves) + ".mergeBezierChain; ex=" + ex + "\n"); continue; } left.id = bc.id; // 接合部ではステップ変化 left.points[left.size() - 1].setControlRightType(BezierControlType.None); chain.points[0].setControlLeftType(BezierControlType.None); chain.points[chain.size() - 1].setControlRightType(BezierControlType.None); right.points[0].setControlLeftType(BezierControlType.None); int copy_start = 0; int copy_end = chain.size() - 1; if (left.points[left.size() - 1].getBase().getY() == chain.points[0].getBase().getY()) { // bcの終点とchainの始点の座標が一致している場合 if (left.points[left.size() - 1].getControlLeftType() != BezierControlType.None) { left.points[left.size() - 1].setControlLeftType(BezierControlType.Master); } left.points[left.size() - 1].setControlRight(chain.points[0].controlLeft); if (chain.points[0].getControlRightType() != BezierControlType.None) { left.points[left.size() - 1].setControlLeftType(BezierControlType.Master); } copy_start = 1; } if (chain.points[chain.size() - 1].getBase().getY() == right.points[0].getBase().getY()) { // bcの終点とchainの始点の座標が一致している場合 if (chain.points[chain.size() - 1].getControlLeftType() != BezierControlType.None) { chain.points[chain.size() - 1].setControlLeftType(BezierControlType.Master); } chain.points[chain.size() - 1].setControlRight(right.points[0].controlLeft); if (right.points[0].getControlRightType() != BezierControlType.None) { chain.points[chain.size() - 1].setControlLeftType(BezierControlType.Master); } copy_end = chain.size() - 2; } // 追加 for (int i = copy_start; i <= copy_end; i++) { chain.points[i].setID(left.getNextId()); left.add(chain.points[i]); } for (int i = 0; i < right.points.Count; i++) { right.points[i].setID(left.getNextId()); left.add(right.points[i]); } //this[curve].Remove( id ); remove(curve, id); chain = left; chain_start = (int)chain.getStart(); chain_end = (int)chain.getEnd(); processed = true; break; } } } if (!processed) { chain.id = this.getNextId(curve); } //this[curve].Add( chain.ID, chain ); addBezierChain(curve, chain, chain.id); }