public void calc_join(IVertexDest vc, VertexWithDistance v0,
VertexWithDistance v1,
VertexWithDistance v2,
double len1,
double len2)
{
double dx1 = m_width * (v1.y - v0.y) / len1;
double dy1 = m_width * (v1.x - v0.x) / len1;
double dx2 = m_width * (v2.y - v1.y) / len2;
double dy2 = m_width * (v2.x - v1.x) / len2;
vc.Clear();
double cp = agg_math.cross_product(v0.x, v0.y, v1.x, v1.y, v2.x, v2.y);
if (cp != 0 && (cp > 0) == (m_width > 0))
{
// Inner join
//---------------
double limit = ((len1 < len2) ? len1 : len2) / m_width_abs;
if (limit < m_inner_miter_limit)
{
limit = m_inner_miter_limit;
}
switch (m_inner_join)
{
default: // inner_bevel
add_vertex(vc, v1.x + dx1, v1.y - dy1);
add_vertex(vc, v1.x + dx2, v1.y - dy2);
break;
case inner_join_e.inner_miter:
calc_miter(vc,
v0, v1, v2, dx1, dy1, dx2, dy2,
line_join_e.miter_join_revert,
limit, 0);
break;
case inner_join_e.inner_jag:
case inner_join_e.inner_round:
cp = (dx1 - dx2) * (dx1 - dx2) + (dy1 - dy2) * (dy1 - dy2);
if (cp < len1 * len1 && cp < len2 * len2)
{
calc_miter(vc,
v0, v1, v2, dx1, dy1, dx2, dy2,
line_join_e.miter_join_revert,
limit, 0);
}
else
{
if (m_inner_join == inner_join_e.inner_jag)
{
add_vertex(vc, v1.x + dx1, v1.y - dy1);
add_vertex(vc, v1.x, v1.y);
add_vertex(vc, v1.x + dx2, v1.y - dy2);
}
else
{
add_vertex(vc, v1.x + dx1, v1.y - dy1);
add_vertex(vc, v1.x, v1.y);
calc_arc(vc, v1.x, v1.y, dx2, -dy2, dx1, -dy1);
add_vertex(vc, v1.x, v1.y);
add_vertex(vc, v1.x + dx2, v1.y - dy2);
}
}
break;
}
}
else
{
// Outer join
//---------------
// Calculate the distance between v1 and
// the central point of the bevel line segment
//---------------
double dx = (dx1 + dx2) / 2;
double dy = (dy1 + dy2) / 2;
double dbevel = Math.Sqrt(dx * dx + dy * dy);
if (m_line_join == line_join_e.round_join || m_line_join == line_join_e.bevel_join)
{
// This is an optimization that reduces the number of points
// in cases of almost collinear segments. If there's no
// visible difference between bevel and miter joins we'd rather
// use miter join because it adds only one point instead of two.
//
// Here we calculate the middle point between the bevel points
// and then, the distance between v1 and this middle point.
// At outer joins this distance always less than stroke width,
// because it's actually the height of an isosceles triangle of
// v1 and its two bevel points. If the difference between this
// width and this value is small (no visible bevel) we can
// add just one point.
//
// The constant in the expression makes the result approximately
// the same as in round joins and caps. You can safely comment
// out this entire "if".
//-------------------
if (m_approx_scale * (m_width_abs - dbevel) < m_width_eps)
{
if (agg_math.calc_intersection(v0.x + dx1, v0.y - dy1,
v1.x + dx1, v1.y - dy1,
v1.x + dx2, v1.y - dy2,
v2.x + dx2, v2.y - dy2,
out dx, out dy))
{
add_vertex(vc, dx, dy);
}
else
{
add_vertex(vc, v1.x + dx1, v1.y - dy1);
}
return;
}
}
switch (m_line_join)
{
case line_join_e.miter_join:
case line_join_e.miter_join_revert:
case line_join_e.miter_join_round:
calc_miter(vc,
v0, v1, v2, dx1, dy1, dx2, dy2,
m_line_join,
m_miter_limit,
dbevel);
break;
case line_join_e.round_join:
calc_arc(vc, v1.x, v1.y, dx1, -dy1, dx2, -dy2);
break;
default: // Bevel join
add_vertex(vc, v1.x + dx1, v1.y - dy1);
add_vertex(vc, v1.x + dx2, v1.y - dy2);
break;
}
}
}