Files
bim_engine/docs-old/SDK使用指南.md

19 KiB
Raw Permalink Blame History

iFlow Engine 使用文档

iFlow Engine 是一个用于 3D BIM 模型展示的 JavaScript SDK支持原生 HTML、Vue 2/3 和 React 框架。

目录


安装

NPM 安装(推荐)

npm install iflow-engine

Yarn 安装

yarn add iflow-engine

PNPM 安装

pnpm add iflow-engine

CDN / 本地文件引入

如果不使用包管理器,可以直接下载 JS 文件引入:

<script src="./lib/iflow-engine.umd.js"></script>

原生 HTML 使用

方式一:使用 NPM + 构建工具

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>BIM Engine Demo</title>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        html, body { width: 100%; height: 100%; overflow: hidden; }
        #app { width: 100%; height: 100%; }
    </style>
</head>
<body>
    <div id="app"></div>

    <script type="module">
        import { BimEngine } from 'iflow-engine';

        // 1. 创建引擎实例
        const engine = new BimEngine('app', {
            locale: 'zh-CN',
            theme: 'light'
        });

        // 2. 初始化 3D 引擎
        const success = engine.engine.initialize({
            version: 'v2',
            showStats: false,
            showViewCube: true
        });

        if (success) {
            // 3. 加载模型
            engine.engine.loadModel('./model/your-model', {
                position: [0, 0, 0],
                rotation: [0, 0, 0],
                scale: [1, 1, 1]
            });
        }
    </script>
</body>
</html>

方式二:使用 UMD无构建工具

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>BIM Engine Demo</title>
    <!-- 引入 UMD 版本 -->
    <script src="https://unpkg.com/iflow-engine/dist/iflow-engine.umd.js"></script>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        html, body { width: 100%; height: 100%; overflow: hidden; }
        #app { width: 100%; height: 100%; }
    </style>
</head>
<body>
    <div id="app"></div>

    <script>
        // 1. 创建引擎实例
        const engine = new LyzBimEngineSDK.BimEngine('app', {
            locale: 'zh-CN',
            theme: 'light'
        });

        // 2. 初始化 3D 引擎
        const success = engine.engine.initialize({
            version: 'v2',
            showStats: false,
            showViewCube: true
        });

        if (success) {
            // 3. 加载模型
            engine.engine.loadModel('./model/your-model', {
                position: [0, 0, 0],
                rotation: [0, 0, 0],
                scale: [1, 1, 1]
            });
        }
    </script>
</body>
</html>

完整功能示例

let engine = null;

// 初始化
function init() {
    engine = new LyzBimEngineSDK.BimEngine('app', {
        locale: 'zh-CN',
        theme: 'light'
    });

    engine.engine.initialize({
        version: 'v2',
        showStats: false,
        showViewCube: true
    });

    engine.engine.loadModel('./model/building');
}

// 回到主视角
function goHome() {
    engine.engine.CameraGoHome();
}

// 激活测量功能
// mode: 'distance' | 'minDistance' | 'angle' | 'elevation' | 'volume' | 'laserDistance' | 'slope' | 'spaceVolume'
function activateMeasure(mode) {
    engine.engine.activateMeasure(mode);
}

// 停用测量
function deactivateMeasure() {
    engine.engine.deactivateMeasure();
}

// 切换主题
function setTheme(theme) {
    engine.setTheme(theme); // 'light' | 'dark'
}

// 切换语言
function setLocale(locale) {
    engine.setLocale(locale); // 'zh-CN' | 'en-US'
}

// 销毁
function destroy() {
    engine.destroy();
}

window.onload = init;

Vue 3 使用

1. 安装

npm install iflow-engine

2. 组件封装

<!-- components/BimViewer.vue -->
<template>
    <div ref="containerRef" class="bim-viewer"></div>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue';
import { BimEngine } from 'iflow-engine';

// Props
const props = defineProps({
    modelUrl: { type: String, default: '' },
    modelOptions: { type: Object, default: () => ({}) },
    engineOptions: { type: Object, default: () => ({}) },
    locale: { type: String, default: 'zh-CN' },
    theme: { type: String, default: 'light' }
});

// Emits
const emit = defineEmits(['ready', 'error']);

// Refs
const containerRef = ref(null);
let engine = null;

