polygon/main_path.cpp

178 lines
3.1 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 += 180.0;
}
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;
}
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, get_stroke_angle(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;
}