文章目录
前言
在三维城市道路设计中,我们时常会模拟物体通过限高路段是是否能正常通过,需要得到不同的通过物体是否存在超过限高的现象,超高多少,如超过,应该对通过物,裁剪多高才能正常通过。已上需求单靠前端的话难以做到,因此我们需要结合后端服务来实现。
一、前端构建通过物以及裁剪面
javascript
entity = viewer.entities.add({
name: '带边框的绿色圆锥',
position: SuperMap3D.Cartesian3.fromDegrees(116.0636726109858, 30.032487387912454, 1600),
cylinder: {
length: 2000,
topRadius: 0.0,
bottomRadius: 600.0,
material: SuperMap3D.Color.BLUE.withAlpha(0.5),
// outline: true,
// outlineColor: SuperMap3D.Color.DARK_GREEN
}
});
viewer.flyTo(entity)
// 定义坐标点数组(经度,纬度,高度)
const positions = [
116.03202241972726, 30.028348734853576, 1500,
116.04873386096398, 30.01183763716355, 2000,
116.09021417949586, 30.033660215083376, 1800,
116.07617627250876, 30.058336989847938, 1200
];
// 创建实体面
const polygonEntity = viewer.entities.add({
name: '空中三维面',
polygon: {
hierarchy: new SuperMap3D.PolygonHierarchy(
SuperMap3D.Cartesian3.fromDegreesArrayHeights(positions)
),
material: SuperMap3D.Color.RED.withAlpha(0.5),
// height: 0, // 设置为0表示完全使用坐标中的高度值
// extrudedHeight: 0, // 设置为0表示不额外拉伸
perPositionHeight: true, // 关键!启用每个顶点独立高度
// closeTop: true,
// closeBottom: false, // 不封闭底部,让面悬浮在空中
// outline: true,
// outlineColor: SuperMap3D.Color.WHITE,
// outlineWidth: 2
}
});