// 初始化引擎
const initEngine = () => {
    if (!containerRef.value) return;

    try {
        engine = new BimEngine(containerRef.value, {
            locale: props.locale,
            theme: props.theme
        });

        const success = engine.engine?.initialize({
            version: 'v2',
            showStats: false,
            showViewCube: true,
            ...props.engineOptions
        });

        if (success) {
            emit('ready', engine);
            if (props.modelUrl) {
                engine.engine?.loadModel(props.modelUrl, props.modelOptions);
            }
        } else {
            throw new Error('3D 引擎初始化失败');
        }
    } catch (error) {
        emit('error', error);
    }
};

// 暴露方法
defineExpose({
    getEngine: () => engine,
    loadModel: (url, options) => engine?.engine?.loadModel(url, options),
    goHome: () => engine?.engine?.CameraGoHome(),
    activateMeasure: (mode) => engine?.engine?.activateMeasure(mode),
    deactivateMeasure: () => engine?.engine?.deactivateMeasure(),
    setTheme: (theme) => engine?.setTheme(theme),
    setLocale: (locale) => engine?.setLocale(locale)
});

onMounted(() => initEngine());
onBeforeUnmount(() => {
    engine?.destroy();
    engine = null;
});
</script>

<style scoped>
.bim-viewer {
    width: 100%;
    height: 100%;
}
</style>

3. 使用组件

<!-- App.vue -->
<template>
    <div class="app">
        <BimViewer
            ref="viewerRef"
            model-url="./model/building"
            :model-options="{ position: [0, 0, 0] }"
            locale="zh-CN"
            theme="light"
            @ready="onEngineReady"
            @error="onEngineError"
        />

        <div class="toolbar">
            <button @click="goHome">主视角</button>
            <button @click="measure('distance')">距离测量</button>
            <button @click="stopMeasure">停止测量</button>
        </div>
    </div>
</template>

<script setup>
import { ref } from 'vue';
import BimViewer from './components/BimViewer.vue';

const viewerRef = ref(null);

const onEngineReady = (engine) => {
    console.log('引擎已就绪', engine);
};

const onEngineError = (error) => {
    console.error('引擎错误', error);
};

const goHome = () => viewerRef.value?.goHome();
const measure = (mode) => viewerRef.value?.activateMeasure(mode);
const stopMeasure = () => viewerRef.value?.deactivateMeasure();
</script>

<style>
.app {
    width: 100vw;
    height: 100vh;
    position: relative;
}
.toolbar {
    position: absolute;
    top: 20px;
    left: 20px;
    z-index: 100;
}
</style>

Vue 2 使用

1. 安装

npm install iflow-engine

2. 组件封装

<!-- components/BimViewer.vue -->
<template>
    <div ref="container" class="bim-viewer"></div>
</template>

<script>
import { BimEngine } from 'iflow-engine';

export default {
    name: 'BimViewer',

    props: {
        modelUrl: { type: String, default: '' },
        modelOptions: { type: Object, default: () => ({}) },
        engineOptions: { type: Object, default: () => ({}) },
        locale: { type: String, default: 'zh-CN' },
        theme: { type: String, default: 'light' }
    },

    data() {
        return {
            engine: null
        };
    },

    mounted() {
        this.initEngine();
    },

    beforeDestroy() {
        this.destroyEngine();
    },

    methods: {
        initEngine() {
            try {
                this.engine = new BimEngine(this.$refs.container, {
                    locale: this.locale,
                    theme: this.theme
                });

                const success = this.engine.engine.initialize({
                    version: 'v2',
                    showStats: false,
                    showViewCube: true,
                    ...this.engineOptions
                });

                if (success) {
                    this.$emit('ready', this.engine);
                    if (this.modelUrl) {
                        this.engine.engine.loadModel(this.modelUrl, this.modelOptions);
                    }
                } else {
                    throw new Error('3D 引擎初始化失败');
                }
            } catch (error) {
                this.$emit('error', error);
            }
        },

        destroyEngine() {
            if (this.engine) {
                this.engine.destroy();
                this.engine = null;
            }
        },

        // 公开方法
        getEngine() { return this.engine; },
        loadModel(url, options) { this.engine?.engine?.loadModel(url, options); },
        goHome() { this.engine?.engine?.CameraGoHome(); },
        activateMeasure(mode) { this.engine?.engine?.activateMeasure(mode); },
        deactivateMeasure() { this.engine?.engine?.deactivateMeasure(); },
        setTheme(theme) { this.engine?.setTheme(theme); },
        setLocale(locale) { this.engine?.setLocale(locale); }
    }
};
</script>

