Skip to content

Commit

Permalink
Update round off vertex to support modification/removal for #657
Browse files Browse the repository at this point in the history
  • Loading branch information
frmdstryr committed Sep 6, 2023
1 parent 0ce0e68 commit 55eaf42
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 23 deletions.
51 changes: 51 additions & 0 deletions src/common/common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <type_traits>
#include <math.h>
#include <array>
#include <sstream>
#include "lut.hpp"

namespace horizon {
Expand Down Expand Up @@ -268,6 +269,13 @@ template <typename T> class Coord {
{
return {x, y};
}

std::string str() const
{
std::stringstream ss;
ss << "(" << x << ", " << y << ")";
return ss.str();
}
};


Expand Down Expand Up @@ -333,4 +341,47 @@ constexpr shallow_copy_t shallow_copy = shallow_copy_t();

enum class CopyMode { DEEP, SHALLOW };


template <typename T> class Segment {
public:
Coord<T> from;
Coord<T> to;

Segment(Coord<T> a, Coord<T> b) : from(a), to(b)
{
}

bool intersect(const Segment<T> &other, Coord<T> &output) const
{
const T &x1 = from.x;
const T &y1 = from.y;
const T &x2 = to.x;
const T &y2 = to.y;
const T &x3 = other.from.x;
const T &y3 = other.from.y;
const T &x4 = other.to.x;
const T &y4 = other.to.y;

// See https://en.wikipedia.org/wiki/Line-line_intersection
double d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
if (fabs(d) < 1e-6) {
return false; // Parallel or coincident
}
T a = (x1 * y2 - y1 * x2);
T b = (x3 * y4 - y3 * x4);
double x = (a * (x3 - x4) - (x1 - x2) * b) / d;
double y = (a * (y3 - y4) - (y1 - y2) * b) / d;
output.x = x;
output.y = y;
return true;
}

std::string str() const
{
std::stringstream ss;
ss << "Segment(from=" << from.str() << ", to=" << to.str() << ")";
return ss.str();
}
};

} // namespace horizon
91 changes: 68 additions & 23 deletions src/core/tools/tool_round_off_vertex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ namespace horizon {

bool ToolRoundOffVertex::can_begin()
{
return sel_count_type(selection, ObjectType::POLYGON_VERTEX) == 1;
return (sel_count_type(selection, ObjectType::POLYGON_VERTEX) == 1
|| sel_count_type(selection, ObjectType::POLYGON_ARC_CENTER) == 1);
}

int ToolRoundOffVertex::wrap_index(int i) const
Expand All @@ -27,49 +28,70 @@ int ToolRoundOffVertex::wrap_index(int i) const
ToolResponse ToolRoundOffVertex::begin(const ToolArgs &args)
{
int vertex_idx = 0;
editing = sel_has_type(selection, ObjectType::POLYGON_ARC_CENTER);
{
auto x = sel_find_one(selection, ObjectType::POLYGON_VERTEX);
ObjectType type = editing ? ObjectType::POLYGON_ARC_CENTER : ObjectType::POLYGON_VERTEX;
auto x = sel_find_one(selection, type);
poly = doc.r->get_polygon(x.uuid);
vertex_idx = x.vertex;
}

auto v_next = wrap_index(vertex_idx + 1);
auto v_prev = wrap_index(vertex_idx - 1);

if ((poly->vertices.at(vertex_idx).type == Polygon::Vertex::Type::ARC)
|| (poly->vertices.at(v_prev).type == Polygon::Vertex::Type::ARC)) {
imp->tool_bar_flash("can't round off arc");
return ToolResponse::end();

if (editing) {
auto v_inserted = v_next; // Inserted vertex
v_next = wrap_index(vertex_idx + 2);

vxp = &poly->vertices.at(vertex_idx);
vxn = &poly->vertices.at(v_inserted);

if (!revert_arc(p0, vxp->position, vxn->position, vxp->arc_center)) {
imp->tool_bar_flash("can't undo arc");
return ToolResponse::end();
}
}
else {
if ((poly->vertices.at(vertex_idx).type == Polygon::Vertex::Type::ARC)
|| (poly->vertices.at(v_prev).type == Polygon::Vertex::Type::ARC)) {
imp->tool_bar_flash("can't round off arc");
return ToolResponse::end();
}
p0 = poly->vertices.at(vertex_idx).position;
}

selection.clear();

p0 = poly->vertices.at(vertex_idx).position;
vn = (Coordd(poly->vertices.at(v_next).position) - p0).normalize();
vp = (Coordd(poly->vertices.at(v_prev).position) - p0).normalize();
Coordd p1 = poly->vertices.at(v_next).position;
Coordd p2 = poly->vertices.at(v_prev).position;

vn = (p1 - p0).normalize();
vp = (p2 - p0).normalize();
vh = (vn + vp).normalize();

delta_max = std::min((poly->vertices.at(v_next).position - poly->vertices.at(vertex_idx).position).magd(),
(poly->vertices.at(v_prev).position - poly->vertices.at(vertex_idx).position).magd());
delta_max = std::min((p1 - p0).mag(), (p2 - p0).mag());
alpha = acos(vh.dot(vp));
if (isnan(alpha) || (alpha > .99 * (M_PI / 2))) {
imp->tool_bar_flash("can't round off collinear edges");
return ToolResponse::end();
}
r_max = tan(alpha) * delta_max;

const bool rev = vn.cross(vp) < 0;
if (!editing) {
const bool rev = vn.cross(vp) < 0;

if (v_next == 0) {
poly->vertices.emplace_back(Coordi());
vxn = &poly->vertices.back();
}
else {
vxn = &*poly->vertices.emplace(poly->vertices.begin() + v_next, Coordi());
if (v_next == 0) {
poly->vertices.emplace_back(Coordi());
vxn = &poly->vertices.back();
}
else {
vxn = &*poly->vertices.emplace(poly->vertices.begin() + v_next, Coordi());
}
vxp = &poly->vertices.at(vertex_idx);
vxp->type = Polygon::Vertex::Type::ARC;
vxp->arc_reverse = rev;
}
vxp = &poly->vertices.at(vertex_idx);
vxp->type = Polygon::Vertex::Type::ARC;
vxp->arc_reverse = rev;

imp->set_snap_filter({{ObjectType::POLYGON, poly->uuid}});

Expand Down Expand Up @@ -122,7 +144,7 @@ ToolResponse ToolRoundOffVertex::update(const ToolArgs &args)
else if (args.type == ToolEventType::ACTION) {
switch (args.action) {
case InToolActionID::LMB:
if (plane_finish())
if (commit())
return ToolResponse::commit();
else
return ToolResponse::revert();
Expand Down Expand Up @@ -153,7 +175,7 @@ ToolResponse ToolRoundOffVertex::update(const ToolArgs &args)
}
else if (data->event == ToolDataWindow::Event::OK) {
imp->dialogs.close_nonmodal();
if (plane_finish())
if (commit())
return ToolResponse::commit();
else
return ToolResponse::revert();
Expand All @@ -162,4 +184,27 @@ ToolResponse ToolRoundOffVertex::update(const ToolArgs &args)
}
return ToolResponse();
}

bool ToolRoundOffVertex::commit()
{
if (radius_current < 1) {
// Tiny radius, just ignore it
if (!editing)
return false; // Not a modification so just revert the action

// Undo change to original vertex
vxp->arc_center = Coordi();
vxp->arc_reverse = false;
vxp->position = p0.to_coordi();
vxp->type = Polygon::Vertex::Type::LINE;

// Remove inserted vertex
vxn->remove = true;
poly->vertices.erase(
std::remove_if(poly->vertices.begin(), poly->vertices.end(), [](const auto &x) { return x.remove; }),
poly->vertices.end());
}
return plane_finish();
}

} // namespace horizon
2 changes: 2 additions & 0 deletions src/core/tools/tool_round_off_vertex.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,11 @@ class ToolRoundOffVertex : public virtual ToolBase, public ToolHelperPlane {
double r_max = 0;
double alpha = 0;
double radius_current = 0;
bool editing = false;

void update_poly(double r);
void update_cursor(const Coordi &c);
void update_tip();
bool commit();
};
} // namespace horizon
20 changes: 20 additions & 0 deletions src/util/geom_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,4 +181,24 @@ Placement transform_text_placement_to_new_reference(Placement pl, Placement old_
return out;
}


/**
* Determine original point that the arc rounded off. If the parameters are
* invalid or it cannot determine the proper value return false.
*/
bool revert_arc(Coordd &output, const Coordd &p0, const Coordd &p1, const Coordd &c)
{
// The original center position is found by computing the intersection of
// lines defined by each arc point and their tangents. Tangents are of an
// arc perpendicular to vector to center.
const Coordd v0 = (p0 - c);
const Coordd v1 = (p1 - c);
double a = v0.cross(v1) > 0 ? M_PI / 2 : -M_PI / 2; // CW / CCW
const Coordd t0 = v0.rotate(a);
const Coordd t1 = v1.rotate(-a);
Segment<double> l0 = Segment<double>(p0, t0 + p0);
Segment<double> l1 = Segment<double>(p1, t1 + p1);
return l0.intersect(l1, output);
}

} // namespace horizon
2 changes: 2 additions & 0 deletions src/util/geom_util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,6 @@ template <typename T> T c2pi(T x);
Placement transform_package_placement_to_new_reference(Placement pl, Placement old_ref, Placement new_ref);
Placement transform_text_placement_to_new_reference(Placement pl, Placement old_ref, Placement new_ref);

bool revert_arc(Coordd &output, const Coordd &p0, const Coordd &p1, const Coordd &c);

} // namespace horizon

0 comments on commit 55eaf42

Please sign in to comment.