[Path Shape] Add corner radius for quadrilateral shapes.

This commit is contained in:
Tanasart 2024-12-28 15:51:57 +07:00
parent df4d289333
commit f1e60b9213
4 changed files with 231 additions and 95 deletions

View file

@ -52,12 +52,12 @@ function draw_corner(x1, y1, xc, yc, x3, y3, thick = 1, col = c_white, sample =
draw_primitive_end();
}
function get_corner(x1, y1, xc, yc, x3, y3, sample = 10) {
function get_corner(x1, y1, xc, yc, x3, y3, sample = 10, thres = 8) {
var dir0 = point_direction(x1, y1, xc, yc);
var dir1 = point_direction(x3, y3, xc, yc);
var dis = point_distance(x1, y1, x3, y3);
if(dis < 8) return [ [x1, y1], [x3, y3] ];
if(dis < thres) return [ [x1, y1], [x3, y3] ];
var p2 = point_rotate(xc, yc, x1, y1, -90);
var x2 = p2[0];
@ -91,4 +91,17 @@ function get_corner(x1, y1, xc, yc, x3, y3, sample = 10) {
}
return pnt;
}
function get_corner_radius(x1, y1, xc, yc, x3, y3, rad, sample = 10, thres = 8) {
var dir0 = point_direction(xc, yc, x1, y1);
var dir1 = point_direction(xc, yc, x3, y3);
x1 = xc + lengthdir_x(rad, dir0);
y1 = yc + lengthdir_y(rad, dir0);
x3 = xc + lengthdir_x(rad, dir1);
y3 = yc + lengthdir_y(rad, dir1);
return get_corner(x1, y1, xc, yc, x3, y3, sample, thres);
}

View file

@ -12,7 +12,7 @@ function Node_Path_Morph(_x, _y, _group = noone) : Node_Processor(_x, _y, _group
newInput(2, nodeValue_Dimension(self));
newInput(3, nodeValue_Int("Subdivision", self, 128))
newInput(3, nodeValue_Int("Subdivision", self, 64))
.setValidator(VV_min(2))
.rejectArray();
@ -52,22 +52,65 @@ function Node_Path_Morph(_x, _y, _group = noone) : Node_Processor(_x, _y, _group
var _cur = _data[5];
var _mid = _data[6];
var _p1 = array_create(_sub * 2);
var _p2 = array_create(_sub * 2);
var _isb = 1 / (_sub - 1);
var _pp = new __vec2();
for( var i = 0; i < _sub; i++ ) {
var _prog = frac(i * _isb);
if(_mid) {
var _p1 = array_create(_sub * 2);
var _p2 = array_create(_sub * 2);
var p1 = array_create(_sub);
var p2 = array_create(_sub);
_pp = _path1.getPointRatio(_prog, 0, _pp);
_p1[i * 2 + 0] = _pp.x;
_p1[i * 2 + 1] = _pp.y;
cx1 = 0; cy1 = 0;
cx2 = 0; cy2 = 0;
_pp = _path2.getPointRatio(_prog, 0, _pp);
_p2[i * 2 + 0] = _pp.x;
_p2[i * 2 + 1] = _pp.y;
for( var i = 0; i < _sub; i++ ) {
var _prog = frac(i * _isb);
_pp = _path1.getPointRatio(_prog, 0, _pp);
p1[i] = [ _pp.x, _pp.y ];
cx1 += _pp.x;
cy1 += _pp.y;
_pp = _path2.getPointRatio(_prog, 0, _pp);
p2[i] = [ _pp.x, _pp.y ];
cx2 += _pp.x;
cy2 += _pp.y;
}
cx1 /= _sub;
cy1 /= _sub;
cx2 /= _sub;
cy2 /= _sub;
// array_sort(p1, (a,b) => { return point_direction(cx1, cy1, a[0], a[1]) - point_direction(cx1, cy1, b[0], b[1]); });
// array_sort(p2, (a,b) => { return point_direction(cx2, cy2, a[0], a[1]) - point_direction(cx2, cy2, b[0], b[1]); });
for( var i = 0; i < _sub; i++ ) {
_p1[i * 2 + 0] = p1[i][0];
_p1[i * 2 + 1] = p1[i][1];
_p2[i * 2 + 0] = p2[i][0];
_p2[i * 2 + 1] = p2[i][1];
}
} else {
var _p1 = array_create(_sub * 2);
var _p2 = array_create(_sub * 2);
for( var i = 0; i < _sub; i++ ) {
var _prog = frac(i * _isb);
_pp = _path1.getPointRatio(_prog, 0, _pp);
_p1[i * 2 + 0] = _pp.x;
_p1[i * 2 + 1] = _pp.y;
_pp = _path2.getPointRatio(_prog, 0, _pp);
_p2[i * 2 + 0] = _pp.x;
_p2[i * 2 + 1] = _pp.y;
}
}
surface_set_shader(_outSurf, sh_path_morph);

View file

@ -79,16 +79,6 @@ function Node_Path_Shape(_x, _y, _group = noone) : Node(_x, _y, _group) construc
_rat = frac(_rat);
switch(shapeScroll[shape].name) {
case "Rectangle" :
case "Trapezoid" :
case "Parallelogram" :
var i = floor(_rat * 4);
var r = (_rat - i * .25) * 4;
out.x = lerp(points[i * 2][0], points[i * 2 + 1][0], r);
out.y = lerp(points[i * 2][1], points[i * 2 + 1][1], r);
break;
case "Ellipse" :
var a = 360 * _rat;
out.x = posx + lengthdir_x(scax, a);
@ -109,6 +99,9 @@ function Node_Path_Shape(_x, _y, _group = noone) : Node(_x, _y, _group) construc
out.y = posy + lengthdir_y(scay * r, a);
break;
case "Trapezoid" :
case "Parallelogram" :
case "Rectangle" :
case "Polygon" :
case "Star" :
case "Line" :
@ -195,7 +188,7 @@ function Node_Path_Shape(_x, _y, _group = noone) : Node(_x, _y, _group) construc
pa2y = _aran[1];
pa3 = _pa3;
corners = _c;
corners = _c;
var ox, oy, nx, ny, x0, y0;
@ -208,66 +201,131 @@ function Node_Path_Shape(_x, _y, _group = noone) : Node(_x, _y, _group) construc
switch(shapeScroll[shape].name) {
case "Rectangle" :
loop = true;
inputs[9].setVisible(true);
loop = true;
var x0 = posx - scax;
var y0 = posy - scay;
var x1 = posx + scax;
var y1 = posy + scay;
points = [
[ x0 + _c[0], y0 ],
[ x1 - _c[1], y0 ],
[ x1, y0 + _c[1] ],
[ x1, y1 - _c[2] ],
[ x1 - _c[2], y1 ],
[ x0 + _c[3], y1 ],
[ x0, y1 - _c[3] ],
[ x0, y0 + _c[0] ],
];
var p = [
[ x0, y1 ],
[ x0, y0 ],
[ x1, y0 ],
[ x0, y0 ],
[ x1, y0 ],
[ x1, y1 ],
[ x1, y0 ],
[ x1, y1 ],
[ x0, y1 ],
[ x1, y1 ],
[ x0, y1 ],
[ x0, y0 ],
];
var ar = array_create(4);
for( var i = 0; i < 4; i++ ) {
ar[i] = _c[i]? get_corner_radius(p[i * 3 + 0][0], p[i * 3 + 0][1],
p[i * 3 + 1][0], p[i * 3 + 1][1],
p[i * 3 + 2][0], p[i * 3 + 2][1], _c[i], 64, 0) : [ p[i * 3 + 1] ];
}
points = array_merge( ar[0], ar[1], ar[2], ar[3] );
break;
case "Trapezoid" :
loop = true;
inputs[4].setVisible(true);
inputs[9].setVisible(true);
points = [
[ posx - scax * saturate(1 - _pa1), posy - scay ],
[ posx + scax * saturate(1 - _pa1), posy - scay ],
[ posx + scax * saturate(1 - _pa1), posy - scay ],
[ posx + scax * saturate(1 + _pa1), posy + scay ],
[ posx + scax * saturate(1 + _pa1), posy + scay ],
[ posx - scax * saturate(1 + _pa1), posy + scay ],
[ posx - scax * saturate(1 + _pa1), posy + scay ],
[ posx - scax * saturate(1 - _pa1), posy - scay ],
];
var x0 = posx - scax * saturate(1 - _pa1);
var y0 = posy - scay;
var x1 = posx + scax * saturate(1 - _pa1);
var y1 = posy - scay;
var x2 = posx + scax * saturate(1 + _pa1);
var y2 = posy + scay;
var x3 = posx - scax * saturate(1 + _pa1);
var y3 = posy + scay;
var p = [
[ x3, y3 ],
[ x0, y0 ],
[ x1, y1 ],
[ x0, y0 ],
[ x1, y1 ],
[ x2, y2 ],
[ x1, y1 ],
[ x2, y2 ],
[ x3, y3 ],
[ x2, y3 ],
[ x3, y3 ],
[ x0, y0 ],
];
var ar = array_create(4);
for( var i = 0; i < 4; i++ ) {
ar[i] = _c[i]? get_corner_radius(p[i * 3 + 0][0], p[i * 3 + 0][1],
p[i * 3 + 1][0], p[i * 3 + 1][1],
p[i * 3 + 2][0], p[i * 3 + 2][1], _c[i], 64, 0) : [ p[i * 3 + 1] ];
}
points = array_merge( ar[0], ar[1], ar[2], ar[3] );
break;
case "Parallelogram" :
loop = true;
inputs[4].setVisible(true);
inputs[9].setVisible(true);
points = [
[ posx - scax * saturate(1 - _pa1), posy - scay ],
[ posx + scax * saturate(1 + _pa1), posy - scay ],
[ posx + scax * saturate(1 + _pa1), posy - scay ],
[ posx + scax * saturate(1 - _pa1), posy + scay ],
[ posx + scax * saturate(1 - _pa1), posy + scay ],
[ posx - scax * saturate(1 + _pa1), posy + scay ],
[ posx - scax * saturate(1 + _pa1), posy + scay ],
[ posx - scax * saturate(1 - _pa1), posy - scay ],
];
var x0 = posx - scax * saturate(1 - _pa1);
var y0 = posy - scay;
var x1 = posx + scax * saturate(1 + _pa1);
var y1 = posy - scay;
var x2 = posx + scax * saturate(1 - _pa1);
var y2 = posy + scay;
var x3 = posx - scax * saturate(1 + _pa1);
var y3 = posy + scay;
var p = [
[ x3, y3 ],
[ x0, y0 ],
[ x1, y1 ],
[ x0, y0 ],
[ x1, y1 ],
[ x2, y2 ],
[ x1, y1 ],
[ x2, y2 ],
[ x3, y3 ],
[ x2, y3 ],
[ x3, y3 ],
[ x0, y0 ],
];
var ar = array_create(4);
for( var i = 0; i < 4; i++ ) {
ar[i] = _c[i]? get_corner_radius(p[i * 3 + 0][0], p[i * 3 + 0][1],
p[i * 3 + 1][0], p[i * 3 + 1][1],
p[i * 3 + 2][0], p[i * 3 + 2][1], _c[i], 64, 0) : [ p[i * 3 + 1] ];
}
points = array_merge( ar[0], ar[1], ar[2], ar[3] );
break;
case "Ellipse" :
@ -381,6 +439,7 @@ function Node_Path_Shape(_x, _y, _group = noone) : Node(_x, _y, _group) construc
}
array_map_ext(points, function(p) /*=>*/ {return point_rotate(p[0], p[1], posx, posy, rot, p)});
var n = array_length(points);
lengths = array_create(n + loop);

View file

@ -131,17 +131,12 @@ float pointOnLine(in vec2 p, in vec2 l0, in vec2 l1) {
return t;
}
float tsign (in vec2 p1, in vec2 p2, in vec2 p3) { return (p1.x - p3.x) * (p2.y - p3.y) - (p2.x - p3.x) * (p1.y - p3.y); }
bool pointInTriangle(in vec2 p, in vec2 t0, in vec2 t1, in vec2 t2) {
float d1 = tsign(p, t0, t1);
float d2 = tsign(p, t1, t2);
float d3 = tsign(p, t2, t0);
float d1 = (p.x - t1.x) * (t0.y - t1.y) - (t0.x - t1.x) * (p.y - t1.y);
float d2 = (p.x - t2.x) * (t1.y - t2.y) - (t1.x - t2.x) * (p.y - t2.y);
float d3 = (p.x - t0.x) * (t2.y - t0.y) - (t2.x - t0.x) * (p.y - t0.y);
bool has_neg = (d1 < 0.) || (d2 < 0.) || (d3 < 0.);
bool has_pos = (d1 > 0.) || (d2 > 0.) || (d3 > 0.);
return !(has_neg && has_pos);
return (d1 >= 0. && d2 >= 0. && d3 >= 0.) || (d1 <= 0. && d2 <= 0. && d3 <= 0.);
}
bool intersect(in vec2 p, in vec2 l0, in vec2 l1) {
@ -197,37 +192,63 @@ void main() {
a = dF / (dF + dT);
} else {
float ma = 99999.;
float index = 0.;
bool infr = false;
a = 0.;
float d1, d2, d3;
for(int i = 1; i < subdivision; i++) {
pF1 = point1[i];
pT1 = point2[i];
pT0 = point2[0];
vec2 f = pointToLine(px, pF0, pF1);
vec2 t = pointToLine(px, pT0, pT1);
if(intersect(px, pF0, pF1) && f.x >= px.x) inFrom = !inFrom;
if(intersect(px, pT0, pT1) && t.x >= px.x) inTo = !inTo;
bool inRegion = pointInTriangle(px, pF0, pF1, pT0) || pointInTriangle(px, pF1, pT0, pT1);
pF0 = pF1;
pT0 = pT1;
if(!inRegion) continue;
float _f = distance(px, f);
float _t = distance(px, t);
a = max(a, _f / (_f + _t));
float pxx_f1x = (px.x - pF1.x);
float pxy_f1y = (px.y - pF1.y);
float pxx_f0x = (px.x - pF0.x);
float pxy_f0y = (px.y - pF0.y);
float f0y_f1y = (pF0.y - pF1.y);
float f0x_f1x = (pF0.x - pF1.x);
float dd1 = pxx_f1x * f0y_f1y - f0x_f1x * pxy_f1y;
infr = true;
for(int j = 1; j < subdivision; j++) {
pT1 = point2[j];
d1 = dd1;
d2 = (px.x - pT0.x) * (pF1.y - pT0.y) - (pF1.x - pT0.x) * (px.y - pT0.y);
d3 = pxx_f0x * (pT0.y - pF0.y) - (pT0.x - pF0.x) * pxy_f0y;
bool i1 = (d1 >= 0. && d2 >= 0. && d3 >= 0.) || (d1 <= 0. && d2 <= 0. && d3 <= 0.);
d1 = (px.x - pT0.x) * (pF1.y - pT0.y) - (pF1.x - pT0.x) * (px.y - pT0.y);
d2 = (px.x - pT1.x) * (pT0.y - pT1.y) - (pT0.x - pT1.x) * (px.y - pT1.y);
d3 = pxx_f1x * (pT1.y - pF1.y) - (pT1.x - pF1.x) * pxy_f1y;
bool i2 = (d1 >= 0. && d2 >= 0. && d3 >= 0.) || (d1 <= 0. && d2 <= 0. && d3 <= 0.);
bool inRegion = i1 || i2;
if(!inRegion) {
pT0 = pT1;
continue;
}
vec2 t = pointToLine(px, pT0, pT1);
float _t = distance(px, t);
a = max(a, _f / (_f + _t));
pT0 = pT1;
inFrom = true;
}
pF0 = pF1;
}
pT0 = point2[0];
for(int i = 1; i < subdivision; i++) {
pT1 = point2[i];
vec2 t = pointToLine(px, pT0, pT1);
if(intersect(px, pT0, pT1) && t.x >= px.x) inTo = !inTo;
pT0 = pT1;
}
if(infr) inFrom = true;
}
if(clip == 1) {