唯杰地图 logo唯杰地图
VJMAP
EN

组合 / 拆分 / 导出

vjmap-service/references/api/05-compose-export.md 13.8 KB325 行
原文

分类代号:C.5 本章共 6 个接口

把多张 DWG 组合成一张、把一张大图按图框 / 图层拆成多张、把图纸导出为 PDF / DXF 或离线瓦片包——这一章就是"图纸经纪人"。

共同特点:这 6 个接口都相对重,后端会真实创建新图档 / 新文件。测试环境请用临时 mapid,不要对生产图做实验。


快速索引

序号 SDK 方法 URL
36 cmd_compose_new_map / cmdComposeNewMap POST /api/v1/map/cmd/composeNewMap/_null/v1
37 cmd_split_map / cmdSplitMap POST /api/v1/map/cmd/cmdSplitMap/_null/v1
38 cmd_export_layout / cmdExportLayout POST /api/v1/map/cmd/exportLayout/_null/v1
39 cmd_export_pdf / cmdExportPdf POST /api/v1/map/cmd/exportPdf/{mapid}/{version}
40 cmd_export_dxf / cmdExportDxf POST /api/v1/map/cmd/exportDxf/{mapid}/{version}
41 cmd_save_offline_tile_db / cmdSaveOfflineTileDb POST /api/v1/map/cmd/saveOfflineTileDb/_null/v1

36 · 组合新地图 composeNewMap

把多张已有 DWG(可各自裁剪范围、四参数变换、按图层过滤)拼成一张新图。

⚠️ 参数是后缀编号风格,不是 maps 数组:第 1 张图用无后缀键(mapid、clipBounds…),第 2 张起加序号(mapid2、clipBounds2…),总数由 count 声明。

请求参数

字段 类型 说明
count int 参与组合的源图数,默认 1
mapid{i} / version{i} string 第 i 张源图(i=1 无后缀,i≥2 后缀 2、3…)
clipBounds{i} string 可选:裁剪范围 [x1,y1,x2,y2]
selByCrossing{i} bool 裁剪时是否含相交实体(默认 false)
layers{i} string 可选:参与的图层名 JSON 数组,如 ["0","TEXT"]
fourParameter{i} string 可选四参数变换 [xOff,yOff,scale,rotRad]
isInverseFourParamter{i} string "true" 反向应用四参数(注意后端拼写 Paramter)
layerPrefix{i} / layerSuffix{i} string 输出图层名加前/后缀
savefilename{i} string 可选:该源图裁剪中间结果文件名,缺省自动生成
purge{i} bool 先对源图 purge 再组合(默认 false)
isFullExtent{i} bool 裁剪结果范围取全图(默认 false)
isRenameBlockNameIfExist bool 块名冲突时自动重命名(默认 true)
subfrom / subdependencies string 协同图元数据的直接来源/依赖(高级)

响应

成功(实采双图组合):

{ "status": true, "fileid": "p2de970c8c9a", "mapfrom": "…", "mapdependencies": "…" }
  • fileid 是组合产物文件({fileid}.dwg,deleteMapFile 可清理)——不是逐图回写数组。
  • mapfrom 不是 subfrom 的回显——是后端合成的源规格串("{mapid}&&{ver}&&{clipbounds}&&0&&…&&1&&" 形态);mapdependencies 也不回显 subdependencies(传了仍返空串)。两字段当只读回执看,别当参数回显校验。
  • count 与实际参数不一致(如 count=2 缺 mapid2)→ HTTP 200 + body 级错误 {error:"file is not exist, ", status:false},不抛异常——调用方必须自查 status。
  • isInverseFourParamter(后端错拼 Paramter)端到端可用:fourParameter + isInverseFourParamter:true 组合正常出图。

失败(实采:源文件不存在 / count 与实参不符):

{
  "error": "file is not exist, ",
  "status": false
}

Python

svc.cmd_compose_new_map(
    count=2,
    mapid="part_a", version="v1",
    clipBounds="[0,0,1000,1000]", layers='["0"]',
    mapid2="part_b", version2="v1",
    fourParameter2="[1000,0,1,0]",   # 第二张图平移 1000
)

Node.js

await svc.cmdComposeNewMap({
  count: 2,
  mapid: 'part_a', version: 'v1', clipBounds: '[0,0,1000,1000]',
  mapid2: 'part_b', version2: 'v1', fourParameter2: '[1000,0,1,0]',
});

37 · 拆分子图 cmdSplitMap

按一组 bbox 把一张大图拆成多张小图。

请求参数