<style scoped>
.bim-viewer {
    width: 100%;
    height: 100%;
}
</style>

3. 使用组件

<!-- App.vue -->
<template>
    <div class="app">
        <BimViewer
            ref="viewer"
            model-url="./model/building"
            :model-options="{ position: [0, 0, 0] }"
            locale="zh-CN"
            theme="light"
            @ready="onEngineReady"
            @error="onEngineError"
        />

        <div class="toolbar">
            <button @click="goHome">主视角</button>
            <button @click="measure('distance')">距离测量</button>
            <button @click="stopMeasure">停止测量</button>
        </div>
    </div>
</template>

<script>
import BimViewer from './components/BimViewer.vue';

export default {
    name: 'App',
    components: { BimViewer },

    methods: {
        onEngineReady(engine) { console.log('引擎已就绪', engine); },
        onEngineError(error) { console.error('引擎错误', error); },
        goHome() { this.$refs.viewer.goHome(); },
        measure(mode) { this.$refs.viewer.activateMeasure(mode); },
        stopMeasure() { this.$refs.viewer.deactivateMeasure(); }
    }
};
</script>

<style>
.app { width: 100vw; height: 100vh; position: relative; }
.toolbar { position: absolute; top: 20px; left: 20px; z-index: 100; }
</style>

React 使用

1. 安装

npm install iflow-engine

2. Hook 封装

// hooks/useBimEngine.js
import { useEffect, useRef, useState, useCallback } from 'react';
import { BimEngine } from 'iflow-engine';

export function useBimEngine(options = {}) {
    const containerRef = useRef(null);
    const engineRef = useRef(null);
    const [isReady, setIsReady] = useState(false);
    const [error, setError] = useState(null);

    useEffect(() => {
        if (!containerRef.current) return;

        try {
            const engine = new BimEngine(containerRef.current, {
                locale: options.locale || 'zh-CN',
                theme: options.theme || 'light'
            });

            const success = engine.engine?.initialize({
                version: 'v2',
                showStats: false,
                showViewCube: true,
                ...options.engineOptions
            });

            if (success) {
                engineRef.current = engine;
                setIsReady(true);
                options.onReady?.(engine);
            } else {
                throw new Error('3D 引擎初始化失败');
            }
        } catch (err) {
            setError(err);
            options.onError?.(err);
        }

        return () => {
            engineRef.current?.destroy();
            engineRef.current = null;
            setIsReady(false);
        };
    }, []);

    const loadModel = useCallback((url, modelOptions) => {
        engineRef.current?.engine?.loadModel(url, modelOptions);
    }, []);

    const goHome = useCallback(() => {
        engineRef.current?.engine?.CameraGoHome();
    }, []);

    const activateMeasure = useCallback((mode) => {
        engineRef.current?.engine?.activateMeasure(mode);
    }, []);

    const deactivateMeasure = useCallback(() => {
        engineRef.current?.engine?.deactivateMeasure();
    }, []);

    const setTheme = useCallback((theme) => {
        engineRef.current?.setTheme(theme);
    }, []);

    const setLocale = useCallback((locale) => {
        engineRef.current?.setLocale(locale);
    }, []);

    return {
        containerRef,
        engine: engineRef.current,
        isReady,
        error,
        loadModel,
        goHome,
        activateMeasure,
        deactivateMeasure,
        setTheme,
        setLocale
    };
}

3. 组件封装

// components/BimViewer.jsx
import React, { useEffect, useImperativeHandle, forwardRef } from 'react';
import { useBimEngine } from '../hooks/useBimEngine';

export const BimViewer = forwardRef((props, ref) => {
    const {
        modelUrl,
        modelOptions,
        locale = 'zh-CN',
        theme = 'light',
        className,
        style,
        onReady,
        onError
    } = props;

    const {
        containerRef,
        engine,
        isReady,
        loadModel,
        goHome,
        activateMeasure,
        deactivateMeasure,
        setTheme,
        setLocale
    } = useBimEngine({ locale, theme, onReady, onError });

    useImperativeHandle(ref, () => ({
        getEngine: () => engine,
        loadModel,
        goHome,
        activateMeasure,
        deactivateMeasure,
        setTheme,
        setLocale
    }));

    useEffect(() => {
        if (isReady && modelUrl) {
            loadModel(modelUrl, modelOptions);
        }
    }, [isReady, modelUrl, modelOptions, loadModel]);

    return (
        <div
            ref={containerRef}
            className={className}
            style={{ width: '100%', height: '100%', ...style }}
        />
    );
});

