-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathCircumscribedCircle.cpp
107 lines (94 loc) · 3.18 KB
/
CircumscribedCircle.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#include "CircumscribedCircle.h"
#include <iostream>
CircumscribedCircle::CircumscribedCircle(HitObject hitObject)
{
for (unsigned i = 0; i < hitObject.curves.size(); i++)
{
sliderX.push_back(hitObject.curves[i].X);
sliderY.push_back(hitObject.curves[i].Y);
}
x = hitObject.pos.X;
y = hitObject.pos.Y;
// construct the three points
this->start = Vector2d(getX(0), getY(0));
this->mid = Vector2d(getX(1), getY(1));
this->end = Vector2d(getX(2), getY(2));
// find the circle center
Vector2d mida = start.midPoint(mid);
Vector2d midb = end.midPoint(mid);
Vector2d nora = (mid - start).nor();
Vector2d norb = (mid - end).nor();
this->circleCenter = intersect(mida, nora, midb, norb);
if (circleCenter == Vector2d(-1, -1))
{
// Temporary fallback to bezier slider
Slider slider(hitObject, true);
curve.resize(slider.curve.size());
curve = slider.curve;
ncurve = slider.ncurve;
return;
}
// find the angles relative to the circle center
Vector2d startAngPoint = start - circleCenter;
Vector2d midAngPoint = mid - circleCenter;
Vector2d endAngPoint = end - circleCenter;
this->startAng = atan2(startAngPoint.Y, startAngPoint.X);
this->midAng = atan2(midAngPoint.Y, midAngPoint.X);
this->endAng = atan2(endAngPoint.Y, endAngPoint.X);
// find the angles that pass through midAng
if (!isIn(startAng, midAng, endAng))
{
if (abs(startAng + TWO_PI - endAng) < TWO_PI && isIn(startAng + (TWO_PI), midAng, endAng))
startAng += TWO_PI;
else if (abs(startAng - (endAng + TWO_PI)) < TWO_PI && isIn(startAng, midAng, endAng + (TWO_PI)))
endAng += TWO_PI;
else if (abs(startAng - TWO_PI - endAng) < TWO_PI && isIn(startAng - (TWO_PI), midAng, endAng))
startAng -= TWO_PI;
else if (abs(startAng - (endAng - TWO_PI)) < TWO_PI && isIn(startAng, midAng, endAng - (TWO_PI)))
endAng -= TWO_PI;
else
{
std::cout << "Cannot find angles between midAng (%.3f %.3f %.3f)." << std::endl;
//startAng, midAng, endAng), null, true
return;
}
}
// find an angle with an arc length of pixelLength along this circle
this->radius = startAngPoint.getLength();
double pixelLength = hitObject.pixelLength;
double arcAng = pixelLength / radius; // len = theta * r / theta = len / r
// now use it for our new end angle
this->endAng = (endAng > startAng) ? startAng + arcAng : startAng - arcAng;
// calculate points
double step = hitObject.pixelLength / CURVE_POINTS_SEPERATION;
ncurve = (int)step;
int len = (int)step + 1;
for (int i = 0; i < len; i++)
{
Vector2d xy = pointAt(i / step);
curve.push_back(Vector2d(xy.X, xy.Y));
}
}
bool CircumscribedCircle::isIn(double a, double b, double c)
{
return (b > a && b < c) || (b < a && b > c);
}
Vector2d CircumscribedCircle::intersect(Vector2d a, Vector2d ta, Vector2d b, Vector2d tb)
{
double des = tb.X * ta.Y - tb.Y * ta.X;
if (abs(des) < 0.00001)
{
std::cout << "Vectors are parallel." << std::endl;
return Vector2d(-1, -1);
}
double u = ((b.Y - a.Y) * ta.X + (a.X - b.X) * ta.Y) / des;
b.X += tb.X * u;
b.Y += tb.Y * u;
return b;
}
Vector2d CircumscribedCircle::pointAt(double t)
{
double ang = lerp(startAng, endAng, t);
return Vector2d((cos(ang) * radius + circleCenter.X),
(sin(ang) * radius + circleCenter.Y));
}