唯杰地图 logo唯杰地图
VJMAP
EN

常用函数

vjmap3d/references/advance/functions.md 13.6 KB419 行
原文

webworker

在三维开发中,保持主线程尽可能空闲是很重要的,这样它就可以快速响应用户交互。UI线程应该仅用于UI工作。WebWorkers是一个web API,允许您在单独的线程中运行代码。为了与另一个线程通信,WebWorkers提供postMessage API。您可以使用myWorker.postMessage(someObject) 将JavaScript对象作为消息发送,从而触发worker内部的消息事件。vjmap3d通过对webworker的封装,使webworker调用像调用本地函数一样,使用更方便。

使用方法

方式一: 通过 createWorker 和 workerWrap 创建

  • 1、通过 createWorker 通过本地函数创建worker
  • 2、通过 workerWrap 以本地函数进行包裹
  • 3、调用(并且异步调用)
  • 4、终止 terminate woker
function sum(num) {
    let result = 0
    for (let i = 0; i < num; i++) {
        result = result + i
    }
    return result;
}
let myWorker = vjmap3d.createWorker(sum);
const sumWorker = vjmap3d.workerWrap(myWorker);
let result1 = await sumWorker(100000);
console.log(result1); // 结果将输出 4999950000
let result2 = await sumWorker(5000000);
console.log(result2); // 结果将输出 12499997500000
myWorker.terminate();

方式二、通过 createWorkerWrap 将上面的的 createWorker 和 workerWrap 合成一步

  • 1、通过 createWorkerWrap 通过本地函数创建worker和本地函数进行包裹
  • 2、调用(并且异步调用)
  • 3、终止 terminate woker

上面的代码用createWorkerWrap实现如下

function sum(num) {
    let result = 0
    for (let i = 0; i < num; i++) {
        result = result + i
    }
    return result;
}
var {worker, wrap} = vjmap3d.createWorkerWrap(sum);
let result1 = await wrap(100000);
console.log(result1); // 结果将输出 4999950000
let result2 = await wrap(5000000);
console.log(result2); // 结果将输出 12499997500000
worker.terminate();

提示

用webworker进行wrap的函数或类,不能依赖其他的函数或类,如用了外部依赖的函数或类,需要把依赖的函数或类做为上下文传入。

⚠️ 上下文对象里的函数值会按 function 名( 的固定格式截取源码再拼进 worker,只有普通 function xxx(){} 声明能正确转换;类、箭头函数、对象方法简写(foo(){})、async 函数会被截坏,worker 启动即 SyntaxError。这类依赖请直接传源码字符串(字符串值会原样拼入 worker),如 { helper: "const helper = (a) => a + 1;", Point: Point.toString() }。

class MyClass {
    constructor(init = 0) {
        console.log(init);
        console.log(randInt(100, 200))
        this._counter = init;
    }
    get counter() {
        return this._counter;
    }
    increment(delta = 1) {
        this._counter += delta;
    }
}
let myWorker = vjmap3d.createWorker(MyClass, {
    randInt: vjmap3d.randInt
});
let instance1, instance2;
async function showState() {
    console.log(`instance1.counter = ${await instance1.counter},instance2.counter = ${await instance2.counter}`);
}
const MyWorkerClass = vjmap3d.workerWrap(myWorker);
instance1 = await new MyWorkerClass();
instance2 = await new MyWorkerClass(42);
await showState();
console.time("increment");
for (let i = 0; i < 100000; i++) {
    await instance1.increment();
}
console.timeEnd("increment");
await showState();
myWorker.terminate();
// 输出结果
/**
0
199
42
177
instance1.counter = 0,instance2.counter = 42
increment: 7185.27685546875 ms
instance1.counter = 100000,instance2.counter = 42
 */

模型分解

对物体进行爆炸分解 explodeGroup

 /** 对物体进行爆炸分解 */
function explodeGroup(group: Object3D) {
    /** 爆炸分解  */
    explode: (opts?: {
        /** 动画时长(毫秒),默认 3000 */
        time?: number;
        /** 爆炸分解分解距离,默认 3 */
        distance?: number;
        /** 允许旋转 */
        enableRotation?: boolean;
        /** 动画类型 */
        easing?: Easing;
    }) => Promise<any>;
    /** 还原 */
    reset: (opts?: {
        /** 动画时长(毫秒),默认 3000 */
        time?: number;
        /** 允许旋转:须与 explode 时传的一致,否则 explode 产生的旋转不会被还原 */
        enableRotation?: boolean;
        /** 动画类型 */
        easing?: Easing;
    }) => Promise<any>;
};

用法

let ent = await vjmap3d.ResManager.loadModel(env.assetsPath + "models/heart.glb", {
    anchor: "middle-bottom",
    position: [-1, 0, 1]
});
ent.addTo(app);
let ep = vjmap3d.explodeGroup(ent.node.children[0])
await ep.explode({
    time: 3000
})
await ep.reset()
let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
    container: "map", // 容器id
    stat: { show: true, left: "0" },
    scene: {
        gridHelper: { visible: true }, // 是否显示坐标网格
    },
    camera: {  // 相机设置
        viewHelper: { enable: true, position: "leftBottom" } // 是否显示视角指示器
    }
})
let ent = await vjmap3d.ResManager.loadModel(env.assetsPath + "models/heart.glb", {
    anchor: "middle-bottom",
    position: [-1, 0, 1]
});
ent.addTo(app);
let ep = vjmap3d.explodeGroup(ent.node.children[0])
for(let n = 0; n < 1000; n++) {
    // 动画循环
    await ep.explode({
        time: 3000
    })
    await ep.reset()
}

