WIP: point editing of multi-segment rulers

This commit is contained in:
Matthias Koefferlein 2022-09-28 21:16:47 +02:00
parent 8cbe5a2359
commit d2d321c35b
4 changed files with 140 additions and 53 deletions

View File

@ -32,6 +32,24 @@
namespace ant namespace ant
{ {
static void
clean_points_impl (ant::Object::point_list &points)
{
auto wp = points.begin ();
auto p = points.begin ();
while (p != points.end ()) {
auto pp = p + 1;
while (pp != points.end () && *pp == *p) {
++pp;
}
*wp++ = *p;
p = pp;
}
points.erase (wp, points.end ());
}
Object::Object () Object::Object ()
: m_id (-1), : m_id (-1),
m_fmt_x ("$X"), m_fmt_y ("$Y"), m_fmt ("$D"), m_fmt_x ("$X"), m_fmt_y ("$Y"), m_fmt ("$D"),
@ -88,7 +106,7 @@ Object::Object (const db::DPoint &_p1, const db::DPoint &_p2, int id, const ant:
} }
Object::Object (const Object::point_list &pts, int id, const ant::Template &t) Object::Object (const Object::point_list &pts, int id, const ant::Template &t)
: m_id (id), : m_points (pts), m_id (id),
m_fmt_x (t.fmt_x ()), m_fmt_y (t.fmt_y ()), m_fmt (t.fmt ()), m_fmt_x (t.fmt_x ()), m_fmt_y (t.fmt_y ()), m_fmt (t.fmt ()),
m_style (t.style ()), m_outline (t.outline ()), m_style (t.style ()), m_outline (t.outline ()),
m_snap (t.snap ()), m_angle_constraint (t.angle_constraint ()), m_snap (t.snap ()), m_angle_constraint (t.angle_constraint ()),
@ -98,7 +116,7 @@ Object::Object (const Object::point_list &pts, int id, const ant::Template &t)
m_xlabel_xalign (t.xlabel_xalign ()), m_xlabel_yalign (t.xlabel_yalign ()), m_xlabel_xalign (t.xlabel_xalign ()), m_xlabel_yalign (t.xlabel_yalign ()),
m_ylabel_xalign (t.ylabel_xalign ()), m_ylabel_yalign (t.ylabel_yalign ()) m_ylabel_xalign (t.ylabel_xalign ()), m_ylabel_yalign (t.ylabel_yalign ())
{ {
set_points (pts); clean_points_impl (m_points);
} }
Object::Object (const ant::Object &d) Object::Object (const ant::Object &d)
@ -224,22 +242,36 @@ Object::operator== (const ant::Object &d) const
; ;
} }
void
Object::clean_points ()
{
auto new_points = m_points;
clean_points_impl (new_points);
set_points_exact (std::move (new_points));
}
void void
Object::set_points (const point_list &points) Object::set_points (const point_list &points)
{ {
point_list new_points; auto new_points = points;
auto p = points.begin (); clean_points_impl (new_points);
while (p != points.end ()) { set_points_exact (std::move (new_points));
auto pp = p + 1; }
while (pp != points.end () && *pp == *p) {
++pp;
}
new_points.push_back (*p);
p = pp;
}
if (m_points != new_points) { void
m_points = new_points; Object::set_points_exact (const point_list &points)
{
if (m_points != points) {
m_points = points;
property_changed ();
}
}
void
Object::set_points_exact (point_list &&points)
{
if (m_points != points) {
m_points.swap (points);
property_changed (); property_changed ();
} }
} }
@ -272,6 +304,30 @@ Object::seg_p2 (size_t seg_index) const
} }
} }
void
Object::seg_p1 (size_t seg_index, const db::DPoint &p)
{
if (seg_index == std::numeric_limits<size_t>::max ()) {
p1 (p);
} else if (seg_index < m_points.size ()) {
m_points[seg_index] = p;
} else if (! m_points.empty ()) {
m_points.back () = p;
}
}
void
Object::seg_p2 (size_t seg_index, const db::DPoint &p)
{
if (seg_index == std::numeric_limits<size_t>::max ()) {
p2 (p);
} else if (seg_index + 1 < m_points.size ()) {
m_points[seg_index + 1] = p;
} else if (! m_points.empty ()) {
m_points.back () = p;
}
}
void void
Object::p1 (const db::DPoint &p) Object::p1 (const db::DPoint &p)
{ {

View File

@ -295,10 +295,17 @@ public:
/** /**
* @brief Sets the ruler's definition points without cleaning * @brief Sets the ruler's definition points without cleaning
*/ */
void set_points_exact (const point_list &points) void set_points_exact (const point_list &points);
{
m_points = points; /**
} * @brief Sets the ruler's definition points without cleaning (move semantics)
*/
void set_points_exact (point_list &&points);
/**
* @brief Cleans the point list
*/
void clean_points ();
/** /**
* @brief Gets the first point of the indicated segment * @brief Gets the first point of the indicated segment
@ -310,6 +317,16 @@ public:
*/ */
db::DPoint seg_p2 (size_t seg_index) const; db::DPoint seg_p2 (size_t seg_index) const;
/**
* @brief Sets the first point of the indicated segment
*/
void seg_p1 (size_t seg_index, const db::DPoint &p);
/**
* @brief Sets the second point of the indicated segment
*/
void seg_p2 (size_t seg_index, const db::DPoint &p);
/** /**
* @brief Gets the number of segments * @brief Gets the number of segments
* *

View File

@ -858,6 +858,7 @@ Service::Service (db::Manager *manager, lay::LayoutViewBase *view)
mp_transient_ruler (0), mp_transient_ruler (0),
m_drawing (false), m_current (), m_drawing (false), m_current (),
m_move_mode (MoveNone), m_move_mode (MoveNone),
m_seg_index (0),
m_current_template (0) m_current_template (0)
{ {
mp_view->annotations_changed_event.add (this, &Service::annotations_changed); mp_view->annotations_changed_event.add (this, &Service::annotations_changed);
@ -1074,29 +1075,28 @@ Service::insert_ruler (const ant::Object &ruler, bool limit_number)
return new_id; return new_id;
} }
/**
* @brief Helper function to determine which move mode to choose given a certain search box and ant::Object
*/
static bool static bool
dragging_what (const ant::Object *robj, const db::DBox &search_dbox, ant::Service::MoveMode &mode, db::DPoint &p1) dragging_what_seg (const ant::Object *robj, const db::DBox &search_dbox, ant::Service::MoveMode &mode, db::DPoint &p1, size_t index)
{ {
ant::Object::outline_type outline = robj->outline ();
db::DPoint p12, p21; db::DPoint p12, p21;
bool has_p12 = false, has_p21 = false; bool has_p12 = false, has_p21 = false;
db::DPoint p11 = robj->p1 (), p22 = robj->p2 (); db::DPoint p11 = robj->seg_p1 (index), p22 = robj->seg_p2 (index);
db::DPoint c = p11 + (p22 - p11) * 0.5; db::DPoint c = p11 + (p22 - p11) * 0.5;
if (robj->outline () == ant::Object::OL_xy || robj->outline () == ant::Object::OL_diag_xy || robj->outline () == ant::Object::OL_box) { if (outline == ant::Object::OL_xy || outline== ant::Object::OL_diag_xy || outline == ant::Object::OL_box) {
p12 = db::DPoint (robj->p2 ().x (), robj->p1 ().y ()); p12 = db::DPoint (p22.x (), p11.y ());
has_p12 = true; has_p12 = true;
} }
if (robj->outline () == ant::Object::OL_yx || robj->outline () == ant::Object::OL_diag_yx || robj->outline () == ant::Object::OL_box) { if (outline == ant::Object::OL_yx || outline == ant::Object::OL_diag_yx || outline == ant::Object::OL_box) {
p21 = db::DPoint (robj->p1 ().x (), robj->p2 ().y ()); p21 = db::DPoint (p11.x (), p22.y ());
has_p21 = true; has_p21 = true;
} }
if (robj->outline () == ant::Object::OL_ellipse) { if (outline == ant::Object::OL_ellipse) {
db::DVector d = (p22 - p11) * 0.5; db::DVector d = (p22 - p11) * 0.5;
p12 = c + db::DVector (d.x (), -d.y ()); p12 = c + db::DVector (d.x (), -d.y ());
p21 = c + db::DVector (-d.x (), d.y ()); p21 = c + db::DVector (-d.x (), d.y ());
@ -1147,18 +1147,28 @@ dragging_what (const ant::Object *robj, const db::DBox &search_dbox, ant::Servic
mode = ant::Service::MoveP2Y; mode = ant::Service::MoveP2Y;
return true; return true;
} }
if ((robj->outline () == ant::Object::OL_diag || robj->outline () == ant::Object::OL_diag_xy || robj->outline () == ant::Object::OL_diag_yx)
&& db::DEdge (p11, p22).distance_abs (search_dbox.center ()) <= search_dbox.width () * 0.5) { return false;
p1 = search_dbox.center (); }
mode = ant::Service::MoveRuler;
return true; /**
} * @brief Helper function to determine which move mode to choose given a certain search box and ant::Object
if ((robj->outline () == ant::Object::OL_box || robj->outline () == ant::Object::OL_ellipse) && search_dbox.inside (db::DBox (p11, p22))) { */
p1 = search_dbox.center (); static bool
mode = ant::Service::MoveRuler; dragging_what (const ant::Object *robj, const db::DBox &search_dbox, ant::Service::MoveMode &mode, db::DPoint &p1, size_t &index)
return true; {
ant::Object::outline_type outline = robj->outline ();
if (outline == ant::Object::OL_box || outline == ant::Object::OL_ellipse) {
index = std::numeric_limits<size_t>::max ();
return dragging_what_seg (robj, search_dbox, mode, p1, index);
} }
for (index = 0; index < robj->segments (); ++index) {
if (dragging_what_seg (robj, search_dbox, mode, p1, index)) {
return true;
}
}
return false; return false;
} }
@ -1185,6 +1195,7 @@ Service::begin_move (lay::Editable::MoveMode mode, const db::DPoint &p, lay::ang
} else if (mode == lay::Editable::Partial) { } else if (mode == lay::Editable::Partial) {
m_move_mode = MoveNone; m_move_mode = MoveNone;
m_seg_index = 0;
// compute search box // compute search box
double l = catch_distance (); double l = catch_distance ();
@ -1216,7 +1227,7 @@ Service::begin_move (lay::Editable::MoveMode mode, const db::DPoint &p, lay::ang
const ant::Object *robj = dynamic_cast <const ant::Object *> ((*ri).ptr ()); const ant::Object *robj = dynamic_cast <const ant::Object *> ((*ri).ptr ());
if (robj && (! robj_min || robj == robj_min)) { if (robj && (! robj_min || robj == robj_min)) {
if (dragging_what (robj, search_dbox, m_move_mode, m_p1) && m_move_mode != MoveRuler) { if (dragging_what (robj, search_dbox, m_move_mode, m_p1, m_seg_index) && m_move_mode != MoveRuler) {
// found anything: make the moved ruler the selection // found anything: make the moved ruler the selection
clear_selection (); clear_selection ();
@ -1273,7 +1284,7 @@ Service::begin_move (lay::Editable::MoveMode mode, const db::DPoint &p, lay::ang
const ant::Object *robj = dynamic_cast <const ant::Object *> ((*r).ptr ()); const ant::Object *robj = dynamic_cast <const ant::Object *> ((*r).ptr ());
if (robj && (! robj_min || robj == robj_min)) { if (robj && (! robj_min || robj == robj_min)) {
if (dragging_what (robj, search_dbox, m_move_mode, m_p1)) { if (dragging_what (robj, search_dbox, m_move_mode, m_p1, m_seg_index)) {
// found anything: make the moved ruler the selection // found anything: make the moved ruler the selection
clear_selection (); clear_selection ();
@ -1340,50 +1351,50 @@ Service::move (const db::DPoint &p, lay::angle_constraint_type ac)
if (m_move_mode == MoveP1) { if (m_move_mode == MoveP1) {
m_current.p1 (snap2 (m_p1, p, &m_current, ac).second); m_current.seg_p1 (m_seg_index, snap2 (m_p1, p, &m_current, ac).second);
m_rulers [0]->redraw (); m_rulers [0]->redraw ();
} else if (m_move_mode == MoveP2) { } else if (m_move_mode == MoveP2) {
m_current.p2 (snap2 (m_p1, p, &m_current, ac).second); m_current.seg_p2 (m_seg_index, snap2 (m_p1, p, &m_current, ac).second);
m_rulers [0]->redraw (); m_rulers [0]->redraw ();
} else if (m_move_mode == MoveP12) { } else if (m_move_mode == MoveP12) {
db::DPoint p12 = snap2 (m_p1, p, &m_current, ac).second; db::DPoint p12 = snap2 (m_p1, p, &m_current, ac).second;
m_current.p1 (db::DPoint (m_current.p1 ().x(), p12.y ())); m_current.seg_p1 (m_seg_index, db::DPoint (m_current.seg_p1 (m_seg_index).x(), p12.y ()));
m_current.p2 (db::DPoint (p12.x (), m_current.p2 ().y ())); m_current.seg_p2 (m_seg_index, db::DPoint (p12.x (), m_current.seg_p2 (m_seg_index).y ()));
m_rulers [0]->redraw (); m_rulers [0]->redraw ();
} else if (m_move_mode == MoveP21) { } else if (m_move_mode == MoveP21) {
db::DPoint p21 = snap2 (m_p1, p, &m_current, ac).second; db::DPoint p21 = snap2 (m_p1, p, &m_current, ac).second;
m_current.p1 (db::DPoint (p21.x (), m_current.p1 ().y ())); m_current.seg_p1 (m_seg_index, db::DPoint (p21.x (), m_current.seg_p1 (m_seg_index).y ()));
m_current.p2 (db::DPoint (m_current.p2 ().x(), p21.y ())); m_current.seg_p2 (m_seg_index, db::DPoint (m_current.seg_p2 (m_seg_index).x(), p21.y ()));
m_rulers [0]->redraw (); m_rulers [0]->redraw ();
} else if (m_move_mode == MoveP1X) { } else if (m_move_mode == MoveP1X) {
db::DPoint pc = snap2 (m_p1, p, &m_current, ac).second; db::DPoint pc = snap2 (m_p1, p, &m_current, ac).second;
m_current.p1 (db::DPoint (pc.x (), m_current.p1 ().y ())); m_current.seg_p1 (m_seg_index, db::DPoint (pc.x (), m_current.seg_p1 (m_seg_index).y ()));
m_rulers [0]->redraw (); m_rulers [0]->redraw ();
} else if (m_move_mode == MoveP2X) { } else if (m_move_mode == MoveP2X) {
db::DPoint pc = snap2 (m_p1, p, &m_current, ac).second; db::DPoint pc = snap2 (m_p1, p, &m_current, ac).second;
m_current.p2 (db::DPoint (pc.x (), m_current.p2 ().y ())); m_current.seg_p2 (m_seg_index, db::DPoint (pc.x (), m_current.seg_p2 (m_seg_index).y ()));
m_rulers [0]->redraw (); m_rulers [0]->redraw ();
} else if (m_move_mode == MoveP1Y) { } else if (m_move_mode == MoveP1Y) {
db::DPoint pc = snap2 (m_p1, p, &m_current, ac).second; db::DPoint pc = snap2 (m_p1, p, &m_current, ac).second;
m_current.p1 (db::DPoint (m_current.p1 ().x (), pc.y ())); m_current.seg_p1 (m_seg_index, db::DPoint (m_current.seg_p1 (m_seg_index).x (), pc.y ()));
m_rulers [0]->redraw (); m_rulers [0]->redraw ();
} else if (m_move_mode == MoveP2Y) { } else if (m_move_mode == MoveP2Y) {
db::DPoint pc = snap2 (m_p1, p, &m_current, ac).second; db::DPoint pc = snap2 (m_p1, p, &m_current, ac).second;
m_current.p2 (db::DPoint (m_current.p2 ().x (), pc.y ())); m_current.seg_p2 (m_seg_index, db::DPoint (m_current.seg_p2 (m_seg_index).x (), pc.y ()));
m_rulers [0]->redraw (); m_rulers [0]->redraw ();
} else if (m_move_mode == MoveRuler) { } else if (m_move_mode == MoveRuler) {
@ -1474,6 +1485,7 @@ Service::end_move (const db::DPoint &, lay::angle_constraint_type)
} else if (m_move_mode != MoveNone) { } else if (m_move_mode != MoveNone) {
// replace the ruler that was moved // replace the ruler that was moved
m_current.clean_points ();
mp_view->annotation_shapes ().replace (m_selected.begin ()->first, db::DUserObject (new ant::Object (m_current))); mp_view->annotation_shapes ().replace (m_selected.begin ()->first, db::DUserObject (new ant::Object (m_current)));
annotation_changed_event (m_current.id ()); annotation_changed_event (m_current.id ());

View File

@ -545,6 +545,8 @@ private:
ant::Object m_original; ant::Object m_original;
// The current move mode // The current move mode
MoveMode m_move_mode; MoveMode m_move_mode;
// The currently moving segment
size_t m_seg_index;
// The ruler template // The ruler template
std::vector<ant::Template> m_ruler_templates; std::vector<ant::Template> m_ruler_templates;
unsigned int m_current_template; unsigned int m_current_template;