字段 类型 说明
mapid / version string 源图(二选一:fileid 直接给 dwg 文件名)
fileid string 源 dwg 文件名,省略时用当前打开的图档
clipBounds array 必填:bbox 列表 [["x1","y1","x2","y2"], ...],每框出一张子图。元素也接受逗号串形式 ["x1,y1,x2,y2"]
isFullExtent bool 子图范围取全图(默认 false)
method string cloneObjects(默认,逐实体克隆)/ cloneDb / cloneMap
accessKey / secretKey string 访问受保护图时必填

响应

成功:{ "fileids": ["a1.dwg", "a2.dwg", ...] }(每个 clipBounds 一个新 fileid;成功时无 status 字段,判失败看 error/status:false)
失败(实采:未给 clipBounds):

{ "error": "clipBounds is empty" }

⚠️ fileids 可能回含源文件名(实采 2026-09-20):clipBounds 覆盖源图数据范围时,拆分出的子图可以直接就是源 dwg——响应为 {"fileids":["<mapid>.dwg"]}。批量 deleteMapFile(fileids) 清理会把地图底图 dwg 一起删掉(mapfiles/<mapid>.dwg 消失,之后 compose/exportLayout 等文件型命令全报 file is not exist,但 db 驱动的 openMap/query/渲染不受影响)。清理时务必排除源文件名:fileids.filter(f => f !== mapid + '.dwg')。


38 · 导出布局为 DWG exportLayout

从 DWG 的布局空间(paper space)单独导出一张新 DWG。CAD 里经常一个文件多个布局(A3、A2、首页),这个接口能一次性把某个布局变成独立图档。

请求参数

字段 类型 说明
mapid / version string 源图(version 缺省取最新版)
layoutIndex int 布局序号(0 起)
layoutName string 或直接用布局名(layoutIndex 优先,二者都给时按 index)
accessKey / secretKey string 访问受保护图时必填

新图 mapid 由后端根据请求参数 hash 自动生成(p 前缀),不接受 newMapid / newVersion 请求参数。

响应(实采:sys_zp/v1, layoutIndex=0)

{
  "fileid": "pf68817b9655",
  "status": true
}

fileid 指向后端缓存里的新 DWG 文件,可以接着调用 open_map(mapid=...) 打开,或用 exportDxf / exportPdf 进一步出图。

⚠️ 不存在/bogus mapid 是 body 级错误:{status:false, error:'File access error: "…/mapfiles/<mapid>"'},HTTP 200 不抛异常——调用方须自查 status。

Python

res = svc.cmd_export_layout(mapid="sys_zp", version="v1", layoutIndex=0)
assert res["status"]
print(res["fileid"])  # 'pf68817b9655'

39 · 导出 PDF exportPdf

把当前图档通过 ODA PDF 导出器输出为 PDF。参数是 ODA 导出选项,不是 bbox 截图式参数(不支持 bounds/width/height/scale/outName)。

请求参数

字段 类型 默认 说明
pageWidth / pageHeight number — 纸张尺寸(mm),两者都给出才生效
pageLeftMargin / pageRightMargin / pageTopMargin / pageBottomMargin number 0 页边距(配合 pageWidth/pageHeight)
bZoomToExtents bool true 内容缩放到纸张范围
bActiveLayout bool true 只导出当前活动布局;false 导出全部布局
bUsePaperFromOptions bool — 使用图纸自带页面设置
geomDPI / colorImagesDPI / bwImagesDPI int — 几何/彩色图/黑白图 DPI
isBlackWhiteMode / isGrayMode / isBwModeBlock / isUseGrayPolicy bool false 黑白/灰度输出
bEmbededTTF / bEmbededOptimizedTTF bool false 嵌入 TTF 字体
bTTFAsAGeometry / bSHXAsAGeometry bool true 字体转几何
bSearchableTTF / bSearchableSHX bool — 文本可搜索
bEnableLayersSupport / bIncludeOffLayers bool — PDF 图层支持 / 含关闭图层
bUseHiddenLineAlgo / bUseSimpleGeomOpt bool — 隐藏线算法 / 几何优化
bHyperlinks / bLinearized / bMeasuring / bExtentsBoundingBox bool — 超链接 / 线性化 / 测量 / extents 边框
bEncoded / bASCIIhexEncoded bool — 内容流编码
nSolidHatchExpType / bOtherHatchExpTypekBitmap int/bool — 填充导出类型
title / author / creator / producer string — PDF 文档元信息
pdfPath string 自动 输出路径(缺省写入 download 目录、按参数 hash 命名)
debugLog / stripProxyOnRetry bool false/true 调试日志 / 重试时剥离代理实体
lineWeight number — 线宽系数

图纸内容由 URL 中的 {mapid}/{version} 选定的已打开图档决定。

⚠️ 同参数重复调用返回不同的 path 文件名(download/<hash1>.pdf → download/<hash2>.pdf),但第二次明显更快(565ms→7ms)——后端内部有加速,但不要假设 path 相同即缓存复用,要复用文件请存好首次返回的 path。