拉伸Geojson多段线或多边形

拉伸多段线 extrudePolyline

拉伸多边形 extrudePolygon

拉伸GeoJson extrudeGeoJSON

用法

// 查询CAD图中的多段线进行拉伸
let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
    container: "map", // 容器id
    stat: { show: true, left: "0" },
    scene: {
        gridHelper: { visible: true } // 是否显示坐标网格
    },
    camera: {  // 相机设置
        viewHelper: { enable: true, position: "leftBottom" } // 是否显示视角指示器
    },
    control: { leftButtonPan: true } // 设置为左键用于平移 (同时右键将用于旋转) 和地图2d使用习惯一样
})
let res = await app.svc.openMap({
    mapid: env.exampleMapId, // 地图ID,(请确保此ID已存在,可上传新图形新建ID)
    mapopenway: vjmap3d.MapOpenWay.GeomRender, // 以几何数据渲染方式打开
    style: vjmap3d.openMapDarkStyle()
});
if (res.error) {
    showError(res.error);
    return;
}
let provider = new vjmap3d.MapProvider(
    [
        {
            url: app.svc.rasterTileUrl()
        }
    ],
    {
        transparent: true
    }
);
let mapBounds = vjmap3d.GeoBounds.fromString(res.bounds)
let scale = 100;
let mapviewEnt = new vjmap3d.MapViewEntity({
    provider,
    baseScale: scale,
    mapBounds: mapBounds.toArray()
});
mapviewEnt.addTo(app);
//
let cadPrj = new vjmap3d.GeoProjection(mapBounds);
let query = await svc.conditionQueryFeature({
    // https://vjmap.com/app/visual/#/query?mapid=sys_zp&version=v1&mapopenway=GeomRender&theme=dark
    condition: ` name = "1" or name = "2"`, // 查询所有的多段线和直线
    fields: "isclosed,points", 
    limit: 100000 //设置很大,相当于把所有的都查出来。不传的话,默认只能取100条
}, pt => {
    // 查询到的每个点进行坐标处理回调
    return cadPrj.fromMercator(pt);// 转成cad的坐标
})
let polylines = [];
if (query.error) {
    showError(query.error);
    return;
} else {
    if (query.recordCount > 0) {
        for(let i = 0; i < query.result.length; i++) {
            let points = query.result[i].points;
            let lines = points.split(";;");
            for(let n = 0; n < lines.length; n++) {
                let line = lines[n].split(";");
                let pts = []
                for(let pt of line) {
                    if (!pt) continue;
                    let p = vjmap3d.GeoPoint.fromString(pt);
                    let world = vjmap3d.toWorld([p.x, p.y]);
                    pts.push( [world.x, world.z])
                }
                if (pts.length >= 2) {
                    if (query.result[i].isclosed) {
                        // 闭合
                        pts.push(pts[0])
                    }
                    polylines.push(pts);
                }
            }
        }
    }
}
const geometry = new THREE.BufferGeometry();
const material = new THREE.MeshStandardMaterial({
   // wireframe: true
});
const {position, normal, indices,uv, boundingRect} = vjmap3d.extrudePolyline(polylines, {
    depth: 1,
    lineWidth: 0.02,
    bevelSize: 0.01,
    bevelSegments: 0,
    miterLimit: 2,
});
geometry.setAttribute('position', new THREE.Float32BufferAttribute(position, 3));
geometry.setAttribute('normal', new THREE.Float32BufferAttribute(normal, 3));
geometry.setAttribute('uv', new THREE.Float32BufferAttribute(uv, 2));
geometry.setIndex(new THREE.Uint32BufferAttribute(indices, 1));
//
const mesh = new THREE.Mesh(geometry, material);
let waveWallMat = vjmap3d.createFlowGradientMaterial(app, {
    object: mesh,
    lightScale: 0.1,
    circleTime: 1,
    lightColor: 0xffff00,
    color: 0x00ffff,
    topColor: 0x9FFCFD,
    opacity: 1,
    transparent: false,
    //topOpacity: 0.6
});
// @ts-ignore
mesh.material = waveWallMat;
app.scene.add(mesh);
// 查询CAD图中的多段线进行拉伸
let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
    container: "map", // 容器id
    stat: { show: true, left: "0" },
    scene: {
        gridHelper: { visible: true } // 是否显示坐标网格
    },
    camera: {  // 相机设置
        viewHelper: { enable: true, position: "leftBottom" } // 是否显示视角指示器
    },
    control: { leftButtonPan: true } // 设置为左键用于平移 (同时右键将用于旋转) 和地图2d使用习惯一样
})
let res = await app.svc.openMap({
    mapid: env.exampleMapId, // 地图ID,(请确保此ID已存在,可上传新图形新建ID)
    mapopenway: vjmap3d.MapOpenWay.GeomRender, // 以几何数据渲染方式打开
    style: vjmap3d.openMapDarkStyle()
});
if (res.error) {
    showError(res.error);
    return;
}
let provider = new vjmap3d.MapProvider(
    [
        {
            url: app.svc.rasterTileUrl()
        }
    ],
    {
        transparent: true
    }
);
let mapBounds = vjmap3d.GeoBounds.fromString(res.bounds)
let scale = 100;
let mapviewEnt = new vjmap3d.MapViewEntity({
    provider,
    baseScale: scale,
    mapBounds: mapBounds.toArray()
});
mapviewEnt.addTo(app);
//
let cadPrj = new vjmap3d.GeoProjection(mapBounds);
let query = await svc.conditionQueryFeature({
    // https://vjmap.com/app/visual/#/query?mapid=sys_zp&version=v1&mapopenway=GeomRender&theme=dark
    condition: ` name = "1" or name = "2"`, // 查询所有的多段线和直线
    fields: "isclosed,points", 
    limit: 100000 //设置很大,相当于把所有的都查出来。不传的话,默认只能取100条
}, pt => {
    // 查询到的每个点进行坐标处理回调
    return cadPrj.fromMercator(pt);// 转成cad的坐标
})
let polylines = [];
if (query.error) {
    showError(query.error);
    return;
} else {
    if (query.recordCount > 0) {
        for(let i = 0; i < query.result.length; i++) {
            let points = query.result[i].points;
            let lines = points.split(";;");
            for(let n = 0; n < lines.length; n++) {
                let line = lines[n].split(";");
                let pts = []
                for(let pt of line) {
                    if (!pt) continue;
                    let p = vjmap3d.GeoPoint.fromString(pt);
                    let world = vjmap3d.toWorld([p.x, p.y]);
                    pts.push( [world.x, world.z])
                }
                if (pts.length >= 2) {
                    if (query.result[i].isclosed) {
                        // 闭合
                        pts.push(pts[0])
                    }
                    polylines.push(pts);
                }
            }
        }
    }
}
const geometry = new THREE.BufferGeometry();
const material = new THREE.MeshStandardMaterial({
   // wireframe: true
});
const {position, normal, indices,uv, boundingRect} = vjmap3d.extrudePolyline(polylines, {
    depth: 1,
    lineWidth: 0.02,
    bevelSize: 0.01,
    bevelSegments: 0,
    miterLimit: 2,
});
geometry.setAttribute('position', new THREE.Float32BufferAttribute(position, 3));
geometry.setAttribute('normal', new THREE.Float32BufferAttribute(normal, 3));
geometry.setAttribute('uv', new THREE.Float32BufferAttribute(uv, 2));
geometry.setIndex(new THREE.Uint32BufferAttribute(indices, 1));
//
const mesh = new THREE.Mesh(geometry, material);
let waveWallMat = vjmap3d.createFlowGradientMaterial(app, {
    object: mesh,
    lightScale: 0.1,
    circleTime: 1,
    lightColor: 0xffff00,
    color: 0x00ffff,
    topColor: 0x9FFCFD,
    opacity: 1,
    transparent: false,
    //topOpacity: 0.6
});
// @ts-ignore
mesh.material = waveWallMat;
app.scene.add(mesh);