Skip to content

Commit 2b49bb9

Browse files
authored
Fixed bezier curve IsLinear check (#509)
1 parent 0b5c7e0 commit 2b49bb9

File tree

1 file changed

+22
-29
lines changed

1 file changed

+22
-29
lines changed

source/LottieToWinComp/CubicBezierFunction2.cs

+22-29
Original file line numberDiff line numberDiff line change
@@ -96,47 +96,40 @@ static bool IsBetween(double a, double b, double c, double d)
9696
return true;
9797
}
9898

99+
static float CrossProduct(SnVector2 v1, SnVector2 v2)
100+
{
101+
return (v1.X * v2.Y) - (v1.Y * v2.X);
102+
}
103+
104+
// Checks if two vectors are colinear.
105+
static bool AlmostColinear(SnVector2 v1, SnVector2 v2)
106+
{
107+
// Epsilon is chosen so that vectors that are very close to being
108+
// colinear are also considered as colinear, since sometimes After Effects
109+
// outputs bezier curves with small precision, which may result in slight deviation.
110+
return Math.Abs(CrossProduct(v1, v2) / (1 + v1.Length() + v2.Length())) < 1e-2;
111+
}
112+
99113
/// <summary>
100114
/// Gets a value indicating whether all of the control points are on the same line.
101115
/// </summary>
102116
bool IsColinear
103117
{
104118
get
105119
{
106-
var p01X = _p0.X - _p1.X;
107-
var p01Y = _p0.Y - _p1.Y;
108-
109-
var p02X = _p0.X - _p2.X;
110-
var p02Y = _p0.Y - _p2.Y;
111-
112-
var p03X = _p0.X - _p3.X;
113-
var p03Y = _p0.Y - _p3.Y;
114-
115-
if (p01Y == 0 || p02Y == 0 || p03Y == 0)
116-
{
117-
// Can't divide by Y because it's 0 in at least one case. (i.e. horizontal line)
118-
if (p01X == 0 || p02X == 0 || p03X == 0)
119-
{
120-
// Can't divide by X because it's 0 in at least one case (i.e. vertical line)
121-
// The points can only be colinear if they're all equal.
122-
return p01X == p02X && p02X == p03X && p03X == p01X;
123-
}
124-
else
125-
{
126-
return (p01Y / p01X) == (p02Y / p02X) &&
127-
(p01Y / p01X) == (p03Y / p03X);
128-
}
129-
}
130-
else
131-
{
132-
return (p01X / p01Y) == (p02X / p02Y) &&
133-
(p01X / p01Y) == (p03X / p03Y);
134-
}
120+
// In order for 4 points to be colinear, any two pairs of directions
121+
// between them should be colinear.
122+
return AlmostColinear(_p1 - _p0, _p3 - _p0) && AlmostColinear(_p2 - _p3, _p0 - _p3);
135123
}
136124
}
137125

138126
/// <inheritdoc/>
139127
// (1-t)^3P0 + 3(1-t)^2tP1 + 3(1-t)t^2P2 + t^3P3
128+
//
129+
// TODO: This also needs some kind of "arc-length parametrization" (https://pomax.github.io/bezierinfo/#tracing)
130+
// because currently point does not move along the curve with a uniform speed.
131+
// This is probably impossible to achieve because translation approach limits us to Windown Composition API
132+
// which does not support this feature, and probably won't, because it is very expensive to compute.
140133
protected override Vector2 Simplify()
141134
{
142135
var oneMinusT = 1 - _t;

0 commit comments

Comments
 (0)