mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-17 17:51:24 +01:00
refactor: grid generation
This commit is contained in:
parent
d18636eb8f
commit
e59b536e83
15 changed files with 157 additions and 105 deletions
|
|
@ -5,5 +5,6 @@ export const MAX_HEIGHT = 100;
|
|||
export enum DISTANCE_FIELD {
|
||||
LAND_COAST = 1,
|
||||
UNMARKED = 0,
|
||||
WATER_COAST = -1
|
||||
WATER_COAST = -1,
|
||||
DEEPER_WATER = -2
|
||||
}
|
||||
|
|
|
|||
|
|
@ -221,9 +221,9 @@ export function open(options) {
|
|||
Lakes.openNearSeaLakes(grid);
|
||||
}
|
||||
OceanLayers(grid);
|
||||
calculateTemperatures();
|
||||
generatePrecipitation();
|
||||
reGraph();
|
||||
calculateTemperatures(grid);
|
||||
generatePrecipitation(grid);
|
||||
reGraph(grid);
|
||||
drawCoastline();
|
||||
|
||||
Rivers.generate(erosionAllowed);
|
||||
|
|
@ -340,9 +340,9 @@ export function open(options) {
|
|||
|
||||
if (erosionAllowed) addLakesInDeepDepressions();
|
||||
OceanLayers(grid);
|
||||
calculateTemperatures();
|
||||
generatePrecipitation();
|
||||
reGraph();
|
||||
calculateTemperatures(grid);
|
||||
generatePrecipitation(grid);
|
||||
reGraph(grid);
|
||||
drawCoastline();
|
||||
|
||||
if (erosionAllowed) Rivers.generate(true);
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ export function open() {
|
|||
}
|
||||
|
||||
function changeHeightExponent() {
|
||||
calculateTemperatures();
|
||||
calculateTemperatures(grid);
|
||||
if (layerIsOn("toggleTemp")) drawTemp();
|
||||
}
|
||||
|
||||
|
|
@ -134,7 +134,7 @@ export function open() {
|
|||
// height exponent
|
||||
heightExponentInput.value = heightExponentOutput.value = 1.8;
|
||||
localStorage.removeItem("heightExponent");
|
||||
calculateTemperatures();
|
||||
calculateTemperatures(grid);
|
||||
|
||||
// scale bar
|
||||
barSizeOutput.value = barSizeInput.value = 2;
|
||||
|
|
|
|||
|
|
@ -399,7 +399,7 @@ async function parseLoadedData(data) {
|
|||
})();
|
||||
|
||||
void (function parsePackData() {
|
||||
reGraph();
|
||||
reGraph(grid);
|
||||
reMarkFeatures();
|
||||
pack.features = JSON.parse(data[12]);
|
||||
pack.cultures = JSON.parse(data[13]);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import {aleaPRNG} from "scripts/aleaPRNG";
|
|||
const {UNMARKED, LAND_COAST, WATER_COAST} = DISTANCE_FIELD;
|
||||
|
||||
// define features (grid.features: ocean, lakes, islands) and calculate distance field (cells.t)
|
||||
export function markupGridFeatures(grid: IGraph & {cells: {h: UintArray}}) {
|
||||
export function markupGridFeatures(grid: IGridWithHeights) {
|
||||
TIME && console.time("markupGridFeatures");
|
||||
Math.random = aleaPRNG(seed); // get the same result on heightmap edit in Erase mode
|
||||
|
||||
|
|
@ -173,8 +173,10 @@ export function reMarkFeatures() {
|
|||
return "gulf";
|
||||
}
|
||||
|
||||
function defineIslandGroup(cell, number) {
|
||||
if (cell && features[cells.f[cell - 1]].type === "lake") return "lake_island";
|
||||
function defineIslandGroup(cellId: number, number: number) {
|
||||
const prevCellFeature = features[cells.f[cellId - 1]];
|
||||
|
||||
if (cellId && prevCellFeature && prevCellFeature.type === "lake") return "lake_island";
|
||||
if (number > grid.cells.i.length / 10) return "continent";
|
||||
if (number > grid.cells.i.length / 1000) return "island";
|
||||
return "isle";
|
||||
|
|
|
|||
|
|
@ -5,11 +5,12 @@ import {minmax} from "utils/numberUtils";
|
|||
import {rand} from "utils/probabilityUtils";
|
||||
|
||||
// simplest precipitation model
|
||||
export function generatePrecipitation() {
|
||||
export function generatePrecipitation(grid) {
|
||||
TIME && console.time("generatePrecipitation");
|
||||
prec.selectAll("*").remove();
|
||||
|
||||
const {cells, cellsX, cellsY} = grid;
|
||||
cells.prec = new Uint8Array(cells.i.length); // precipitation array
|
||||
const precipitation = new Uint8Array(cells.i.length); // precipitation array
|
||||
|
||||
const cellsNumberModifier = (pointsInput.dataset.cells / 10000) ** 0.25;
|
||||
const precInputModifier = precInput.value / 100;
|
||||
|
|
@ -94,20 +95,20 @@ export function generatePrecipitation() {
|
|||
if (cells.h[current] < 20) {
|
||||
// water cell
|
||||
if (cells.h[current + next] >= 20) {
|
||||
cells.prec[current + next] += Math.max(humidity / rand(10, 20), 1); // coastal precipitation
|
||||
precipitation[current + next] += Math.max(humidity / rand(10, 20), 1); // coastal precipitation
|
||||
} else {
|
||||
humidity = Math.min(humidity + 5 * modifier, maxPrec); // wind gets more humidity passing water cell
|
||||
cells.prec[current] += 5 * modifier; // water cells precipitation (need to correctly pour water through lakes)
|
||||
precipitation[current] += 5 * modifier; // water cells precipitation (need to correctly pour water through lakes)
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// land cell
|
||||
const isPassable = cells.h[current + next] <= MAX_PASSABLE_ELEVATION;
|
||||
const precipitation = isPassable ? getPrecipitation(humidity, current, next) : humidity;
|
||||
cells.prec[current] += precipitation;
|
||||
const evaporation = precipitation > 1.5 ? 1 : 0; // some humidity evaporates back to the atmosphere
|
||||
humidity = isPassable ? minmax(humidity - precipitation + evaporation, 0, maxPrec) : 0;
|
||||
const cellPrec = isPassable ? getPrecipitation(humidity, current, next) : humidity;
|
||||
precipitation[current] += cellPrec;
|
||||
const evaporation = cellPrec > 1.5 ? 1 : 0; // some humidity evaporates back to the atmosphere
|
||||
humidity = isPassable ? minmax(humidity - cellPrec + evaporation, 0, maxPrec) : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -162,4 +163,5 @@ export function generatePrecipitation() {
|
|||
})();
|
||||
|
||||
TIME && console.timeEnd("generatePrecipitation");
|
||||
return precipitation;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -125,10 +125,8 @@ window.Submap = (function () {
|
|||
OceanLayers(grid);
|
||||
|
||||
calculateMapCoordinates();
|
||||
// calculateTemperatures();
|
||||
// generatePrecipitation();
|
||||
stage("Cell cleanup.");
|
||||
reGraph();
|
||||
reGraph(grid);
|
||||
|
||||
// remove misclassified cells
|
||||
stage("Define coastline.");
|
||||
|
|
|
|||
|
|
@ -1,35 +0,0 @@
|
|||
import * as d3 from "d3";
|
||||
|
||||
import {TIME} from "config/logging";
|
||||
import {minmax, rn} from "utils/numberUtils";
|
||||
|
||||
// temperature model
|
||||
export function calculateTemperatures() {
|
||||
TIME && console.time("calculateTemperatures");
|
||||
const cells = grid.cells;
|
||||
cells.temp = new Int8Array(cells.i.length); // temperature array
|
||||
|
||||
const tEq = +temperatureEquatorInput.value;
|
||||
const tPole = +temperaturePoleInput.value;
|
||||
const tDelta = tEq - tPole;
|
||||
const int = d3.easePolyInOut.exponent(0.5); // interpolation function
|
||||
|
||||
d3.range(0, cells.i.length, grid.cellsX).forEach(function (r) {
|
||||
const y = grid.points[r][1];
|
||||
const lat = Math.abs(mapCoordinates.latN - (y / graphHeight) * mapCoordinates.latT); // [0; 90]
|
||||
const initTemp = tEq - int(lat / 90) * tDelta;
|
||||
for (let i = r; i < r + grid.cellsX; i++) {
|
||||
cells.temp[i] = minmax(initTemp - convertToFriendly(cells.h[i]), -128, 127);
|
||||
}
|
||||
});
|
||||
|
||||
// temperature decreases by 6.5 degree C per 1km
|
||||
function convertToFriendly(h) {
|
||||
if (h < 20) return 0;
|
||||
const exponent = +heightExponentInput.value;
|
||||
const height = Math.pow(h - 18, exponent);
|
||||
return rn((height / 1000) * 6.5);
|
||||
}
|
||||
|
||||
TIME && console.timeEnd("calculateTemperatures");
|
||||
}
|
||||
47
src/modules/temperature.ts
Normal file
47
src/modules/temperature.ts
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import * as d3 from "d3";
|
||||
|
||||
import {TIME} from "config/logging";
|
||||
import {minmax} from "utils/numberUtils";
|
||||
import {getInputNumber} from "utils/nodeUtils";
|
||||
import {MIN_LAND_HEIGHT} from "config/generation";
|
||||
|
||||
const interpolate = d3.easePolyInOut.exponent(0.5); // interpolation function
|
||||
|
||||
export function calculateTemperatures(grid: IGridWithHeights) {
|
||||
TIME && console.time("calculateTemperatures");
|
||||
|
||||
const {cells, cellsX, points} = grid;
|
||||
const heights = cells.h;
|
||||
|
||||
const temperatures = new Int8Array(heights.length); // temperature array
|
||||
|
||||
// temperature decreases by 6.5 Celsius per kilometer
|
||||
const heightExponent = getInputNumber("heightExponentInput");
|
||||
function decreaseTempFromElevation(height: number) {
|
||||
if (height < MIN_LAND_HEIGHT) return 0;
|
||||
|
||||
const realHeight = Math.pow(height - 18, heightExponent);
|
||||
return (realHeight / 1000) * 6.5;
|
||||
}
|
||||
|
||||
const tEq = getInputNumber("temperatureEquatorInput");
|
||||
const tPole = getInputNumber("temperaturePoleInput");
|
||||
const tDelta = tEq - tPole;
|
||||
|
||||
const {latN, latT} = window.mapCoordinates;
|
||||
|
||||
d3.range(0, heights.length, cellsX).forEach(rowStart => {
|
||||
const y = points[rowStart][1];
|
||||
const lat = Math.abs(latN - (y / graphHeight) * latT); // [0; 90]
|
||||
|
||||
const initTemp = tEq - interpolate(lat / 90) * tDelta;
|
||||
for (let i = rowStart; i < rowStart + cellsX; i++) {
|
||||
const elevationDecrease = decreaseTempFromElevation(heights[i]);
|
||||
temperatures[i] = minmax(initTemp - elevationDecrease, -128, 127);
|
||||
}
|
||||
});
|
||||
|
||||
TIME && console.timeEnd("calculateTemperatures");
|
||||
|
||||
return temperatures;
|
||||
}
|
||||
|
|
@ -60,8 +60,8 @@ export function editWorld() {
|
|||
|
||||
updateGlobeTemperature();
|
||||
updateGlobePosition();
|
||||
calculateTemperatures();
|
||||
generatePrecipitation();
|
||||
calculateTemperatures(grid);
|
||||
generatePrecipitation(grid);
|
||||
const heights = new Uint8Array(pack.cells.h);
|
||||
Rivers.generate();
|
||||
Lakes.defineGroup();
|
||||
|
|
|
|||
|
|
@ -3,16 +3,24 @@ import * as d3 from "d3";
|
|||
import {ERROR, INFO, WARN} from "config/logging";
|
||||
import {closeDialogs} from "dialogs/utils";
|
||||
import {initLayers, renderLayer, restoreLayers} from "layers";
|
||||
// @ts-expect-error js module
|
||||
import {drawCoastline} from "modules/coastline";
|
||||
import {calculateMapCoordinates, defineMapSize} from "modules/coordinates";
|
||||
import {markupGridFeatures, markupGridOcean} from "modules/markup";
|
||||
import {markupGridFeatures} from "modules/markup";
|
||||
// @ts-expect-error js module
|
||||
import {drawScaleBar, Rulers} from "modules/measurers";
|
||||
// @ts-expect-error js module
|
||||
import {generatePrecipitation} from "modules/precipitation";
|
||||
import {calculateTemperatures} from "modules/temperature";
|
||||
// @ts-expect-error js module
|
||||
import {unfog} from "modules/ui/editors";
|
||||
// @ts-expect-error js module
|
||||
import {applyMapSize, randomizeOptions} from "modules/ui/options";
|
||||
// @ts-expect-error js module
|
||||
import {applyStyleOnLoad} from "modules/ui/stylePresets";
|
||||
// @ts-expect-error js module
|
||||
import {addZones} from "modules/zones";
|
||||
// @ts-expect-error js module
|
||||
import {aleaPRNG} from "scripts/aleaPRNG";
|
||||
import {hideLoading, showLoading} from "scripts/loading";
|
||||
import {clearMainTip, tip} from "scripts/tooltips";
|
||||
|
|
@ -45,9 +53,9 @@ export async function generate(options?: IGenerationOptions) {
|
|||
applyMapSize();
|
||||
randomizeOptions();
|
||||
|
||||
const updatedGrid = await updateGrid(precreatedGraph);
|
||||
const updatedGrid = await updateGrid(grid, precreatedGraph);
|
||||
|
||||
reGraph();
|
||||
reGraph(updatedGrid);
|
||||
drawCoastline();
|
||||
|
||||
Rivers.generate();
|
||||
|
|
@ -75,6 +83,8 @@ export async function generate(options?: IGenerationOptions) {
|
|||
Markers.generate();
|
||||
addZones();
|
||||
|
||||
OceanLayers(updatedGrid);
|
||||
|
||||
drawScaleBar(scale);
|
||||
Names.getMapName();
|
||||
|
||||
|
|
@ -110,35 +120,33 @@ export async function generate(options?: IGenerationOptions) {
|
|||
}
|
||||
}
|
||||
|
||||
async function updateGrid(precreatedGraph?: IGrid) {
|
||||
const globalGrid = grid;
|
||||
|
||||
const updatedGrid: IGraph & Partial<IGrid> = shouldRegenerateGridPoints(globalGrid)
|
||||
async function updateGrid(globalGrid: IGrid, precreatedGraph?: IGrid): Promise<IGrid> {
|
||||
const baseGrid: IGridBase = shouldRegenerateGridPoints(globalGrid)
|
||||
? (precreatedGraph && undressGrid(precreatedGraph)) || generateGrid()
|
||||
: undressGrid(globalGrid);
|
||||
|
||||
const heights = await HeightmapGenerator.generate(updatedGrid);
|
||||
updatedGrid.cells.h = heights;
|
||||
const heights: Uint8Array = await HeightmapGenerator.generate(baseGrid);
|
||||
if (!heights) throw new Error("Heightmap generation failed");
|
||||
const heightsGrid = {...baseGrid, cells: {...baseGrid.cells, h: heights}};
|
||||
|
||||
const {featureIds, distanceField, features} = markupGridFeatures(updatedGrid);
|
||||
updatedGrid.cells.f = featureIds;
|
||||
updatedGrid.cells.t = distanceField;
|
||||
updatedGrid.features = features;
|
||||
const {featureIds, distanceField, features} = markupGridFeatures(heightsGrid);
|
||||
const markedGrid = {...heightsGrid, features, cells: {...heightsGrid.cells, f: featureIds, t: distanceField}};
|
||||
|
||||
const touchesEdges = features.some(feature => feature && feature.land && feature.border);
|
||||
defineMapSize(touchesEdges);
|
||||
|
||||
Lakes.addLakesInDeepDepressions(updatedGrid);
|
||||
Lakes.openNearSeaLakes(updatedGrid);
|
||||
|
||||
OceanLayers(updatedGrid);
|
||||
|
||||
window.mapCoordinates = calculateMapCoordinates();
|
||||
calculateTemperatures();
|
||||
generatePrecipitation();
|
||||
|
||||
Lakes.addLakesInDeepDepressions(markedGrid);
|
||||
Lakes.openNearSeaLakes(markedGrid);
|
||||
|
||||
const temperature = calculateTemperatures(markedGrid);
|
||||
const temperatureGrid = {...markedGrid, cells: {...markedGrid.cells, temp: temperature}};
|
||||
|
||||
const prec = generatePrecipitation(temperatureGrid);
|
||||
return {...temperatureGrid, cells: {...temperatureGrid.cells, prec}};
|
||||
}
|
||||
|
||||
function undressGrid(extendedGrid: IGrid) {
|
||||
function undressGrid(extendedGrid: IGrid): IGridBase {
|
||||
const {spacing, cellsDesired, boundary, points, cellsX, cellsY, cells, vertices} = extendedGrid;
|
||||
const {i, b, c, v} = cells;
|
||||
return {spacing, cellsDesired, boundary, points, cellsX, cellsY, cells: {i, b, c, v}, vertices};
|
||||
|
|
@ -154,12 +162,17 @@ export async function generateMapOnLoad() {
|
|||
// clear the map
|
||||
export function undraw() {
|
||||
viewbox.selectAll("path, circle, polygon, line, text, use, #zones > g, #armies > g, #ruler > g").remove();
|
||||
|
||||
byId("deftemp")
|
||||
.querySelectorAll("path, clipPath, svg")
|
||||
?.querySelectorAll("path, clipPath, svg")
|
||||
.forEach(el => el.remove());
|
||||
byId("coas").innerHTML = ""; // remove auto-generated emblems
|
||||
|
||||
// remove auto-generated emblems
|
||||
if (byId("coas")) byId("coas")!.innerHTML = "";
|
||||
|
||||
notes = [];
|
||||
rulers = new Rulers();
|
||||
|
||||
unfog();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,9 +5,12 @@ import {UINT16_MAX} from "constants";
|
|||
import {createTypedArray} from "utils/arrayUtils";
|
||||
import {calculateVoronoi, getPackPolygon} from "utils/graphUtils";
|
||||
import {rn} from "utils/numberUtils";
|
||||
import {DISTANCE_FIELD, MIN_LAND_HEIGHT} from "config/generation";
|
||||
|
||||
const {LAND_COAST, WATER_COAST, DEEPER_WATER} = DISTANCE_FIELD;
|
||||
|
||||
// recalculate Voronoi Graph to pack cells
|
||||
export function reGraph() {
|
||||
export function reGraph(grid: IGrid) {
|
||||
TIME && console.time("reGraph");
|
||||
const {cells: gridCells, points, features} = grid;
|
||||
const newCells: {p: TPoints; g: number[]; h: number[]} = {p: [], g: [], h: []}; // store new data
|
||||
|
|
@ -16,14 +19,18 @@ export function reGraph() {
|
|||
for (const i of gridCells.i) {
|
||||
const height = gridCells.h[i];
|
||||
const type = gridCells.t[i];
|
||||
if (height < 20 && type !== -1 && type !== -2) continue; // exclude all deep ocean points
|
||||
if (type === -2 && (i % 4 === 0 || features[gridCells.f[i]].type === "lake")) continue; // exclude non-coastal lake points
|
||||
if (height < MIN_LAND_HEIGHT && type !== WATER_COAST && type !== DEEPER_WATER) continue; // exclude all deep ocean points
|
||||
|
||||
const feature = features[gridCells.f[i]];
|
||||
const isLake = feature && feature.type === "lake";
|
||||
|
||||
if (type === DEEPER_WATER && (i % 4 === 0 || isLake)) continue; // exclude non-coastal lake points
|
||||
const [x, y] = points[i];
|
||||
|
||||
addNewPoint(i, x, y, height);
|
||||
|
||||
// add additional points for cells along coast
|
||||
if (type === 1 || type === -1) {
|
||||
if (type === LAND_COAST || type === WATER_COAST) {
|
||||
if (gridCells.b[i]) continue; // not for near-border cells
|
||||
gridCells.c[i].forEach(e => {
|
||||
if (i > e) return;
|
||||
|
|
@ -55,7 +62,7 @@ export function reGraph() {
|
|||
pack.cells.p = newCells.p;
|
||||
pack.cells.g = createTypedArray({maxValue: grid.points.length, from: newCells.g});
|
||||
pack.cells.q = d3.quadtree(newCells.p.map(([x, y], i) => [x, y, i]));
|
||||
pack.cells.h = createTypedArray({maxValue: 100, from: newCells.h});
|
||||
pack.cells.h = new Uint8Array(newCells.h);
|
||||
pack.cells.area = createTypedArray({maxValue: UINT16_MAX, from: pack.cells.i}).map(getCellArea);
|
||||
|
||||
TIME && console.timeEnd("reGraph");
|
||||
|
|
|
|||
20
src/types/grid.d.ts
vendored
20
src/types/grid.d.ts
vendored
|
|
@ -5,16 +5,26 @@ interface IGrid extends IGraph {
|
|||
spacing: number;
|
||||
boundary: TPoints;
|
||||
points: TPoints;
|
||||
cells: IGridCells;
|
||||
cells: IGraphCells & IGridCells;
|
||||
features: TGridFeatures;
|
||||
}
|
||||
|
||||
interface IGridCells extends IGraphCells {
|
||||
h: UintArray; // heights, [0, 100], see MIN_LAND_HEIGHT constant
|
||||
interface IGridCells {
|
||||
h: Uint8Array; // heights, [0, 100], see MIN_LAND_HEIGHT constant
|
||||
t: Int8Array; // see DISTANCE_FIELD enum
|
||||
f: Uint16Array; // feature id, see IGridFeature
|
||||
temp: UintArray; // temparature in Celsius
|
||||
prec: UintArray; // precipitation in inner units
|
||||
temp: Int8Array; // temparature in Celsius
|
||||
prec: Uint8Array; // precipitation in inner units
|
||||
}
|
||||
|
||||
interface IGridBase extends IGrid {
|
||||
cells: IGraphCells & Partial<IGridCells>;
|
||||
features?: TGridFeatures;
|
||||
}
|
||||
|
||||
interface IGridWithHeights extends IGrid {
|
||||
cells: IGraphCells & Partial<IGridCells> & {h: Uint8Array};
|
||||
features?: TGridFeatures;
|
||||
}
|
||||
|
||||
type TGridFeatures = [0, ...IGridFeature[]];
|
||||
|
|
|
|||
25
src/types/overrides.d.ts
vendored
25
src/types/overrides.d.ts
vendored
|
|
@ -6,16 +6,23 @@ interface Navigator {
|
|||
|
||||
interface Window {
|
||||
mapCoordinates: IMapCoordinates;
|
||||
$: typeof $;
|
||||
$: typeof $; // jQuery
|
||||
|
||||
// untyped IIFE modules
|
||||
Biomes: typeof Biomes;
|
||||
Names: typeof Names;
|
||||
ThreeD: typeof ThreeD;
|
||||
ReliefIcons: typeof ReliefIcons;
|
||||
Zoom: typeof Zoom;
|
||||
Lakes: typeof Lakes;
|
||||
HeightmapGenerator: typeof HeightmapGenerator;
|
||||
OceanLayers: typeof OceanLayers;
|
||||
Biomes: any;
|
||||
Names: any;
|
||||
ThreeD: any;
|
||||
ReliefIcons: any;
|
||||
Zoom: any;
|
||||
Lakes: any;
|
||||
HeightmapGenerator: any;
|
||||
OceanLayers: any;
|
||||
Rivers: any;
|
||||
Cultures: any;
|
||||
BurgsAndStates: any;
|
||||
Religions: any;
|
||||
Military: any;
|
||||
Markers: any;
|
||||
}
|
||||
|
||||
interface Node {
|
||||
|
|
|
|||
2
src/types/pack.d.ts
vendored
2
src/types/pack.d.ts
vendored
|
|
@ -11,7 +11,7 @@ interface IPack extends IGraph {
|
|||
|
||||
interface IPackCells extends IGraphCells {
|
||||
p: TPoints; // cell center points
|
||||
h: UintArray; // heights, [0, 100], see MIN_LAND_HEIGHT constant
|
||||
h: Uint8Array; // heights, [0, 100], see MIN_LAND_HEIGHT constant
|
||||
t: Int8Array; // see DISTANCE_FIELD enum
|
||||
f: Uint16Array; // feature id, see TPackFeature
|
||||
g: UintArray;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue