better handle outliers in voronoi

This commit is contained in:
ajuvercr 2020-04-20 10:04:24 +02:00
parent c2365d3668
commit b1f41d7974

View file

@ -5,10 +5,60 @@ import { DefaultRenderable } from "../webgl/renderer";
import { IndexBuffer, VertexBuffer } from "../webgl/buffer"; import { IndexBuffer, VertexBuffer } from "../webgl/buffer";
import { VertexBufferLayout, VertexArray } from "../webgl/vertexBufferLayout"; import { VertexBufferLayout, VertexArray } from "../webgl/vertexBufferLayout";
function arcctg(x: number): number { return Math.PI / 2 - Math.atan(x); }
function to_key(p: Point): string { function to_key(p: Point): string {
return [p.x, p.y] + ""; return [p.x, p.y] + "";
} }
function round_point(center: Point, point: Point, amount_fn = (b: number) => 0.7): Point {
const d = dist(center, point, true);
console.log("f:", amount_fn(d));
const x = center.x + amount_fn(d) * (point.x - center.x);
const y = center.y + amount_fn(d) * (point.y - center.y);
return { 'x': x, 'y': y };
}
function median_point(c: Point, p: Point, n: Point, d = 0.1): number[] {
const dd = 1.0 - 2 * d;
return [
dd * c.x + d * p.x + d * n.x,
dd * c.y + d * p.y + d * n.y,
]
}
function build_point_map(es: Voronoi.HalfEdge[]): (point: Point) => Point {
const mean = es.map(e => dist(e.getStartpoint(), e.getEndpoint())).reduce((a, b) => a + b, 0) / es.length;
const map = {};
for (let edge of es) {
const start = edge.getStartpoint();
const end = edge.getEndpoint();
if (dist(start, end) < 0.1 * mean) { // These points have to be merged
const middle = { 'x': (start.x + end.x) / 2, 'y': (start.y + end.y) / 2 };
map[to_key(start)] = middle;
map[to_key(end)] = middle;
}
}
return (p) => map[to_key(p)] || p;
}
function get_round_fn(dist_mean: number, amount = 0.7): (d: number) => number {
return (d) => {
console.log(arcctg(d - dist_mean));
return arcctg((d - dist_mean) * 3) / Math.PI / 2 + 0.5
}
}
function dist(a: Point, b: Point, norm = false): number {
const dx = a.x - b.x;
const dy = a.y - b.y;
if (norm) return Math.sqrt(dx * dx + dy * dy);
return dx * dx + dy * dy;
}
export class VoronoiBuilder { export class VoronoiBuilder {
inner: DefaultRenderable; inner: DefaultRenderable;
@ -18,10 +68,10 @@ export class VoronoiBuilder {
constructor(gl: WebGLRenderingContext, shader: Shader, planets: Point[], bbox: BBox) { constructor(gl: WebGLRenderingContext, shader: Shader, planets: Point[], bbox: BBox) {
const voronoi = new Voronoi(); const voronoi = new Voronoi();
// This voronoi sorts the planets, then owners don't align anymore
const own_map = {}; const own_map = {};
planets.forEach((p, i) => own_map[to_key(p)] = i); planets.forEach((p, i) => own_map[to_key(p)] = i);
// This voronoi sorts the planets, then owners don't align anymore
this.vor = voronoi.compute(planets, bbox); this.vor = voronoi.compute(planets, bbox);
const a_pos = []; const a_pos = [];
@ -33,27 +83,39 @@ export class VoronoiBuilder {
for (let i = 0; i < this.vor.cells.length; i++) { for (let i = 0; i < this.vor.cells.length; i++) {
const cell = this.vor.cells[i]; const cell = this.vor.cells[i];
const planetId = own_map[to_key(cell.site)]; const planetId = own_map[to_key(cell.site)];
const point_map = build_point_map(cell.halfedges);
const centerId = vertCount++; const centerId = vertCount++;
a_pos.push(cell.site.x, cell.site.y); a_pos.push(cell.site.x, cell.site.y);
a_own.push(planetId); a_own.push(planetId);
const dist_mean = cell.halfedges.map(e => dist(cell.site, e.getStartpoint(), true)).reduce((a, b) => a + b, 0) / cell.halfedges.length;
const round_fn = get_round_fn(dist_mean);
for (let edge of cell.halfedges) { for (let edge of cell.halfedges) {
const start = edge.getStartpoint(); let start = point_map(edge.getStartpoint());
const end = edge.getEndpoint(); let end = point_map(edge.getEndpoint());
const center = {'x': (start.x + end.x) / 2, 'y': (start.y + end.y) / 2}; let center = { 'x': (start.x + end.x) / 2, 'y': (start.y + end.y) / 2 };
if (to_key(start) == to_key(end)) continue;
start = round_point(cell.site, start, round_fn);
center = round_point(cell.site, center, round_fn);
end = round_point(cell.site, end, round_fn);
ids.push(centerId); ids.push(centerId);
ids.push(vertCount++); ids.push(vertCount++);
a_pos.push(start.x, start.y); a_pos.push(start.x, start.y);
a_own.push(-1); a_own.push(-1);
// ids.push(vertCount++); ids.push(vertCount++);
// a_pos.push(center.x, center.y); a_pos.push(center.x, center.y);
// a_own.push(planetId); a_own.push(-1);
ids.push(centerId);
ids.push(vertCount - 1);
// ids.push(centerId);
// ids.push(vertCount-1);
ids.push(vertCount++); ids.push(vertCount++);
a_pos.push(end.x, end.y); a_pos.push(end.x, end.y);
a_own.push(-1); a_own.push(-1);