poly line

This commit is contained in:
Vadim Lopatin 2016-11-07 15:04:46 +03:00
parent ec4b6c9392
commit 1b80fbb77a
3 changed files with 96 additions and 17 deletions

View File

@ -1092,17 +1092,17 @@ void main()
for (int i = 0; i < 40; i+=3)
buf.drawLine(Point(x+200 + i * 4, y+290), Point(x+150 + i * 7, y+420 + i * 2), 0x008000 + i * 5);
// poly line test
Rect newClipRect = Rect(x + 110, y + 100, x + 350, y + 320);
buf.fillRect(newClipRect, 0xC08080FF);
Rect oldClip = buf.clipRect;
buf.clipRect = newClipRect;
//Rect newClipRect = Rect(x + 110, y + 100, x + 350, y + 320);
//buf.fillRect(newClipRect, 0xC08080FF);
//Rect oldClip = buf.clipRect;
//buf.clipRect = newClipRect;
PointF[] poly = [vec2(x+130, y+150), vec2(x+240, y+80), vec2(x+170, y+170), vec2(x+380, y+270), vec2(x+220, y+400), vec2(x+180, y+330)];
buf.polyLineF(poly, 8.0f, 0x804020, true);
buf.fillTriangleF(vec2(x+230, y+50), vec2(x+400, y+250), vec2(x+130, y+200), 0xC0FF0000);
buf.fillTriangleF(vec2(x+230, y+250), vec2(x+200, y+350), vec2(x+80, y+200), 0xC000FF00);
buf.fillTriangleF(vec2(x+430, y+250), vec2(x+280, y+150), vec2(x+200, y+300), 0xC00000FF);
buf.fillTriangleF(vec2(x+80, y+150), vec2(x+280, y+250), vec2(x+80, y+200), 0xC0008080);
buf.clipRect = oldClip;
buf.polyLineF(poly, 18.0f, 0x80804020, true);
//buf.fillTriangleF(vec2(x+230, y+50), vec2(x+400, y+250), vec2(x+130, y+200), 0xC0FF0000);
//buf.fillTriangleF(vec2(x+230, y+250), vec2(x+200, y+350), vec2(x+80, y+200), 0xC000FF00);
//buf.fillTriangleF(vec2(x+430, y+250), vec2(x+280, y+150), vec2(x+200, y+300), 0xC00000FF);
//buf.fillTriangleF(vec2(x+80, y+150), vec2(x+280, y+250), vec2(x+80, y+200), 0xC0008080);
//buf.clipRect = oldClip;
canvas.font.drawText(buf, x + 190, y + 260, "polyLineF()"d, 0x603010);
};
tabs.addTab(canvas, "TAB_CANVAS"c);

View File

