数据库用的pg
pom引用(我自己是搭建的maven私服):
<dependency>
<groupId>org.kabeja</groupId>
<artifactId>kabeja</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.kabeja</groupId>
<artifactId>kabeja-svg</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
链接:https://pan.baidu.com/s/1LSk9IKS1w0uL5SmUU3FCew
提取码:0b1d
–kabeja离线包下载地址
解析dxf如下:
```java
@Override
public Object uploadDxf(MultipartFile file) {
try {
Parser dxfParser = ParserBuilder.createDefaultParser();
dxfParser.parse(file.getInputStream(), "UTF-8");
DXFDocument doc = dxfParser.getDocument();
Bounds bounds = doc.getBounds();
VectorBox box = new VectorBox();
//包围盒必须是正方形否则进行4096切分是会拉伸变形
Double subX = bounds.getMaximumX()-bounds.getMinimumX();
Double subY = bounds.getMaximumY()-bounds.getMinimumY();
if(subY>subX){
Double minX = (bounds.getMinimumX()+subX/2)-subY/2;
Double maxX = (bounds.getMaximumX()-subX/2)+subY/2;
box.setxMin(minX);
box.setyMin(bounds.getMinimumY());
box.setxMax(maxX);
box.setyMax(bounds.getMaximumY());
}else{
Double minY = (bounds.getMinimumY()+subY/2)-subX/2;
Double maxY = (bounds.getMaximumY()-subY/2)+subX/2;
box.setxMin(bounds.getMinimumX());
box.setyMin(minY);
box.setxMax(bounds.getMaximumX());
box.setyMax(maxY);
}
vectorBoxService.save(box);
Iterator<DXFLayer> dxfLayerIterator = doc.getDXFLayerIterator();
for (Iterator<DXFLayer> it = dxfLayerIterator; it.hasNext(); ) {
DXFLayer dxfLayer = it.next();
VectorLayer vectorLayer = new VectorLayer();
vectorLayer.setName(dxfLayer.getName());
vectorLayerService.save(vectorLayer);
}
List<VectorLayer> vectorLayers = vectorLayerService.list();
Map<String,VectorLayer> vectorLayerMap = vectorLayers.stream().collect(Collectors.toMap(VectorLayer::getName, e -> e));
List<DXFEntity> dxfEntities = DXFUtil.getDXFEntities(doc);
List<VectorTile> vectorTiles = new ArrayList<>();
for (DXFEntity d : dxfEntities) {
if (d instanceof DXFLine) {
//直线
DXFLine line = (DXFLine) d;
VectorTile vectorTile = new VectorTile();
vectorTile.setName(line.getLayerName());
String coordinateWkt = "LINESTRING(" + line.getStartPoint().getX() + " " + line.getStartPoint().getY() + "," +
line.getEndPoint().getX() + " " + line.getEndPoint().getY() +
")";
vectorTile.setGeom(coordinateWkt);
vectorTile.setColor(DXFUtil.getColor(line.getColor()));
vectorTile.setType("LINESTRING");
vectorTile.setLineWidth(line.getLineWeight());
vectorTile.setLayerId(vectorLayerMap.get(line.getLayerName()).getId());
vectorTiles.add(vectorTile);
}
if (d instanceof DXFArc) {
//曲线
DXFArc arc = (DXFArc) d;
VectorTile vectorTile = new VectorTile();
vectorTile.setName(arc.getLayerName());
Point middlePoint = arc.getPointAt(arc.getStartAngle()+arc.getTotalAngle()/2);
String coordinateWkt = "CIRCULARSTRING(" + arc.getStartPoint().getX() + " " + arc.getStartPoint().getY() + "," +
middlePoint.getX() + " " + middlePoint.getY() + " " + "," +
arc.getEndPoint().getX() + " " + arc.getEndPoint().getY() + " " +
")";
vectorTile.setGeom(coordinateWkt);
vectorTile.setColor(DXFUtil.getColor(arc.getColor()));
vectorTile.setType("CIRCULARSTRING");
vectorTile.setLineWidth(arc.getLineWeight());
vectorTile.setLayerId(vectorLayerMap.get(arc.getLayerName()).getId());
vectorTiles.add(vectorTile);
}
if(d instanceof DXFCircle){
//圆或半圆
DXFCircle circle = (DXFCircle) d;
VectorTile vectorTile = new VectorTile();
vectorTile.setName(circle.getLayerName());
Point startPoint = circle.getPointAt(0);
Point topPoint = circle.getPointAt(90);
Point farPoint = circle.getPointAt(180);
Point bottomPoint = circle.getPointAt(270);
Point endPoint = circle.getPointAt(360);
String coordinateWkt = "CIRCULARSTRING(" + startPoint.getX() + " " + startPoint.getY() + "," +
topPoint.getX() + " " + topPoint.getY() + " " + "," +
farPoint.getX() + " " + farPoint.getY() + " " + "," +
bottomPoint.getX() + " " + bottomPoint.getY() + " " + "," +
endPoint.getX() + " " + endPoint.getY() + " " +
")";
vectorTile.setGeom(coordinateWkt);
vectorTile.setColor(DXFUtil.getColor(circle.getColor()));
vectorTile.setType("CIRCLE");
vectorTile.setLineWidth(circle.getLineWeight());
vectorTile.setLayerId(vectorLayerMap.get(circle.getLayerName()).getId());
vectorTiles.add(vectorTile);
}
if(d instanceof DXFPolyline){
//线段
DXFPolyline dxfPolyline = (DXFPolyline) d;
VectorTile vectorTile = new VectorTile();
vectorTile.setName(dxfPolyline.getLayerName());
Iterator<DXFVertex> lineIte = dxfPolyline.getVertexIterator();
List<DXFVertex> lines = new ArrayList<>();
lineIte.forEachRemaining(lines::add);
StringBuilder coordinateWkt = new StringBuilder("LINESTRING(");
for (int i=0; i<lines.size();i++) {
if(Double.isInfinite(lines.get(i).getPoint().getX()) || Double.isInfinite(lines.get(i).getPoint().getY())){
break;
}
coordinateWkt.append(lines.get(i).getPoint().getX()).append(" ").append(lines.get(i).getPoint().getY());
if(i!=(lines.size()-1)){
coordinateWkt.append(" ,");
}
}
coordinateWkt.append(")");
vectorTile.setGeom(coordinateWkt.toString());
vectorTile.setColor(DXFUtil.getColor(dxfPolyline.getColor()));
vectorTile.setType("POLYLINE");
vectorTile.setLineWidth(dxfPolyline.getLineWeight());
vectorTile.setLayerId(vectorLayerMap.get(dxfPolyline.getLayerName()).getId());
vectorTiles.add(vectorTile);
}
if(d instanceof DXFText){
//TODO 文字还有问题欢迎评论区讨论
DXFText dxfText = (DXFText) d;
Font font = new Font("宋体",Font.PLAIN,(int)Math.rint(dxfText.getHeight()));
// FontRenderContext frc = new FontRenderContext(AffineTransform.getRotateInstance(360-dxfText.getRotation(),dxfText.getInsertPoint().getX(),dxfText.getInsertPoint().getY()), false, false);
FontRenderContext frc = new FontRenderContext((AffineTransform)null, false, false);
GlyphVector v = font.createGlyphVector(FontDesignMetrics.getMetrics(font, frc).getFontRenderContext(), dxfText.getText());
Shape shape = v.getOutline();
// Shape shape = v.getGlyphOutline(0,new Double(dxfText.getInsertPoint().getX()).floatValue(),new Double(dxfText.getInsertPoint().getY()).floatValue());
AffineTransform transform = new AffineTransform();
transform.setToRotation(Math.toRadians(180));
transform.setToTranslation(dxfText.getInsertPoint().getX(),dxfText.getInsertPoint().getY());
// shape = transform.createTransformedShape(shape);
PathIterator pathIterator = shape.getPathIterator(transform);
List<Coordinate> path = new ArrayList<>();
List<List<Coordinate>> pathList = new ArrayList<>();
while (!pathIterator.isDone()){
float[] coords = new float[6];
int type = pathIterator.currentSegment(coords);
if(PathIterator.SEG_CLOSE == type){
pathList.add(path);
path = new ArrayList<>();
pathIterator.next();
continue;
}
if(PathIterator.SEG_MOVETO == type){
if(path.size()>0){
pathList.add(path);
}
path = new ArrayList<>();
pathIterator.next();
continue;
}
if(PathIterator.SEG_LINETO == type){
Coordinate coordinate = new Coordinate(coords[0],coords[1]);
path.add(coordinate);
}
if(PathIterator.SEG_CUBICTO == type){
VectorTile vectorTile = new VectorTile();
vectorTile.setName(dxfText.getLayerName());
String coordinateWkt = "CIRCULARSTRING(" + coords[0] + " " + coords[1] + "," +
coords[2] + " " + coords[3] + " " + "," +
coords[4] + " " + coords[5] + " " +
")";
vectorTile.setGeom(coordinateWkt);
vectorTile.setColor(DXFUtil.getColor(dxfText.getColor()));
vectorTile.setType("TEXT");
vectorTile.setRotation(dxfText.getRotation());
vectorTile.setLayerId(vectorLayerMap.get(dxfText.getLayerName()).getId());
vectorTiles.add(vectorTile);
path = new ArrayList<>();
pathIterator.next();
continue;
}
if(PathIterator.SEG_QUADTO == type){
Coordinate c1 = new Coordinate(coords[0],coords[1]);
Coordinate c2 = new Coordinate(coords[2],coords[3]);
path.add(c1);
path.add(c2);
}
pathIterator.next();
}
for(List<Coordinate> p:pathList){
VectorTile vectorTile = new VectorTile();
vectorTile.setName(dxfText.getLayerName());
StringBuilder coordinateWkt = new StringBuilder("LINESTRING(");
for (int i=0; i<p.size();i++) {
coordinateWkt.append(p.get(i).getX()).append(" ").append(p.get(i).getY());
if(i!=(p.size()-1)){
coordinateWkt.append(" ,");
}
}
coordinateWkt.append(")");
vectorTile.setColor(DXFUtil.getColor(dxfText.getColor()));
vectorTile.setGeom(coordinateWkt.toString());
vectorTile.setType("TEXT");
vectorTile.setRotation(dxfText.getRotation());
vectorTile.setLayerId(vectorLayerMap.get(dxfText.getLayerName()).getId());
vectorTiles.add(vectorTile);
}
}
}
this.saveBatch(vectorTiles);
}catch (Exception e){
e.printStackTrace();
}
return null;
}
查询矢量切图代码如下:
@Override
public byte[] selectVectorTile(Integer x, Integer y, Integer z, List<Long> layerIds) {
VectorBox vectorBox = vectorBoxService.lambdaQuery().one();
VectorTile vTile=this.baseMapper.selectTile(x,y,z,vectorBox.getxMin(),vectorBox.getyMin(),vectorBox.getxMax(),vectorBox.getyMax(),layerIds);
return vTile.getTile();
}
查询SQL如下:
SELECT
ST_AsMVT (a, 'points',4096,'geom') As tile
FROM
(
SELECT t.id,
st_asmvtgeom (
(case st_geometrytype(t.geom)
when 'ST_CircularString'
then st_curvetoline(t.geom)
else t.geom
end),
ST_TileEnvelope( #{z}, #{x}, #{y},
st_makeenvelope (
#{xMin} ,
#{yMin} ,
#{xMax} ,
#{yMax} , 4775)),
4096,
64,
true
) AS geom,
t.color AS color
FROM
vector_tile t
<where>
<if test="layerIds !=null ">
and t.layer_id in
<foreach collection="layerIds" separator="," open="(" close=")" item="item">
#{item}
</foreach>
</if>
</where>
) AS a where a.geom is not null
前端openlayer渲染
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<!--<link rel="stylesheet" href="https://openlayers.org/en/v4.6.4/css/ol.css" type="text/css">-->
<!-- The line below is only needed for old environments like Internet Explorer and Android 4.x -->
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL"></script>
<link href="https://cdn.bootcdn.net/ajax/libs/openlayers/4.6.5/ol-debug.css" rel="stylesheet">
<script src="https://cdn.bootcdn.net/ajax/libs/openlayers/4.6.5/ol-debug.js"></script>
<style>
html, body, #map {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
background-color: black;
}
</style>
</head>
<body>
<div id="map">
</div>
</body>
<script>
const projection = new ol.proj.Projection({
code: 'EPSG:4775',
units: 'degrees',
});
const defaultView = new ol.View({
projection: projection,
center: [114.15, 22.65],
//new ol.proj.fromLonLat([114.15, 22.65]),
zoom: 2
//旋转
// rotation: Math.PI/3
});
const styleFunction = function (feature) {
const color = feature.get("color");
const width = feature.get("linewidth")/100;
console.log(width)
const type = feature.get("type");
const text = feature.get("text");
const zoom = map.getView().getZoom();
const textScale = calculateTextScale(zoom);
const rotation = (360-feature.get("rotation"))*(Math.PI/180);
if(type=="TEXT"){
const retStyle = new ol.style.Style({
text: new ol.style.Text({
text: text,
placement: 'point',
rotation: rotation,
rotateWithView:true,
font: '14px Microsoft YaHei',
fill: new ol.style.Fill({
color: color
}),
textAlign: 'center',
textBaseline: 'middle',
scale: textScale // 根据地图缩放级别设置文字缩放比例
})
});
return retStyle;
}else{
const retStyle = new ol.style.Style({
stroke: new ol.style.Stroke({
color: color,
// width: width
})
});
return retStyle;
}
};
const vectorLayer = new ol.layer.VectorTile({
projection: projection,
source: new ol.source.VectorTile({
format: new ol.format.MVT(),
projection: projection,
tilePixelRatio: 1,
url: 'http://127.0.0.1/zgis/vector/tile/{z}/{x}/{y}'
}),
style: styleFunction,
});
const layers = [
new ol.layer.Tile({
source: new ol.source.OSM()
})
];
layers.push(vectorLayer);
const map = new ol.Map({
layers: layers,
target: 'map',
view: defaultView
});
</script>
</html>
目前文字和填充还有些问题,其他可正常支持。