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