You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
135 lines
3.2 KiB
135 lines
3.2 KiB
function rdp_find_max(points, start, end) { |
|
const EPS = 0.5; |
|
|
|
let result = -1; |
|
let max_dist = 0; |
|
|
|
const a = points[start]; |
|
const b = points[end]; |
|
|
|
const dx = b.x - a.x; |
|
const dy = b.y - a.y; |
|
|
|
const dist_ab = Math.sqrt(dx * dx + dy * dy); |
|
const sin_theta = dy / dist_ab; |
|
const cos_theta = dx / dist_ab; |
|
|
|
for (let i = start; i < end; ++i) { |
|
const p = points[i]; |
|
|
|
const ox = p.x - a.x; |
|
const oy = p.y - a.y; |
|
|
|
const rx = cos_theta * ox + sin_theta * oy; |
|
const ry = -sin_theta * ox + cos_theta * oy; |
|
|
|
const x = rx + a.x; |
|
const y = ry + a.y; |
|
|
|
const dist = Math.abs(y - a.y); |
|
|
|
if (dist > EPS && dist > max_dist) { |
|
result = i; |
|
max_dist = dist; |
|
} |
|
} |
|
|
|
return result; |
|
} |
|
|
|
function process_rdp_r(points, start, end) { |
|
let result = []; |
|
|
|
const max = rdp_find_max(points, start, end); |
|
|
|
if (max !== -1) { |
|
const before = process_rdp_r(points, start, max); |
|
const after = process_rdp_r(points, max, end); |
|
result = [...before, points[max], ...after]; |
|
} |
|
|
|
return result; |
|
} |
|
|
|
function process_rdp(points) { |
|
const result = process_rdp_r(points, 0, points.length - 1); |
|
result.unshift(points[0]); |
|
result.push(points[points.length - 1]); |
|
return result; |
|
} |
|
|
|
function process_ewmv(points, round = false) { |
|
const result = []; |
|
const alpha = 0.4; |
|
|
|
result.push(points[0]); |
|
|
|
for (let i = 1; i < points.length; ++i) { |
|
const p = points[i]; |
|
const x = Math.round(alpha * p.x + (1 - alpha) * result[result.length - 1].x); |
|
const y = Math.round(alpha * p.y + (1 - alpha) * result[result.length - 1].y); |
|
result.push({'x': x, 'y': y}); |
|
} |
|
|
|
return result; |
|
} |
|
|
|
function process_stroke(points) { |
|
const result0 = process_ewmv(points); |
|
const result1 = process_rdp(result0, true); |
|
return result1; |
|
} |
|
|
|
function stroke_stats(points, width) { |
|
let length = 0; |
|
let xmin = points[0].x, ymin = points[0].y; |
|
let xmax = xmin, ymax = ymin; |
|
|
|
for (let i = 0; i < points.length; ++i) { |
|
const point = points[i]; |
|
if (point.x < xmin) xmin = point.x; |
|
if (point.y < ymin) ymin = point.y; |
|
if (point.x > xmax) xmax = point.x; |
|
if (point.y > ymax) ymax = point.y; |
|
|
|
if (i > 0) { |
|
const last = points[i - 1]; |
|
const dx = point.x - last.x; |
|
const dy = point.y - last.y; |
|
length += Math.sqrt(dx * dx + dy * dy); |
|
} |
|
} |
|
|
|
xmin -= width; |
|
ymin -= width; |
|
xmax += width * 2; |
|
ymax += width * 2; |
|
|
|
const bbox = { |
|
'xmin': Math.floor(xmin), |
|
'ymin': Math.floor(ymin), |
|
'xmax': Math.ceil(xmax), |
|
'ymax': Math.ceil(ymax) |
|
}; |
|
|
|
return { |
|
'bbox': bbox, |
|
'length': length, |
|
}; |
|
} |
|
|
|
function rectangles_intersect(a, b) { |
|
const result = ( |
|
a.xmin <= b.xmax |
|
&& a.xmax >= b.xmin |
|
&& a.ymin <= b.ymax |
|
&& a.ymax >= b.ymin |
|
); |
|
|
|
return result; |
|
} |
|
|
|
function stroke_intersects_region(points, bbox) { |
|
const stats = stroke_stats(points, storage.cursor.width); |
|
return rectangles_intersect(stats.bbox, bbox); |
|
} |