197 lines
3.6 KiB
C++
197 lines
3.6 KiB
C++
#include <iostream>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <utility>
|
|
|
|
#include <math.h>
|
|
|
|
using namespace std;
|
|
|
|
struct Point
|
|
{
|
|
double x;
|
|
double y;
|
|
|
|
Point& operator/=(const double& val)
|
|
{
|
|
x /= val;
|
|
y /= val;
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
Point operator-(const Point& p1, const Point& p2)
|
|
{
|
|
return Point{.x = p1.x - p2.x, .y = p1.y - p2.y};
|
|
}
|
|
|
|
Point operator+(const Point& p1, const Point& p2)
|
|
{
|
|
return Point{.x = p1.x + p2.x, .y = p1.y + p2.y};
|
|
}
|
|
|
|
double radians(double degrees)
|
|
{
|
|
return degrees * M_PI / 180.0;
|
|
}
|
|
|
|
double degrees(double radians)
|
|
{
|
|
return radians * 180.0 / M_PI;
|
|
}
|
|
|
|
Point& vec_normalize(Point& vec)
|
|
{
|
|
double len = sqrt(vec.x * vec.x + vec.y * vec.y);
|
|
vec /= len;
|
|
return vec;
|
|
}
|
|
|
|
double get_angle(Point start, Point end)
|
|
{
|
|
double angle;
|
|
Point vec;
|
|
double dot;
|
|
|
|
vec = end - start;
|
|
vec_normalize(vec);
|
|
|
|
angle = degrees(acos(vec.x));
|
|
|
|
if (vec.y < 0)
|
|
{
|
|
angle = 360 - angle;
|
|
}
|
|
|
|
return angle;
|
|
}
|
|
|
|
double get_stroke_angle(double prev_angle, double curr_angle)
|
|
{
|
|
double angle;
|
|
|
|
angle = (curr_angle - prev_angle) / 2 + prev_angle + 90;
|
|
|
|
return angle;
|
|
}
|
|
|
|
pair<Point, Point> perform_stroke(double stroke_size, double stroke_angle, Point point)
|
|
{
|
|
pair<Point, Point> result;
|
|
Point add;
|
|
|
|
add.x = cos(radians(stroke_angle)) * stroke_size / 2;
|
|
add.y = sin(radians(stroke_angle)) * stroke_size / 2;
|
|
|
|
result.first = point + add;
|
|
result.second = point - add;
|
|
|
|
return result;
|
|
}
|
|
|
|
pair<Point, Point> perform_stroke(double stroke_size, double prev_angle, double curr_angle, Point point)
|
|
{
|
|
pair<Point, Point> result;
|
|
Point add;
|
|
double stroke_angle;
|
|
double extra_angle;
|
|
|
|
extra_angle = (curr_angle - prev_angle) / 2 + 90.0;
|
|
stroke_angle = extra_angle + prev_angle;
|
|
|
|
add.x = cos(radians(stroke_angle)) * stroke_size / 2 / sin(radians(extra_angle));
|
|
add.y = sin(radians(stroke_angle)) * stroke_size / 2 / sin(radians(extra_angle));
|
|
|
|
result.first = point + add;
|
|
result.second = point - add;
|
|
|
|
return result;
|
|
}
|
|
|
|
void usage(const string& name)
|
|
{
|
|
cout << "Usage: " << name << " <stroke size> <x1> <y1> <x2> <y2> [<xN> <yN> ...]" << endl;
|
|
cout << "\tstroke size - how big the stroke should be" << endl;
|
|
cout << "\tx1 - x coordinate of first point" << endl;
|
|
cout << "\ty1 - y coordinate of first point" << endl;
|
|
}
|
|
|
|
void get_polygon(double stroke_size, const vector<Point>& points)
|
|
{
|
|
double prev_angle;
|
|
double curr_angle;
|
|
vector<Point> forward;
|
|
vector<Point> backward;
|
|
pair<Point, Point> tmp;
|
|
|
|
for (int i = 1; i < points.size(); ++i)
|
|
{
|
|
prev_angle = curr_angle;
|
|
curr_angle = get_angle(points[i - 1], points[i]);
|
|
|
|
if (1 == i)
|
|
{
|
|
// First angle is end cap
|
|
tmp = perform_stroke(stroke_size, curr_angle + 90, points[i - 1]);
|
|
}
|
|
else
|
|
{
|
|
tmp = perform_stroke(stroke_size, prev_angle, curr_angle, points[i - 1]);
|
|
}
|
|
|
|
forward.push_back(tmp.first);
|
|
backward.push_back(tmp.second);
|
|
}
|
|
|
|
// Last angle is end cap
|
|
tmp = perform_stroke(stroke_size, curr_angle + 90, points[points.size() - 1]);
|
|
forward.push_back(tmp.first);
|
|
backward.push_back(tmp.second);
|
|
|
|
for (int i = 0; i < forward.size(); ++i)
|
|
{
|
|
cout << forward[i].x << "," << forward[i].y << " ";
|
|
}
|
|
|
|
for (int i = backward.size() - 1; i >= 0; --i)
|
|
{
|
|
cout << backward[i].x << "," << backward[i].y << " ";
|
|
}
|
|
|
|
cout << endl;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
double stroke_size;
|
|
Point tmp;
|
|
vector<Point> points;
|
|
int last_idx;
|
|
|
|
if (argc < 5)
|
|
{
|
|
usage(argv[0]);
|
|
cout << "Insufficient arguments" << endl;
|
|
return -1;
|
|
}
|
|
|
|
stroke_size = stod(argv[1]);
|
|
|
|
last_idx = argc;
|
|
if (0 != last_idx % 2)
|
|
{
|
|
--last_idx;
|
|
}
|
|
|
|
for (int i = 2; i < last_idx; i += 2)
|
|
{
|
|
tmp.x = stod(argv[i]);
|
|
tmp.y = stod(argv[i + 1]);
|
|
points.push_back(tmp);
|
|
}
|
|
|
|
get_polygon(stroke_size, points);
|
|
|
|
return 0;
|
|
}
|