Blame c++/vector/outlinearea.cpp

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