diff --git a/aegisub/spline.cpp b/aegisub/spline.cpp index 84799a043..946234514 100644 --- a/aegisub/spline.cpp +++ b/aegisub/spline.cpp @@ -181,9 +181,26 @@ void Spline::DecodeFromASS(wxString str) { //////////////////////////////// -// Append a curve to the spline -void Spline::AppendCurve(SplineCurve &curve) { - curves.push_back(curve); +// Insert a curve to the spline +void Spline::InsertCurve(SplineCurve &curve,int index) { + if (index == -1) curves.push_back(curve); + else { + std::list::iterator cur; + int i=0; + for (cur=curves.begin();cur!=curves.end() && i < index;cur++,i++); + curves.insert(cur,curve); + } +} + + +//////////////////////// +// Get a specific curve +SplineCurve *Spline::GetCurve(int index) { + int i=0; + for (std::list::iterator cur=curves.begin();cur!=curves.end() && i <= index;cur++,i++) { + if (i==index) return &(*cur); + } + return NULL; } @@ -279,7 +296,7 @@ void Spline::GetPointList(std::vector &points) { int steps = len/8; // Render curve - for (int i=0;iGetPoint(t)); diff --git a/aegisub/spline.h b/aegisub/spline.h index 7f4136f1b..8ff869da2 100644 --- a/aegisub/spline.h +++ b/aegisub/spline.h @@ -56,11 +56,13 @@ public: wxString EncodeToASS(); void DecodeFromASS(wxString str); - void AppendCurve(SplineCurve &curve); + void AppendCurve(SplineCurve &curve) { InsertCurve(curve,-1); } + void InsertCurve(SplineCurve &curve,int index); void MovePoint(int curveIndex,int point,wxPoint pos); void Smooth(float smooth=1.0f); void GetPointList(std::vector &points); + SplineCurve *GetCurve(int index); void GetClosestParametricPoint(Vector2D reference,int &curve,float &t,Vector2D &point); Vector2D GetClosestPoint(Vector2D reference); diff --git a/aegisub/spline_curve.cpp b/aegisub/spline_curve.cpp index 25d7c3986..a5b982073 100644 --- a/aegisub/spline_curve.cpp +++ b/aegisub/spline_curve.cpp @@ -55,9 +55,9 @@ void SplineCurve::Split(SplineCurve &c1,SplineCurve &c2,float t) { c1.type = CURVE_LINE; c2.type = CURVE_LINE; c1.p1 = p1; - c1.p2 = p1*t+p2*(1-t); - c2.p1 = c1.p2; c2.p2 = p2; + c1.p2 = p1*(1-t)+p2*t; + c2.p1 = c1.p2; } // Split a bicubic @@ -67,22 +67,22 @@ void SplineCurve::Split(SplineCurve &c1,SplineCurve &c2,float t) { // Sub-divisions float u = 1-t; - Vector2D p12 = p1*t+p2*u; - Vector2D p23 = p2*t+p3*u; - Vector2D p34 = p3*t+p4*u; - Vector2D p123 = p12*t+p23*u; - Vector2D p234 = p23*t+p34*u; - Vector2D p1234 = p123*t+p234*u; + Vector2D p12 = p1*u+p2*t; + Vector2D p23 = p2*u+p3*t; + Vector2D p34 = p3*u+p4*t; + Vector2D p123 = p12*u+p23*t; + Vector2D p234 = p23*u+p34*t; + Vector2D p1234 = p123*u+p234*t; // Set points c1.p1 = p1; + c2.p4 = p4; c1.p2 = p12; c1.p3 = p123; c1.p4 = p1234; c2.p1 = p1234; c2.p2 = p234; c2.p3 = p34; - c2.p4 = p4; } } @@ -168,8 +168,7 @@ Vector2D SplineCurve::GetClosestPoint(Vector2D ref) const { float SplineCurve::GetClosestParam(Vector2D ref) const { // Line if (type == CURVE_LINE) { - //return MID(0.0f,((ref.x-p1.x)*(p2.x-p1.x) + (ref.y-p1.y)*(p2.y-p1.y))/(p2-p1).SquareLen(),1.0f); - return MID(0.0f,(ref-p1).Dot(p2-p1)/(p2-p1).SquareLen(),1.0f); + return GetClosestSegmentPart(p1,p2,ref); } // Bicubic @@ -196,6 +195,32 @@ float SplineCurve::GetClosestParam(Vector2D ref) const { ////////////////// // Quick distance float SplineCurve::GetQuickDistance(Vector2D ref) const { - if (type == CURVE_BICUBIC) return MIN(MIN((ref-p1).Len(),(ref-p2).Len()),MIN((ref-p3).Len(),(ref-p4).Len())); + // Bicubic + if (type == CURVE_BICUBIC) { + float len1 = GetClosestSegmentDistance(p1,p2,ref); + float len2 = GetClosestSegmentDistance(p2,p3,ref); + float len3 = GetClosestSegmentDistance(p3,p4,ref); + float len4 = GetClosestSegmentDistance(p4,p1,ref); + float len5 = GetClosestSegmentDistance(p1,p3,ref); + float len6 = GetClosestSegmentDistance(p2,p4,ref); + return MIN(MIN(MIN(len1,len2),MIN(len3,len4)),MIN(len5,len6)); + } + + // Something else else return (GetClosestPoint(ref)-ref).Len(); } + + +////////////////////////////////////////// +// Closest t in segment p1-p2 to point p3 +float SplineCurve::GetClosestSegmentPart(Vector2D pt1,Vector2D pt2,Vector2D pt3) const { + return MID(0.0f,(pt3-pt1).Dot(pt2-pt1)/(pt2-pt1).SquareLen(),1.0f); +} + + +///////////////////////////////////////////////// +// Closest distance between p3 and segment p1-p2 +float SplineCurve::GetClosestSegmentDistance(Vector2D pt1,Vector2D pt2,Vector2D pt3) const { + float t = GetClosestSegmentPart(pt1,pt2,pt3); + return (pt1*(1.0f-t)+pt2*t-pt3).Len(); +} diff --git a/aegisub/spline_curve.h b/aegisub/spline_curve.h index ae3d130b7..511ea2988 100644 --- a/aegisub/spline_curve.h +++ b/aegisub/spline_curve.h @@ -55,6 +55,10 @@ enum CurveType { //////////////// // Spline curve class SplineCurve { +private: + float GetClosestSegmentPart(Vector2D p1,Vector2D p2,Vector2D p3) const; + float GetClosestSegmentDistance(Vector2D p1,Vector2D p2,Vector2D p3) const; + public: Vector2D p1,p2,p3,p4; CurveType type; diff --git a/aegisub/visual_tool_vector_clip.cpp b/aegisub/visual_tool_vector_clip.cpp index 3ef968f8d..c873f6ebe 100644 --- a/aegisub/visual_tool_vector_clip.cpp +++ b/aegisub/visual_tool_vector_clip.cpp @@ -289,7 +289,7 @@ void VisualToolVectorClip::ClickedFeature(VisualDraggableFeature &feature) { ///////////// // Can hold? bool VisualToolVectorClip::HoldEnabled() { - return mode == 1 || mode == 2 || mode == 6 || mode == 7; + return mode <= 4 || mode == 6 || mode == 7; } @@ -320,8 +320,45 @@ void VisualToolVectorClip::InitializeHold() { spline.AppendCurve(curve); } + // Convert and insert + else if (mode == 3 || mode == 4) { + // Get closest point + Vector2D pt; + int curve; + float t; + spline.GetClosestParametricPoint(Vector2D(mx,my),curve,t,pt); + + // Convert + if (mode == 3) { + } + + // Insert + else { + // Split the curve + SplineCurve *c1 = spline.GetCurve(curve); + SplineCurve c2; + if (!c1) { + SplineCurve ct; + ct.type = CURVE_LINE; + ct.p1 = spline.curves.back().GetEndPoint(); + ct.p2 = spline.curves.front().p1; + ct.p2 = ct.p1*(1-t) + ct.p2*t; + spline.AppendCurve(ct); + } + else { + c1->Split(*c1,c2,t); + spline.InsertCurve(c2,curve+1); + } + } + + // Commit + SetOverride(_T("\\clip"),_T("(") + spline.EncodeToASS() + _T(")")); + Commit(true); + holding = false; + } + // Freehand - if (mode == 6 || mode == 7) { + else if (mode == 6 || mode == 7) { spline.curves.clear(); lastX = -100000; lastY = -100000; @@ -386,7 +423,7 @@ void VisualToolVectorClip::CommitHold() { if (!holding && mode == 7) spline.Smooth(); // Save it - SetOverride(_T("\\clip"),_T("(") + spline.EncodeToASS() + _T(")")); + if (mode != 3 && mode != 4) SetOverride(_T("\\clip"),_T("(") + spline.EncodeToASS() + _T(")")); }