-
Notifications
You must be signed in to change notification settings - Fork 78
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
6 changed files
with
213 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
#include "tool_round_off_vertex.hpp" | ||
#include "common/polygon.hpp" | ||
#include "imp/imp_interface.hpp" | ||
#include "util/util.hpp" | ||
#include "document/idocument.hpp" | ||
#include <gdk/gdkkeysyms.h> | ||
#include "util/selection_util.hpp" | ||
#include "clipper/clipper.hpp" | ||
|
||
namespace horizon { | ||
|
||
ToolRoundOffVertex::ToolRoundOffVertex(IDocument *c, ToolID tid) : ToolBase(c, tid) | ||
{ | ||
} | ||
|
||
bool ToolRoundOffVertex::can_begin() | ||
{ | ||
return sel_count_type(selection, ObjectType::POLYGON_VERTEX) == 1; | ||
} | ||
|
||
int ToolRoundOffVertex::wrap_index(int i) const | ||
{ | ||
while (i < 0) { | ||
i += poly->vertices.size(); | ||
} | ||
while (i >= (int)poly->vertices.size()) | ||
i -= poly->vertices.size(); | ||
return i; | ||
} | ||
|
||
using Coordd = Coord<double>; | ||
|
||
static Coordd normalize(const Coordd &c) | ||
{ | ||
return c / (sqrt(c.mag_sq())); | ||
} | ||
|
||
static Coordi to_coordi(const Coordd &c) | ||
{ | ||
return Coordi(c.x, c.y); | ||
} | ||
|
||
ToolResponse ToolRoundOffVertex::begin(const ToolArgs &args) | ||
{ | ||
int vertex_idx = 0; | ||
{ | ||
auto x = sel_find_one(selection, ObjectType::POLYGON_VERTEX); | ||
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(); | ||
} | ||
|
||
selection.clear(); | ||
|
||
p0 = poly->vertices.at(vertex_idx).position; | ||
vn = normalize(Coordd(poly->vertices.at(v_next).position) - p0); | ||
vp = normalize(Coordd(poly->vertices.at(v_prev).position) - p0); | ||
vh = normalize(vn + vp); | ||
|
||
delta_max = sqrt(std::min((poly->vertices.at(v_next).position - poly->vertices.at(vertex_idx).position).mag_sq(), | ||
(poly->vertices.at(v_prev).position - poly->vertices.at(vertex_idx).position).mag_sq())); | ||
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(); | ||
} | ||
|
||
bool rev = false; | ||
{ | ||
ClipperLib::Path path; | ||
path.reserve(poly->vertices.size()); | ||
std::transform(poly->vertices.begin(), poly->vertices.end(), std::back_inserter(path), | ||
[](const Polygon::Vertex &v) { return ClipperLib::IntPoint(v.position.x, v.position.y); }); | ||
rev = (!ClipperLib::Orientation(path)); | ||
} | ||
|
||
|
||
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; | ||
|
||
poly->temp = true; | ||
|
||
update_cursor(args.coords); | ||
|
||
return ToolResponse(); | ||
} | ||
|
||
void ToolRoundOffVertex::update_poly(double r) | ||
{ | ||
auto r_max = tan(alpha) * delta_max; | ||
r = std::min(r_max, r); | ||
auto delta = r / tan(alpha); | ||
auto u = r / sin(alpha); | ||
vxp->position = to_coordi(p0 + vp * delta); | ||
vxp->arc_center = to_coordi(p0 + vh * u); | ||
vxn->position = to_coordi(p0 + vn * delta); | ||
} | ||
|
||
void ToolRoundOffVertex::update_cursor(const Coordi &c) | ||
{ | ||
auto vm = Coordd(c) - p0; | ||
auto u = std::max(sqrt(vm.mag_sq()) * vh.dot(normalize(vm)), 0.); | ||
auto r = u * sin(alpha); | ||
auto r_max = tan(alpha) * delta_max; | ||
r = std::min(r_max, r); | ||
radius_current = r; | ||
imp->tool_bar_set_tip( | ||
"<b>LMB:</b>set radius <b>RMB:</b>cancel <b>Return:</b>enter radius <b>e:</b>flip arc <i>Current radius:" | ||
+ dim_to_string(r, false) + "</i>"); | ||
update_poly(r); | ||
} | ||
|
||
ToolResponse ToolRoundOffVertex::update(const ToolArgs &args) | ||
{ | ||
if (args.type == ToolEventType::MOVE) { | ||
update_cursor(args.coords); | ||
} | ||
else if (args.type == ToolEventType::CLICK) { | ||
if (args.button == 1) { | ||
poly->temp = false; | ||
return ToolResponse::commit(); | ||
} | ||
else if (args.button == 3) { | ||
selection.clear(); | ||
return ToolResponse::revert(); | ||
} | ||
} | ||
else if (args.type == ToolEventType::KEY) { | ||
if (args.key == GDK_KEY_Escape) { | ||
selection.clear(); | ||
return ToolResponse::revert(); | ||
} | ||
else if (args.key == GDK_KEY_e) { | ||
vxp->arc_reverse = !vxp->arc_reverse; | ||
} | ||
else if (args.key == GDK_KEY_Return) { | ||
auto r = imp->dialogs.ask_datum("Enter arc radius", radius_current); | ||
if (r.first && r.second > 0) { | ||
update_poly(r.second); | ||
poly->temp = false; | ||
return ToolResponse::commit(); | ||
} | ||
} | ||
} | ||
return ToolResponse(); | ||
} | ||
} // namespace horizon |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
#pragma once | ||
#include "common/polygon.hpp" | ||
#include "core/tool.hpp" | ||
#include <forward_list> | ||
|
||
namespace horizon { | ||
|
||
class ToolRoundOffVertex : public ToolBase { | ||
public: | ||
ToolRoundOffVertex(IDocument *c, ToolID tid); | ||
ToolResponse begin(const ToolArgs &args) override; | ||
ToolResponse update(const ToolArgs &args) override; | ||
bool can_begin() override; | ||
bool is_specific() override | ||
{ | ||
return true; | ||
} | ||
|
||
private: | ||
Polygon *poly = nullptr; | ||
int wrap_index(int i) const; | ||
|
||
Polygon::Vertex *vxn = nullptr; | ||
Polygon::Vertex *vxp = nullptr; | ||
|
||
Coord<double> p0; | ||
Coord<double> vp; | ||
Coord<double> vn; | ||
Coord<double> vh; | ||
double delta_max = 0; | ||
double alpha = 0; | ||
double radius_current = 0; | ||
|
||
void update_poly(double r); | ||
void update_cursor(const Coordi &c); | ||
|
||
bool orientation = false; | ||
}; | ||
} // namespace horizon |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
b028dbe
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a great and welcome addition.
Two comments – right now we can set the radius via:
I'd really love it if additionally we could:
Bonus points for seting the radius in 0.1 mm increments per default and making it finer with Alt modifier.
What do you think? This could be a model for trace rounding as well (but there we have a routing issue, I know...)
b028dbe
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that would be too intuitive. I'd expect the scroll wheel to zoom the board view as it does with other tools active. Especially if the tool is later extended to work with multiple vertices at once, you'd lose the ability to quickly zoom in on different corners of a shape while adjusting the corner radius.
b028dbe
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I have an idea that also solves the scrolling issue: Instead of making the dialog for setting the radius a modal window, make it a non-modal window so that the user can change the radius with the scroll wheel and observe the change in real time.
Clicking cancel will return to setting the radius by mouse, clicking Okay will end the tool with the current radius.
b028dbe
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you scroll and the screen doesn't change you will see the radius of the selected vertecies change. So hitting Escto abort the action should be really the intuitive way to get out of this.
I didn't even think this would need a window to be honest, although I'd have nothing against it either.
b028dbe
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dunno, but scrolling anywhere on the screen to change a parameter strikes me as a bit odd. I guess this is a blender thing, right? Zooming and panning should be possible regardless of any mode the user is in. With the window, users get something they're already somewhat familiar with.
b028dbe
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right, their Bevel tool (more or less a round tool for polygon edges) uses this – but for another parameter: by scrolling you dial in the number of steps the polygon arc uses (which is more important in 3D I guess). Navigating the space is even more important in a 3D application, but it never remotely bothered me that the scroll wheel is captured there, I always found it more intuitive and quick than setting a number in a window especially if the helper bar on the bottom also tells you what scrolling does. If you really need to zoom in or out you hit Esc scroll out and fire up that tool again.
However I understand if that is not your preference, as I said I'd have nothing against a window, the most important thing to me is beeing able to judge the result in realtime with having actual numbers displayed.