|
 |
2fb9fd |
|
|
 |
2fb9fd |
|
|
 |
2fb9fd |
#include "curvesarea.h"
|
|
 |
2fb9fd |
|
|
 |
2fb9fd |
|
|
 |
2fb9fd |
namespace {
|
|
 |
2fb9fd |
struct DrawSegment {
|
|
 |
2fb9fd |
private:
|
|
 |
2fb9fd |
const Context &context;
|
|
 |
2fb9fd |
const Segment &segment;
|
|
 |
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)
|
|
 |
2fb9fd |
{ return segment(l) + segment.t(l).perp().norm()*width; }
|
|
 |
2fb9fd |
|
|
 |
2fb9fd |
void step(const Real &l1) {
|
|
 |
2fb9fd |
Vector p1 = segment(l1) + segment.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:
|
|
 |
2fb9fd |
DrawSegment(const Context &context, const Segment &segment, const Real &width):
|
|
 |
2fb9fd |
context(context), segment(segment), width(width), precision_sqr(context.pixelsize_sqr()), level(), l0()
|
|
 |
2fb9fd |
{
|
|
 |
2fb9fd |
context.line_to(p0 = func(0));
|
|
 |
2fb9fd |
step(1);
|
|
 |
2fb9fd |
}
|
|
 |
2fb9fd |
};
|
|
 |
2fb9fd |
}
|
|
 |
2fb9fd |
|
|
 |
2fb9fd |
|
|
 |
2fb9fd |
CurvesArea::CurvesArea()
|
|
 |
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);
|
|
 |
2fb9fd |
curve.push_back(CurvePoint(center + v*radius, v*tangent_len));
|
|
 |
2fb9fd |
curve.back().add_to(*this);
|
|
 |
2fb9fd |
}
|
|
 |
2fb9fd |
curve.loop = true;
|
|
 |
2fb9fd |
}
|
|
 |
2fb9fd |
|
|
 |
2fb9fd |
void CurvesArea::put_segment(const Context &context, const Segment &segment, const Real width) {
|
|
 |
2fb9fd |
if (equal(width, 0)) context.segment(segment);
|
|
 |
2fb9fd |
else DrawSegment(context, segment, width);
|
|
 |
2fb9fd |
}
|
|
 |
2fb9fd |
|
|
 |
2fb9fd |
void CurvesArea::put_curve(const Context &context, const Curve &curve, const Real width) {
|
|
 |
2fb9fd |
for(Curve::const_iterator curr = curve.begin(); curr != curve.end(); ++curr) {
|
|
 |
2fb9fd |
Curve::const_iterator next = curve.next(curr);
|
|
 |
2fb9fd |
put_segment(context, Segment(curr->get_p(), next->get_p(), curr->get_t(), next->get_t()), width);
|
|
 |
2fb9fd |
}
|
|
 |
2fb9fd |
}
|
|
 |
2fb9fd |
|
|
 |
2fb9fd |
void CurvesArea::draw_curve(const Context &context, const Curve &curve) {
|
|
 |
2fb9fd |
context->save();
|
|
 |
2fb9fd |
|
|
 |
2fb9fd |
Real width = 50;
|
|
 |
2fb9fd |
context.set_line_width_px(1);
|
|
 |
2fb9fd |
|
|
 |
2fb9fd |
// tangents
|
|
 |
2fb9fd |
context.set_source_rgba(Color::gray());
|
|
 |
2fb9fd |
for(Curve::const_iterator i = curve.begin(); i != curve.end(); ++i) {
|
|
 |
2fb9fd |
context.move_to(i->p->position);
|
|
 |
2fb9fd |
context.line_to(i->t->position);
|
|
 |
2fb9fd |
context->stroke();
|
|
 |
2fb9fd |
}
|
|
 |
2fb9fd |
|
|
 |
2fb9fd |
// middle line
|
|
 |
2fb9fd |
context.set_source_rgba(Color::black());
|
|
 |
2fb9fd |
put_curve(context, curve);
|
|
 |
2fb9fd |
context->stroke();
|
|
 |
2fb9fd |
|
|
 |
2fb9fd |
// borders
|
|
 |
2fb9fd |
context.set_source_rgba(Color::blue());
|
|
 |
2fb9fd |
put_curve(context, curve, width);
|
|
 |
2fb9fd |
context->stroke();
|
|
 |
2fb9fd |
put_curve(context, curve, -width);
|
|
 |
2fb9fd |
context->stroke();
|
|
 |
2fb9fd |
|
|
 |
2fb9fd |
context->restore();
|
|
 |
2fb9fd |
}
|
|
 |
2fb9fd |
|
|
 |
2fb9fd |
|
|
 |
2fb9fd |
void CurvesArea::on_draw_content(const Context &context) {
|
|
 |
2fb9fd |
draw_curve(context, curve);
|
|
 |
2fb9fd |
}
|