响应(实采:sys_zp/v1)

{
  "path": "download/d5f939154c.pdf",
  "status": true
}

完整下载 URL 是 http://127.0.0.1:27660/{path}?token=<jwt>。

Python

res = svc.cmd_export_pdf(
    mapid="sys_zp", version="v1",
    pageWidth=297, pageHeight=210,
)
url = svc.base_gateway() + res["path"] + f"?token={svc.token}"

Node.js

const res = await svc.cmdExportPdf({
  mapid: 'sys_zp', version: 'v1',
  pageWidth: 297, pageHeight: 210,
});
const url = `${svc.baseGateway()}${res.path}?token=${svc.token}`;

40 · 导出 DXF exportDxf

把当前图档整体导出为 DXF 文件(不支持裁剪/选层——导出的是整个 database)。

请求参数

⚠️ cmd 路由对空 JSON body 的 POST 回 HTTP 500 param error,本接口同样适用。SDK 已处理:除 mapid/version 外没有其它参数时 cmdExportDxf / cmdExportPdf 改走 GET(GET 不校验),按缺省参数导出;手写 REST 时要么 GET,要么 POST 至少带一个字段(如 cadVersion:"*")。

字段 类型 说明
filename string 输出文件名(自动补 .dxf;缺省用源图名 + _.dxf)
cadVersion string 目标 CAD 版本:2000/2004/2007/2010/2013/2018;* = 沿用源图版本

响应

成功:{ "status": true, "fileid": "xxx.dxf" }(fileid 是后端 mapfiles 目录里的文件名)
失败(实采:当前地图没有可导出图元):

{
  "error": "Invalid Symbol Table name",
  "status": false
}

Python

res = svc.cmd_export_dxf(
    mapid="sys_zp", version="v1",
    filename="sys_zp_out",   # 实际写 sys_zp_out.dxf
    cadVersion="2018",
)

41 · 离线瓦片包 saveOfflineTileDb

把指定地图已有的栅格/矢量瓦片库按 zoom 范围抽成一个新的离线 sqlite 包(offlinetiles/<id>.db)。注意:它复制既有瓦片,不切新瓦片——源图需先生成过瓦片。

请求参数

字段 类型 说明
mapid / version string 源图
layers string 必填:db_source 中的 style 表名(s<hex> 形态,即瓦片 URL /map/tile/{mapid}/{ver}/{sXXX}/… 里的那段),逗号分隔
rasterMinZoom / rasterMaxZoom int 栅格瓦片 zoom 区间(max > min 才导栅格)
vectorMinZoom / vectorMaxZoom int 矢量瓦片 zoom 区间(max > min 才导矢量)

输出文件名后端自动生成(_yyyyMMddhhmmss_NNN),不接受 outName/bounds/ismvt/minzoom/maxzoom。

响应

成功:{ "status": true, "dbfilename": "<绝对路径>.db" }
失败(实采:缺 layers 或 zoom 区间为空):

{ "error": "param error" }

⚠️ layers 的值被原样插进后端 SQL(insert into <layers> select * from db_source.<layers> where zoom_level >= …)。给了不存在的表名时返回的是 HTTP 200 + body 级 { "error": "exec sql error: insert into …" } 而非 param error——调用方要检查 r.error,不能只看 status/dbfilename。文档旧示例里的 layers="s_default" 就是一条 SQL 错误;正确值是真实 style 表名(如 s6d04d896e)。

Python

res = svc.cmd_save_offline_tile_db(
    mapid="sys_zp", version="v1",
    layers="s6d04d896e",  # 用瓦片 URL 里的 style 表名(s<hex>),不是 "s_default"
    rasterMinZoom=0, rasterMaxZoom=7,
    vectorMinZoom=0, vectorMaxZoom=7,
)

组合示例:DWG → PDF 一把梭

# 1. 上传并打开 DWG
up = svc.upload_map("project.dwg")
svc.open_map(
    mapid="proj", version="v1",
    fileid=up["fileid"], uploadname=up["uploadname"],
    mapopenway=vjmap.MapOpenWay.GeomRender,
)

# 2. 导出第 0 号布局(新图 mapid 由后端 hash 生成,看返回 fileid)
lay = svc.cmd_export_layout(mapid="proj", version="v1", layoutIndex=0)

# 3. 打开刚生成的布局图并导 PDF(fileid=12 位 hash,uploadname=<fileid>.dwg)
svc.open_map(mapid="proj_layout0", version="v1",
             fileid=lay["fileid"], uploadname=lay["fileid"] + ".dwg",
             mapopenway=vjmap.MapOpenWay.GeomRender)
pdf = svc.cmd_export_pdf(mapid="proj_layout0", version="v1",
                          pageWidth=297, pageHeight=210)
print(svc.base_gateway() + pdf["path"])