本文档以某水动力模型数据为例,介绍如何将带有时间维度的原始数据导入SuperMap iDesktopX,并生成时序模型瓦片,以及如何在SuperMap iClient3D for WebGL/WebGPU中加载。
文档将从以下几个方面分别进行说明:
其中涉及的产品有:SuperMap iDesktopX或SuperMap iObjects Java,SuperMap iServer ,SuperMap iClient3D for WebGL/WebGPU。
1.1软件配置
1.2原始数据准备
基于水动力模型数据输出的中转数据,数据格式包括*.shp、*.xlsx、*.txt、*csv。
SuperMap GIS支持通过点集+约束面或者三角网+要素两种方式生成时序模型瓦片。
目前,通常直接使用SuperMap iDesktopX通过点集+约束面方式生成时序模型瓦片。三角网+要素方式生成时序模型瓦片通常使用SuperMap iObjects Java,仅该方式支持多要素追加的情况。
2.1点集+约束面方式生成时序模型瓦片
点集+约束面方式生成时序模型瓦片是指基于原始的时序点位数据及约束面数据生成S3M瓦片数据。如果原始数据包含点数据和约束面数据,可以将点和面数据导入SuperMap iDesktopX后,直接进行生成瓦片操作。
如果与本应用示例数据一样,原始数据只有约束面数据,可以按照以下操作方法先从面数据中提取点数据,再进行生成瓦片操作。
2.1.1点位数据处理
该流程是通过数据导入、坐标设定、类型转换等相关功能,将*.shp格式的原始点位数据导入SuperMap iDesktopX,并转成三维点数据集,具体操作步骤如下:
详细操作,请参考以下 SuperMap iDesktopX 帮助文档:
2.1.2写入点位多时刻水深属性
该流程主要将点数据中多时刻的属性信息写入三维点数据集属性表中。这里是将示例点数据中多时刻的水深信息写入三维点数据集的属性表中。具体操作步骤如下:
for(int i = 1; i < mfile.Length; i++)
{
path = @"D:\data_directory\result"+ i.ToString() + ".txt";
sr = new StreamReader(path, Encoding.Default);
fieldInfos = dv.FieldInfos;
fieldInfo = new FieldInfo();
fieldInfo.Type = FieldType.Double;
fieldInfo.Name ="水深"+ i.ToString();
fieldInfos.Add(fieldInfo);
}
recordset.MoveFirst();
while ((line = sr.ReadLine()) != null)
{
if (line.Split(''). Count() >3)
{
fieldInfoname = "水深"+i.ToString();
var splitDepth= line.Split('').Where(x => x !=" ").ToList()[2];
var spliu = line. Split('').Where(x => x !=" ").ToList() [3];
var splitV = line. Split('').Where(x =>x!=" ").ToList() [4];
bool bSet = recordset.SetFieldValue(fieldInfoname,double. Parse(splitDepth));
recordset. MoveNext();
}
}
注意:
(1)当模拟结果.txt里没有点的位置信息时,可以通过上述方法,借助SuperMap iObjects Java 代码将水深信息导入点数据集。
(2)如果模拟结果.txt记录了点的位置信息,可以直接将其导入成点数据集,并通过追加列的方式将不同时刻的水深值储存到属性表中。
2.1.3生成时序模型瓦片
注意:
(1)由于原始数据的范围是不规则的,所以生成时序模型瓦片时需要指定瓦片范围进行约束。
(2)生成时序模型瓦片时,必须勾选必要的时序字段。
(3)如有疑问,具体操作请参考SuperMap iDesktopX帮助文档点集生成时序模型瓦片。
该流程首先详细说明包含矢量数据集的已有数据源的数据组成及操作,然后基于SuperMap iObjects Java 11.2.0实现时序模型瓦片生成和多要素追加。具体操作步骤如下:
2.2.1数据组成说明
如果原始数据格式为*.nc的三角网数据,需要将*.nc数据转换为面数据集,并建议将三角网中的点及单个要素信息(例如水深、水温等)存储为单个三维点数据集。
三角面的结点ID分别为28(t1:第一个结点)、43(t2:第二个结点)、42(t3:第三个结点)。
2.2.2生成时序模型瓦片
该流程主要介绍如何使用11.2.0及更高版本的SuperMap iObjects Java生成时序模型瓦片。主要操作步骤及关键代码如下:
public static void main(String[] args)
{
startTime = System.currentTimeMillis();
string strDatasource = "D:\\data_directory\\演示用数据\\多时序瓦片\\ModelDataHanding.udbx";
DatasourceConnectionInfo info = new DatasourceConnectionInfo();
info.setserver(strDatasource);
info.setEngineType(EngineType.UDBX);
m_workspace = new Workspace();
DatasetVector datasetVector =(DatasetVector)datasource.getDatasets() .get(1);
datasource = m_workspace.getDatasources() .open(info);
addAttribute(datasetVector,true); //获取要素属性
addindices(); //添加要素(指标)
BuildCache(); //生成时序模型瓦片
TestAppend(); //要素(指标)追加
m_points.clear();
m_indices.clear();
ptsAtts.clear();
}
/**
* 获取要素属性
* @param datasetVector
* @param bGetPoint
*/
public static void addAttribute(DatasetVector datasetVector,boolean bGetPoint)
{
prjCoordSys = new PrjCoordSys(datasetVector.getPrjCoordSys());
Recordset recordset = datasetVector.getRecordset(false,CursorType.STATIC);
if (bGetPoint)
{
m_points = new ArrayList();
}
ArrayListnames = GetAttributeNames (datasetVector);
ptsAtts = new ArrayList>();
while (!recordset .isEOF())
{
if (bGetPoint)
{
Geometry geometry = recordset.getGeometry();
double dx= ((GeoPoint3D)geometry).getX();
double dy=((GeoPoint3D)geometry).getY();
double dz=((GeoPoint3D)geometry).getZ();
Point3D pt = new Point3D(dx,dy,dz);
m_points.add(pt);
}
ArrayListatts = new ArrayList();
for (int i = 0; i < names.size(); i++)
{
atts.add(recordset.getDouble(names.get(i)));
}
ptsAtts.add(atts);
recordset.moveNext();
}
recordset.close();
recordset.dispose();
datasetVector.close();
datasetVector.dispose();
}
/** * 获取当前要素里的时序名称集合 * @param DataV * @return */ public static ArrayListGetAttributeNames(DatasetVector DataV) { ArrayList names=new ArrayList (); for(int i = 8;i < DataV.getFieldInfos().getCount();i++) { if((!DataV.getFieldInfos().get(i).isSystemField())&&(!DataV.getFieldInfos().get(i).getName().equals("SmUserID"))) { String filedinfoname = DataV.getFieldInfos().get(i).getName(); names.add(filedinfoname); } } return names; }
/**
* 添加要素(指标)
*/
public static void addindices()
{
//获取面数据集
DatasetVector datasetVectorRgion = (DatasetVector) datasource.getDatasets().get("vzvzorndv_node_index");
Recordset recordsetRegion = datasetVectorRgion.getRecordset(false,CursorType.STATIC);
m_indices = new ArrayList();
while (!recordsetRegion .isEOF())
{
int nId0 = recordsetRegion.getInt32("t1");
int nId1 = recordsetRegion.getInt32("t2");
int nId2 = recordsetRegion.getInt32("t3");
if (nId0 * nId1 * nId2 == 0)
{
recordsetRegion.moveNext();
continue;
}
m_indices.add(nId0-1);
m_indices.add(nId1-1);
m_indices.add(nId2-1);
recordsetRegion.moveNext();
}
recordsetRegion.close();
recordsetRegion.dispose();
datasetVectorRgion.close();
datasetVectorRgion.dispose();
}
/**
* 生成时序瓦片
*/
public static void BuildCache()
{
String strOutput="D:\\各类场景使用项\\矢量数据缓存\\水利部\\";
String strCacheName="buildFromMesh_250916";
VectorTemporalCacheBuilder builder= new VectorTemporalCacheBuilder();
builder.setCacheName(strCacheName); //瓦片名称
builder.setOutputFolder(strOutput); //瓦片输出路径
builder.setPrjCoordSys(prjCoordSys); //设置瓦片的坐标系
builder.setPoints(m_points); //设置网格顶点(仅三角网方式生成时序模型瓦片使用)
builder.setIndices(m_indices); //设置网格索引(仅三角网方式生成时序模型瓦片使用)
builder.setAttributes("depth",ptsAtts); //设置网格顶点属性(仅三角网方式生成时序模型瓦片使用)
double cost=(System.currentTimeMillis()-startTime)*1.0;
String strTime=(cost/1000)+"";
System.out.println("get data:"+strTime+"s");
long startTime1=System.currentTimeMillis();
builder.buildFromMesh(); //执行,生成时序模型瓦片
double cost1=(System.currentTimeMillis()-startTime1)*1.0;
String strTime1=(cost1/1000)+"";
System.out.println("build:"+strTime1+"s");
}
/**
* 追加多要素
*/
public static void TestAppend()
{
int sum = 0;
VectorTemporalCacheBuilder builder = new VectorTemporalCacheBuilder();
//用于追加多要素时,设置时序模型瓦片的配置文件
builder.setSCPFile("D:\\各类场景使用项\\矢量数据缓存\\水利部\\buildFromMesh_250916\\buildFromMesh_250916.scp");
for(int j = 2;j< datasource.getDatasets().getCount();j++)
{
if (datasource.getDatasets().get(j).getType() == DatasetType.POINT3D) {
long startTime1 = System.currentTimeMillis();
DatasetVector m_DV = (DatasetVector)datasource.getDatasets().get(j);
addAttribute(m_DV,false);
String categoryname = datasource.getDatasets().get(j).getName();
double cost=(System.currentTimeMillis()-startTime1)*1.0;
String strTime1=(cost/1000)+"";
System.out.println(categoryname +":"+strTime1+"s");
double startTime2=System.currentTimeMillis()*1.0;
builder.setAttributes(categoryname,ptsAtts);
builder.append();
double cost1=(System.currentTimeMillis()-startTime2)*1.0;
String strTime2=(cost1/1000)+"";
System.out.println("Append"+(sum++)+":"+strTime2+"s");
}
}
datasource.close();
prjCoordSys.dispose();
}
3.1保存工作空间
将章节2中得到的时序模型瓦片添加到SuperMap iDesktopX的场景中,并保存场景和工作空间。
3.2发布三维服务
将上一步骤得到的工作空间在SuperMap iServer中发布为三维服务,具体操作请参考SuperMap iServer帮助文档发布文件型工作空间。
3.3SuperMap iClient3D for WebGL/WebGPU中加载
在SuperMap iClient3D for WebGL/WebGPU加载上一步发布的三维服务,并采用分层设色的方式进行数据的可视化表达。主要参考代码如下:
promise.then(function (layers) {
layer = layers[0];
updateLayerHyp(layer);
layer.temporalSetting = new SuperMap3D.TemporalSetting();
layer.temporalSetting.location = 0;
layer.temporalSetting.changeZValue = true;
layer.minTransparentAlpha = 1;
// 更新图层分层设色函数
function updateLayerHyp(layer, colorIndex = 0, step = 24) { // step 颜色表插入的总数
// 图层上的时间总数,11.11 temporalCount,主版本外挂-图层上的时间总数 _temporalInfo
let temporalInfo = layer._temporalInfo;
temporalCount = temporalInfo.length > 0 ? temporalInfo[colorIndex].count : layer.temporalCount;
let minValue = layer._hypMinCategory;
let maxValue = layer._hypMaxCategory;
let hyp = new SuperMap3D.HypsometricSetting();
hyp.ColorTable = createColorTable();
hyp.DisplayMode = SuperMap3D.HypsometricSettingEnum.DisplayMode.FACE;
hyp.Opacity = 1.0;
hyp.LineInterval = 1.0;
hyp.ColorTableMaxKey = maxValue;
hyp.ColorTableMinKey = minValue;
//设置非法值颜色
hyp.noValueColor = new SuperMap3D.Color(1.0, 0.0, 0.0, 1);
hyp.MaxVisibleValue = maxValue;
hyp.MinVisibleValue = minValue;
hyp.filterMode = SuperMap3D.HypsometricSettingEnum.FilterMode.NEAREST;
layer.hypsometricSetting = {
hypsometricSetting: hyp,
analysisMode: SuperMap3D.HypsometricSettingEnum.AnalysisRegionMode.ARM_ALL,
};
}
// 创建颜色表
function createColorTable(keys, colors, alphas) {
let colorTable = new SuperMap3D.ColorTable();
colorTable.insert(0.0, SuperMap3D.Color.fromCssColorString("#00A2FF").withAlpha(0));
colorTable.insert(0.01, SuperMap3D.Color.fromCssColorString("#0082FF").withAlpha(0.3));
colorTable.insert(0.05, SuperMap3D.Color.fromCssColorString("#008CFF").withAlpha(0.50));
colorTable.insert(0.1, SuperMap3D.Color.fromCssColorString("#0096FF").withAlpha(0.70));
colorTable.insert(0.15, SuperMap3D.Color.fromCssColorString("#0096FF").withAlpha(0.70));
colorTable.insert(0.30, SuperMap3D.Color.fromCssColorString("#00B9FF").withAlpha(0.70));
colorTable.insert(0.40, SuperMap3D.Color.fromCssColorString("#00C4FF").withAlpha(0.70));
colorTable.insert(0.48, SuperMap3D.Color.fromCssColorString("#00A0FF").withAlpha(0.80));
colorTable.insert(0.56, SuperMap3D.Color.fromCssColorString("#9AFF00").withAlpha(0.80));
colorTable.insert(0.60, SuperMap3D.Color.fromCssColorString("#00FF8C").withAlpha(0.80));
colorTable.insert(0.64, SuperMap3D.Color.fromCssColorString("#FFC400").withAlpha(0.80));
colorTable.insert(0.72, SuperMap3D.Color.fromCssColorString("#FF7B00").withAlpha(0.80));
colorTable.insert(0.80, SuperMap3D.Color.fromCssColorString("#0089FF").withAlpha(0.80));
colorTable.insert(0.88, SuperMap3D.Color.fromCssColorString("#0089FF").withAlpha(0.80));
colorTable.insert(0.96, SuperMap3D.Color.fromCssColorString("#005CE6").withAlpha(0.80));
colorTable.insert(1.04, SuperMap3D.Color.fromCssColorString("#005CE6").withAlpha(0.88));
colorTable.insert(1.12, SuperMap3D.Color.fromCssColorString("#005CE6").withAlpha(0.90));
colorTable.insert(1.20, SuperMap3D.Color.fromCssColorString("#005CE6").withAlpha(0.90));
colorTable.insert(1.28, SuperMap3D.Color.fromCssColorString("#005CE6").withAlpha(0.90));
colorTable.insert(1.36, SuperMap3D.Color.fromCssColorString("#005CE6").withAlpha(0.90));
colorTable.insert(1.44, SuperMap3D.Color.fromCssColorString("#005CE6").withAlpha(0.90));
colorTable.insert(1.52, SuperMap3D.Color.fromCssColorString("#005CE6").withAlpha(0.90));
colorTable.insert(1.61, SuperMap3D.Color.fromCssColorString("#005CE6").withAlpha(0.90));
colorTable.insert(10.97198486328125, SuperMap3D.Color.fromCssColorString("#005CE6").withAlpha(1.0));
return colorTable
}
3.4多时序模型瓦片加载效果
如有疑问请参考范例:多时序多要素水场。
(1)如果只在SuperMap iClient3D for WebGL/WebGPU 11.1.1中实现数据可视化,建议使用SuperMap iDesktopX 11.1.1生成时序模型瓦片。
(2)如果在SuperMap iClient3D for WebGL/WebGPU 11.2.0及以上版本中实现数据可视化,SuperMap iDesktopX的版本不受限制。