我遇到一个问题,我试图弄清楚如何将多边形面积转换为表面积测量值,例如平方英尺、公顷甚至英亩。
我有 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将多边形转换为某些区域大小,例如,将多边形保存到数据库中,然后立即运行一些更新查询来在数据库中执行此操作?不确定性能,但这是我唯一想到的。
非常感谢有关此问题以及如何改进现有代码的所有帮助,因为这听起来很简单(只需将多边形转换为区域大小),但我不确定应该如何完成?
谢谢!
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 没有意义,第二个数字是以平方米为单位的面积,可以简单地转换为平方英尺。