mirror of https://github.com/buggins/dlangui.git
implement clipping for line drawing
This commit is contained in:
parent
0778b77531
commit
01d39e0635
|
@ -342,14 +342,8 @@ class DrawBuf : RefCountedObject {
|
||||||
|
|
||||||
/// draw line from point p1 to p2 with specified color
|
/// draw line from point p1 to p2 with specified color
|
||||||
void drawLine(Point p1, Point p2, uint colour) {
|
void drawLine(Point p1, Point p2, uint colour) {
|
||||||
if (p1.x < _clipRect.left && p2.x < _clipRect.left)
|
if (!clipLine(_clipRect, p1, p2))
|
||||||
return;
|
return;
|
||||||
if (p1.y < _clipRect.top && p2.y < _clipRect.top)
|
|
||||||
return;
|
|
||||||
if (p1.x >= _clipRect.right && p2.x >= _clipRect.right)
|
|
||||||
return;
|
|
||||||
if (p1.y >= _clipRect.bottom && p2.y >= _clipRect.bottom)
|
|
||||||
return;
|
|
||||||
// from rosettacode.org
|
// from rosettacode.org
|
||||||
import std.math: abs;
|
import std.math: abs;
|
||||||
immutable int dx = p2.x - p1.x;
|
immutable int dx = p2.x - p1.x;
|
||||||
|
@ -1003,3 +997,105 @@ class ColorDrawBuf : ColorDrawBufBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// line clipping algorithm from https://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm
|
||||||
|
private alias OutCode = int;
|
||||||
|
|
||||||
|
private const int INSIDE = 0; // 0000
|
||||||
|
private const int LEFT = 1; // 0001
|
||||||
|
private const int RIGHT = 2; // 0010
|
||||||
|
private const int BOTTOM = 4; // 0100
|
||||||
|
private const int TOP = 8; // 1000
|
||||||
|
|
||||||
|
// Compute the bit code for a point (x, y) using the clip rectangle
|
||||||
|
// bounded diagonally by (xmin, ymin), and (xmax, ymax)
|
||||||
|
|
||||||
|
// ASSUME THAT xmax, xmin, ymax and ymin are global constants.
|
||||||
|
|
||||||
|
private OutCode ComputeOutCode(Rect clipRect, double x, double y)
|
||||||
|
{
|
||||||
|
OutCode code;
|
||||||
|
|
||||||
|
code = INSIDE; // initialised as being inside of clip window
|
||||||
|
|
||||||
|
if (x < clipRect.left) // to the left of clip window
|
||||||
|
code |= LEFT;
|
||||||
|
else if (x > clipRect.right) // to the right of clip window
|
||||||
|
code |= RIGHT;
|
||||||
|
if (y < clipRect.top) // below the clip window
|
||||||
|
code |= BOTTOM;
|
||||||
|
else if (y > clipRect.bottom) // above the clip window
|
||||||
|
code |= TOP;
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
package bool clipLine(ref Rect clipRect, ref Point p1, ref Point p2) {
|
||||||
|
double x0 = p1.x;
|
||||||
|
double y0 = p1.y;
|
||||||
|
double x1 = p2.x;
|
||||||
|
double y1 = p2.y;
|
||||||
|
bool res = CohenSutherlandLineClipAndDraw(clipRect, x0, y0, x1, y1);
|
||||||
|
if (res) {
|
||||||
|
p1.x = cast(int)x0;
|
||||||
|
p1.y = cast(int)y0;
|
||||||
|
p2.x = cast(int)x1;
|
||||||
|
p2.y = cast(int)y1;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cohen–Sutherland clipping algorithm clips a line from
|
||||||
|
// P0 = (x0, y0) to P1 = (x1, y1) against a rectangle with
|
||||||
|
// diagonal from (xmin, ymin) to (xmax, ymax).
|
||||||
|
private bool CohenSutherlandLineClipAndDraw(ref Rect clipRect, ref double x0, ref double y0, ref double x1, ref double y1)
|
||||||
|
{
|
||||||
|
// compute outcodes for P0, P1, and whatever point lies outside the clip rectangle
|
||||||
|
OutCode outcode0 = ComputeOutCode(clipRect, x0, y0);
|
||||||
|
OutCode outcode1 = ComputeOutCode(clipRect, x1, y1);
|
||||||
|
bool accept = false;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (!(outcode0 | outcode1)) { // Bitwise OR is 0. Trivially accept and get out of loop
|
||||||
|
accept = true;
|
||||||
|
break;
|
||||||
|
} else if (outcode0 & outcode1) { // Bitwise AND is not 0. Trivially reject and get out of loop
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
// failed both tests, so calculate the line segment to clip
|
||||||
|
// from an outside point to an intersection with clip edge
|
||||||
|
double x, y;
|
||||||
|
|
||||||
|
// At least one endpoint is outside the clip rectangle; pick it.
|
||||||
|
OutCode outcodeOut = outcode0 ? outcode0 : outcode1;
|
||||||
|
|
||||||
|
// Now find the intersection point;
|
||||||
|
// use formulas y = y0 + slope * (x - x0), x = x0 + (1 / slope) * (y - y0)
|
||||||
|
if (outcodeOut & TOP) { // point is above the clip rectangle
|
||||||
|
x = x0 + (x1 - x0) * (clipRect.bottom - y0) / (y1 - y0);
|
||||||
|
y = clipRect.bottom;
|
||||||
|
} else if (outcodeOut & BOTTOM) { // point is below the clip rectangle
|
||||||
|
x = x0 + (x1 - x0) * (clipRect.top - y0) / (y1 - y0);
|
||||||
|
y = clipRect.top;
|
||||||
|
} else if (outcodeOut & RIGHT) { // point is to the right of clip rectangle
|
||||||
|
y = y0 + (y1 - y0) * (clipRect.right - x0) / (x1 - x0);
|
||||||
|
x = clipRect.right;
|
||||||
|
} else if (outcodeOut & LEFT) { // point is to the left of clip rectangle
|
||||||
|
y = y0 + (y1 - y0) * (clipRect.left - x0) / (x1 - x0);
|
||||||
|
x = clipRect.left;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we move outside point to intersection point to clip
|
||||||
|
// and get ready for next pass.
|
||||||
|
if (outcodeOut == outcode0) {
|
||||||
|
x0 = x;
|
||||||
|
y0 = y;
|
||||||
|
outcode0 = ComputeOutCode(clipRect, x0, y0);
|
||||||
|
} else {
|
||||||
|
x1 = x;
|
||||||
|
y1 = y;
|
||||||
|
outcode1 = ComputeOutCode(clipRect, x1, y1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return accept;
|
||||||
|
}
|
|
@ -152,14 +152,8 @@ class GLDrawBuf : DrawBuf, GLConfigCallback {
|
||||||
/// draw line from point p1 to p2 with specified color
|
/// draw line from point p1 to p2 with specified color
|
||||||
override void drawLine(Point p1, Point p2, uint colour) {
|
override void drawLine(Point p1, Point p2, uint colour) {
|
||||||
assert(_scene !is null);
|
assert(_scene !is null);
|
||||||
if (p1.x < _clipRect.left && p2.x < _clipRect.left)
|
if (!clipLine(_clipRect, p1, p2))
|
||||||
return;
|
return;
|
||||||
if (p1.y < _clipRect.top && p2.y < _clipRect.top)
|
|
||||||
return;
|
|
||||||
if (p1.x >= _clipRect.right && p2.x >= _clipRect.right)
|
|
||||||
return;
|
|
||||||
if (p1.y >= _clipRect.bottom && p2.y >= _clipRect.bottom)
|
|
||||||
return;
|
|
||||||
_scene.add(new LineSceneItem(p1, p2, colour));
|
_scene.add(new LineSceneItem(p1, p2, colour));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue