Подскажите формулы/исходник для расчёта контура полилинии, заданной набором вершин и толщиной.
Здравствуйте, Fox007, Вы писали:
F>Подскажите формулы/исходник для расчёта контура полилинии, заданной набором вершин и толщиной.
Это тривиально и весьма непросто одновременно. В общем, надо посчитать точку пересечения прямых:
const double intersection_epsilon = 1.0e-8;
//------------------------------------------------------------------------
inline bool calc_intersection(double ax, double ay, double bx, double by,
double cx, double cy, double dx, double dy,
double* x, double* y)
{
double num = (ay-cy) * (dx-cx) - (ax-cx) * (dy-cy);
double den = (bx-ax) * (dy-cy) - (by-ay) * (dx-cx);
if(fabs(den) < intersection_epsilon) return false;
double r = num / den;
*x = ax + r * (bx-ax);
*y = ay + r * (by-ay);
return true;
}
которые отстоят от заданных на величину thickness / 2:
//------------------------------------------------------------------------
inline void calc_orthogonal(double thickness,
double x1, double y1,
double x2, double y2,
double* x, double* y)
{
double dx = x2 - x1;
double dy = y2 - y1;
double d = sqrt(dx*dx + dy*dy);
*x = thickness * dy / d;
*y = thickness * dx / d;
}
Это тривиальность. Сложность заключается в "числовой устойчивости" (numerical stability). Когда один отрезок является в точности продолжением другого — вычисления "сбоят", поскольку делитель (den) в calc_intersection получается близким к нулю. Другая проблема — очень острые углы. Точка перечечения может улететь на пару километров вдаль. Чтобы это отследить, надо угол считать. А угол — это 2 вызова atan2(dy,dx), что делать очень не хочется, потому как медленно. Ну и потом, существуют разные типы (как это по русски?) line join и line cap. То есть, beveled join, miter join, round join. Для концов — butt cap, square cap, round cap.
В исходниках все лежит здесь:
http://www.antigrain.com/agg2.zip
Правда к своему стыду должен признаться, что по части разных line join и line cap там пока что и конь не валялся.