Skip to content

几何计算示例

本示例展示如何使用 expo-gaode-map 提供的几何计算功能,包括距离计算、面积计算和点位关系判断。

基础用法

typescript
import React, { useState } from 'react';
import { View, Text, Button, ScrollView, StyleSheet } from 'react-native';
import {ExpoGaodeMapModule} from 'expo-gaode-map';

export default function GeometryUtilsExample() {
  const [results, setResults] = useState<string[]>([]);

  const runCalculations = async () => {
    const newResults: string[] = [];

    try {
      // 1. 计算两点之间的距离
      const distance = await ExpoGaodeMapModule.distanceBetweenCoordinates(
        { latitude: 39.90923, longitude: 116.397428 }, // 天安门
        { latitude: 39.916527, longitude: 116.397545 }  // 故宫
      );
      newResults.push(`天安门到故宫的距离: ${distance.toFixed(2)} 米`);

      // 2. 计算多边形面积
      const polygon = [
        { latitude: 39.923, longitude: 116.391 },
        { latitude: 39.923, longitude: 116.424 },
        { latitude: 39.886, longitude: 116.424 },
        { latitude: 39.886, longitude: 116.391 },
      ];
      const polygonArea = await ExpoGaodeMapModule.calculatePolygonArea(polygon);
      newResults.push(`多边形面积: ${(polygonArea / 1000000).toFixed(2)} 平方公里`);

      // 3. 计算矩形面积
      const rectArea = await ExpoGaodeMapModule.calculateRectangleArea(
        { latitude: 39.886, longitude: 116.391 },
        { latitude: 39.923, longitude: 116.424 }
      );
      newResults.push(`矩形面积: ${(rectArea / 1000000).toFixed(2)} 平方公里`);

      // 4. 判断点是否在多边形内
      const testPoint = { latitude: 39.9, longitude: 116.4 };
      const isInPolygon = await ExpoGaodeMapModule.isPointInPolygon(testPoint, polygon);
      newResults.push(`点 (39.9, 116.4) 是否在多边形内: ${isInPolygon ? '是' : '否'}`);

      // 5. 判断点是否在圆内
      const center = { latitude: 39.90923, longitude: 116.397428 };
      const isInCircle = await ExpoGaodeMapModule.isPointInCircle(
        testPoint,
        center,
        10000 // 10公里
      );
      newResults.push(`点是否在10公里圆内: ${isInCircle ? '是' : '否'}`);

      setResults(newResults);
    } catch (error) {
      console.error('计算失败:', error);
      newResults.push(`错误: ${error.message}`);
      setResults(newResults);
    }
  };

  return (
    <View style={styles.container}>
      <Button title="运行几何计算" onPress={runCalculations} />
      
      <ScrollView style={styles.resultsContainer}>
        {results.map((result, index) => (
          <Text key={index} style={styles.resultText}>
            • {result}
          </Text>
        ))}
      </ScrollView>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
  },
  resultsContainer: {
    marginTop: 20,
  },
  resultText: {
    fontSize: 14,
    marginVertical: 5,
    lineHeight: 20,
  },
});

实际应用场景

1. 附近商家距离显示

typescript
async function calculateNearbyShops(userLocation: LatLng, shops: Shop[]) {
  const shopsWithDistance = await Promise.all(
    shops.map(async (shop) => {
      const distance = await ExpoGaodeMapModule.distanceBetweenCoordinates(
        userLocation,
        shop.location
      );
      return {
        ...shop,
        distance,
        distanceText: distance < 1000 
          ? `${Math.round(distance)}米` 
          : `${(distance / 1000).toFixed(1)}公里`
      };
    })
  );

  // 按距离排序
  return shopsWithDistance.sort((a, b) => a.distance - b.distance);
}

2. 地理围栏(进入/离开区域检测)

typescript
function useGeofencing(location: LatLng, area: LatLng[]) {
  const [isInside, setIsInside] = useState(false);

  useEffect(() => {
    const checkLocation = async () => {
      const inside = await ExpoGaodeMapModule.isPointInPolygon(
        location,
        area
      );
      
      if (inside !== isInside) {
        setIsInside(inside);
        // 触发进入或离开事件
        if (inside) {
          console.log('用户进入了区域');
        } else {
          console.log('用户离开了区域');
        }
      }
    };

    checkLocation();
  }, [location]);

  return isInside;
}

3. 土地面积测量工具

typescript
function LandAreaCalculator() {
  const [points, setPoints] = useState<LatLng[]>([]);
  const [area, setArea] = useState<number>(0);

  const addPoint = (point: LatLng) => {
    setPoints([...points, point]);
  };

  const calculateArea = async () => {
    if (points.length < 3) {
      alert('至少需要3个点才能计算面积');
      return;
    }

    const calculatedArea = await ExpoGaodeMapModule.calculatePolygonArea(points);
    setArea(calculatedArea);
  };

  const clearPoints = () => {
    setPoints([]);
    setArea(0);
  };

  return (
    <View>
      <Text>已标记 {points.length} 个点</Text>
      {area > 0 && (
        <Text>
          面积: {(area / 1000000).toFixed(2)} 平方公里
          ({(area / 10000).toFixed(2)} 公顷)
        </Text>
      )}
      <Button title="计算面积" onPress={calculateArea} />
      <Button title="清除" onPress={clearPoints} />
    </View>
  );
}

4. 配送范围判断

typescript
async function isInDeliveryRange(
  userLocation: LatLng,
  shopLocation: LatLng,
  maxDistance: number
): Promise<boolean> {
  const isInRange = await ExpoGaodeMapModule.isPointInCircle(
    userLocation,
    shopLocation,
    maxDistance
  );
  
  if (!isInRange) {
    const distance = await ExpoGaodeMapModule.distanceBetweenCoordinates(
      userLocation,
      shopLocation
    );
    console.log(`超出配送范围 ${(distance / 1000).toFixed(1)}km,最大配送距离 ${(maxDistance / 1000).toFixed(1)}km`);
  }
  
  return isInRange;
}

性能优化建议

  1. 批量计算: 对于多个点的距离计算,考虑使用 Promise.all 并行处理
  2. 结果缓存: 对于固定区域的判断结果可以缓存,避免重复计算
  3. 精度控制: 根据实际需求选择合适的精度,避免过度计算
typescript
// 批量距离计算示例
async function batchCalculateDistances(
  origin: LatLng,
  destinations: LatLng[]
) {
  return Promise.all(
    destinations.map(dest => 
      ExpoGaodeMapModule.distanceBetweenCoordinates(origin, dest)
    )
  );
}

// 结果缓存示例
const areaCache = new Map<string, boolean>();

async function isInAreaCached(
  point: LatLng,
  polygon: LatLng[]
): Promise<boolean> {
  const key = `${point.latitude},${point.longitude}`;
  
  if (areaCache.has(key)) {
    return areaCache.get(key)!;
  }
  
  const result = await ExpoGaodeMapModule.isPointInPolygon(point, polygon);
  areaCache.set(key, result);
  return result;
}

相关文档

Released under the MIT License.