//@ts-ignore
import Module from '../core/build/main.js';
interface WasmModule {
HEAPU8: Uint8Array;
HEAPU32: Uint32Array;
HEAPF32: Float32Array;
_malloc(size: number): number;
_free(ptr: number): void;
_create_weighted_straight_skeleton(ptr: number, weightsPtr: number): number;
}
/**
* Each skeleton vertex is represented by x, y and time. Time can be used to calculate z coordinate.
*/
export type Vertex = [number, number, number];
/**
* Each polygon is represented by an array of vertex indices.
*/
export type Polygon = number[];
/**
* Straight skeleton calculation result.
*/
export interface Skeleton {
vertices: Vertex[];
polygons: Polygon[];
}
export class SkeletonBuilder {
private static module: WasmModule = null;
/**
* Initializes the WebAssembly module. Must be called before any other method.
*/
public static async init(): Promise<void> {
return Module().then((library: WasmModule) => {
this.module = library;
});
}
/**
* Builds a skeleton from a GeoJSON polygon.
* The polygon must have at least one ring. The first ring is always the outer ring, and the rest are inner rings.
* Outer rings must be counter-clockwise oriented and inner rings must be clockwise oriented.
* All rings must be weakly simple.
* Each ring must have a duplicate of the first vertex at the end.
* @param polygon The GeoJSON polygon.
* @param weights The weights for each vertex.
*/
public static buildFromGeoJSONPolygon(polygon: GeoJSON.Polygon, weights: number[][]): Skeleton {
this.checkModule();
return this.buildFromPolygon(polygon.coordinates, weights);
}
/**
* Builds a skeleton from a polygon represented as an array of rings.
* The polygon must have at least one ring. The first ring is always the outer ring, and the rest are inner rings.
* Outer rings must be counter-clockwise oriented and inner rings must be clockwise oriented.
* All rings must be weakly simple.
* Each ring must have a duplicate of the first vertex at the end.
* @param coordinates The polygon represented as an array of rings.
* @param weights The weights for each vertex.
*/
public static buildFromPolygon(coordinates: number[][][], weights: number[][]): Skeleton {
this.checkModule();
const inputBuffer = this.serializeInput(coordinates);
const inputPtr = this.module._malloc(inputBuffer.byteLength);
this.module.HEAPU8.set(new Uint8Array(inputBuffer), inputPtr);
const weightsBuffer = this.serializeWeights(weights);
console.log("DEBUG WEIGHTSBUFFER", new Float32Array(weightsBuffer))
const weightsPtr = this.module._malloc(weightsBuffer.byteLength);
this.module.HEAPU8.set(new Uint8Array(weightsBuffer), weightsPtr);
const ptr = this.module._create_weighted_straight_skeleton(inputPtr, weightsPtr);
if (ptr === 0) {
return null;
}
let offset = ptr / 4;
const arrayU32 = this.module.HEAPU32;
const arrayF32 = this.module.HEAPF32;
const vertices: Vertex[] = [];
const polygons: number[][] = [];
const vertexCount = arrayU32[offset++];
for (let i = 0; i < vertexCount; i++) {
const x = arrayF32[offset++];
const y = arrayF32[offset++];
const time = arrayF32[offset++];
vertices.push([x, y, time]);
}
let polygonVertexCount = arrayU32[offset++];
while (polygonVertexCount > 0) {
const polygon = [];
for (let i = 0; i < polygonVertexCount; i++) {
polygon.push(arrayU32[offset++]);
}
polygons.push(polygon);
polygonVertexCount = arrayU32[offset++];
}
// this.module._free(ptr);
// this.module._free(inputPtr);
// this.module._free(weightsPtr);
return { vertices, polygons };
}
private static checkModule(): void {
if (this.module === null) {
throw new Error('The WebAssembly module has not been initialized, call SkeletonBuilder.init() first.');
}
}
private static serializeInput(input: number[][][]): ArrayBuffer {
let size: number = 1;
for (const ring of input) {
size += 1 + (ring.length - 1) * 2;
}
const uint32Array = new Uint32Array(size);
const float32Array = new Float32Array(uint32Array.buffer);
let offset = 0;
for (const ring of input) {
uint32Array[offset++] = ring.length - 1;
for (let i = 0; i < ring.length - 1; i++) {
float32Array[offset++] = ring[i][0];
float32Array[offset++] = ring[i][1];
}
}
uint32Array[offset++] = 0;
return float32Array.buffer;
}
private static serializeWeights(weights: number[][]): ArrayBuffer {
let size: number = 0;
for (const ringWeights of weights) {
size += ringWeights.length;
}
const float32Array = new Float32Array(size);
let offset = 0;
for (const ringWeights of weights) {
for (const weight of ringWeights) {
float32Array[offset++] = weight;
}
}
return float32Array.buffer;
}
}
问题似乎是序列压力的函数。不知何故,我弄乱了类型或指针,或者我没有看到的任何东西。
我正在使用权重,我会从WASM中获得“内存访问”错误。如果我不使用转移到CPP的权重,而是在CPP的最后一行中使用一个空{}(generate_weighted_skeleton(data,testWeights);然后代码运行并且不返回问题。我的猜测是我在这里设置了错误的缓冲区:
const weightsBuffer = this.serializeWeights(weights);
console.log("DEBUG WEIGHTSBUFFER", new Float32Array(weightsBuffer))
const weightsPtr = this.module._malloc(weightsBuffer.byteLength);
this.module.HEAPU8.set(new Uint8Array(weightsBuffer), weightsPtr);
但是我无法弄清楚这里的问题。
由于我不知道如何在CPP文件为WASM汇编后如何从CPP文件中记录某些内容,所以我很难弄清楚问题是什么。
如果有人知道我如何继续找到问题,我会很高兴!
答案与WASM无关,而更多的是数据类型。 在打字稿方面,我必须更改制作缓冲区的方式:
Https://github.com/pcace/weighted-straight-skeleton/blob/d84eddc9a250914333ccccf1728ab71c30555552a9be/src/src/src/src/wrapper/wrapper/index.ts#l92-l92-l92-l92-l92-l92-l92-l92-l92-l92-l92-l92l1 l92-l107在CPP一侧,它也需要适应类型:
Https://github.com/pcace/weighted-straight-skeleton/blob/d84eddc9a250914333ccccf1728ab71c30555552a9be/src/src/src/core/core/main.cpp#l183-l192,