---
title: Map Service REST API
source: https://vjmap.com/en/guide/restinterface.html
---

# Map Service REST API

## Introduction

The map service uses REST APIs. Frontend development can use the `Service` class in the `vjmap` JS SDK to call the service. To get map metadata, use:

```js
let svc = new vjmap.Service(env.serviceUrl, env.accessToken);
let res = await svc.metadata("sys_zp" /*map id*/, "v1" /*map version, empty for latest*/);
console.log(res)
```
When this code runs in the browser, F12 Network shows an `http` request to the map service.

![image-20230524140958184](https://vjmap.com/blogimages/image-20230524140958184.png)

For backend calls, send the same `http` request.

Test in Postman:
![image-20230524141331530](https://vjmap.com/blogimages/image-20230524141331530.png)

The map service REST API returns correct results when called from Postman.

Note: All service calls must use `application/json` and include the `Token` header (or `token=xxxx` query parameter for GET requests) for authentication. To open password-protected maps without a password prompt, add `secretKey` or `accessKey` in the request header. (This is not repeated in examples below; remember to add Token in practice.)

## Common Service APIs

(For brevity, only relative URLs are shown. E.g. `https://vjmap.com/server/api/v1/map/cmd/metadata/sys_zp/v1` is abbreviated as `/api/v1/map/cmd/metadata/sys_zp/v1`)

### Upload Drawing

|      |                     |
|:-----|:--------------------|
| Service URL | /api/v1/map/uploads |
| Request Type | Post                |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| fileToUpload | File binary content ||

### Create or Open Drawing
|      |                     |
|:-----|:--------------------|
| Service URL | /api/v1/map/openmap/{mapid} |
| Request Type | Get or Post                |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| version | Map version | |
| layer | Style |   |
| geom | Open with geometry render mode |   true |
| fileid | File unique ID. Pass fileid when opening map for first time |   cfbe8dc085fb |
| imageLeft | Image top-left x. Valid when opening image type for first time |  undefined |
| imageTop | Image top-left y. Valid when opening image type for first time |   |
| imageResolution | Image resolution. Valid when opening image type for first time |  |
| uploadname | Upload filename |   zp.dwg |
| mapfrom | Map source (for collaborative drawings) |   |
| mapdependencies | Map dependencies (for collaborative drawings) |   |
| subfrom | Map source for sub-items (for collaborative drawings) |   |
| subdependencies | Map dependencies for sub-items (for collaborative drawings) |   |
| stylename | Style layer name |   |
| layeron | Layer indices to turn on, e.g. [0,1,3] |   |
| layeroff | Layer indices to turn off, e.g. [2,4] |    |
| clipbounds | Map clip bounds, e.g. [x1,y1,x2,y2] |   |
| bkcolor | Background color |  0 |
| lineweight | Line weight, e.g. [1,1,1,1,0] |   |
| expression | Style expression |   |
| secretKey | Set when encrypting map on first creation |   |
| accessKey | Access key when map has password  |   |

Note: When setting a password on first upload, set `secretKey`. Compute as: MD5(MD5(MD5(MD5(password)))), take first 16 chars.

Node.js backend upload and create/open example

```js

// app.js
const fs = require('fs')
const FormData = require('form-data')
const axios = require('axios')
const prompt = require('prompt');

(async ()=>{
    const defaultServiceUrl = 'https://vjmap.com/server/api/v1';
    const defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJJRCI6MiwiVXNlcm5hbWUiOiJhZG1pbjEiLCJOaWNrTmFtZSI6ImFkbWluMSIsIkF1dGhvcml0eUlkIjoiYWRtaW4iLCJCdWZmZXJUaW1lIjo4NjQwMCwiZXhwIjo0ODEzMjY3NjM3LCJpc3MiOiJ2am1hcCIsIm5iZiI6MTY1OTY2NjYzN30.cDXCH2ElTzU2sQU36SNHWoTYTAc4wEkVIXmBAIzWh6M';

    let formData = new FormData();
    let { filepath } =  await prompt.get('filepath'); // Enter file path to upload
    if (!filepath) return;
    let file = fs.createReadStream(filepath)   
    formData.append('fileToUpload', file);
    
    let len = await new Promise((resolve, reject) => {
      return formData.getLength((err, length) => (err ? reject(err) : resolve(length)));
    });
    let res = await axios({
        url: `${defaultServiceUrl}/map/uploads?token=${defaultAccessToken}`,
        method: 'POST',
        data: formData,
        headers: {
          ...formData.getHeaders(),
          'Content-Length': len,  
        },
    });
    /*
    {
        fileid: 'c036d8ca23eb',
        mapid: 'c036d8ca23eb', // mapid is suggested; if previously uploaded/opened, use that mapid
        uploadname: 'base1.dwg'
    }
    */
    console.log(res.data);

    // Upload sends file to server. On first open, pass fileid to openMap and assign mapid. Afterwards open by mapid.
    let { mapid } =  await prompt.get('mapid'); // Enter mapid
    if (!mapid) {
        // If no mapid, use default from upload response
        mapid = res.data.mapid;
    }
    let url = `${defaultServiceUrl}/map/openmap/${res.data.mapid}?version=&layer=&geom=true&fileid=${res.data.fileid}&uploadname=${res.data.uploadname}&mapfrom=&mapdependencies=&subfrom=&subdependencies=&stylename=&layeron=&layeroff=&clipbounds=&bkcolor=0&lineweight=&expression=`;
    // To set password, e.g. 123456
    //  MD5 four times, strMd5 is MD5 helper, implement as needed
    // let secretKey =  strMd5(strMd5(strMd5(strMd5("123456")))).substr(0, 16);
    // url += "&secretKey=" + secretKey
    let result = await axios({
        url: url,
        method: 'GET',
        headers: {
          token: defaultAccessToken,  
        },
    });
    console.log(result)
})();


```


To create drawings from parameters in the backend, generate a JSON object from the entity objects, serialize to string (or base64), and pass as `fileid`.
Node.js parameter-based drawing creation:
```js
const axios = require("axios");


(async () => {
  const defaultServiceUrl = "https://vjmap.com/server/api/v1";
  const defaultAccessToken =
    "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJJRCI6MiwiVXNlcm5hbWUiOiJhZG1pbjEiLCJOaWNrTmFtZSI6ImFkbWluMSIsIkF1dGhvcml0eUlkIjoiYWRtaW4iLCJCdWZmZXJUaW1lIjo4NjQwMCwiZXhwIjo0ODEzMjY3NjM3LCJpc3MiOiJ2am1hcCIsIm5iZiI6MTY1OTY2NjYzN30.cDXCH2ElTzU2sQU36SNHWoTYTAc4wEkVIXmBAIzWh6M";

  let doc = {};
  let entitys = [];
  // See official docs https://vjmap.com/doc/Class_DbDocument.html for parameters
  entitys.push({
    typename: "DbLine",
    start: [14, 0],
    end: [14, 15],
    colorIndex: 1,
  });
  entitys.push({
    typename: "DbCircle",
    center: [14, 7.5],
    radius: 1.83,
    color: 0xff0000,
  });
  entitys.push({
    typename: "DbText",
    position: [14, 16],
    contents: "Basketball court diagram",
    colorIndex: 1,
    horizontalMode: 4,
    height: 1,
  });
  doc.entitys = entitys;

  // Base64 encoding also works but not recommended; JSON string is fine
  //var bytes = new Buffer(JSON.stringify(doc));
  //var base64 = "data:application/dwg;base64," + bytes.toString('base64')// let fileid = base64;

    let fileid = JSON.stringify(doc);
  // Upload sends file to server. On first open, pass fileid to openMap and assign mapid. Afterwards open by mapid.
  let mapid = "mybackendmap"
  let url = `${defaultServiceUrl}/map/updatemap/${mapid}`;
  let data = {
    fileid: fileid,
    clipbounds: '',
    bkcolor: 0,
    geom: true,
    uploadname: ""
  }
  // To set password (e.g. 123456): MD5 four times; implement strMd5 as needed
  // let secretKey =  strMd5(strMd5(strMd5(strMd5("123456")))).substr(0, 16);
  // url += "&secretKey=" + secretKey
  let result = await axios({
    url: url,
    method: "POST",
    headers: {
      token: defaultAccessToken,
    },
    data
  });
  console.log(result);
})();


```

Result:

![image-20230524172844505](https://vjmap.com/blogimages/image-20230524172844505.png)

### Check If File Already Uploaded

|      |                     |
|:-----|:--------------------|
| Service URL | api/v1/map/mapfile |
| Request Type | Get                |
| Service Description | Check if file exists on server before upload; if so return fileid without uploading. Can be skipped in practice.                |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| md5 | File MD5 value |fbe8dc085fbcdac502c640cf2dd8065c|

Node.js implementation for file MD5 (other backends can adapt):
```js
import SparkMD5 = require("spark-md5");
/**
     * Get file MD5 value
     * @param file
     * @return {Promise<any>}
     */
    function fileMd5(file: File): Promise<any> {
        return new Promise((resolve, reject) => {
            const blobSlice =
                // @ts-ignore
                File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
            const chunkSize = 2097152; // Read in chunks of 2MB
            const chunks = Math.ceil(file.size / chunkSize);
            let currentChunk = 0;
            const spark = new SparkMD5.ArrayBuffer();
            const fileReader = new FileReader();

            fileReader.onload = function(e) {
                // @ts-ignore
                spark.append(e.target.result); // Append array buffer
                currentChunk++;

                if (currentChunk < chunks) {
                    loadNext();
                } else {
                    var md5 = spark.end();
                    resolve(md5);
                }
            };

            fileReader.onerror = function() {
                reject("file reader error");
            };

            function loadNext() {
                var start = currentChunk * chunkSize;
                var end = start + chunkSize >= file.size ? file.size : start + chunkSize;
                fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
            }

            loadNext();
        });
    }
```

### Update Drawing
|      |                     |
|:-----|:--------------------|
| Service URL | /api/v1/map/updatemap/{mapid} |
| Request Type | Get or Post                |

Same parameters as `Create or Open Drawing`


### Raster Tile URL

|      |                     |
|:-----|:--------------------|
| Service URL | api/v1/map/tile/{mapid}/{version}/{stylename}/{zoom}/{x}/{y} |
| Request Type | Get                |
| Service Description | mapid: map id; version: version; stylename: style name; zoom: level; x,y: tile column/row            |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| tag | fileid ||

### Vector Tile URL

|      |                     |
|:-----|:--------------------|
| Service URL | api/v1/map/tile/{mapid}/{version}/{stylename}/{zoom}/{x}/{y}.mvt |
| Request Type | Get                |
| Service Description | mapid: map id; version: version; stylename: style name; zoom: level; x,y: tile column/row            |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| tag | fileid ||

### Execute Map Command

|      |                     |
|:-----|:--------------------|
| Service URL | api/v1/map/cmd/${cmdname}/${mapid}/${version}|
| Request Type | Get or Post               |
| Service Description | cmdname: command name; mapid: map id; version: version       |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| Parameters vary by command name |  ||

### Get Map Metadata

|      |                     |
|:-----|:--------------------|
| Service URL | api/v1/map/cmd/metadata/${mapid}/${version}|
| Request Type | Get or Post               |
| Service Description | mapid: map id; version: version       |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| geom | Whether geometry rendering ||

### Update Map Metadata

|      |                     |
|:-----|:--------------------|
| Service URL | api/v1/map/cmd/updateMetadata/${mapid}/${version}|
| Request Type | Get or Post               |
| Service Description | mapid: map id; version: version       |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| Metadata key | Value for the metadata key ||

### Proactively Close Open Map

|      |                     |
|:-----|:--------------------|
| Service URL | api/v1/map/cmd/closemap/${mapid}/${version}|
| Request Type | Get or Post               |
| Service Description | mapid: map id; version: version       |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| (none) | (none) ||


### Get Map List

|      |                     |
|:-----|:--------------------|
| Service URL | api/v1/map/cmd/listmaps/${mapid}/${version}|
| Request Type | Get or Post               |
| Service Description | mapid: map id (empty = get all); pass map ID array to get specified maps; use pagination e.g. {curPage: 1, pageCount: 10}; version: version (empty = latest, * = all versions) |


|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| mapIds | When mapid is empty, specify map ID array to query ||

### Query Entities

|      |                     |
|:-----|:--------------------|
| Service URL | api/v1/map/cmd/queryFeatures/${mapid}/${version}|
| Request Type | Get or Post               |
| Service Description | mapid: map id; version: version |


|  Request Parameter | Parameter Description    | Parameter Example                                                                                                |
|:-----|:--------|:----------------------------------------------------------------------------------------------------|
| querytype | Query type: "condition", "rect", "point", "expresion" | condition                                                                                           |
| beginpos | Record start position | 0                                                                                                   |
| bounds | Bounds | ""                                                                                                  |
| condition | Query condition | layerindex = 0                                                                                      |
| fields | Comma-separated field list to return, e.g. "name,objectid" |                                                                                                     |
| geom | Whether geometry query | true                                                                                                |
| includegeom | Return geometry: when realgeom is false, if count>1 returns bounding rect per entity, if count=1 returns real GeoJSON; when realgeom is true returns GeoJSON per entity | true                                                                                                |
| isContains  | Contain vs intersect: true=contain, false=intersect (default false). Used when bounds is set | false                                                                                               |
| layername  | Style name (required). Use stylename from createMapStyle, e.g. api/v1/map/cmd/createMapStyle/yourMapid/v1?geom=true&token=xxx |
|maxReturnCount| Max records to return | 50000                                                                                               |
| realgeom  | Return real entity geometry GeoJSON. Used with includegeom | true                                                                                                |
| expr | Expression |                                                                                                     |
| x | Point query x |                                                                                                     |
| y | Point query y |                                                                                                     |
| pixelsize | Point query pixel size |                                                                                                     |
| zoom | Current zoom level | 1                                                                                                   |
| toMapCoordinate | By default query returns Mercator; result is converted to CAD. Set true to return CAD coordinates directly. |                                                                                                     |

Relevant SDK query source in JS:
```js

/**
 * Query entity parameters
 */
export interface IQueryBaseFeatures {
    /** Current zoom level. */
    zoom?: number;
    /** Map ID (empty = current map). */
    mapid?: string;
    /** Map version (empty = current). */
    version?: string;
    /** Layer name (empty = current map layer). */
    layer?: string;
    /** Max records to return. */
    limit?: number;
    /** Comma-separated field list to return, e.g. "name,objectid" */
    fields?: string;
    /** Whether geometry query. */
    geom?: boolean;
    /** GeoJSON simplify tolerance in Mercator; 0 = no simplify. */
    simplifyTolerance?: boolean;
    /** Enable cache (for in-memory maps). */
    useCache?: boolean;
    /** By default returns Mercator; set true to return CAD coordinates. */
    toMapCoordinate?: boolean;
}

/**
 * Point query entity parameters
 */
export interface IPointQueryFeatures extends IQueryBaseFeatures {
    /** Query X. */
    x: number;
    /** Query Y. */
    y: number;
    /** Pixel size. */
    pixelsize?: number;
    /** Condition. */
    condition?: string;
    /** Max geometry bytes to return. */
    maxGeomBytesSize?: number;
    /** Geo length per pixel; if set, overrides zoom-based calculation. */
    pixelToGeoLength?: number;
}

/**
 * Rect query entity parameters
 */
export interface IRectQueryFeatures extends IQueryBaseFeatures {
    /** X1 (omit x1,y1,x2,y2 to query full map). */
    x1?: number;
    /** Y1. */
    y1?: number;
    /** X2. */
    x2?: number;
    /** Y2. */
    y2?: number;
    /** Condition. */
    condition?: string;
    /** Max geometry bytes to return. */
    maxGeomBytesSize?: number;
}

/**
 * Expression query entity parameters
 */
export interface IExprQueryFeatures extends IQueryBaseFeatures {
    /** Expression. */
    expr: string;
    /** Record start position. */
    beginpos?: number;
}

/**
 * Condition query entity parameters
 */
export interface IConditionQueryFeatures extends IQueryBaseFeatures {
    /** Condition. */
    condition: string;
    /** Bounds. */
    bounds?: [number,number,number,number];
    /** Record start position. */
    beginpos?: number;
    /** Include geometry; when realgeom false, multiple results get bbox only, single gets GeoJSON; when realgeom true each gets GeoJSON. */
    includegeom?: boolean;
    /** Return real entity GeoJSON; used with includegeom. */
    realgeom?: boolean;
    /** Contain (true) vs intersect (false) when bounds set; default false. */
    isContains?: boolean;
}
    /**
     * Point query entities
     * @param param Parameters
     * @param cb Callback for each point in result; null = default handling
     */
    async pointQueryFeature(param: IPointQueryFeatures, cb?: (point: [number, number]) => [number, number] | null | undefined): Promise<any> {
        const res = await this.execCommand(
            "queryFeatures",
            {
                querytype: "point",
                zoom: param.zoom ?? 1,
                pixelToGeoLength: param.pixelToGeoLength ?? undefined,
                layername: param?.layer ?? this._cur_map_param?.layer,
                x: param.x,
                y: param.y,
                pixelsize: param.pixelsize ?? 5,
                condition: param.condition ?? undefined,
                maxReturnCount: param.limit ?? undefined,
                maxGeomBytesSize: param.maxGeomBytesSize ?? undefined,
                fields: param.fields ?? "",
                geom: param.geom ?? undefined,
                simplifyTolerance: param.simplifyTolerance ?? undefined,
                useCache: param.useCache,
                toMapCoordinate: param.toMapCoordinate,
            },
            param.mapid,
            param.version
        );
        return this._processQueryResult(res, cb);
    }

    /**
     * Rect query entities
     * @param param Parameters
     * @param cb Callback for each point; null = default handling
     */
    async rectQueryFeature(param: IRectQueryFeatures, cb?: (point: [number, number]) => [number, number] | null | undefined): Promise<any> {
        const res = await this.execCommand(
            "queryFeatures",
            {
                querytype: "rect",
                zoom: param.zoom ?? 1,
                layername: param?.layer ?? this._cur_map_param?.layer,
                x1: param.x1,
                y1: param.y1,
                x2: param.x2,
                y2: param.y2,
                condition: param.condition ?? undefined,
                maxReturnCount: param.limit ?? undefined,
                maxGeomBytesSize: param.maxGeomBytesSize ?? undefined,
                fields: param.fields ?? "",
                geom: param.geom ?? undefined,
                simplifyTolerance: param.simplifyTolerance ?? undefined,
                useCache: param.useCache,
                toMapCoordinate: param.toMapCoordinate,
            },
            param.mapid,
            param.version
        );
        return this._processQueryResult(res, cb);
    }

    /**
     * Expression query entities
     * @param param Parameters
     * @param cb Callback for each point; null = default handling
     */
    async exprQueryFeature(param: IExprQueryFeatures, cb?: (point: [number, number]) => [number, number] | null | undefined): Promise<any> {
        const res = await this.execCommand(
            "queryFeatures",
            {
                querytype: "expresion",
                zoom: param.zoom ?? 1,
                layername: param?.layer ?? this._cur_map_param?.layer,
                expr: param.expr,
                beginpos: param.beginpos,
                maxReturnCount: param.limit ?? undefined,
                limit: param.limit ?? undefined,
                fields: param.fields ?? "",
                useCache: param.useCache ?? false,
                geom: param.geom ?? undefined,
                simplifyTolerance: param.simplifyTolerance ?? undefined,
                toMapCoordinate: param.toMapCoordinate,
            },
            param.mapid,
            param.version
        );
        return this._processQueryResult(res, cb);
    }

    /**
     * Condition query entities
     * @param param Parameters
     * @param cb Callback for each point; null = default handling
     */
    async conditionQueryFeature(param: IConditionQueryFeatures, cb?: (point: [number, number]) => [number, number] | null | undefined): Promise<any> {
        const res = await this.execCommand(
            "queryFeatures",
            {
                querytype: "condition",
                zoom: param.zoom ?? 1,
                layername: param?.layer ?? this._cur_map_param?.layer,
                condition: param.condition,
                beginpos: param.beginpos,
                maxReturnCount: param.limit ?? undefined,
                limit: param.limit ?? undefined,
                includegeom: param.includegeom ?? undefined,
                realgeom: param.realgeom ?? undefined,
                isContains: param.isContains ?? undefined,
                fields: param.fields ?? "",
                bounds: param.bounds ? JSON.stringify(param.bounds) : "",
                geom: param.geom ?? undefined,
                simplifyTolerance: param.simplifyTolerance ?? undefined,
                useCache: param.useCache,
                toMapCoordinate: param.toMapCoordinate,
            },
            param.mapid,
            param.version
        );
        return this._processQueryResult(res, cb);
    }

// _processQueryResult converts returned Mercator coordinates to CAD coordinates. For backend queries returning CAD coordinates directly, set toMapCoordinate to true.
```
You can also inspect request parameters via the visual interface:

[https://vjmap.com/app/visual/#/query?mapid=sys_zp&version=v1&mapopenway=GeomRender&theme=dark](https://vjmap.com/app/visual/#/query?mapid=sys_zp&version=v1&mapopenway=GeomRender&theme=dark)
(Replace sys_zp with your mapid)

![image-20230524160509120](https://vjmap.com/blogimages/image-20230524160509120.png)

When testing in Postman, set `toMapCoordinate` to true to return CAD coordinates directly.

![image-20230524160843420](https://vjmap.com/blogimages/image-20230524160843420.png)


### Switch Layer

|      |                     |
|:-----|:--------------------|
| Service URL | api/v1/map/cmd/switchlayer/${mapid}/${version}|
| Request Type | Get or Post               |
| Service Description | mapid: map id; version: version       |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| visibleLayers | Array of visible layer indices ||
| darkMode | Whether dark theme ||


### Get Style Layer Name

|      |                     |
|:-----|:--------------------|
| Service URL | api/v1/map/cmd/createMapStyle/${mapid}/${version}|
| Request Type | Get or Post               |
| Service Description | mapid: map id; version: version       |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| geom | Whether geometry rendering ||
| name | Style name ||
| layeron | Layer indices to turn on, e.g. [0,1,3] ||
| layeroff | Layer indices to turn off, e.g. [2,4]. Use either layeron or layeroff ||
| clipbounds | Map clip bounds [x1,y1,x2,y2]. Single number = scale factor ||
| backcolor | Background color ||
| lineweight | Line weight [1,1,1,1,0]: levels 1–4 on, level 5 off; empty = same as original ||
| expression | Expression ||


### Get Data Bounds of Drawing
|      |                     |
|:-----|:--------------------|
| Service URL | api/v1/map/cmd/getDataBounds/${mapid}/${version}|
| Request Type | Get or Post               |
| Service Description | mapid: map id; version: version       |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| (none) |  ||

### Get Map Thumbnail
|      |                     |
|:-----|:--------------------|
| Service URL | api/v1/map/cmd/thumbnail/${mapid}/${version}|
| Request Type | Get or Post               |
| Service Description | mapid: map id; version: version       |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| width | Width in pixels ||
| height | Height in pixels ||
| darkTheme | Dark theme; if true, image is inverted (black to white) ||


### WMS Tile URL
|      |                     |
|:-----|:--------------------|
| Service URL | api/v1/map/cmd/wms/${mapid}/${version}|
| Request Type | Get or Post               |
| Service Description | mapid: map id; version: version       |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| layers | Layer name (empty = current map layer). ||
| bbox | Bounds, default {bbox-epsg-3857}. For CAD extent without conversion, use CAD bounds and leave srs, crs, mapbounds empty. ||
| srs | Current CRS, default EPSG:3857 ||
| crs | CAD map CRS; empty = from metadata. Can be proj4 string ||
| mapbounds | Geographic bounds; when set, srs is ignored  ||
| width | Tile width in pixels ||
| height | Tile height in pixels ||
| transparent | Background when opaque; default white. Must be rgb(r,g,b) or rgba(r,g,b,a), a=255 for opaque. ||
| backgroundColor | Background color when not transparent ||
| fourParameter | Four-parameter (x offset, y offset, scale, rotation in radians), optional ||
| isInverseFourParamter | Use inverse of four-parameter, default false ||
| mvt | Whether vector tiles ||
| useImageRotate | Consider rotation for CRS conversion. Default auto ||
| imageProcessAlg | Image processing for rotation: 1 or 2, default auto ||
| webMapType | Web base map type: WGS84 (e.g. Tianditu, OSM), GCJ02 (e.g. Amap, Tencent), BD09LL/Bd09MC (Baidu) ||

JS source:
```js

/**
 * WMS service URL parameters
 */
export interface IWmsTileUrl {
    /** Map ID (empty = current); array = request multiple. */
    mapid?: string | string[];
    /** Map version (empty = current). */
    version?: string | string[];
    /** Layer name (empty = current map layer). */
    layers?: string | string[];
    /** Bounds, default {bbox-epsg-3857}. For CAD extent without conversion use CAD bounds and leave srs, crs, mapbounds empty. */
    bbox?: string;
    /** Current CRS, default EPSG:3857. */
    srs?: string;
    /** CAD map CRS; empty = from metadata. Can be proj4 string. */
    crs?: string | string[];
    /** Geographic bounds; when set, srs is ignored. */
    mapbounds?: string;
    /** Width. */
    width?: number;
    /** Height. */
    height?: number;
    /** Transparent. */
    transparent?: boolean;
    /** Background when opaque; default white. rgb(r,g,b) or rgba(r,g,b,a), a=255 for opaque. */
    backgroundColor?: string;
    /** Four-parameter (x, y offset, scale, rotation rad), optional. */
    fourParameter?: string | string[];
    /** Use inverse four-parameter, default false. */
    isInverseFourParamter?:  boolean | boolean[];
    /** Vector tiles. */
    mvt?: boolean;
    /** Consider rotation for CRS conversion; default auto. */
    useImageRotate?: boolean;
    /** Image processing for rotation: 1 or 2, default auto. */
    imageProcessAlg?: number;
    /** Web base map type: WGS84, GCJ02, BD09LL, BD09MC. */
    webMapType?: "WGS84" | "GCJ02" | "BD09LL" | "BD09MC"
}
    wmsTileUrl(param: IWmsTileUrl): string {
        const mapid = param.mapid ?? this._cur_map_param?.mapid;
        const version = param.version ?? ((param.mapid == this._cur_map_param?.mapid) ? this._cur_map_param?.version : "_") ?? "_";
        const layers = param.layers ?? this._cur_map_param?.layer;
        const bbox = param.bbox ?? "{bbox-epsg-3857}";
        const srs = param.srs ?? "EPSG:3857";// base map CRS
        let crs = param.crs ?? ""; // CAD map CRS
        if (crs.indexOf("+") >= 0) {
            // proj4 string
            // @ts-ignore
            crs = encodeURIComponent(crs);
        }
        const mapbounds = param.mapbounds ?? "";
        const width = param.width ?? 256;
        const height = param.height ?? 256;
        const transparent = param.transparent ?? true;
        const fourParameter = param.fourParameter ?? "";
        const isInverseFourParamter = param.isInverseFourParamter === true ? `&isInverseFourParamter=true` : "";
        const mvt = param.mvt === true ? ".mvt" : ""
        const useImageRotate = param.useImageRotate === true ? `&useImageRotate=true` : "";
        const imageProcessAlg = isNumber(param.imageProcessAlg) ? `&imageProcessAlg=${param.imageProcessAlg}` : "";
        const webMapType = param.webMapType ? `&webMapType=${param.webMapType}` : "";
        const backgroundColor = (param.backgroundColor && !transparent) ? `&backgroundColor=${param.backgroundColor}` : "";
        if (!Array.isArray(mapid)) {
            // Single map WMS request
            return  `${this._url("cmd")}/wms/${mapid}/${version}${mvt}` +
                `?mapbounds=${mapbounds}${bbox ? "&bbox=": ""}${bbox}&format=image/png&service=WMS&request=GetMap&srs=${srs}&transparent=${transparent}&width=${width}&height=${height}&layers=${layers}&crs=${crs}&fourParameter=${fourParameter}${isInverseFourParamter}${useImageRotate}${imageProcessAlg}${webMapType}${backgroundColor}&token=${this.accessToken}`
        } else {
            // Multiple maps WMS request
            //&layers=${layers}&crs=${crs}&fourParameter=${fourParameter}
            //${mapid}/${version}
            let mapidArr = mapid;
            let versionArr = Array.isArray(version) && version.length == mapidArr.length ?  version : mapidArr.map(m => version ?? "_")
            let layersArr = Array.isArray(layers) && layers.length == mapidArr.length ?  layers : mapidArr.map(m => layers ?? "")
            let crsArr = Array.isArray(crs) && crs.length == mapidArr.length ?  crs : mapidArr.map(m => crs ?? "")
            let fourParameterArr = Array.isArray(fourParameter) && fourParameter.length == mapidArr.length ?  fourParameter : mapidArr.map(m => fourParameter ?? "")
            let isInverseFourParamterArr = Array.isArray(isInverseFourParamter) && isInverseFourParamter.length == mapidArr.length ?  isInverseFourParamter : mapidArr.map(m => isInverseFourParamter ?? "")
            let param = `bbox=${bbox}&mapbounds=${mapbounds}&format=image/png&service=WMS&request=GetMap&srs=${srs}&transparent=${transparent}&width=${width}&height=${height}`
            let arrayParam = `mapid=${mapidArr.join("_,")}&version=${versionArr.join("_,")}&layers=${layersArr.join("_,")}&crs=${crsArr.join("_,")}&fourParameter=${fourParameterArr.join("_,")}&isInverseFourParamter=${isInverseFourParamterArr.join("_,")}`
            if (mapidArr.length == 1) {
               return `${this._url("cmd")}/wms/${mapidArr[0]}/${versionArr[0]}${mvt}` +
                    `?mapbounds=${mapbounds}${bbox ? "&bbox=": ""}${bbox}&format=image/png&service=WMS&request=GetMap&srs=${srs}&transparent=${transparent}&width=${width}&height=${height}&layers=${layersArr[0]}&crs=${crsArr[0]}&fourParameter=${fourParameterArr[0]}&isInverseFourParamter=${isInverseFourParamterArr[0]}${useImageRotate}${imageProcessAlg}${webMapType}${backgroundColor}&token=${this.accessToken}`
            } else {
                return `${this._svr_url_service}wms?${param}&${arrayParam}${useImageRotate}${imageProcessAlg}${webMapType}${backgroundColor}&token=${this.accessToken}`;
            }
        }
    }
```

### Delete Map

|      |                     |
|:-----|:--------------------|
| Service URL | api/v1/map/cmd/deletemap/${mapid}/${version}|
| Request Type | Get or Post               |
| Service Description | mapid: map id; version: version; use "*" to delete all versions       |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| retainVersionMaxCount | When deleting all versions, keep this many latest (e.g. 10 versions, 3 = keep latest 3) ||


### Rename Map

|      |                     |
|:-----|:--------------------|
| Service URL | api/v1/map/cmd/deletemap/${mapid}/_|
| Request Type | Get or Post               |
| Service Description | mapid: map id      |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| newMapId | New map id ||




### Clear Map Geometry and Tile Cache

|      |                     |
|:-----|:--------------------|
| Service URL | api/v1/map/cmd/clearCacheTiles/${mapid}/${version}|
| Request Type | Get or Post               |
| Service Description | mapid: map id; version: version     |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| (none) |  ||

### Clear Map Tile Cache

|      |                     |
|:-----|:--------------------|
| Service URL | api/v1/map/cmd/clearCacheStyles/${mapid}/${version}|
| Request Type | Get or Post               |
| Service Description | mapid: map id; version: version     |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| (none) |  ||

### Delete Map Style

|      |                     |
|:-----|:--------------------|
| Service URL | api/v1/map/cmd/deletestyle/${mapid}/${version}|
| Request Type | Get or Post               |
| Service Description | mapid: map id; version: version     |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| styleid | Style id ||
| onlycleardata | Only clear data ||

### Delete Map Cache

|      |                     |
|:-----|:--------------------|
| Service URL | api/v1/map/cmd/deletecache/${mapid}/${version}|
| Request Type | Get or Post               |
| Service Description | mapid: map id; version: version     |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| key | Cache key prefix ||

### Get System Run Status
|      |                     |
|:-----|:--------------------|
| Service URL | api/v1/map/cmd/runstatus/${mapid}/${version}|
| Request Type | Get or Post               |
| Service Description | mapid: map id; version: version     |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| detail | Whether to return detailed data ||

### Compose New Map
|      |                     |
|:-----|:--------------------|
| Service URL | api/v1/map/cmd/composeNewMap/_null/v1|
| Request Type | Get or Post               |
| Service Description |    |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| mapid | Map ID |
| version | Map version |
| clipbounds | Map clip bounds [x1,y1,x2,y2]; empty = no clip ||
| selByCrossing | Contain vs intersect (default false = contain, true = intersect) ||
| fourParameter | Four-parameter (x, y offset, scale, rotation rad), optional ||
| isInverseFourParamter | Use inverse four-parameter, default false ||
| layers | Layer names to show; empty = all ||
| layerPrefix | Layer name prefix for new map ||
| layerSuffix | Layer name suffix for new map ||
| savefilename | Output filename; empty = auto from params ||
| purge | Purge after compose to reduce DWG size ||
| cadVersion | Export CAD version; * = current ||

JS source:
```js
/**
 * Compose new map parameters
 */
export interface IComposeNewMap {
    /** Map ID. */
    mapid: string;
    /** Map version (empty = current). */
    version?: string;
    /** Clip bounds [x1,y1,x2,y2]; empty = no clip. */
    clipbounds?: [number, number, number, number];
    /** Contain (false) vs intersect (true). */
    selByCrossing?: boolean;
    /** Four-parameter (x, y offset, scale, rotation rad), optional. */
    fourParameter?:  [number, number, number, number];
    /** Use inverse four-parameter, default false. */
    isInverseFourParamter?:  boolean;
    /** Layer names to show; empty = all. */
    layers?: string[];
    /** Layer name prefix for new map. */
    layerPrefix?: string;
    /** Layer name suffix for new map. */
    layerSuffix?: string;
    /** Output filename; empty = auto from params. */
    savefilename?: string;
    /** Purge after compose to reduce DWG size. */
    purge?: boolean
    /** Export CAD version; * = current. */
    cadVersion?: string | "*" | "cad2000" | "cad2004" | "cad2007" | "cad2010" | "cad2013"| "cad2018"
}

    /**
     * Compose new map
     * @param param Compose parameters
     * @return {Promise<any>}
     */
    async composeNewMap(param: IComposeNewMap | IComposeNewMap[]) {
        if (!Array.isArray(param)) {
            param = [param] // normalize to array
        }
        let cmdParam: Record<string, any> = {};
        if (param.length > 1) {
            cmdParam['count'] = param.length;
        }

        for(let i = 0; i < param.length; i++) {
            let paramKey = i === 0 ? "" : ((i + 1) + "")
            cmdParam['mapid' + paramKey] = param[i].mapid;
            cmdParam['version' + paramKey] = param[i].version;
            cmdParam['clipBounds' + paramKey] = Array.isArray(param[i].clipbounds) ? JSON.stringify(param[i].clipbounds) : undefined;
            cmdParam['selByCrossing' + paramKey] = param[i].selByCrossing;
            cmdParam['fourParameter' + paramKey] = Array.isArray(param[i].fourParameter) ? JSON.stringify(param[i].fourParameter) : undefined;
            cmdParam['isInverseFourParamter' + paramKey] = param[i].isInverseFourParamter === true ? true : undefined;
            cmdParam['layers' + paramKey] = Array.isArray(param[i].layers) ? JSON.stringify(param[i].layers) : undefined;
            cmdParam['layerPrefix' + paramKey] = param[i].layerPrefix;
            cmdParam['layerSuffix' + paramKey] = param[i].layerSuffix;
            cmdParam['savefilename' + paramKey] = param[i].savefilename;
            cmdParam['purge' + paramKey] = param[i].purge;
            if (param[i].cadVersion) {
                cmdParam['cadVersion' + paramKey] = param[i].cadVersion;
            }
        }
        return await this.execCommand("composeNewMap", cmdParam, "_null", "v1", false);
    }

```



### Projection PRJ WKT to Proj4 String
|      |                                    |
|:-----|:-----------------------------------|
| Service URL | api/v1/map/cmd/prjWktToPrj4Str/_/_ |
| Request Type | Post                               |
| Service Description | Convert PRJ WKT to proj4 string.   |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| wkt | PRJ file WKT string |



### Export Layout to DWG
|      |                     |
|:-----|:--------------------|
| Service URL | api/v1/map/cmd/exportLayout/_null/v1|
| Request Type | Get or Post               |
| Service Description | mapid: map id; version: version     |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| mapid | Map ID |
| version | Map version (empty = current) |
| layoutIndex | Layout index; use either layoutIndex or layoutName, layoutIndex takes precedence. Both empty = current DWG layout. |
| layoutName | Layout name. Use either layoutIndex or layoutName. Both empty = current DWG layout. |
  
  
  ### Object Match
|      |                     |
|:-----|:--------------------|
| Service URL | api/v1/map/cmd/objectMatch/_null/v1|
| Request Type | Get or Post               |
| Service Description |    |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| mapid | Map ID |
| version | Map version (empty = current) |
| layer | Style layer name; empty = determined by selected entities |
| mapBounds | Match extent; default full map |
| objectIds | Entity objectId array, separated by \|\| |
| objectBounds | Entity bounds |
| layeron | Layers to turn on for match |
| size | Image size for match, default 10000 |
| method | "matchTemplate" or "matchPattern" |
| maxCount | Score threshold (0–1), default 0.6 |
| minReduceArea | Pyramid size (64–2048), default 256; for matchPattern |
| canOverlap | Allow overlap (default false) |
| maxOverlap | Overlap ratio (0–0.8), default 0.3 |
| toleranceAngle | Angle range (-180, 180) for rotation; for matchPattern, default 180 |
| useToleranceRange | Use angle range (default false); for matchPattern |
| tolerance1 | Angle range 1 start; for matchPattern |
| tolerance2 | Angle range 1 end; for matchPattern |
| tolerance3 | Angle range 2 start; for matchPattern |
| tolerance4 | Angle range 2 end; for matchPattern |
  
 ### Get Created Entity Geometry Data
|      |                     |
|:-----|:--------------------|
| Service URL | api/v1/map/cmd/createEntityGeoData/_null/v1|
| Request Type | Get or Post               |
| Service Description |    |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| filedoc | File document |
| mapBounds | Drawing bounds; empty = full map |
| renderAccuracy | Render accuracy, default 1. Increase if circles/arcs are not smooth (clears cache and may increase file size and hurt performance) |
| excludeAttribute | Exclude attributes from result (default true) |
| useZip | Use zip compression for result (default true) |

### Get All Workspaces
|      |                     |
|:-----|:--------------------|
| Service URL | api/v1/service/getWorkspace|
| Request Type | Get             |
| Service Description |    |

## Workspace Switch
The request URLs above are for the default workspace.

To use a different workspace, change the path prefix:

Replace `/api/v1/map/` with `/api/v1/workspace/{workspaceName}/`

Example: upload URL `/api/v1/map/uploads` for workspace `w1` becomes `/api/v1/workspace/w1/uploads`

Frontend code to switch workspace:
```js
/**
* Switch to workspace
* @param workspaceName Workspace name
* @return
*/
function  switchWorkspace(workspaceName) {
    workspaceName = workspaceName.trim()
    this._workspaceName = workspaceName;
    if (workspaceName != "") {
        // specified workspace
        this._svr_url_map = this.serverUrl + "workspace/" + workspaceName + "/";
    } else {
        // default workspace
        this._svr_url_map = this.serverUrl + "map/";
    }
}
```

### Full-Text Search API

#### Add Single Document
|      |                     |
|:-----|:--------------------|
| Service URL | /api/v1/service/fullsearch/add |
| Request Type | Post                |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| document | Document with fields: id, map_ver, content, type (1:single-line text, 2:multiline, 3:attribute, 4:block attribute, 5:layer, 6:block name, 7:linetype, 8:hatch, 9:custom), min_x, min_y, max_x, max_y, props (JSON), create_time, workspace, data ||

#### Batch Add Documents
|      |                     |
|:-----|:--------------------|
| Service URL | /api/v1/service/fullsearch/batchAdd |
| Request Type | Post                |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| documents | Document list; each has same fields as document above ||

#### Update Document
|      |                     |
|:-----|:--------------------|
| Service URL | /api/v1/service/fullsearch/update |
| Request Type | Put                |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| document | Document with fields: id, map_ver, content, type (1:single-line text, 2:multiline, 3:attribute, 4:block attribute, 5:layer, 6:block name, 7:linetype, 8:hatch, 9:custom), min_x, min_y, max_x, max_y, props (JSON), create_time, workspace, data ||

#### Delete Document
|      |                     |
|:-----|:--------------------|
| Service URL | /api/v1/service/fullsearch/delete |
| Request Type | Delete                |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| id | Document ID ||

#### Delete Documents by Map Version
|      |                     |
|:-----|:--------------------|
| Service URL | /api/v1/service/fullsearch/deleteByMapver |
| Request Type | Delete                |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| map_ver | Map version ||
| workspace | Workspace name ||

#### Batch Delete Documents
|      |                     |
|:-----|:--------------------|
| Service URL | /api/v1/service/fullsearch/batchDelete |
| Request Type | Post                |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| ids | Document ID array ||
| query | Query condition ||
| map_ver | Map version ||
| workspace | Workspace ||
| type | Document type ||
| bounding_box | Bounding box [minX, minY, maxX, maxY] ||
| time_range | Time range ||

#### Delete Documents by ID Prefix
|      |                     |
|:-----|:--------------------|
| Service URL | /api/v1/service/fullsearch/deleteByIDPrefix |
| Request Type | Delete                |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| id_prefix | ID prefix ||

#### Search Documents
|      |                     |
|:-----|:--------------------|
| Service URL | /api/v1/service/fullsearch/search |
| Request Type | Get or Post                |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| query | Search keyword ||
| map_ver | Map version (optional, comma-separated e.g. map1,map2_v2) ||
| workspace | Workspace (optional, comma-separated; use * for all) ||
| type | Document type (optional: single, multiple, range e.g. 1,2,5 or 1-3) ||
| bounding_box | Bounding box (optional, "minX,minY,maxX,maxY") ||
| time_range | Time range (optional, "start~end" or N days) ||
| limit | Results per page ||
| offset | Pagination offset ||
| fields | Return fields (comma-separated) ||
| facet | Aggregate MapVer (true/1 to enable) ||

#### Get Document Count
|      |                     |
|:-----|:--------------------|
| Service URL | /api/v1/service/fullsearch/count |
| Request Type | Get                |

#### Manually Trigger Data Sync
|      |                     |
|:-----|:--------------------|
| Service URL | /api/v1/service/fullsearch/sync |
| Request Type | Get                |

#### Get Workspace Index Status
|      |                     |
|:-----|:--------------------|
| Service URL | /api/v1/service/fullsearch/workspaceStatus |
| Request Type | Get                |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| workspace | Workspace name ||

#### Get Search Suggestions
|      |                     |
|:-----|:--------------------|
| Service URL | /api/v1/service/fullsearch/suggestions |
| Request Type | Get                |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| prefix | Search prefix ||
| map_ver | Map version ||
| workspace | Workspace ||
| type | Document type ||
| limit | Max suggestions ||

#### Search Documents by ID Prefix
|      |                     |
|:-----|:--------------------|
| Service URL | /api/v1/service/fullsearch/searchByIDPrefix |
| Request Type | Get or Post                |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| id_prefix | ID prefix ||
| map_ver | Map version (optional) ||
| workspace | Workspace (optional) ||
| limit | Page size ||
| offset | Offset ||
| fields | Return fields (comma-separated) ||

## Recognizer API

### Get Recognizer Config List

|      |                     |
|:-----|:--------------------|
| Service URL | /api/v1/service/recognizer/list |
| Request Type | Get                |
| Service Description | Get all saved recognizer configs                |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| (none) |  ||

### Delete Recognizer Config

|      |                     |
|:-----|:--------------------|
| Service URL | /api/v1/service/recognizer/delete |
| Request Type | Delete                |
| Service Description | Delete specified recognizer config file                |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| filename | Config file name prefix | config_20231201_001 |

### Add Recognizer Config

|      |                     |
|:-----|:--------------------|
| Service URL | /api/v1/service/recognizer/add |
| Request Type | Post                |
| Service Description | Save new recognizer config                |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| name | Config name | My recognizer config |
| sameColor | Entities must have same color | true |
| sameLayer | Entities must be on same layer | false |
| sameTextContent | Text content must match | false |
| thumbnail | Thumbnail base64 (optional) | data:image/png;base64,... |
| global | Global match rules | {...} |
| rules | Recognizer rules array | [...] |

### Get Recognizer Config Detail

|      |                     |
|:-----|:--------------------|
| Service URL | /api/v1/service/recognizer/detail |
| Request Type | Get                |
| Service Description | Get recognizer config details                |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| filenames | Config filenames, comma-separated | config_20231201_001,config_20231201_002 |

### Run Object Recognition

|      |                     |
|:-----|:--------------------|
| Service URL | /api/v1/map/cmd/objectDetection/_null/v1 |
| Request Type | Get or Post                |
| Service Description | Run smart object recognition on map; identify similar entities by config pattern                |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| mapid | Map ID | sys_zp |
| version | Map version | v1 |
| layer | Style layer name | default |
| pattern | Pattern config JSON | {"name":"test","sameColor":true,"rules":[...]} |
| patternList | Array of pattern configs (alternative to pattern) | ["{"name":"config1",...}","{"name":"config2",...}"] |
| detailedLog | Output detailed match info | false |
| bounds | Recognition bounds, GeoBounds string | -1000,-1000,1000,1000 |

## Drawing Analysis API

### Extract Center Lines

|      |                     |
|:-----|:--------------------|
| Service URL | /api/v1/map/cmd/extractCenterLines/_null/v1 |
| Request Type | Get or Post                |
| Service Description | Extract center lines from parallel segments; for pipelines, roads, etc.                |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| mapid | Map ID | sys_zp |
| version | Map version | v1 |
| layer | Style layer name | default |
| geom | Geometry rendering | true |
| bounds | Extract bounds, coords or polygon | -1000,-1000,1000,1000 |
| isContains | Contain (true) vs intersect (false) | false |
| minSpaceDistance | Min distance array, comma-separated | 2.5,5.0 |
| maxSpaceDistance | Max distance array, comma-separated | 7.5,15.0 |
| collinearTolerance | Collinear tolerance | 1.0 |
| duplicateTolerance | Duplicate point tolerance | 0.2 |
| maxGapDistance | Max gap to connect segments | 15 |
| numDecimalDigits | Decimal places | 3 |
| minDlMinRatio | Min overlap ratio for double lines | 0.01 |
| paralleSlopeAngleTolerance | Parallel slope angle tolerance (degrees) | 1.5 |
| mergeSlopeAngleTolerance | Merge center line slope tolerance (degrees) | 20 |
| maxCenterMergeDistance | Max distance to merge center segments | 15 |
| minCenterDistance | Min center segment distance | 5.1 |
| bConnectGrapLine | Connect lines within gap | true |
| bMergeNode | Merge endpoints | true |
| bFilterShortLine | Filter lines shorter than min distance | true |
| bMergeLine | Merge connected lines | true |
| bSaveParalleLineJson | Output parallel line coords | false |
| bCenterGeoJson | Return center line as GeoJSON | false |
| bExtractLines | Output extracted line coords | false |

### Map Entity Compare

|      |                     |
|:-----|:--------------------|
| Service URL | /api/v1/map/cmd/mapCompare/_null/v1 |
| Request Type | Get or Post                |
| Service Description | Compare entities between two map versions; returns added, deleted, modified lists                |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| mapid1 | First map ID | sys_zp |
| version1 | First map version | v1 |
| mapid2 | Second map ID | sys_zp |
| version2 | Second map version | v2 |

### Map Pixel Compare

|      |                     |
|:-----|:--------------------|
| Service URL | api/v1/map/cmd/mapDiff/_null/v1|
| Request Type | Get or Post               |
| Service Description | Compare two maps by pixel                |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| mapid1 | Map 1 ID |
| version1 | Map 1 version (empty = current) |
| layer1 | Map 1 style layer |
| mapid2 | Map 2 ID |
| version2 | Map 2 version (empty = current) |
| layer2 | Map 2 style layer |
| noCompareNew | Do not compare new parts |
| noCompareDelete | Do not compare deleted parts |
| size | Compare size |
| cellsize | Cell size |
| diffMinAlpha | Min diff pixel alpha |
| diffMinAlpha | Min diff transparency |
| diffMinColor | Min diff color |

### Map Similarity Analysis

|      |                     |
|:-----|:--------------------|
| Service URL | /api/v1/map/cmd/imageSimilarity/_null/v1 |
| Request Type | Get or Post                |
| Service Description | Analyze similarity between map and others; returns map IDs sorted by similarity                |

|  Request Parameter | Parameter Description    | Parameter Example    |
|:-----|:--------|:--------|
| mapid | Reference map ID | sys_zp |
| version | Reference map version | v1 |
