如何在 Java / Spring / PostGIS 中将多边形面积转换为平方英尺

问题描述 投票:0回答:1

我遇到一个问题,我试图弄清楚如何将多边形面积转换为表面积测量值,例如平方英尺、公顷甚至英亩。

我有 Hibernate Spatial 和 JTS Core 的依赖项:

<dependency>
        <groupId>org.hibernate.orm</groupId>
    <artifactId>hibernate-spatial</artifactId>
    <version>${hibernate.version}</version>
</dependency>

<dependency>
    <groupId>org.locationtech.jts</groupId>
    <artifactId>jts-core</artifactId>
    <version>${jts.version}</version>
</dependency>

这是我已经编写的一些代码...

具有实体字段的字段实体,其中包含面积字段,它是一个多边形和我正在尝试计算的大小...

@Entity(name = "field")
@Table(name = "field")
public class Field {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    @Column(updatable = false, nullable = false, unique = true)
    private Long id;

    @Column(name = "name", nullable = false)
    private String name;

    @Column(name = "area", columnDefinition = "geometry(Polygon, 4326)", nullable = false)
    private Polygon area;

    @Column(name = "center", columnDefinition = "geometry(Point, 4326)")
    private Point center;

    @Column(name = "size")
    private Double size;

    @ManyToOne
    @JoinColumn(name = "fk_farm_id")
    private Farm farm;
}

该领域的简单存储库...

@Repository
public interface FieldRepository extends JpaRepository<Field, Long> {
}

FieldService 的接口,包含我想要返回的响应 DTO 类和

publicFarmId
参数,该参数用于代替向用户显示主键字段...

public interface FieldService {

    CreateFieldResponseDto createNewField(UUID publicFarmId, FieldDto fieldDto);
}

createNewField
实现类中重写
FieldServiceImpl
方法,并使用辅助方法将
fieldDto
的坐标转换为 Polygon,计算 Polygon 的中心坐标。

@Override
public CreateFieldResponseDto createNewField(UUID publicFarmId, FieldDto fieldDto) {

     Farm farm = farmRepository.findByPublicId(publicFarmId)
                .orElseThrow(() -> new FarmNotFoundException("Farm not found"));

    Field newField = new Field();

    newField.setName(fieldDto.getName());
    newField.setArea(convertToPolygon(fieldDto.getCoordinates()));
    newField.setCenter(calculateCenter(newField.getArea()));
//    newField.setSize(calculateFieldSize(newField.getArea()));
    newField.setFarm(farm);

    fieldRepository.save(newField);

    return fieldMapper.INSTANCE.toCreateFieldResponseDto(newField);
}

//--------------------------------------------|
// HELPER METHODS FOR CREATING A NEW FIELD... |
//--------------------------------------------|

private Polygon convertToPolygon(List<List<List<Double>>> coordinates) {

    GeometryFactory geometryFactory = new GeometryFactory();

    LinearRing shell = geometryFactory.createLinearRing(
            convertToCoordinateArray(coordinates.get(0))
    );

    LinearRing[] holes = new LinearRing[coordinates.size() - 1];

    for (int i = 1; i < coordinates.size(); i++) {
        holes[i - 1] = geometryFactory.createLinearRing(
                convertToCoordinateArray(coordinates.get(i))
        );
    }

    return geometryFactory.createPolygon(shell, holes);
}

private Coordinate[] convertToCoordinateArray(List<List<Double>> coordinatesList) {

    Coordinate[] coordinates = new Coordinate[coordinatesList.size()];

    for (int i = 0; i < coordinatesList.size(); i++) {
        List<Double> point = coordinatesList.get(i);
        coordinates[i] = new Coordinate(point.get(0), point.get(1));
    }

    return coordinates;
}

private Point calculateCenter(Polygon polygon) {

    GeometryFactory geometryFactory = new GeometryFactory();

    return geometryFactory.createPoint(polygon.getCentroid().getCoordinate());
}

我们的控制器类...

@PostMapping("/{publicFarmId}/fields")
public ResponseEntity<Object> createField(
    @PathVariable UUID publicFarmId, @RequestBody FieldDto fieldDTO
) {
    CreateFieldResponseDto createdField = fieldService.createNewField(publicFarmId, fieldDTO);

    return ResponseHandler.generateResponse(
            HttpStatus.CREATED,
            "success",
            "Field created successfully.",
            new LinkedHashMap<>() {{
                put("name", createdField.name());
                put("coordinates", createdField.coordinates());
                put("center", createdField.center());
                put("size", createdField.size());
                put("unitOfMeasurement", "metric"); // CODE THIS LATER !!!
            }}
    );
}

字段 DTO 类是请求对象,包含农民可以提供的字段名称以及我们用来构造多边形的坐标。坐标位于列表列表内,因此我们也可以创建带孔的多边形...

public class FieldDto {

    private String name;
    private List<List<List<Double>>> coordinates;
}

我对这样的问题的最佳解决方案感到非常困惑,我应该在Java代码中计算多边形大小,还是PostGIS已经有方法可以帮助使用SQL将多边形转换为某些区域大小,例如,将多边形保存到数据库中,然后立即运行一些更新查询来在数据库中执行此操作?不确定性能,但这是我唯一想到的。

非常感谢有关此问题以及如何改进现有代码的所有帮助,因为这听起来很简单(只需将多边形转换为区域大小),但我不确定应该如何完成?

谢谢!

java spring spring-boot geospatial postgis
1个回答
0
投票

PostGIS可以使用ST_Area函数计算面积。您需要知道的是,使用 4326 投影(几何类型)无法获得有用的区域。这将返回平坦和扭曲地图上的面积,这是没有意义的,并且无法转换为平方英尺。

您要么需要使用地理类型,要么转换为合适的投影(这取决于您正在使用的地球上的位置)。这是小演示:

postgres=# select st_area('polygon((1 1, 2 1, 2 2, 1 1))');
 st_area 
---------
     0.5
(1 row)

postgres=# select st_area('polygon((1 1, 2 1, 2 2, 1 1))'::geography);
      st_area      
-------------------
 6153961068.605661
(1 row)

第一个数字 0.5 没有意义,第二个数字是以平方米为单位的面积,可以简单地转换为平方英尺。

© www.soinside.com 2019 - 2024. All rights reserved.