BimViewer.displayName = 'BimViewer';

4. 使用组件

// App.jsx
import React, { useRef } from 'react';
import { BimViewer } from './components/BimViewer';

function App() {
    const viewerRef = useRef(null);

    const handleReady = (engine) => console.log('引擎已就绪', engine);
    const handleError = (error) => console.error('引擎错误', error);

    return (
        <div style={{ width: '100vw', height: '100vh', position: 'relative' }}>
            <BimViewer
                ref={viewerRef}
                modelUrl="./model/building"
                modelOptions={{ position: [0, 0, 0] }}
                locale="zh-CN"
                theme="light"
                onReady={handleReady}
                onError={handleError}
            />

            <div style={{ position: 'absolute', top: 20, left: 20, zIndex: 100 }}>
                <button onClick={() => viewerRef.current?.goHome()}>主视角</button>
                <button onClick={() => viewerRef.current?.activateMeasure('distance')}>距离测量</button>
                <button onClick={() => viewerRef.current?.deactivateMeasure()}>停止测量</button>
            </div>
        </div>
    );
}

export default App;

API 参考

BimEngine

主引擎类。

构造函数

import { BimEngine } from 'iflow-engine';

new BimEngine(container, options)
参数 类型 说明
container HTMLElement | string 容器元素或容器 ID
options.locale string 语言:'zh-CN' | 'en-US',默认 'zh-CN'
options.theme string 主题:'light' | 'dark',默认 'light'

属性

属性 类型 说明
engine EngineManager 3D 引擎管理器
toolbar ToolbarManager 工具栏管理器
dialog DialogManager 弹窗管理器
measure MeasureDialogManager 测量面板管理器

方法

方法 参数 说明
setLocale(locale) 'zh-CN' | 'en-US' 设置语言
getLocale() - 获取当前语言
setTheme(theme) 'light' | 'dark' 设置主题
destroy() - 销毁引擎

EngineManager

3D 引擎管理器,通过 engine.engine 访问。

方法

方法 参数 返回值 说明
initialize(options) EngineOptions boolean 初始化 3D 引擎
isInitialized() - boolean 检查是否已初始化
loadModel(url, options) string, ModelLoadOptions void 加载模型
CameraGoHome() - void 回到主视角
activateMeasure(mode) MeasureMode void 激活测量功能
deactivateMeasure() - void 停用测量功能
getCurrentMeasureType() - MeasureMode | null 获取当前测量类型
getEngine() - any 获取原始引擎实例
destroy() - void 销毁引擎

类型定义

EngineOptions

interface EngineOptions {
    version?: 'v1' | 'v2';       // WebGL 版本,默认 'v2'
    showStats?: boolean;          // 是否显示性能统计,默认 false
    showViewCube?: boolean;       // 是否显示视图立方体,默认 true
}

ModelLoadOptions

interface ModelLoadOptions {
    position?: [number, number, number];  // 位置,默认 [0, 0, 0]
    rotation?: [number, number, number];  // 旋转(弧度),默认 [0, 0, 0]
    scale?: [number, number, number];     // 缩放,默认 [1, 1, 1]
    id?: string;                          // 模型 ID可选
}

MeasureMode

type MeasureMode =
    | 'distance'        // 距离测量
    | 'minDistance'     // 最小距离测量
    | 'angle'           // 角度测量
    | 'elevation'       // 标高测量
    | 'volume'          // 体积测量
    | 'laserDistance'   // 激光测距
    | 'slope'           // 坡度测量
    | 'spaceVolume';    // 空间体积测量

注意事项

  1. 容器尺寸:确保容器元素有明确的宽度和高度

  2. 销毁清理:页面关闭或组件卸载前务必调用 destroy()

  3. 浏览器兼容:需要支持 WebGL 的现代浏览器


常见问题

Q: 模型加载失败?

检查:

  • 模型路径是否正确
  • 网络请求是否正常F12 查看 Network
  • 模型格式是否支持

Q: 如何监听引擎事件?

engine.on('modelLoaded', (data) => {
    console.log('模型已加载', data);
});

技术支持