@ -97,6 +97,16 @@ struct vec2 {
return this;
}
/// returns vector rotated 90 degrees counter clockwise
vec2 rotated90ccw() const {
return vec2(-y, x);
}
/// returns vector rotated 90 degrees clockwise
vec2 rotated90cw() const {
return vec2(y, -x);
}
/// add value to all components of vector
vec2 opBinary(string op : "+")(float v) const {
vec2 res = this;
@ -119,11 +129,10 @@ struct vec2 {
return res;
}
/// divide all components of vector by value
vec3 opBinary(string op : "/")(float v) const {
vec3 res = this;
vec2 opBinary(string op : "/")(float v) const {
vec2 res = this;
res.vec[0] /= v;
res.vec[1] /= v;
res.vec[2] /= v;
return res;
}
@ -207,6 +216,11 @@ struct vec2 {
return res;
}
/// cross product of 2 vec2 is scalar in Z axis
float crossProduct(const vec2 v2) const {
return x * v2.y - y * v2.x;
}
/// returns vector with all components which are negative of components for this vector
vec2 opUnary(string op : "-")() const {
vec2 ret = this;

View File

@ -548,7 +548,8 @@ class DrawBuf : RefCountedObject {
// direction vector
PointF v = (p2 - p1).normalized;
// calculate normal vector
PointF n;
// calculate normal vector : rotate CCW 90 degrees
PointF n = v.rotated90ccw();
// rotate CCW 90 degrees
n.y = v.x;
n.x = -v.y;
@ -558,15 +559,79 @@ class DrawBuf : RefCountedObject {
fillQuadF(p1 - n, p2 - n, p2 + n, p1 + n, colour);
}
// find intersection point for two vectors with start points p1, p2 and normalized directions dir1, dir2
protected static PointF intersectVectors(PointF p1, PointF dir1, PointF p2, PointF dir2) {
/*
L1 = P1 + a * V1
L2 = P2 + b * V2
P1 + a * V1 = P2 + b * V2
a * V1 = (P2 - P1) + b * V2
a * (V1 X V2) = (P2 - P1) X V2
a = (P2 - P1) * V2 / (V1*V2)
return P1 + a * V1
*/
// just return middle point
PointF p2p1 = (p2 - p1); //.normalized;
float d1 = p2p1.crossProduct(dir2);
float d2 = dir1.crossProduct(dir2);
// a * d1 = d2
if (d2 >= -0.1f && d2 <= 0.1f) {
return p1; //PointF((p1.x + p2.x)/2, (p1.y + p2.y)/2);
}
float a = d1 / d2;
return p1 + dir1 * a;
}
/// draw line of arbitrary width in float coordinates p1..p2 with angle based on previous (p0..p1) and next (p2..p3) segments
void drawLineSegmentF(PointF p0, PointF p1, PointF p2, PointF p3, float width, uint colour) {
// direction vector
PointF v = (p2 - p1).normalized;
// calculate normal vector : rotate CCW 90 degrees
PointF n = v.rotated90ccw();
// offset by normal * half_width
n *= width / 2;
// draw line using quad
PointF pp10 = p1 - n;
PointF pp20 = p2 - n;
PointF pp11 = p1 + n;
PointF pp21 = p2 + n;
if ((p1 - p0).length > 0.1f) {
// has prev segment
PointF prevv = (p1 - p0).normalized;
PointF prevn = prevv.rotated90ccw();
PointF prev10 = p1 - prevn * width / 2;
PointF prev11 = p1 + prevn * width / 2;
PointF intersect0 = intersectVectors(pp10, -v, prev10, prevv);
PointF intersect1 = intersectVectors(pp11, -v, prev11, prevv);
pp10 = intersect0;
pp11 = intersect1;
}
if ((p3 - p2).length > 0.1f) {
// has next segment
PointF nextv = (p3 - p2).normalized;
PointF nextn = nextv.rotated90ccw();
PointF next20 = p2 - nextn * width / 2;
PointF next21 = p2 + nextn * width / 2;
PointF intersect0 = intersectVectors(pp20, v, next20, -nextv);
PointF intersect1 = intersectVectors(pp21, v, next21, -nextv);
pp20 = intersect0;
pp21 = intersect1;
}
fillQuadF(pp10, pp20, pp21, pp11, colour);
}
/// draw poly line of arbitrary width in float coordinates; when cycled is true, connect first and last point
void polyLineF(PointF[] points, float width, uint colour, bool cycled) {
if (points.length < 2)
return;
for(int i = 0; i + 1 < points.length; i++) {
drawLineF(points[i], points[i + 1], width, colour);
PointF prevPoint = (i > 0) ? points[i - 1] : (cycled ? points[$-1] : points[i]);
PointF nextPoint = (i + 2 < points.length) ? points[i + 2] : (cycled ? points[0] : points[$ - 1]);
drawLineSegmentF(prevPoint, points[i], points[i + 1], nextPoint, width, colour);
}
if (cycled && points.length > 2) {
drawLineSegmentF(points[$ - 2], points[$ - 1], points[0], points[1], width, colour);
}
if (cycled && points.length > 2)
drawLineF(points[$ - 1], points[0], width, colour);
}
/// draw poly line of width == 1px; when cycled is true, connect first and last point