diff --git a/aegisub/spline.cpp b/aegisub/spline.cpp index 3b53b71b6..84799a043 100644 --- a/aegisub/spline.cpp +++ b/aegisub/spline.cpp @@ -261,18 +261,10 @@ void Spline::GetPointList(std::vector &points) { // Generate points for each curve for (std::list::iterator cur = curves.begin();cur!=curves.end();cur++) { // First point - if (isFirst) { - pt.x = cur->p1.x; - pt.y = cur->p1.y; - points.push_back(pt); - } + if (isFirst) points.push_back(cur->p1); // Line - if (cur->type == CURVE_LINE) { - pt.x = cur->p2.x; - pt.y = cur->p2.y; - points.push_back(pt); - } + if (cur->type == CURVE_LINE) points.push_back(cur->p2); // Bicubic else if (cur->type == CURVE_BICUBIC) { @@ -290,11 +282,7 @@ void Spline::GetPointList(std::vector &points) { for (int i=0;iGetPoint(t)); } } } @@ -308,16 +296,47 @@ void Spline::GetPointList(std::vector &points) { /////////////////////////////////////////////////////// // t value and curve of the point closest to reference -void GetClosestParametricPoint(Vector2D reference,int &curve,float &t) { - // TODO +void Spline::GetClosestParametricPoint(Vector2D reference,int &curve,float &t,Vector2D &pt) { + // Has at least one curve? + curve = 0; + t = 0.0f; + if (curves.size() == 0) return; + + // Close the shape + SplineCurve pad; + pad.p1 = curves.back().GetEndPoint(); + pad.p2 = curves.front().p1; + pad.type = CURVE_LINE; + curves.push_back(pad); + + // Prepare + float closest = 8000000.0f; + int i = 0; + for (std::list::iterator cur = curves.begin();cur!=curves.end();cur++,i++) { + float param = cur->GetClosestParam(reference); + Vector2D p1 = cur->GetPoint(param); + float dist = (p1-reference).Len(); + if (dist < closest) { + closest = dist; + t = param; + curve = i; + pt = p1; + } + } + + // Remove closing and return + curves.pop_back(); } ////////////////////////////// // Point closest to reference Vector2D Spline::GetClosestPoint(Vector2D reference) { - // TODO - return Vector2D(-1,-1); + int curve; + float t; + Vector2D point; + GetClosestParametricPoint(reference,curve,t,point); + return point; } diff --git a/aegisub/spline.h b/aegisub/spline.h index ede60db7e..7f4136f1b 100644 --- a/aegisub/spline.h +++ b/aegisub/spline.h @@ -62,7 +62,7 @@ public: void GetPointList(std::vector &points); - void GetClosestParametricPoint(Vector2D reference,int &curve,float &t); + void GetClosestParametricPoint(Vector2D reference,int &curve,float &t,Vector2D &point); Vector2D GetClosestPoint(Vector2D reference); Vector2D GetClosestControlPoint(Vector2D reference); }; diff --git a/aegisub/spline_curve.cpp b/aegisub/spline_curve.cpp index 3763ee043..25d7c3986 100644 --- a/aegisub/spline_curve.cpp +++ b/aegisub/spline_curve.cpp @@ -120,12 +120,33 @@ void SplineCurve::Smooth(Vector2D P0,Vector2D P3,float smooth) { } +/////////////// +// Get a point +Vector2D SplineCurve::GetPoint(float t) const { + // Point + if (type == CURVE_POINT) return p1; + + // Line + else if (type == CURVE_LINE) { + return p1*(1.0f-t) + p2*t; + } + + // Bicubic + else if (type == CURVE_BICUBIC) { + float u = 1.0f-t; + return p1*u*u*u + 3*p2*t*u*u + 3*p3*t*t*u + p4*t*t*t; + } + + else return Vector2D(0,0); +} + + /////////////////////// // Get start/end point -Vector2D SplineCurve::GetStartPoint() { +Vector2D SplineCurve::GetStartPoint() const { return p1; } -Vector2D SplineCurve::GetEndPoint() { +Vector2D SplineCurve::GetEndPoint() const { switch (type) { case CURVE_POINT: return p1; case CURVE_LINE: return p2; @@ -133,3 +154,48 @@ Vector2D SplineCurve::GetEndPoint() { default: return p1; } } + + +////////////////////////////////// +// Get point closest to reference +Vector2D SplineCurve::GetClosestPoint(Vector2D ref) const { + return GetPoint(GetClosestParam(ref)); +} + + +/////////////////////////////////////////// +// Get value of parameter closest to point +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); + } + + // Bicubic + if (type == CURVE_BICUBIC) { + int steps = 100; + float bestDist = 80000000.0f; + float bestT = 0.0f; + for (int i=0;i<=steps;i++) { + float t = float(i)/float(steps); + float dist = (GetPoint(t)-ref).Len(); + if (dist < bestDist) { + bestDist = dist; + bestT = t; + } + } + return bestT; + } + + // Something else + return 0.0f; +} + + +////////////////// +// 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())); + else return (GetClosestPoint(ref)-ref).Len(); +} diff --git a/aegisub/spline_curve.h b/aegisub/spline_curve.h index abf335475..ae3d130b7 100644 --- a/aegisub/spline_curve.h +++ b/aegisub/spline_curve.h @@ -62,6 +62,11 @@ public: SplineCurve(); void Split(SplineCurve &c1,SplineCurve &c2,float t=0.5); void Smooth(Vector2D prev,Vector2D next,float smooth=1.0f); - Vector2D GetStartPoint(); - Vector2D GetEndPoint(); + + Vector2D GetPoint(float t) const; + Vector2D GetStartPoint() const; + Vector2D GetEndPoint() const; + Vector2D GetClosestPoint(Vector2D ref) const; + float GetClosestParam(Vector2D ref) const; + float GetQuickDistance(Vector2D ref) const; }; diff --git a/aegisub/vector2d.cpp b/aegisub/vector2d.cpp index 0fcce40c4..17bfc0cc4 100644 --- a/aegisub/vector2d.cpp +++ b/aegisub/vector2d.cpp @@ -109,14 +109,14 @@ Vector2D Vector2D::operator -= (const Vector2D param) { ////////// // Negate -Vector2D Vector2D::operator - () { +Vector2D Vector2D::operator - () const { return Vector2D(-x,-y); } //////////////////////////// // Multiplication by scalar -Vector2D Vector2D::operator * (float param) { +Vector2D Vector2D::operator * (float param) const { return Vector2D(x * param,y * param); } @@ -133,7 +133,7 @@ Vector2D operator * (float f,const Vector2D &v) { ////////////////////// // Division by scalar -Vector2D Vector2D::operator / (float param) { +Vector2D Vector2D::operator / (float param) const { return Vector2D(x / param,y / param); } @@ -169,9 +169,16 @@ float Vector2D::Len () const { } +////////////////// +// Squared Length +float Vector2D::SquareLen () const { + return x*x + y*y; +} + + /////////// // Unitary -Vector2D Vector2D::Unit () { +Vector2D Vector2D::Unit () const { float l = Len(); if (l != 0) { Vector2D temp; diff --git a/aegisub/vector2d.h b/aegisub/vector2d.h index f5f14b5c0..b056c9532 100644 --- a/aegisub/vector2d.h +++ b/aegisub/vector2d.h @@ -51,23 +51,25 @@ public: bool operator == (const Vector2D param) const; bool operator != (const Vector2D param) const; - Vector2D operator - (); + Vector2D operator - () const; Vector2D operator + (const Vector2D param) const; Vector2D operator - (const Vector2D param) const; - Vector2D operator * (float param); - Vector2D operator / (float param); + Vector2D operator * (float param) const; + Vector2D operator / (float param) const; Vector2D operator += (const Vector2D param); Vector2D operator -= (const Vector2D param); Vector2D operator *= (float param); Vector2D operator /= (float param); - Vector2D Unit (); + Vector2D Unit () const; float Cross (const Vector2D param) const; float Dot (const Vector2D param) const; float Len () const; float Length () const { return Len(); } + float SquareLen () const; + float SquareLength () const { return SquareLen(); } }; diff --git a/aegisub/visual_tool_vector_clip.cpp b/aegisub/visual_tool_vector_clip.cpp index fa371cdb7..3ef968f8d 100644 --- a/aegisub/visual_tool_vector_clip.cpp +++ b/aegisub/visual_tool_vector_clip.cpp @@ -167,6 +167,12 @@ void VisualToolVectorClip::Draw() { DrawDashedLine(mx,my,c1->GetEndPoint().x,c1->GetEndPoint().y,6); } } + + // Draw preview of insert point + if (mode == 4) { + Vector2D p1 = spline.GetClosestPoint(Vector2D(mx,my)); + DrawCircle(p1.x,p1.y,4); + } }