mirror of
https://github.com/aseprite/aseprite.git
synced 2024-10-04 05:50:15 +00:00
Add snap line to more angles (fix #1641)
This commit is contained in:
parent
e87fdbb3af
commit
b6026ad433
@ -153,45 +153,16 @@ public:
|
||||
stroke[0] = m_first;
|
||||
stroke[1] = pt;
|
||||
|
||||
bool isoAngle = false;
|
||||
int snapM = 0;
|
||||
|
||||
if ((int(loop->getModifiers()) & int(ToolLoopModifiers::kSquareAspect))) {
|
||||
int dx = stroke[1].x - m_first.x;
|
||||
int dy = stroke[1].y - m_first.y;
|
||||
int minsize = std::min(ABS(dx), ABS(dy));
|
||||
int maxsize = std::max(ABS(dx), ABS(dy));
|
||||
const int dx = stroke[1].x - m_first.x;
|
||||
const int dy = stroke[1].y - m_first.y;
|
||||
const int minsize = std::min(ABS(dx), ABS(dy));
|
||||
|
||||
// Lines
|
||||
if (loop->getIntertwine()->snapByAngle()) {
|
||||
double angle = 180.0 * std::atan(static_cast<double>(-dy) /
|
||||
static_cast<double>(dx)) / PI;
|
||||
angle = ABS(angle);
|
||||
|
||||
// Snap horizontally
|
||||
if (angle < 18.0) {
|
||||
stroke[1].y = m_first.y;
|
||||
}
|
||||
// Snap at 26.565
|
||||
else if (angle < 36.0) {
|
||||
stroke[1].x = m_first.x + SGN(dx)*maxsize;
|
||||
stroke[1].y = m_first.y + SGN(dy)*maxsize/2;
|
||||
isoAngle = true;
|
||||
}
|
||||
// Snap at 45
|
||||
else if (angle < 54.0) {
|
||||
stroke[1].x = m_first.x + SGN(dx)*minsize;
|
||||
stroke[1].y = m_first.y + SGN(dy)*minsize;
|
||||
}
|
||||
// Snap at 63.435
|
||||
else if (angle < 72.0) {
|
||||
stroke[1].x = m_first.x + SGN(dx)*maxsize/2;
|
||||
stroke[1].y = m_first.y + SGN(dy)*maxsize;
|
||||
isoAngle = true;
|
||||
}
|
||||
// Snap vertically
|
||||
else {
|
||||
stroke[1].x = m_first.x;
|
||||
}
|
||||
snapM = doc::algo_line_snap_endpoint(&stroke[1].x, &stroke[1].y, m_first.x, m_first.y, stroke[1].x, stroke[1].y);
|
||||
}
|
||||
// Rectangles and ellipses
|
||||
else {
|
||||
@ -209,12 +180,24 @@ public:
|
||||
stroke[1].y = m_center.y + ry;
|
||||
}
|
||||
else if ((int(loop->getModifiers()) & int(ToolLoopModifiers::kFromCenter))) {
|
||||
int rx = stroke[1].x - m_first.x;
|
||||
int ry = stroke[1].y - m_first.y;
|
||||
stroke[0].x = m_first.x - rx + (isoAngle && ABS(rx) > ABS(ry) ? SGN(rx)*(rx & 1): 0);
|
||||
stroke[0].y = m_first.y - ry + (isoAngle && ABS(rx) < ABS(ry) ? SGN(ry)*(ry & 1): 0);
|
||||
stroke[1].x = m_first.x + rx;
|
||||
stroke[1].y = m_first.y + ry;
|
||||
const int rx = stroke[1].x - stroke[0].x;
|
||||
const int ry = stroke[1].y - stroke[0].y;
|
||||
if (snapM == 0 || snapM == INT_MAX) {
|
||||
stroke[0].x -= rx;
|
||||
stroke[0].y -= ry;
|
||||
}
|
||||
else {
|
||||
if (std::abs(rx) >= std::abs(ry)) {
|
||||
const int c = std::abs(rx) / snapM;
|
||||
stroke[0].x -= SGN(rx) * c * snapM;
|
||||
stroke[0].y -= SGN(ry) * c;
|
||||
}
|
||||
else {
|
||||
const int c = std::abs(ry) / snapM;
|
||||
stroke[0].x -= SGN(rx) * c;
|
||||
stroke[0].y -= SGN(ry) * c * snapM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust points for selection like tools (so we can select tiles)
|
||||
|
@ -151,16 +151,18 @@ doc::AlgoLineWithAlgoPixel Intertwine::getLineAlgo(ToolLoop* loop,
|
||||
}
|
||||
}
|
||||
|
||||
if (// When "Snap Angle" in being used or...
|
||||
(int(loop->getModifiers()) & int(ToolLoopModifiers::kSquareAspect)) ||
|
||||
// "Snap to Grid" is enabled
|
||||
(loop->getController()->canSnapToGrid() && loop->getSnapToGrid())) {
|
||||
// We prefer the perfect pixel lines that matches grid tiles
|
||||
if (loop->getController()->canSnapToGrid() && loop->getSnapToGrid()) {
|
||||
// "Snap to Grid" is enabled. Has precedence over other modifiers.
|
||||
return (needsFixForLineBrush ? algo_line_perfect_with_fix_for_line_brush:
|
||||
algo_line_perfect);
|
||||
}
|
||||
else if (int(loop->getModifiers()) & int(ToolLoopModifiers::kSquareAspect)) {
|
||||
// When "Snap Angle" in being used.
|
||||
return (needsFixForLineBrush ? algo_line_perfect_with_fix_for_line_brush:
|
||||
algo_line_snap);
|
||||
}
|
||||
else {
|
||||
// In other case we use the regular algorithm that is useful to
|
||||
// Otherwise use the regular algorithm that is useful to
|
||||
// draw continuous lines/strokes.
|
||||
return (needsFixForLineBrush ? algo_line_continuous_with_fix_for_line_brush:
|
||||
algo_line_continuous);
|
||||
|
@ -20,6 +20,82 @@
|
||||
|
||||
namespace doc {
|
||||
|
||||
int algo_line_snap_endpoint(int* x_out, int* y_out, int x1, int y1, int x2, int y2)
|
||||
{
|
||||
constexpr int MAX_M = 8;
|
||||
|
||||
int dx = x2 - x1;
|
||||
int dy = y2 - y1;
|
||||
const bool swapxy = std::abs(dy) > std::abs(dx);
|
||||
if (swapxy) {
|
||||
std::swap(dx, dy);
|
||||
}
|
||||
|
||||
const int m_limit = std::min(MAX_M, std::max(1, std::abs(dx) / 2));
|
||||
int m = dy != 0 ? (std::abs(dx) + std::abs(dy)/2) / std::abs(dy) : INT_MAX;
|
||||
if (m > 2 * m_limit) m = INT_MAX;
|
||||
else if (m > m_limit) m = m_limit;
|
||||
|
||||
if (!x_out || !y_out) {
|
||||
return m;
|
||||
}
|
||||
|
||||
if (m != INT_MAX) {
|
||||
const int v2 = m*m + 1;
|
||||
dx = SGN(dx) * (m * (std::abs(dx*m) + std::abs(dy)) + v2/2) / v2;
|
||||
dy = SGN(dy) * std::abs(dx) / m;
|
||||
|
||||
if (swapxy) {
|
||||
std::swap(dx, dy);
|
||||
}
|
||||
*x_out = x1 + dx;
|
||||
*y_out = y1 + dy;
|
||||
}
|
||||
else {
|
||||
if (swapxy) {
|
||||
*x_out = x1;
|
||||
*y_out = y2;
|
||||
}
|
||||
else {
|
||||
*x_out = x2;
|
||||
*y_out = y1;
|
||||
}
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
void algo_line_snap(int x1, int y1, int x2, int y2, void* data, AlgoPixel proc)
|
||||
{
|
||||
const int m = algo_line_snap_endpoint(nullptr, nullptr, x1, y1, x2, y2);
|
||||
|
||||
const bool swapxy = std::abs(y2-y1) > std::abs(x2-x1);
|
||||
if (swapxy) {
|
||||
std::swap(x1, y1);
|
||||
std::swap(x2, y2);
|
||||
}
|
||||
|
||||
const int dx = SGN(x2-x1);
|
||||
const int dy = SGN(y2-y1);
|
||||
|
||||
x2 += dx;
|
||||
|
||||
int e = m;
|
||||
int y = y1;
|
||||
for (int x=x1; x!=x2; x+=dx) {
|
||||
if (swapxy)
|
||||
proc(y, x, data);
|
||||
else
|
||||
proc(x, y, data);
|
||||
|
||||
e--;
|
||||
if (!e) {
|
||||
y += dy;
|
||||
e = m;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void algo_line_perfect(int x1, int y1, int x2, int y2, void* data, AlgoPixel proc)
|
||||
{
|
||||
bool yaxis;
|
||||
|
@ -28,6 +28,10 @@ namespace doc {
|
||||
void algo_line_perfect(int x1, int y1, int x2, int y2, void* data, AlgoPixel proc);
|
||||
void algo_line_perfect_with_fix_for_line_brush(int x1, int y1, int x2, int y2, void *data, AlgoPixel proc);
|
||||
|
||||
// For lines with constant integer pixel runs throughout the line.
|
||||
void algo_line_snap(int x1, int y1, int x2, int y2, void* data, AlgoPixel proc);
|
||||
int algo_line_snap_endpoint(int* x_out, int* y_out, int x1, int y1, int x2, int y2);
|
||||
|
||||
// Useful to create continuous lines (you can draw from one point to
|
||||
// another, and continue from that point to another in the same
|
||||
// angle and the line will look continous).
|
||||
|
Loading…
Reference in New Issue
Block a user