|
|
145120 |
#ifndef ACTIVECURVE_H
|
|
|
145120 |
#define ACTIVECURVE_H
|
|
|
145120 |
|
|
|
145120 |
|
|
|
145120 |
#include <vector></vector>
|
|
|
145120 |
|
|
|
145120 |
#include "curve.h"
|
|
|
145120 |
#include "activearea.h"
|
|
|
145120 |
|
|
|
145120 |
class ActiveCurvePoint {
|
|
|
145120 |
public:
|
|
|
145120 |
ActivePoint::Handle p, t0, t1;
|
|
|
145120 |
|
|
|
145120 |
ActiveCurvePoint(const Vector &p, const Vector &t0, const Vector &t1):
|
|
|
145120 |
p(new ActivePoint(p)),
|
|
|
145120 |
t0(new ActivePoint(p + t0, Color::yellow())),
|
|
|
145120 |
t1(new ActivePoint(p + t1, Color::yellow()))
|
|
|
145120 |
{ }
|
|
|
145120 |
explicit ActiveCurvePoint(const Vector &p = Vector(), const Vector &t = Vector()):
|
|
|
145120 |
ActiveCurvePoint(p, t, t) { }
|
|
|
145120 |
|
|
|
145120 |
const Vector& get_p() const { return p->position; }
|
|
|
145120 |
Vector get_t0() const { return t0->position - get_p(); }
|
|
|
145120 |
Vector get_t1() const { return t1->position - get_p(); }
|
|
|
145120 |
Vector get_pp0() const { return get_t0()/3 + get_p(); }
|
|
|
145120 |
Vector get_pp1() const { return get_t1()/3 + get_p(); }
|
|
|
145120 |
|
|
|
145120 |
void add_to(ActiveArea &area) const {
|
|
|
145120 |
area.add_point(p);
|
|
|
145120 |
area.add_point(t0);
|
|
|
145120 |
area.add_point(t1);
|
|
|
145120 |
}
|
|
|
145120 |
void remove_from(ActiveArea &area) const {
|
|
|
145120 |
area.remove_point(p);
|
|
|
145120 |
area.remove_point(t0);
|
|
|
145120 |
area.remove_point(t1);
|
|
|
145120 |
}
|
|
|
145120 |
};
|
|
|
145120 |
|
|
|
145120 |
class ActiveCurve: public std::vector<activecurvepoint> {</activecurvepoint>
|
|
|
145120 |
public:
|
|
|
145120 |
template<typename t=""></typename>
|
|
|
145120 |
class SegIterBase {
|
|
|
145120 |
public:
|
|
|
145120 |
typedef T Type;
|
|
|
145120 |
private:
|
|
|
145120 |
Type begin, end, last, i0, i1;
|
|
|
145120 |
bool loop, valid;
|
|
|
145120 |
protected:
|
|
|
145120 |
SegIterBase():
|
|
|
145120 |
begin(), end(), i0(), i1(), loop(), valid() { }
|
|
|
145120 |
SegIterBase(const Type &begin, const Type &end, bool loop):
|
|
|
145120 |
begin(begin), end(end), last(end), i0(begin), i1(begin), loop(loop), valid(true)
|
|
|
145120 |
{
|
|
|
145120 |
--last; ++i1;
|
|
|
145120 |
if (i0 == end) i1 = end;
|
|
|
145120 |
if (loop && i1 == end) i1 = begin;
|
|
|
145120 |
}
|
|
|
145120 |
public:
|
|
|
145120 |
operator bool () const
|
|
|
145120 |
{ return valid && i0 != end && i1 != end; }
|
|
|
145120 |
bool is_first() const
|
|
|
145120 |
{ assert(*this); return i0 == begin; }
|
|
|
145120 |
bool is_last() const
|
|
|
145120 |
{ assert(*this); return i1 == (loop ? begin : last); }
|
|
|
145120 |
|
|
|
145120 |
bool next() {
|
|
|
145120 |
assert(*this);
|
|
|
145120 |
++i0; ++i1;
|
|
|
145120 |
if (loop && i1 == end) i1 = begin;
|
|
|
145120 |
return *this;
|
|
|
145120 |
}
|
|
|
145120 |
|
|
|
145120 |
const ActiveCurvePoint& point0() const { assert(*this); return *i0; }
|
|
|
145120 |
const ActiveCurvePoint& point1() const { assert(*this); return *i1; }
|
|
|
145120 |
const Vector& p0() const { return point0().get_p(); }
|
|
|
145120 |
const Vector& p1() const { return point1().get_p(); }
|
|
|
145120 |
};
|
|
|
145120 |
|
|
|
145120 |
class SegIter: public SegIterBase<const_iterator> {</const_iterator>
|
|
|
145120 |
public:
|
|
|
145120 |
SegIter() { }
|
|
|
145120 |
explicit SegIter(const ActiveCurve &curve):
|
|
|
145120 |
SegIterBase(curve.begin(), curve.end(), curve.loop) { }
|
|
|
145120 |
Vector t0() const { return point0().get_t1(); }
|
|
|
145120 |
Vector t1() const { return point1().get_t0(); }
|
|
|
145120 |
Vector pp0() const { return point0().get_pp1(); }
|
|
|
145120 |
Vector pp1() const { return point1().get_pp0(); }
|
|
|
145120 |
Hermite hermite() const { return Hermite(p0(), p1(), t0(), -t1()); }
|
|
|
145120 |
Bezier bezier() const { return Bezier (p0(), p1(), pp0(), pp1()); }
|
|
|
145120 |
};
|
|
|
145120 |
|
|
|
145120 |
class SegRIter: public SegIterBase<const_reverse_iterator> {</const_reverse_iterator>
|
|
|
145120 |
public:
|
|
|
145120 |
SegRIter() { }
|
|
|
145120 |
explicit SegRIter(const ActiveCurve &curve):
|
|
|
145120 |
SegIterBase(curve.rbegin(), curve.rend(), curve.loop) { }
|
|
|
145120 |
Vector t0() const { return point0().get_t0(); }
|
|
|
145120 |
Vector t1() const { return point1().get_t1(); }
|
|
|
145120 |
Vector pp0() const { return point0().get_pp0(); }
|
|
|
145120 |
Vector pp1() const { return point1().get_pp1(); }
|
|
|
145120 |
Hermite hermite() const { return Hermite(p0(), p1(), t0(), -t1()); }
|
|
|
145120 |
Bezier bezier() const { return Bezier (p0(), p1(), pp0(), pp1()); }
|
|
|
145120 |
};
|
|
|
145120 |
|
|
|
145120 |
bool loop;
|
|
|
145120 |
Color color;
|
|
|
145120 |
Color tangent_color;
|
|
|
145120 |
|
|
|
145120 |
ActiveCurve(): loop(), color(Color::black()), tangent_color(Color::gray()) { }
|
|
|
145120 |
|
|
|
145120 |
void set_tail_tangents_visible(bool x)
|
|
|
145120 |
{ if (!empty()) front().t0->visible = back().t1->visible = x; }
|
|
|
145120 |
void set_tail_tangents_visible()
|
|
|
145120 |
{ set_tail_tangents_visible(loop); }
|
|
|
145120 |
|
|
|
145120 |
void put(const Context &context, bool jump = false) const {
|
|
|
145120 |
for(SegIter i(*this); i; i.next())
|
|
|
145120 |
context.hermite( i.hermite(), jump && i.is_first() );
|
|
|
145120 |
if (loop && jump) context->close_path();
|
|
|
145120 |
}
|
|
|
145120 |
|
|
|
145120 |
void put_tangents(const Context &context) const {
|
|
|
145120 |
for(SegIter i(*this); i; i.next()) {
|
|
|
145120 |
context.move_to(i.p0());
|
|
|
145120 |
context.line_to(i.p0() + i.t0());
|
|
|
145120 |
context.move_to(i.p1());
|
|
|
145120 |
context.line_to(i.p1() + i.t1());
|
|
|
145120 |
}
|
|
|
145120 |
}
|
|
|
145120 |
|
|
|
145120 |
void on_point_move(const ActivePoint::Handle &point, const Vector &oldposition, const Vector &/*newposition*/) {
|
|
|
145120 |
for(const_iterator i = begin(); i != end(); ++i) {
|
|
|
145120 |
if (i->p == point) {
|
|
|
145120 |
Vector d = i->p->position - oldposition;
|
|
|
145120 |
i->t0->position += d;
|
|
|
145120 |
i->t1->position += d;
|
|
|
145120 |
break;
|
|
|
145120 |
}
|
|
|
145120 |
}
|
|
|
145120 |
}
|
|
|
145120 |
|
|
|
145120 |
void draw(const Context &context) const {
|
|
|
145120 |
context->save();
|
|
|
145120 |
|
|
|
145120 |
context.set_line_width_px(1);
|
|
|
145120 |
|
|
|
145120 |
context.set_source_rgba(color);
|
|
|
145120 |
put_tangents(context);
|
|
|
145120 |
context->stroke();
|
|
|
145120 |
|
|
|
145120 |
context.set_source_rgba(tangent_color);
|
|
|
145120 |
put(context, true);
|
|
|
145120 |
context->stroke();
|
|
|
145120 |
|
|
|
145120 |
context->restore();
|
|
|
145120 |
}
|
|
|
145120 |
};
|
|
|
145120 |
|
|
|
145120 |
|
|
|
145120 |
#endif
|