Flutter地理坐标转换插件dart_crs的使用

发布于 1周前 作者 ionicwang 来自 Flutter

Flutter地理坐标转换插件dart_crs的使用

该插件扩展了 proj4dart,通过嵌入由国际地球测量学委员会地学分委会维护的 EPSG 地理参数数据集。EPSG 数据集版本为 v11.001。

功能

  • 获取 EPSG 坐标参考系统定义的 WKT(Well-Known Text)。
  • 在两个 EPSG 坐标参考系统之间转换坐标。
  • 使用任何 EPSG 定义的代码创建一个命名的 proj4dart 投影。

开始使用

要使用此插件,在 pubspec.yaml 文件中添加 dart_crs 作为依赖项。例如:

dependencies:
  dart_crs: '^1.0.2'

使用示例

创建坐标参考系统

CoordinateReferenceSystem crsLatLong = await CRSFactory.createCRS('EPSG:4326');

转换坐标

CoordinateTransform transform = 
    await CRSFactory.createCoordinateTransformFromCodes('EPSG:4326', 'EPSG:3183');
Point geoPoint = Point(-45.2395, 60.1425);
Point? gr96Point = transform!.transform(geoPoint);
Point? inversePoint = transform!.inverse(gr96Point!);

提取 WKT 定义

String wkt1 = await WKTReader().fetchWkt('EPSG:4326');

完整示例代码

以下是一个完整的 Flutter 应用程序示例,演示如何使用 dart_crs 插件进行地理坐标转换。

