init
This commit is contained in:
commit
e811c04eeb
42
convex_hull.c
Normal file
42
convex_hull.c
Normal file
@ -0,0 +1,42 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
// 定义一个点结构体
|
||||
typedef struct {
|
||||
int x, y;
|
||||
} Point;
|
||||
|
||||
// 计算两点的极角
|
||||
int orientation(Point p, Point q, Point r) {
|
||||
int val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
|
||||
if (val == 0) return 0; // 共线
|
||||
return (val > 0) ? 1 : 2; // 顺时针或逆时针
|
||||
}
|
||||
|
||||
// 对点的极角排序
|
||||
int compare(const void *vp1, const void *vp2) {
|
||||
Point *p1 = (Point *)vp1;
|
||||
Point *p2 = (Point *)vp2;
|
||||
return (p1->y < p2->y) || (p1->y == p2->y && p1->x < p2->x);
|
||||
}
|
||||
|
||||
// 凸包主函数
|
||||
void convexHull(Point points[], int n, Point result[], int *result_size) {
|
||||
// 如果点数小于 3,无法构成凸包
|
||||
if (n < 3) {
|
||||
*result_size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// 按 y 坐标排序,如果 y 坐标相同则按 x 坐标排序
|
||||
qsort(points, n, sizeof(Point), compare);
|
||||
|
||||
// 构建凸包
|
||||
int m = 0; // 凸包的点数
|
||||
for (int i = 0; i < n; i++) {
|
||||
while (m >= 2 && orientation(result[m-2], result[m-1], points[i]) != 2)
|
||||
m--;
|
||||
result[m++] = points[i];
|
||||
}
|
||||
|
||||
*result_size = m;
|
||||
}
|
2614
convex_hull.js
Normal file
2614
convex_hull.js
Normal file
File diff suppressed because it is too large
Load Diff
BIN
convex_hull.wasm
Executable file
BIN
convex_hull.wasm
Executable file
Binary file not shown.
196
convex_hull.worker.js
Normal file
196
convex_hull.worker.js
Normal file
@ -0,0 +1,196 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2015 The Emscripten Authors
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
// Pthread Web Worker startup routine:
|
||||
// This is the entry point file that is loaded first by each Web Worker
|
||||
// that executes pthreads on the Emscripten application.
|
||||
|
||||
'use strict';
|
||||
|
||||
var Module = {};
|
||||
|
||||
// Node.js support
|
||||
var ENVIRONMENT_IS_NODE = typeof process == 'object' && typeof process.versions == 'object' && typeof process.versions.node == 'string';
|
||||
if (ENVIRONMENT_IS_NODE) {
|
||||
// Create as web-worker-like an environment as we can.
|
||||
|
||||
// See the parallel code in shell.js, but here we don't need the condition on
|
||||
// multi-environment builds, as we do not have the need to interact with the
|
||||
// modularization logic as shell.js must (see link.py:node_es6_imports and
|
||||
// how that is used in link.py).
|
||||
|
||||
var nodeWorkerThreads = require('worker_threads');
|
||||
|
||||
var parentPort = nodeWorkerThreads.parentPort;
|
||||
|
||||
parentPort.on('message', (data) => onmessage({ data: data }));
|
||||
|
||||
var fs = require('fs');
|
||||
var vm = require('vm');
|
||||
|
||||
Object.assign(global, {
|
||||
self: global,
|
||||
require,
|
||||
Module,
|
||||
location: {
|
||||
// __filename is undefined in ES6 modules, and import.meta.url only in ES6
|
||||
// modules.
|
||||
href: __filename
|
||||
},
|
||||
Worker: nodeWorkerThreads.Worker,
|
||||
importScripts: (f) => vm.runInThisContext(fs.readFileSync(f, 'utf8'), {filename: f}),
|
||||
postMessage: (msg) => parentPort.postMessage(msg),
|
||||
performance: global.performance || { now: Date.now },
|
||||
});
|
||||
}
|
||||
|
||||
// Thread-local guard variable for one-time init of the JS state
|
||||
var initializedJS = false;
|
||||
|
||||
function assert(condition, text) {
|
||||
if (!condition) abort('Assertion failed: ' + text);
|
||||
}
|
||||
|
||||
function threadPrintErr(...args) {
|
||||
var text = args.join(' ');
|
||||
// See https://github.com/emscripten-core/emscripten/issues/14804
|
||||
if (ENVIRONMENT_IS_NODE) {
|
||||
fs.writeSync(2, text + '\n');
|
||||
return;
|
||||
}
|
||||
console.error(text);
|
||||
}
|
||||
function threadAlert(...args) {
|
||||
var text = args.join(' ');
|
||||
postMessage({cmd: 'alert', text, threadId: Module['_pthread_self']()});
|
||||
}
|
||||
// We don't need out() for now, but may need to add it if we want to use it
|
||||
// here. Or, if this code all moves into the main JS, that problem will go
|
||||
// away. (For now, adding it here increases code size for no benefit.)
|
||||
var out = () => { throw 'out() is not defined in worker.js.'; }
|
||||
var err = threadPrintErr;
|
||||
self.alert = threadAlert;
|
||||
var dbg = threadPrintErr;
|
||||
|
||||
Module['instantiateWasm'] = (info, receiveInstance) => {
|
||||
// Instantiate from the module posted from the main thread.
|
||||
// We can just use sync instantiation in the worker.
|
||||
var module = Module['wasmModule'];
|
||||
// We don't need the module anymore; new threads will be spawned from the main thread.
|
||||
Module['wasmModule'] = null;
|
||||
var instance = new WebAssembly.Instance(module, info);
|
||||
// TODO: Due to Closure regression https://github.com/google/closure-compiler/issues/3193,
|
||||
// the above line no longer optimizes out down to the following line.
|
||||
// When the regression is fixed, we can remove this if/else.
|
||||
return receiveInstance(instance);
|
||||
}
|
||||
|
||||
// Turn unhandled rejected promises into errors so that the main thread will be
|
||||
// notified about them.
|
||||
self.onunhandledrejection = (e) => {
|
||||
throw e.reason || e;
|
||||
};
|
||||
|
||||
function handleMessage(e) {
|
||||
try {
|
||||
if (e.data.cmd === 'load') { // Preload command that is called once per worker to parse and load the Emscripten code.
|
||||
|
||||
// Until we initialize the runtime, queue up any further incoming messages.
|
||||
let messageQueue = [];
|
||||
self.onmessage = (e) => messageQueue.push(e);
|
||||
|
||||
// And add a callback for when the runtime is initialized.
|
||||
self.startWorker = (instance) => {
|
||||
// Notify the main thread that this thread has loaded.
|
||||
postMessage({ 'cmd': 'loaded' });
|
||||
// Process any messages that were queued before the thread was ready.
|
||||
for (let msg of messageQueue) {
|
||||
handleMessage(msg);
|
||||
}
|
||||
// Restore the real message handler.
|
||||
self.onmessage = handleMessage;
|
||||
};
|
||||
|
||||
// Module and memory were sent from main thread
|
||||
Module['wasmModule'] = e.data.wasmModule;
|
||||
|
||||
// Use `const` here to ensure that the variable is scoped only to
|
||||
// that iteration, allowing safe reference from a closure.
|
||||
for (const handler of e.data.handlers) {
|
||||
Module[handler] = (...args) => {
|
||||
postMessage({ cmd: 'callHandler', handler, args: args });
|
||||
}
|
||||
}
|
||||
|
||||
Module['wasmMemory'] = e.data.wasmMemory;
|
||||
|
||||
Module['buffer'] = Module['wasmMemory'].buffer;
|
||||
|
||||
Module['workerID'] = e.data.workerID;
|
||||
|
||||
Module['ENVIRONMENT_IS_PTHREAD'] = true;
|
||||
|
||||
if (typeof e.data.urlOrBlob == 'string') {
|
||||
importScripts(e.data.urlOrBlob);
|
||||
} else {
|
||||
var objectUrl = URL.createObjectURL(e.data.urlOrBlob);
|
||||
importScripts(objectUrl);
|
||||
URL.revokeObjectURL(objectUrl);
|
||||
}
|
||||
} else if (e.data.cmd === 'run') {
|
||||
// Pass the thread address to wasm to store it for fast access.
|
||||
Module['__emscripten_thread_init'](e.data.pthread_ptr, /*is_main=*/0, /*is_runtime=*/0, /*can_block=*/1);
|
||||
|
||||
// Await mailbox notifications with `Atomics.waitAsync` so we can start
|
||||
// using the fast `Atomics.notify` notification path.
|
||||
Module['__emscripten_thread_mailbox_await'](e.data.pthread_ptr);
|
||||
|
||||
assert(e.data.pthread_ptr);
|
||||
// Also call inside JS module to set up the stack frame for this pthread in JS module scope
|
||||
Module['establishStackSpace']();
|
||||
Module['PThread'].receiveObjectTransfer(e.data);
|
||||
Module['PThread'].threadInitTLS();
|
||||
|
||||
if (!initializedJS) {
|
||||
initializedJS = true;
|
||||
}
|
||||
|
||||
try {
|
||||
Module['invokeEntryPoint'](e.data.start_routine, e.data.arg);
|
||||
} catch(ex) {
|
||||
if (ex != 'unwind') {
|
||||
// The pthread "crashed". Do not call `_emscripten_thread_exit` (which
|
||||
// would make this thread joinable). Instead, re-throw the exception
|
||||
// and let the top level handler propagate it back to the main thread.
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
} else if (e.data.cmd === 'cancel') { // Main thread is asking for a pthread_cancel() on this thread.
|
||||
if (Module['_pthread_self']()) {
|
||||
Module['__emscripten_thread_exit'](-1);
|
||||
}
|
||||
} else if (e.data.target === 'setimmediate') {
|
||||
// no-op
|
||||
} else if (e.data.cmd === 'checkMailbox') {
|
||||
if (initializedJS) {
|
||||
Module['checkMailbox']();
|
||||
}
|
||||
} else if (e.data.cmd) {
|
||||
// The received message looks like something that should be handled by this message
|
||||
// handler, (since there is a e.data.cmd field present), but is not one of the
|
||||
// recognized commands:
|
||||
err(`worker.js received unknown command ${e.data.cmd}`);
|
||||
err(e.data);
|
||||
}
|
||||
} catch(ex) {
|
||||
err(`worker.js onmessage() captured an uncaught exception: ${ex}`);
|
||||
if (ex?.stack) err(ex.stack);
|
||||
Module['__emscripten_thread_crashed']?.();
|
||||
throw ex;
|
||||
}
|
||||
};
|
||||
|
||||
self.onmessage = handleMessage;
|
54
test.html
Normal file
54
test.html
Normal file
@ -0,0 +1,54 @@
|
||||
<body></body>
|
||||
<script>
|
||||
//计算凸包
|
||||
function convex_hull(points) {
|
||||
var points = [
|
||||
{ x: 0, y: 0 }, { x: 1, y: 1 }, { x: 2, y: 2 },
|
||||
{ x: 0, y: 3 }, { x: 3, y: 0 }, { x: 3, y: 3 },
|
||||
{ x: 2, y: 1 }, { x: 1, y: 2 }
|
||||
];
|
||||
//长度
|
||||
var n = points.length;
|
||||
var pointsPtr = Module._malloc(n * 8); //8字节一个点
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
Module.setValue(pointsPtr + i * 8, points[i].x, 'i32');
|
||||
Module.setValue(pointsPtr + i * 8 + 4, points[i].y, 'i32');
|
||||
}
|
||||
//多少点
|
||||
var resultPtr = Module._malloc(n * 8);
|
||||
var resultSizePtr = Module._malloc(4);
|
||||
Module._convexHull(pointsPtr, n, resultPtr, resultSizePtr);
|
||||
var resultSize = Module.getValue(resultSizePtr, 'i32');
|
||||
var resultPoints = [];
|
||||
//读
|
||||
for (let i = 0; i < resultSize; i++) {
|
||||
var x = Module.getValue(resultPtr + i * 8, 'i32');
|
||||
var y = Module.getValue(resultPtr + i * 8 + 4, 'i32');
|
||||
resultPoints.push({ x: x, y: y });
|
||||
}
|
||||
console.log(resultPoints);
|
||||
|
||||
// 释放
|
||||
Module._free(pointsPtr);
|
||||
Module._free(resultPtr);
|
||||
Module._free(resultSizePtr);
|
||||
}
|
||||
|
||||
|
||||
//loadwasm
|
||||
function loadwasm() {
|
||||
var wasm_url = "./convex_hull.js";
|
||||
var script = document.createElement('script');
|
||||
script.src = wasm_url;
|
||||
script.onload = function () {
|
||||
//loadwasm
|
||||
console.log(Module)
|
||||
Module.onRuntimeInitialized = function () {
|
||||
convex_hull()
|
||||
}
|
||||
}
|
||||
document.body.appendChild(script);
|
||||
}
|
||||
loadwasm()
|
||||
</script>
|
3
生成
Normal file
3
生成
Normal file
@ -0,0 +1,3 @@
|
||||
docker run --rm -v $(pwd):/src emscripten/emsdk emcc convex_hull.c -o convex_hull.js -s IMPORTED_MEMORY=1 -s INITIAL_MEMORY=104857600 -s EXPORTED_FUNCTIONS="['_convexHull','_malloc','_free','setValue','getValue']" -s EXTRA_EXPORTED_RUNTIME_METHODS='["ccall", "cwrap"]'
|
||||
|
||||
docker run --rm -v $(pwd):/src emscripten/emsdk emcc convex_hull.c -o convex_hull.js -s USE_PTHREADS=1 -s IMPORTED_MEMORY=1 -s EXPORTED_FUNCTIONS="['_convexHull','_malloc','_free','setValue','getValue']" -s EXTRA_EXPORTED_RUNTIME_METHODS='["ccall", "cwrap"]'
|
Loading…
Reference in New Issue
Block a user