npm package: @kimap/indoor-positioning-sdk
Description: 基于Three.js的室内定位地图SDK - Indoor Positioning Map SDK based on Three.js
Author: Kimap Team
Latest version: 1.0.0

# Kimap Indoor Positioning SDK

> 🗺️ 专业的室内定位地图SDK - 模块化、功能完整、易于扩展

基于Three.js的企业级室内定位地图SDK，提供完整的室内定位、导航、分析功能。

---

## 🎉 最新更新

### 🎨 图形生成器（ShapeGenerator）⭐ v1.0.0

**程序化图形生成，无需用户交互！**

```typescript
// 一行代码生成圆形
kimap.createCircle('id', { x: 10, y: 0, z: 10 }, 5, { color: 0xff0000 });

// 批量生成100个图形
for (let i = 0; i < 100; i++) {
  kimap.createRectangle(`area-${i}`, { x: i*2, y: 0, z: 0 }, 1, 1);
}
```

📖 **详细文档**: [SHAPE_GENERATOR_GUIDE.md](../SHAPE_GENERATOR_GUIDE.md)

---

## ✨ 核心特性

### 🎯 基础功能
- ✅ **3D地图渲染** - 加载并渲染OBJ格式的室内地图模型
- ✅ **坐标系管理** - 自定义零点坐标和坐标范围
- ✅ **实时定位** - 显示和更新当前位置，支持脉冲动画效果
- ✅ **位置标记** - 添加、移除和管理多个位置标记点
- ✅ **点击交互** - 点击地图显示弹窗信息
- ✅ **相机控制** - 支持旋转、缩放、平移等交互操作

### 🎨 高级功能
- ✅ **交互式绘制** - 用户在地图上逐点绘制（测距、圆形、矩形、多边形）
- ✅ **图形生成器** - 通过API直接生成图形，无需用户交互
- ✅ **轨迹追踪** - 历史轨迹显示和实时路径跟踪
- ✅ **区域选择** - 框选/圆选/多边形选择，返回区域内元素
- ✅ **路径规划** - A*、Dijkstra算法自动路径规划
- ✅ **POI管理** - 兴趣点管理和搜索
- ✅ **面积计算** - 多边形、圆形面积周长计算
- ✅ **坐标转换** - 世界坐标、地图坐标、屏幕坐标互转
- ✅ **自定义元素** - 支持图片精灵和HTML元素叠加

## 📦 模块化架构

```
sdk/
├── index.ts                    # 主入口（KimapSDK）
├── core/                       # 核心模块
│   └── MapCore.ts             # 地图初始化核心
├── modules/                    # 功能模块
│   ├── DrawingModule.ts       # ✏️ 交互式绘制（用户点击绘制）
│   ├── ShapeGenerator.ts      # 🎨 图形生成器（程序化生成）
│   ├── TrackingModule.ts      # 🚶 轨迹追踪
│   └── SelectionModule.ts     # 🎯 区域选择
├── utils/                      # 工具类
│   ├── CoordinateUtils.ts     # 📐 坐标转换
│   ├── GeometryCalculator.ts  # 📊 几何计算
│   ├── PathPlanner.ts         # 🗺️ 路径规划
│   └── VectorHelper.ts        # 🔄 向量转换工具
└── types/                      # 类型定义
    ├── enums.ts               # 枚举
    └── interfaces.ts          # 接口
```

## 安装

```bash
npm install three
```

## 快速开始