import 'package:dart_crs/dart_crs.dart';
import 'package:flutter/material.dart';
import 'package:proj4dart/proj4dart.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.teal),
        useMaterial3: true,
        elevatedButtonTheme: ElevatedButtonThemeData(
            style: ElevatedButton.styleFrom(
                backgroundColor: Colors.teal,
                textStyle:
                    const TextStyle(color: Colors.white, fontSize: 14.0))),
      ),
      home: const MyHomePage(title: 'Dart_Crs Demo'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  [@override](/user/override)
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  CoordinateTransform? transform;
  TextEditingController xController = TextEditingController();
  TextEditingController yController = TextEditingController();
  TextEditingController xTransformController = TextEditingController();
  TextEditingController yTransformController = TextEditingController();
  TextEditingController sourceCRSController = TextEditingController();
  TextEditingController targetCRSController = TextEditingController();
  Point? sourcePoint;
  Point? targetPoint;

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomInset: false,
      appBar: PreferredSize(
        preferredSize: const Size.fromHeight(50.0),
        child: AppBar(
          centerTitle: true,
          backgroundColor: Theme.of(context).colorScheme.primary,
          title: Text(widget.title,
              style: const TextStyle(
                  fontSize: 22.0,
                  color: Colors.white,
                  fontWeight: FontWeight.bold)),
        ),
      ),
      body: Container(
        padding: const EdgeInsets.all(15.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          children: [
            const SizedBox(height: 30),
            const Text('Coordinate Reference Systems',
                style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500)),
            const SizedBox(height: 20.0),
            Row(
              children: [
                Expanded(
                  child: TextField(
                    controller: sourceCRSController,
                    decoration: const InputDecoration(
                      label: Text('Source CRS',
                          style: TextStyle(
                              fontSize: 14.0, fontWeight: FontWeight.w500)),
                      contentPadding:
                          EdgeInsets.symmetric(vertical: 5.0, horizontal: 5.0),
                      border: OutlineInputBorder(),
                      hintText: 'EPSG:xxxx',
                      hintStyle: TextStyle(fontSize: 13),
                      enabled: true,
                    ),
                  ),
                ),
                const SizedBox(width: 15.0),
                Expanded(
                  child: TextField(
                    controller: targetCRSController,
                    decoration: const InputDecoration(
                      label: Text('Target CRS',
                          style: TextStyle(
                              fontSize: 14.0, fontWeight: FontWeight.w500)),
                      contentPadding:
                          EdgeInsets.symmetric(vertical: 5.0, horizontal: 5.0),
                      border: OutlineInputBorder(),
                      hintText: 'EPSG:xxxx',
                      hintStyle: TextStyle(fontSize: 13),
                    ),
                  ),
                ),
              ],
            ),
            const SizedBox(height: 30),
            const Text('Source Coordinates',
                style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500)),
            const SizedBox(height: 20.0),
            Row(
              children: [
                Expanded(
                  child: TextField(
                    controller: xController,
                    decoration: const InputDecoration(
                      label: Text('X (East) Coordinate',
                          style: TextStyle(
                              fontSize: 14.0, fontWeight: FontWeight.w500)),
                      contentPadding:
                          EdgeInsets.symmetric(vertical: 5.0, horizontal: 5.0),
                      border: OutlineInputBorder(),
                      hintText: 'Enter Coordinate',
                      hintStyle: TextStyle(fontSize: 13),
                      enabled: true,
                    ),
                  ),
                ),
                const SizedBox(width: 15.0),
                Expanded(
                  child: TextField(
                    controller: yController,
                    decoration: const InputDecoration(
                      label: Text('Y (North) Coordinate',
                          style: TextStyle(
                              fontSize: 14.0, fontWeight: FontWeight.w500)),
                      contentPadding:
                          EdgeInsets.symmetric(vertical: 5.0, horizontal: 5.0),
                      border: OutlineInputBorder(),
                      hintText: 'Enter Coordinate',
                      hintStyle: TextStyle(fontSize: 13),
                    ),
                  ),
                ),
              ],
            ),
            const SizedBox(height: 30),
            const Text('Transformed Coordinates',
                style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500)),
            const SizedBox(height: 20.0),
            Row(
              children: [
                Expanded(
                  child: TextField(
                    readOnly: true,
                    controller: xTransformController,
                    decoration: const InputDecoration(
                      label: Text('X (East) Coordinate',
                          style: TextStyle(
                              fontSize: 14.0, fontWeight: FontWeight.w500)),
                      contentPadding:
                          EdgeInsets.symmetric(vertical: 5.0, horizontal: 5.0),
                      border: OutlineInputBorder(),
                      // hintText: 'Enter Coordinate',
                      // hintStyle: TextStyle(fontSize: 13),
                      enabled: true,
                    ),
                  ),
                ),
                const SizedBox(width: 15.0),
                Expanded(
                  child: TextField(
                    controller: yTransformController,
                    decoration: const InputDecoration(
                      label: Text('Y (North) Coordinate',
                          style: TextStyle(
                              fontSize: 14.0, fontWeight: FontWeight.w500)),
                      contentPadding:
                          EdgeInsets.symmetric(vertical: 5.0, horizontal: 5.0),
                      border: OutlineInputBorder(),
                      // hintText: 'Enter Coordinate',
                      // hintStyle: TextStyle(fontSize: 13),
                    ),
                  ),
                ),
              ],
            ),
            const SizedBox(height: 40),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                ElevatedButton(
                  child: const Text('Forward',
                      style: TextStyle(color: Colors.white, fontSize: 14.0)),
                  onPressed: () async {
                    final sourceCRS = sourceCRSController.text.toUpperCase();
                    if (!validateCRS(sourceCRS)) {
                      FocusManager.instance.primaryFocus?.unfocus();
                      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
                          content: Text('Invalid or missing source SRS')));
                      return;
                    }
                    final targetCRS = targetCRSController.text.toUpperCase();
                    if (!validateCRS(targetCRS)) {
                      FocusManager.instance.primaryFocus?.unfocus();
                      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
                          content: Text('Invalid or missing target SRS')));
                      return;
                    }
                    try {
                      transform ??=
                          await CRSFactory.createCoordinateTransformFromCodes(
                              sourceCRS, targetCRS);
                      final x = double.parse(xController.value.text);
                      final y = double.parse(yController.value.text);
                      sourcePoint = Point(x: x, y: y);
                      targetPoint = transform!.transform(sourcePoint!);
                      setState(() {
                        if (targetPoint != null) {
                          xTransformController.text =
                              targetPoint!.x.toStringAsPrecision(11);
                          yTransformController.text =
                              targetPoint!.y.toStringAsPrecision(11);
                        }
                      });
                    } on InvalidArgumentException {
                      if (context.mounted) {
                        FocusManager.instance.primaryFocus?.unfocus();
                        ScaffoldMessenger.of(context).showSnackBar(
                            const SnackBar(
                                content:
                                    Text('Invalid or missing source or target SRS')));
                        return;
                      }
                    }
                  },
                ),
                const SizedBox(width: 30.0),
                ElevatedButton(
                  style: ButtonStyle(
                    shape: MaterialStateProperty.all<RoundedRectangleBorder>(
                        RoundedRectangleBorder(
                            borderRadius: BorderRadius.circular(24.0),
                            side: const BorderSide(color: Colors.teal))),
                  ),
                  child: const Text('Inverse',
                      style: TextStyle(color: Colors.white, fontSize: 16.0)),
                  onPressed: () async {
                    if (targetPoint != null) {
                      targetPoint = transform!.inverse(targetPoint!);
                      setState(() {
                        if (targetPoint != null) {
                          xTransformController.text =
                              targetPoint!.x.toStringAsPrecision(11);
                          yTransformController.text =
                              targetPoint!.y.toStringAsPrecision(11);
                        }
                      });
                    }
                  },
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }

  bool validateCRS(String crsCode) {
    final lc = crsCode.toLowerCase();
    return lc.startsWith("epsg:");
  }
}

