#include #include #include #include #include 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 perform_stroke(double stroke_size, double stroke_angle, Point point) { pair 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 perform_stroke(double stroke_size, double prev_angle, double curr_angle, Point point) { pair 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 << " [ ...]" << 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& points) { double prev_angle; double curr_angle; vector forward; vector backward; pair 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 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; }