diff --git a/src/layers/renderers/drawCultures.ts b/src/layers/renderers/drawCultures.ts index 4458a0ab..7090f417 100644 --- a/src/layers/renderers/drawCultures.ts +++ b/src/layers/renderers/drawCultures.ts @@ -1,41 +1,22 @@ -import {connectVertices} from "scripts/connectVertices"; +import * as d3 from "d3"; + +import {getPaths} from "./utilts"; export function drawCultures() { /* uses */ const {cells, vertices, cultures} = pack; - cults.selectAll("path").remove(); // cleanup + const getType = (cellId: number) => cells.culture[cellId]; + const paths = getPaths(cells.c, cells.v, vertices, getType); - const used = new Uint8Array(cells.i.length); - const paths = new Array(cultures.length).fill(""); + const getColor = (i: number) => i && (cultures[i] as ICulture).color; - for (const i of cells.i) { - if (!cells.culture[i]) continue; - if (used[i]) continue; - used[i] = 1; - const cultureId = cells.culture[i]; - const onborder = cells.c[i].some(n => cells.culture[n] !== cultureId); - if (!onborder) continue; - - const startingVertex = cells.v[i].find(v => vertices.c[v].some(i => cells.culture[i] !== cultureId)); - if (startingVertex === undefined) - throw new Error(`Draw cultures: starting vertex for culture ${cultureId} is not found`); - - const ofSameType = (cellId: number) => cells.culture[cellId] === cultureId; - const chain = connectVertices({vertices, startingVertex, ofSameType}); - - if (chain.length < 3) continue; - const points = chain.map(v => vertices.p[v]); - - paths[cultureId] += "M" + points.join("L") + "Z"; - } - - const data = paths.map((p, i) => [p, i]).filter(d => d[0].length > 10); - cults + d3.select("#cults") .selectAll("path") - .data(data) + .remove() + .data(Object.entries(paths)) .enter() .append("path") - .attr("d", d => d[0]) - .attr("fill", d => cultures[d[1]].color) - .attr("id", d => "culture" + d[1]); + .attr("d", ([, path]) => path) + .attr("fill", ([i]) => getColor(Number(i))) + .attr("id", ([i]) => "culture" + i); } diff --git a/src/layers/renderers/utilts.ts b/src/layers/renderers/utilts.ts new file mode 100644 index 00000000..cf454606 --- /dev/null +++ b/src/layers/renderers/utilts.ts @@ -0,0 +1,40 @@ +import {connectVertices} from "scripts/connectVertices"; + +export function getPaths( + cellNeighbors: number[][], + cellVertices: number[][], + vertices: IGraphVertices, + getType: (cellId: number) => number +) { + const paths: Dict = {}; + + function addPath(index: number, points: TPoints) { + if (!paths[index]) paths[index] = ""; + paths[index] += "M" + points.join("L") + "Z"; + } + + const checkedCells = new Uint8Array(cellNeighbors.length); + for (let cellId = 0; cellId < cellNeighbors.length; cellId++) { + if (checkedCells[cellId]) continue; + if (!getType(cellId)) continue; + checkedCells[cellId] = 1; + + const type = getType(cellId); + const ofSameType = (cellId: number) => getType(cellId) === type; + + const isOnborder = cellNeighbors[cellId].some(cellId => !ofSameType(cellId)); + if (!isOnborder) continue; + + const startingVertex = cellVertices[cellId].find(v => vertices.c[v].some(cellId => !ofSameType(cellId))); + if (startingVertex === undefined) throw new Error(`getPath: starting vertex for cell ${cellId} is not found`); + + const chain = connectVertices({vertices, startingVertex, ofSameType, checkedCellsMutable: checkedCells}); + + if (chain.length < 3) continue; + const points = chain.map(v => vertices.p[v]); + + addPath(type, points); + } + + return paths; +} diff --git a/src/scripts/connectVertices.ts b/src/scripts/connectVertices.ts index 5fbd1b47..cec69aba 100644 --- a/src/scripts/connectVertices.ts +++ b/src/scripts/connectVertices.ts @@ -94,21 +94,34 @@ const CONNECT_VERTICES_MAX_ITERATIONS = 50000; export function connectVertices({ vertices, startingVertex, - ofSameType + ofSameType, + checkedCellsMutable }: { vertices: IGraphVertices; startingVertex: number; ofSameType: (cellId: number) => boolean; + checkedCellsMutable?: Uint8Array; }) { const chain: number[] = []; // vertices chain to form a path + const addToChecked = (cellIds: number[]) => { + if (checkedCellsMutable) { + cellIds.forEach(cellId => { + checkedCellsMutable[cellId] = 1; + }); + } + }; + let next = startingVertex; for (let i = 0; i === 0 || (next !== startingVertex && i < CONNECT_VERTICES_MAX_ITERATIONS); i++) { const previous = chain.at(-1); const current = next; chain.push(current); - const [c1, c2, c3] = vertices.c[current].map(ofSameType); + const neibCells = vertices.c[current]; + addToChecked(neibCells); + + const [c1, c2, c3] = neibCells.map(ofSameType); const [v1, v2, v3] = vertices.v[current]; if (v1 !== previous && c1 !== c2) next = v1; diff --git a/src/types/common.d.ts b/src/types/common.d.ts index a8ccea8b..4d479105 100644 --- a/src/types/common.d.ts +++ b/src/types/common.d.ts @@ -6,6 +6,9 @@ interface Dict { [key: string]: T; } +// element of Object.entries +type ObjectEntry = [string, T]; + type UintArray = Uint8Array | Uint16Array | Uint32Array; type IntArray = Int8Array | Int16Array | Int32Array;