A.Olokhtonov
10 months ago
10 changed files with 262 additions and 119 deletions
@ -0,0 +1,114 @@
@@ -0,0 +1,114 @@
|
||||
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; |
||||
} |
@ -0,0 +1,115 @@
@@ -0,0 +1,115 @@
|
||||
float sqrtf(float x); |
||||
float fabsf(float x); |
||||
|
||||
static int |
||||
rdp_find_max(float *coordinates, float zoom, int coords_from, |
||||
int segment_start, int segment_end) |
||||
{ |
||||
float EPS = 1.0 / zoom; |
||||
|
||||
int result = -1; |
||||
float max_dist = 0.0f; |
||||
|
||||
float ax = coordinates[coords_from + segment_start * 2 + 0]; |
||||
float ay = coordinates[coords_from + segment_start * 2 + 1]; |
||||
float bx = coordinates[coords_from + segment_end * 2 + 0]; |
||||
float by = coordinates[coords_from + segment_end * 2 + 1]; |
||||
|
||||
float dx = bx - ax; |
||||
float dy = by - ay; |
||||
|
||||
float dist_ab = sqrtf(dx * dx + dy * dy); |
||||
float dir_nx = dy / dist_ab; |
||||
float dir_ny = -dx / dist_ab; |
||||
|
||||
for (int i = segment_start + 1; i < segment_end; ++i) { |
||||
float px = coordinates[coords_from + i * 2 + 0]; |
||||
float py = coordinates[coords_from + i * 2 + 1]; |
||||
|
||||
float apx = px - ax; |
||||
float apy = py - ay; |
||||
|
||||
float dist = fabsf(apx * dir_nx + apy * dir_ny); |
||||
|
||||
if (dist > EPS && dist > max_dist) { |
||||
result = i; |
||||
max_dist = dist; |
||||
} |
||||
} |
||||
|
||||
return(result); |
||||
} |
||||
|
||||
int |
||||
do_lod(int *clipped_indices, int clipped_count, float zoom, |
||||
int *stroke_coords_from, int *stroke_coords_to, |
||||
float *line_threshold, float *coordinates, |
||||
int *segments_from, int *segments) |
||||
{ |
||||
int segments_head = 0; |
||||
int stack[4096]; |
||||
|
||||
for (int i = 0; i < clipped_count; ++i) { |
||||
int stroke_index = clipped_indices[i]; |
||||
|
||||
// TODO: convert to a proper CSR, save half the memory
|
||||
int coords_from = stroke_coords_from[stroke_index]; |
||||
int coords_to = stroke_coords_to[stroke_index]; |
||||
|
||||
int point_count = (coords_to - coords_from) / 2; |
||||
|
||||
// Basic CSR crap
|
||||
segments_from[i] = segments_head; |
||||
|
||||
if (zoom < line_threshold[stroke_index]) { |
||||
// Fast paths for collapsing to a single line segment
|
||||
segments[segments_head++] = 0; |
||||
segments[segments_head++] = point_count - 1; |
||||
continue; |
||||
} |
||||
|
||||
int segment_count = 2; |
||||
int stack_head = 0; |
||||
|
||||
segments[segments_head++] = 0; |
||||
|
||||
stack[stack_head++] = 0; |
||||
stack[stack_head++] = 0; |
||||
stack[stack_head++] = point_count - 1; |
||||
|
||||
while (stack_head > 0) { |
||||
int end = stack[--stack_head]; |
||||
int start = stack[--stack_head]; |
||||
int type = stack[--stack_head]; |
||||
|
||||
if (type == 1) { |
||||
segments[segments_head++] = start; |
||||
} else { |
||||
int max = rdp_find_max(coordinates, zoom, coords_from, start, end); |
||||
if (max != -1) { |
||||
segment_count += 1; |
||||
|
||||
stack[stack_head++] = 0; |
||||
stack[stack_head++] = max; |
||||
stack[stack_head++] = end; |
||||
|
||||
stack[stack_head++] = 1; |
||||
stack[stack_head++] = max; |
||||
stack[stack_head++] = -1; |
||||
|
||||
stack[stack_head++] = 0; |
||||
stack[stack_head++] = start; |
||||
stack[stack_head++] = max; |
||||
} |
||||
} |
||||
} |
||||
|
||||
segments[segments_head++] = point_count - 1; |
||||
|
||||
if (segment_count == 2 && zoom > line_threshold[stroke_index]) { |
||||
line_threshold[stroke_index] = zoom; |
||||
} |
||||
} |
||||
|
||||
return(segments_head); |
||||
} |
Binary file not shown.
Loading…
Reference in new issue