|
|
2fb9fd |
|
|
|
2fb9fd |
|
|
|
145120 |
#include "outlinearea.h"
|
|
|
2fb9fd |
|
|
|
2fb9fd |
|
|
|
2fb9fd |
namespace {
|
|
|
145120 |
struct DrawBezier {
|
|
|
2fb9fd |
private:
|
|
|
2fb9fd |
const Context &context;
|
|
|
145120 |
const Bezier &bezier;
|
|
|
2fb9fd |
const Real width;
|
|
|
2fb9fd |
const Real precision_sqr;
|
|
|
2fb9fd |
const int max_level = 16;
|
|
|
2fb9fd |
int level;
|
|
|
2fb9fd |
Vector p0;
|
|
|
2fb9fd |
Real l0;
|
|
|
2fb9fd |
|
|
|
2fb9fd |
Vector func(const Real &l)
|
|
|
145120 |
{ return bezier(l) + bezier.t(l).perp().norm()*width; }
|
|
|
2fb9fd |
|
|
|
2fb9fd |
void step(const Real &l1) {
|
|
|
145120 |
Vector p1 = bezier(l1) + bezier.t(l1).perp().norm()*width;
|
|
|
2fb9fd |
if (++level < max_level)
|
|
|
2fb9fd |
while (greater((p1 - p0).lensqr(), precision_sqr))
|
|
|
2fb9fd |
step(l0 + 0.5*(l1 - l0));
|
|
|
2fb9fd |
--level;
|
|
|
2fb9fd |
context.line_to(p1);
|
|
|
2fb9fd |
p0 = p1; l0 = l1;
|
|
|
2fb9fd |
}
|
|
|
2fb9fd |
|
|
|
2fb9fd |
public:
|
|
|
145120 |
DrawBezier(const Context &context, const Bezier &bezier, const Real &width = 0, bool jump = false):
|
|
|
145120 |
context(context), bezier(bezier), width(width), precision_sqr(context.pixelsize_sqr()), level(), l0()
|
|
|
2fb9fd |
{
|
|
|
145120 |
p0 = func(0);
|
|
|
145120 |
if (jump) context.move_to(p0); else context.line_to(p0);
|
|
|
2fb9fd |
step(1);
|
|
|
2fb9fd |
}
|
|
|
2fb9fd |
};
|
|
|
2fb9fd |
}
|
|
|
2fb9fd |
|
|
|
2fb9fd |
|
|
|
145120 |
OutlineArea::OutlineArea():
|
|
|
6b4ca4 |
w(new ActivePoint(Vector(), Color::red()))
|
|
|
2fb9fd |
{
|
|
|
2fb9fd |
set_size_request(500, 500);
|
|
|
2fb9fd |
|
|
|
2fb9fd |
Vector center(250, 250);
|
|
|
2fb9fd |
const Real radius = 100;
|
|
|
2fb9fd |
const Real tangent_len = 50;
|
|
|
2fb9fd |
const int count = 5;
|
|
|
2fb9fd |
for(int i = 0; i < count; ++i) {
|
|
|
2fb9fd |
Real a = 2*pi*i/count;
|
|
|
2fb9fd |
Vector v = Vector::from_angle(a);
|
|
|
145120 |
curve.push_back(ActiveCurvePoint(center + v*radius, v*tangent_len));
|
|
|
2fb9fd |
curve.back().add_to(*this);
|
|
|
2fb9fd |
}
|
|
|
145120 |
//curve.loop = true;
|
|
|
145120 |
curve.set_tail_tangents_visible();
|
|
|
6b4ca4 |
add_point(w);
|
|
|
6b4ca4 |
set_width(50);
|
|
|
6b4ca4 |
}
|
|
|
6b4ca4 |
|
|
|
145120 |
Real OutlineArea::get_width() const
|
|
|
145120 |
{ return fabs(dot(curve.front().get_t1().perp().norm(), w->position - curve.front().get_p())); }
|
|
|
6b4ca4 |
|
|
|
145120 |
void OutlineArea::set_width(const Real &width)
|
|
|
145120 |
{ w->position = curve.front().get_p() + curve.front().get_t1().perp().norm()*width; }
|
|
|
6b4ca4 |
|
|
|
145120 |
void OutlineArea::on_point_move(const ActivePoint::Handle &point, const Vector &oldposition, const Vector &newposition) {
|
|
|
6b4ca4 |
Real width = -1;
|
|
|
6b4ca4 |
if (point == w)
|
|
|
6b4ca4 |
width = get_width();
|
|
|
145120 |
if (!curve.empty())
|
|
|
145120 |
if (curve.front().p == point || curve.front().t1 == point)
|
|
|
145120 |
width = get_width();
|
|
|
145120 |
|
|
|
145120 |
curve.on_point_move(point, oldposition, newposition);
|
|
|
145120 |
|
|
|
6b4ca4 |
if (width >= 0)
|
|
|
6b4ca4 |
set_width(width);
|
|
|
2fb9fd |
}
|
|
|
2fb9fd |
|
|
|
145120 |
void OutlineArea::put_bezier(const Context &context, const Bezier &bezier, const Real &width, bool jump) {
|
|
|
145120 |
if (equal(width, 0))
|
|
|
145120 |
context.bezier(bezier, jump);
|
|
|
145120 |
else
|
|
|
145120 |
DrawBezier(context, bezier, width, jump);
|
|
|
2fb9fd |
}
|
|
|
2fb9fd |
|
|
|
145120 |
void OutlineArea::put_curve(const Context &context, const ActiveCurve &curve, const Real &width) {
|
|
|
145120 |
for(ActiveCurve::SegIter i(curve); i; i.next())
|
|
|
145120 |
put_bezier(context, i.bezier(), width);
|
|
|
145120 |
if (curve.loop) context->close_path();
|
|
|
145120 |
for(ActiveCurve::SegRIter i(curve); i; i.next())
|
|
|
145120 |
put_bezier(context, i.bezier(), width);
|
|
|
145120 |
context->close_path();
|
|
|
2fb9fd |
}
|
|
|
2fb9fd |
|
|
|
145120 |
void OutlineArea::draw_curve(const Context &context, const ActiveCurve &curve, const Real &width) {
|
|
|
2fb9fd |
context->save();
|
|
|
2fb9fd |
|
|
|
145120 |
curve.draw(context);
|
|
|
2fb9fd |
|
|
|
145120 |
context.set_line_width_px(1);
|
|
|
2fb9fd |
context.set_source_rgba(Color::blue());
|
|
|
2fb9fd |
put_curve(context, curve, width);
|
|
|
2fb9fd |
context->stroke();
|
|
|
2fb9fd |
|
|
|
2fb9fd |
context->restore();
|
|
|
2fb9fd |
}
|
|
|
2fb9fd |
|
|
|
145120 |
void OutlineArea::on_draw_content(const Context &context) {
|
|
|
6b4ca4 |
draw_curve(context, curve, get_width());
|
|
|
2fb9fd |
}
|