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.
158 lines
4.0 KiB
158 lines
4.0 KiB
function screen_to_canvas(state, p) { |
|
// should be called with coordinates obtained from MouseEvent.clientX/clientY * window.devicePixelRatio |
|
const xc = (p.x - state.canvas.offset.x) / state.canvas.zoom; |
|
const yc = (p.y - state.canvas.offset.y) / state.canvas.zoom; |
|
|
|
return {'x': xc, 'y': yc}; |
|
} |
|
|
|
function rdp_find_max(state, points, start, end) { |
|
const EPS = 0.5 / state.canvas.zoom; |
|
// const EPS = 10.0; |
|
|
|
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(state, points, start, end) { |
|
let result = []; |
|
|
|
const max = rdp_find_max(state, points, start, end); |
|
|
|
if (max !== -1) { |
|
const before = process_rdp_r(state, points, start, max); |
|
const after = process_rdp_r(state, points, max, end); |
|
result = [...before, points[max], ...after]; |
|
} |
|
|
|
return result; |
|
} |
|
|
|
function process_rdp(state, points) { |
|
const result = process_rdp_r(state, 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.5; |
|
|
|
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(state, points) { |
|
// const result0 = process_ewmv(points); |
|
const result1 = process_rdp(state, points, true); |
|
return result1; |
|
} |
|
|
|
function strokes_intersect_line(state, a, b) { |
|
// TODO: handle stroke / eraser width |
|
const result = []; |
|
|
|
for (let i = 0; i < state.events.length; ++i) { |
|
const event = state.events[i]; |
|
if (event.type === EVENT.STROKE && !event.deleted) { |
|
for (let i = 0; i < event.points.length - 1; ++i) { |
|
const c = event.points[i + 0]; |
|
const d = event.points[i + 1]; |
|
|
|
if (segments_intersect(a, b, c, d)) { |
|
result.push(i); |
|
break; |
|
} |
|
} |
|
} |
|
} |
|
|
|
return result; |
|
} |
|
|
|
function color_to_u32(color_str) { |
|
const r = parseInt(color_str.substring(0, 2), 16); |
|
const g = parseInt(color_str.substring(2, 4), 16); |
|
const b = parseInt(color_str.substring(4, 6), 16); |
|
|
|
return (r << 16) | (g << 8) | b; |
|
} |
|
|
|
function color_from_u32(color_u32) { |
|
const r = (color_u32 >> 16) & 0xFF; |
|
const g = (color_u32 >> 8) & 0xFF; |
|
const b = color_u32 & 0xFF; |
|
|
|
let r_str = r.toString(16); |
|
let g_str = g.toString(16); |
|
let b_str = b.toString(16); |
|
|
|
if (r <= 0xF) r_str = '0' + r_str; |
|
if (g <= 0xF) g_str = '0' + g_str; |
|
if (b <= 0xF) b_str = '0' + b_str; |
|
|
|
return '#' + r_str + g_str + b_str; |
|
} |
|
|
|
function ccw(A, B, C) { |
|
return (C.y - A.y) * (B.x - A.x) > (B.y - A.y) * (C.x - A.x); |
|
} |
|
|
|
// https://stackoverflow.com/a/9997374/11420590 |
|
function segments_intersect(A, B, C, D) { |
|
return ccw(A, C, D) != ccw(B, C, D) && ccw(A, B, C) !== ccw(A, B, D); |
|
} |
|
|
|
function dist_v2(a, b) { |
|
const dx = a.x - b.x; |
|
const dy = a.y - b.y; |
|
return Math.sqrt(dx * dx + dy * dy); |
|
} |
|
|
|
function mid_v2(a, b) { |
|
return { |
|
'x': (a.x + b.x) / 2.0, |
|
'y': (a.y + b.y) / 2.0, |
|
}; |
|
} |