> ⭐ **新功能**: 图形生成器（ShapeGenerator）已上线！
> 
> 除了让用户手动绘制，现在可以通过API直接生成图形：
> ```typescript
> // 直接生成圆形，无需用户点击
> kimap.createCircle('fence-1', { x: 10, y: 0, z: 10 }, 5, { color: 0xff0000 });
> ```
> 详见: [第9节 - 图形生成器](#9-图形生成器程序化绘制)

### 1. 基础用法

```typescript
import KimapSDK from './sdk/KimapSDK';
import * as THREE from 'three';

// 创建SDK实例
const kimap = new KimapSDK({
  container: document.getElementById('map-container')!,
  objUrl: '/path/to/your/model.obj',
  origin: { x: 0, y: 0, z: 0 },      // 零点坐标
  maxX: 50,                           // X轴最大坐标（米）
  maxY: 10,                           // Y轴最大坐标（高度，米）
  onPositionClick: (position, object) => {
    console.log('点击位置:', position);
    console.log('点击对象:', object);
  }
});
```

### 2. 添加位置标记

```typescript
// 添加静态标记点
kimap.addLocationMarker({
  id: 'entrance',
  position: new THREE.Vector3(5, 0, 5),
  label: '入口',
  color: 0x4CAF50
});

kimap.addLocationMarker({
  id: 'exit',
  position: new THREE.Vector3(45, 0, 45),
  label: '出口',
  color: 0xF44336
});
```

### 3. 更新实时位置

```typescript
// 模拟实时位置更新
let currentX = 0;
let currentZ = 0;

setInterval(() => {
  currentX += 0.1;
  currentZ += 0.05;
  
  const position = new THREE.Vector3(currentX, 0, currentZ);
  kimap.updateCurrentPosition(position);
}, 100);
```

### 4. 显示弹窗

```typescript
// 基础用法：显示弹窗
kimap.showPopup({
  title: '当前位置',
  content: '您在一楼大厅',
  position: new THREE.Vector3(25, 0, 25)
});

// 人员移动时弹窗自动跟随（默认启用）
kimap.showPopup({
  title: '张三',
  content: '工号: 001',
  position: new THREE.Vector3(25, 0, 25)
}, true); // true表示跟随目标（默认值）

// 人员移动时更新弹窗位置
setInterval(() => {
  const newPosition = getUserPosition(); // 获取人员新位置
  kimap.updatePopupTarget(newPosition); // 更新弹窗跟随目标
}, 1000);

// 禁用跟随功能（固定位置弹窗）
kimap.showPopup({
  title: '提示',
  content: '请保持安静',
  position: new THREE.Vector3(25, 0, 25)
}, false); // false表示不跟随

// 手动关闭弹窗
setTimeout(() => {
  kimap.hidePopup();
}, 3000);
```

### 5. 坐标转换

```typescript
// 地图坐标转世界坐标
const worldPos = kimap.mapToWorld(10, 0, 15);
console.log('世界坐标:', worldPos);

// 世界坐标转地图坐标
const mapPos = kimap.worldToMap(new THREE.Vector3(10, 0, 15));
console.log('地图坐标:', mapPos);
```

### 6. 绘制功能

```typescript
import { DrawMode } from './sdk/types/enums';

// 开始测距
kimap.startDraw(DrawMode.MEASURE, {
  onDrawClick: (pos) => console.log('点击:', pos),
  onDrawComplete: (points) => {
    const distance = points[0].distanceTo(points[1]);
    console.log(`距离: ${distance.toFixed(2)}米`);
  }
});

// 绘制圆形
kimap.startDraw(DrawMode.CIRCLE);

// 绘制多边形（双击完成）
kimap.startDraw(DrawMode.POLYGON, {
  onDrawComplete: (points) => {
    console.log('多边形顶点:', points);
  }
});

// 清除所有绘制
kimap.clearDrawings();
```

### 7. 区域选择（返回内部元素）

```typescript
// 框选矩形区域
const selection = kimap.selectByPolygon([
  new THREE.Vector3(10, 0, 10),
  new THREE.Vector3(30, 0, 10),
  new THREE.Vector3(30, 0, 30),
  new THREE.Vector3(10, 0, 30)
]);

console.log('选中元素:', selection.elements);
console.log('选中标记:', selection.markers);
console.log('选中POI:', selection.pois);

// 计算选择区域面积
const area = kimap.calculateSelectionArea(selection.area);
console.log(`面积: ${area.toFixed(2)} 平方米`);

// 高亮显示选中的元素
kimap.highlightSelection(selection, 0xffff00);

// 圆形选择
const circleSelection = kimap.selectByCircle(
  new THREE.Vector3(20, 0, 20),  // 圆心
  15                              // 半径
);
```

### 8. 路径规划

```typescript
import { PathAlgorithm } from './sdk/types/enums';

// A*算法路径规划
const pathResult = kimap.planPath({
  start: new THREE.Vector3(0, 0, 0),
  end: new THREE.Vector3(50, 0, 50),
  algorithm: PathAlgorithm.ASTAR,
  obstacles: [
    // 障碍物（如墙体）
    [
      new THREE.Vector3(20, 0, 10),
      new THREE.Vector3(30, 0, 10),
      new THREE.Vector3(30, 0, 30),
      new THREE.Vector3(20, 0, 30)
    ]
  ]
});

console.log('路径长度:', pathResult.distance, '米');
console.log('预计时长:', pathResult.duration, '秒');

// 显示路径
kimap.addTrack({
  id: 'nav-path',
  points: pathResult.path.map(pos => ({
    position: pos,
    timestamp: Date.now()
  })),
  color: 0x00ff00,
  showMarkers: true
});
```

### 9. 图形生成器（程序化绘制）

```typescript
// ⭐ 直接生成圆形（无需用户交互）
kimap.createCircle('fence-1', 
  { x: 10, y: 0, z: 10 },  // 圆心
  5,                        // 半径（米）
  { color: 0xff0000, opacity: 0.5 }
);

// 创建矩形区域
kimap.createRectangle('office-1',
  { x: 0, y: 0, z: 0 },    // 左下角
  10,                       // 宽度（米）
  8,                        // 深度（米）
  { color: 0x00ff00, opacity: 0.3 }
);

// 创建多边形
const points = [
  { x: 0, y: 0, z: 0 },
  { x: 10, y: 0, z: 0 },
  { x: 10, y: 0, z: 10 },
  { x: 0, y: 0, z: 10 }
];
kimap.createPolygon('area-1', points, { color: 0x0000ff });

// 创建线条
kimap.createLine('path-1', points, { 
  color: 0xff0000, 
  linewidth: 2,
  dashed: true 
});

// 创建3D盒子
kimap.createBox('box-1',
  { x: 15, y: 1, z: 15 },  // 中心位置
  2, 2, 2,                  // 宽、高、深
  { color: 0xffff00 }
);

// 管理图形
kimap.updateShape('fence-1', { color: 0x00ffff, opacity: 0.8 });
kimap.setShapeVisible('fence-1', false);  // 隐藏
kimap.removeShape('fence-1');             // 移除
kimap.clearAllShapes();                   // 清除所有

// 📘 详见: SHAPE_GENERATOR_GUIDE.md
```

### 10. POI管理

```typescript
// 添加POI
kimap.addPOI({
  id: 'cafe-1',
  name: '星巴克',
  category: '餐饮',
  position: { x: 15, y: 0, z: 20 },
  tags: ['咖啡', '休闲'],
  data: { phone: '123-4567', hours: '8:00-22:00' }
});

// 搜索POI
const results = kimap.searchPOI('咖啡');
console.log('搜索结果:', results);

// 导航到POI
if (results.length > 0) {
  const path = kimap.planPath({
    start: currentPosition,
    end: results[0].position,
    algorithm: PathAlgorithm.ASTAR
  });
}
```

### 11. 清理资源

```typescript
// 销毁SDK实例
kimap.destroy();
```

## 📚 详细文档

### 核心文档
- **[SDK_MODULAR_GUIDE.md](../SDK_MODULAR_GUIDE.md)** - 模块化架构详细指南
- **[SDK_DEMO_README.md](../SDK_DEMO_README.md)** - 演示页面使用说明

### 绘制系统
- **[SDK_DRAWING_FEATURES.md](../SDK_DRAWING_FEATURES.md)** - 交互式绘制功能（DrawingModule）
- **[SHAPE_GENERATOR_GUIDE.md](../SHAPE_GENERATOR_GUIDE.md)** - 图形生成器（ShapeGenerator）⭐

### 坐标与转换
- **[COORDINATE_TRANSFORM_GUIDE.md](../COORDINATE_TRANSFORM_GUIDE.md)** - 坐标转换使用指南
- **[COORDINATE_API_UPDATE.md](../COORDINATE_API_UPDATE.md)** - 坐标API更新说明
- **[API_MIGRATION_GUIDE.md](../API_MIGRATION_GUIDE.md)** - API迁移指南

### 其他功能
- **[INDOOR_POSITIONING_GUIDE.md](../INDOOR_POSITIONING_GUIDE.md)** - 室内定位功能
- **[KIMAP_FILE_FORMAT.md](../KIMAP_FILE_FORMAT.md)** - Kimap文件格式
- **[RENDERING_CONSISTENCY.md](../RENDERING_CONSISTENCY.md)** - 渲染一致性保证

## API 文档

### 配置选项 (KimapConfig)

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `container` | `HTMLElement` | ✅ | 地图容器DOM元素 |
| `objUrl` | `string` | ✅ | OBJ模型文件URL |
| `origin` | `{x, y, z}` | ✅ | 坐标系零点坐标 |
| `maxX` | `number` | ✅ | X轴最大坐标（米） |
| `maxY` | `number` | ✅ | Y轴最大坐标/高度（米） |
| `onPositionClick` | `function` | ❌ | 点击位置回调函数 |

### 主要方法

#### addLocationMarker(marker: LocationMarker)

添加位置标记点。

**参数:**
- `marker.id` (string) - 标记唯一ID
- `marker.position` (Vector3) - 标记位置
- `marker.label` (string, 可选) - 标记文字标签
- `marker.color` (number, 可选) - 标记颜色（十六进制）

**示例:**
```typescript
kimap.addLocationMarker({
  id: 'poi-001',
  position: { x: 25, y: 0, z: 25 },
  label: 'POI点',
  color: 0xFF5722
});
```

#### removeLocationMarker(id: string)

移除指定ID的位置标记。

**示例:**
```typescript
kimap.removeLocationMarker('poi-001');
```

#### updateCurrentPosition(position: Vector3)

更新当前实时位置（带脉冲动画效果）。

**示例:**
```typescript
kimap.updateCurrentPosition(new THREE.Vector3(15, 0, 25));
```

#### showPopup(info: PopupInfo, follow?: boolean)

显示信息弹窗。

**参数:**
- `info.title` (string) - 弹窗标题
- `info.content` (string) - 弹窗内容
- `info.position` (Vector3) - 弹窗显示位置
- `follow` (boolean, 可选) - 是否跟随目标位置，默认为 `true`

**示例:**
```typescript
// 跟随模式（默认）
kimap.showPopup({
  title: '张三',
  content: '工号: 001<br>部门: 研发部',
  position: new THREE.Vector3(30, 0, 40)
}, true);

// 固定位置模式
kimap.showPopup({
  title: '会议室A',
  content: '3层东侧，可容纳20人',
  position: new THREE.Vector3(30, 0, 40)
}, false);
```

#### updatePopupTarget(position: Vector3D)

更新弹窗跟随的目标位置。用于人员移动时实时更新弹窗位置。

**参数:**
- `position` (Vector3D) - 新的目标位置

**示例:**
```typescript
// 显示人员弹窗
kimap.showPopup({
  title: '张三',
  content: '工号: 001',
  position: personPosition
});

// 人员移动时更新弹窗位置
setInterval(() => {
  const newPos = getPersonPosition();
  kimap.updatePopupTarget(newPos);
}, 100);
```

#### hidePopup()

隐藏当前弹窗并停止跟随。

#### mapToWorld(x, y, z)

将地图坐标转换为世界坐标。

**返回:** `THREE.Vector3`

#### worldToMap(position)

将世界坐标转换为地图坐标。

**返回:** `{x: number, y: number, z: number}`

#### getCoordinateSystem()

获取当前坐标系信息。

**返回:** `{origin: Vector3, maxX: number, maxY: number}`

#### destroy()

销毁SDK实例，释放资源。

## 完整示例

```html
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Kimap SDK Demo</title>
  <style>
    #map-container {
      width: 100vw;
      height: 100vh;
      position: relative;
    }
    .control-panel {
      position: absolute;
      top: 20px;
      left: 20px;
      background: white;
      padding: 20px;
      border-radius: 8px;
      box-shadow: 0 4px 12px rgba(0,0,0,0.15);
      z-index: 100;
    }
  </style>
</head>
<body>
  <div id="map-container">
    <div class="control-panel">
      <h3>室内定位演示</h3>
      <button onclick="startTracking()">开始定位</button>
      <button onclick="stopTracking()">停止定位</button>
      <button onclick="addMarker()">添加标记</button>
    </div>
  </div>

  <script type="module">
    import KimapSDK from './sdk/KimapSDK.js';
    import * as THREE from 'three';

    // 初始化SDK
    const kimap = new KimapSDK({
      container: document.getElementById('map-container'),
      objUrl: './models/building.obj',
      origin: { x: 0, y: 0, z: 0 },
      maxX: 100,
      maxY: 15,
      onPositionClick: (position, object) => {
        if (object && object.userData.type === 'locationMarker') {
          kimap.showPopup({
            title: object.userData.label,
            content: `坐标: (${position.x.toFixed(2)}, ${position.z.toFixed(2)})`,
            position: position
          });
        }
      }
    });

    // 添加初始标记
    kimap.addLocationMarker({
      id: 'start',
      position: new THREE.Vector3(10, 0, 10),
      label: '起点',
      color: 0x4CAF50
    });

    kimap.addLocationMarker({
      id: 'end',
      position: new THREE.Vector3(90, 0, 90),
      label: '终点',
      color: 0xF44336
    });

    // 定位追踪
    let trackingInterval = null;
    let currentPos = { x: 10, z: 10 };

    window.startTracking = function() {
      if (trackingInterval) return;
      
      trackingInterval = setInterval(() => {
        // 模拟移动
        currentPos.x += Math.random() * 2 - 1;
        currentPos.z += Math.random() * 2 - 1;
        
        // 限制在范围内
        currentPos.x = Math.max(0, Math.min(100, currentPos.x));
        currentPos.z = Math.max(0, Math.min(100, currentPos.z));
        
        kimap.updateCurrentPosition(
          new THREE.Vector3(currentPos.x, 0, currentPos.z)
        );
      }, 100);
    };

    window.stopTracking = function() {
      if (trackingInterval) {
        clearInterval(trackingInterval);
        trackingInterval = null;
      }
    };

    window.addMarker = function() {
      const id = 'marker-' + Date.now();
      const x = Math.random() * 100;
      const z = Math.random() * 100;
      
      kimap.addLocationMarker({
        id: id,
        position: new THREE.Vector3(x, 0, z),
        label: `标记-${id.substr(-4)}`,
        color: 0x2196F3
      });
    };

    // 清理
    window.addEventListener('beforeunload', () => {
      kimap.destroy();
    });
  </script>
</body>
</html>
```

## 浏览器兼容性

- Chrome 90+
- Firefox 88+
- Safari 14+
- Edge 90+

需要支持WebGL 2.0。

## 许可证

MIT License

## 技术支持

如有问题请联系技术支持或查看源码注释。