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.
 
 
 

114 lines
3.7 KiB

function rdp_find_max(state, zoom, coords_from, start, end) {
// Finds a point from the range [start, end) with the maximum distance from the line (start--end) that is also further than EPS
const EPS = 1.0 / zoom;
let result = -1;
let max_dist = 0;
const ax = state.coordinates.data[coords_from + start * 2 + 0];
const ay = state.coordinates.data[coords_from + start * 2 + 1];
const bx = state.coordinates.data[coords_from + end * 2 + 0];
const by = state.coordinates.data[coords_from + end * 2 + 1];
const dx = bx - ax;
const dy = by - ay;
const dist_ab = Math.sqrt(dx * dx + dy * dy);
const dir_nx = dy / dist_ab;
const dir_ny = -dx / dist_ab;
for (let i = start + 1; i < end; ++i) {
const px = state.coordinates.data[coords_from + i * 2 + 0];
const py = state.coordinates.data[coords_from + i * 2 + 1];
const apx = px - ax;
const apy = py - ay;
const dist = Math.abs(apx * dir_nx + apy * dir_ny);
if (dist > EPS && dist > max_dist) {
result = i;
max_dist = dist;
}
}
state.stats.rdp_max_count++;
state.stats.rdp_segments += end - start - 1;
return result;
}
function do_lod(state, context) {
const zoom = state.canvas.zoom;
const segments_data = state.segments.data;
let segments_head = 0;
for (let i = 0; i < context.clipped_indices.count; ++i) {
const stroke_index = context.clipped_indices.data[i];
const stroke = state.events[stroke_index];
const point_count = (stroke.coords_to - stroke.coords_from) / 2;
const coords_from = stroke.coords_from;
if (point_count > state.rdp_traverse_stack.length) {
//console.count('allocate')
state.rdp_traverse_stack = new Uint32Array(round_to_pow2(point_count, 4096));
}
const stack = state.rdp_traverse_stack;
// Basic CSR crap
state.segments_from.data[i] = segments_head;
if (state.canvas.zoom <= state.line_threshold.data[stroke_index]) {
segments_data[segments_head++] = 0;
segments_data[segments_head++] = point_count - 1;
} else {
let segment_count = 2;
segments_data[segments_head++] = 0;
let head = 0;
// Using stack.push() allocates even if the stack is pre-allocated!
stack[head++] = 0;
stack[head++] = 0;
stack[head++] = point_count - 1;
while (head > 0) {
const end = stack[--head];
const value = start = stack[--head];
const type = stack[--head];
if (type === 1) {
segments_data[segments_head++] = value;
} else {
const max = rdp_find_max(state, zoom, coords_from, start, end);
if (max !== -1) {
segment_count += 1;
stack[head++] = 0;
stack[head++] = max;
stack[head++] = end;
stack[head++] = 1;
stack[head++] = max;
stack[head++] = -1;
stack[head++] = 0;
stack[head++] = start;
stack[head++] = max;
}
}
}
segments_data[segments_head++] = point_count - 1;
if (segment_count === 2 && state.canvas.zoom > state.line_threshold.data[stroke_index]) {
state.line_threshold.data[stroke_index] = state.canvas.zoom;
}
}
}
return segments_head;
}