二、后端创建接口实现布尔运算
1、根据前端传过来的参数构建体
java
//获取前端传过来的三维面
String points = request.getParameter("points");
//解析三维面节点字符串
JSONArray jsonArray = new JSONArray(points);
String[][] strings = new String[jsonArray.length()][3];
// 遍历 JSONArray 并存入 String[]
for (int i = 0; i < jsonArray.length(); i++) {
JSONArray jsonArray_child = new JSONArray(jsonArray.getString(i));
strings[i][0] = jsonArray_child.getString(0);
strings[i][1] = jsonArray_child.getString(1);
strings[i][2] = jsonArray_child.getString(2);
}
//构造三维点集 用于构造三维面
Point3Ds point3Ds = new Point3Ds();
for (int i = 0; i < strings.length; i++) {
Point3D point3D = new Point3D();
point3D.setX(Double.parseDouble(strings[i][0]));
point3D.setY(Double.parseDouble(strings[i][1]));
point3D.setZ(Double.parseDouble(strings[i][2]));
point3Ds.add(point3D);
}
//拉伸闭合体参数
EnvelopParameter envelopParameter = new EnvelopParameter();
envelopParameter.setLonLat(true);
envelopParameter.setStretchHeight(-3000);
//初始化工作空间
workspace = new Workspace();
//创建内存型数据源
DatasourceConnectionInfo info = new DatasourceConnectionInfo();
info.setEngineType(EngineType.UDB);
info.setServer(":memory:");
Datasource datasource = workspace.getDatasources().create(info);
//创建一个模型数据集
DatasetVectorInfo datasetvectorinfo = new DatasetVectorInfo();
datasetvectorinfo.setType(DatasetType.MODEL);
datasetvectorinfo.setName("NewModel_1");
DatasetVector datasetVector_result = datasource.getDatasets().create(datasetvectorinfo);
datasetVector_result.setPrjCoordSys(new PrjCoordSys(4490));
// DatasetVector datasetVector_result = (DatasetVector) datasource.getDatasets().get("NewModel_1");
//获取模型数据集的记录集
Recordset recordset = datasetVector_result.getRecordset(false, CursorType.DYNAMIC);
System.out.println("recordsetCount:"+recordset.getRecordCount());
recordset.edit();
recordset.moveLast();
//构造三维面
GeoRegion3D geoRegion3D = new GeoRegion3D();
geoRegion3D.addPart(point3Ds);
//三维面几何对象构建闭合体,用于跟通过物模型做运算
ArrayList<GeoModel3D> arrayList = ModelBuilder3D.envelop(geoRegion3D, envelopParameter);
for (int i = 0; i < arrayList.size(); i++) {
recordset.addNew(arrayList.get(i));
recordset.moveNext();
}
System.out.println("recordsetCount:"+recordset.getRecordCount());
//获取前端传过来的通过物构造参数
Double positionX = Double.valueOf(request.getParameter("x"));
Double positionY = Double.valueOf(request.getParameter("y"));
Double positionZ = Double.valueOf(request.getParameter("z"));
Double bottomRadius = Double.valueOf(request.getParameter("bottomRadius"));
Double height = Double.valueOf(request.getParameter("height"));
//构造圆锥体通过物
GeoCone geoCone = new GeoCone();
geoCone.setPosition(new Point3D(positionX,positionY,positionZ));
geoCone.setBottomRadius(bottomRadius);
geoCone.setHeight(height);
2、体和面构建完成之后进行布尔运算
java
//获取数据集中需要做运算的模型对象
Recordset recordset_result = datasetVector_result.query("SmID=1",CursorType.DYNAMIC);
GeoModel3D geoModel3D = (GeoModel3D) recordset_result.getGeometry();
System.out.println("通过物模型最高点高程:"+(geoCone.getHeight()+geoCone.getPosition().getZ()));
//进行布尔运算求差
Geometry3D geometry3D = BooleanOperator3D.erase(geoCone,geoModel3D);
if (geometry3D.isEmpty()){
return "该物体没有相交";
}
geometry3D.setPosition(new Point3D(positionX,positionY,positionZ));
if(!geometry3D.isEmpty()){
System.out.println("布尔运算擦除成功!!!");
}
3、布尔元算结果数据保存
java
ModelFileSetting fileSetting = new ModelFileSetting();
String modelPath = "E:\\工作\\iserver\\supermap-iserver-2025u1-windows-x64-deploy\\webapps\\iserver\\";
String name = Math.random()+".s3m";
fileSetting.setFilePath(modelPath+name);
boolean isConvert = ModelConvertor.toFile(((GeoModel3D) geometry3D).getModel(),fileSetting);
4、计算通过物超高高度
java
//获取模型三维底面,用于计算超高高度
GeoRegion geoRegion = ModelBuilder3D.planeProjection2D((GeoModel3D) geometry3D,new Plane());
ArrayList<Geometry> arrayList_region = new ArrayList<>();
arrayList_region.add(geoRegion);
MatchParameter matchParameter = new MatchParameter();
matchParameter.setAttach(AttachOption.BOTTOM);
matchParameter.setSampleDistance(0.1);
ArrayList<Geometry3D> arrayList_region3d = ModelBuilder3D.geometryMatch((GeoModel3D)geometry3D,arrayList_region,matchParameter);
GeoRegion3D region3D = (GeoRegion3D) arrayList_region3d.get(0);
if(region3D.getPartCount()<0){
return "三维面对象为0";
}
double overMaxZ = region3D.getPart(0).getItem(0).getZ();
double overMinZ = region3D.getPart(0).getItem(0).getZ();
for (int i = 0; i < region3D.getPartCount(); i++) {
for (int j = 0; j < region3D.getPart(i).getCount(); j++) {
double currentZ = region3D.getPart(i).getItem(j).getZ();
if (currentZ > overMaxZ) {
overMaxZ = currentZ;
}
if (currentZ < overMinZ) {
overMinZ = currentZ;
}
}
}
overMinZ = (((GeoModel3D)geometry3D).getMaxZ()-overMinZ);
overMaxZ = (((GeoModel3D)geometry3D).getMaxZ()-overMaxZ);
System.out.println("通过物体最高超高:"+overMinZ+"米");
System.out.println("通过物体最低超高:"+overMaxZ+"米");
5、运算结果返回前端
java
if (isConvert){
JSONObject jsonObject = new JSONObject();
jsonObject.put("name", name);
jsonObject.put("minZ", positionZ);
jsonObject.put("overMaxZ", overMinZ);
jsonObject.put("overMinZ", overMaxZ);
String jsonString = jsonObject.toString();
System.out.println("擦除结果保存到模型数据集成功!!!");
return jsonString;
}else {
System.out.println("擦除结果保存到模型数据集失败!!!!");
return "擦除结果保存到模型数据集失败!!!!";
}
三、前端调用后端接口
javascript
var sqlParameter = {
"x": 116.0636726109858,
"y": 30.032487387912454,
"z": 600,
"bottomRadius": 600,
"height": 2000,
"points": "[[116.03202241972726,30.028348734853576,1500],[116.04873386096398,30.01183763716355,2000],[116.09021417949586,30.033660215083376,1800],[116.07617627250876,30.058336989847938,1200]]"
};
var url = "http://localhost:8099/iServer/geoExtrudedBody";
$.ajax({
type: "post",
url: url,
data: sqlParameter,
success: function (result) {
var resultObj = JSON.parse(result);
console.log(resultObj)
//将超高部分绘制出来
var s3mInstanceColc = new SuperMap3D.S3MInstanceCollection(scene._context);
scene.primitives.add(s3mInstanceColc);
s3mInstanceColc.add("http://localhost:8090/iserver/" + resultObj.name, {
position: SuperMap3D.Cartesian3.fromDegrees(116.0636726109858, 30.032487387912454, resultObj.minZ),
hpr: new SuperMap3D.HeadingPitchRoll(0, 0, 0),
scale: new SuperMap3D.Cartesian3(1, 1, 1),
color: SuperMap3D.Color.YELLOW
});
},
error: function (msg) {
console.log(msg);
},
})