更多关于Flutter地理坐标转换插件dart_crs的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter地理坐标转换插件dart_crs的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter项目中使用dart_crs插件来进行地理坐标转换的代码示例。dart_crs插件用于在不同坐标参考系统(CRS)之间进行转换,这在处理地理数据时非常有用。

首先,确保你已经在pubspec.yaml文件中添加了dart_crs依赖:

dependencies:
  flutter:
    sdk: flutter
  dart_crs: ^最新版本号  # 替换为实际可用的最新版本号

然后,运行flutter pub get来安装依赖。

接下来,下面是一个简单的示例,演示如何使用dart_crs进行地理坐标转换。这个示例假设我们要从WGS84(EPSG:4326)转换到Web Mercator(EPSG:3857):

import 'package:flutter/material.dart';
import 'package:dart_crs/dart_crs.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('地理坐标转换示例'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text('输入WGS84坐标 (例如: 经度 116.397128, 纬度 39.916527)'),
              SizedBox(height: 20),
              ElevatedButton(
                onPressed: () {
                  // 示例坐标:北京的经纬度
                  double lon = 116.397128;
                  double lat = 39.916527;
                  
                  // 创建WGS84坐标
                  Coordinate wgs84Coordinate = Coordinate(lon, lat, CoordinateReferenceSystem.EPSG_4326);
                  
                  // 转换到Web Mercator
                  Coordinate mercatorCoordinate = wgs84Coordinate.transformTo(CoordinateReferenceSystem.EPSG_3857);
                  
                  // 输出转换后的坐标
                  print('WGS84坐标: ($lon, $lat)');
                  print('Web Mercator坐标: (${mercatorCoordinate.x}, ${mercatorCoordinate.y})');
                },
                child: Text('转换坐标'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

在这个示例中,我们做了以下几件事:

  1. 定义依赖:在pubspec.yaml中添加dart_crs依赖。
  2. 创建Flutter应用:在MyApp中,我们定义了一个简单的UI,包含一个按钮用于触发坐标转换。
  3. 定义WGS84坐标:使用Coordinate类创建一个WGS84坐标(EPSG:4326)。
  4. 转换坐标:使用transformTo方法将WGS84坐标转换为Web Mercator坐标(EPSG:3857)。
  5. 输出结果:在控制台打印转换前后的坐标。

请注意,dart_crs插件的具体API和使用方式可能会随着版本更新而变化,因此建议查阅最新的dart_crs文档(如果可用)以获取最准确的信息。

希望这个示例能帮你理解如何在Flutter项目中使用dart_crs进行地理坐标转换!

回到顶部