forked from MapComplete/MapComplete
More work on replaceGeometry
This commit is contained in:
parent
ba4f4ac685
commit
7124cd184c
4 changed files with 291 additions and 48 deletions
|
@ -81,8 +81,7 @@ export default class ReplaceGeometryAction extends OsmChangeAction {
|
||||||
|
|
||||||
// noinspection JSUnusedGlobalSymbols
|
// noinspection JSUnusedGlobalSymbols
|
||||||
public async getPreview(): Promise<FeatureSource> {
|
public async getPreview(): Promise<FeatureSource> {
|
||||||
const {closestIds, allNodesById, detachedNodeIds} = await this.GetClosestIds();
|
const {closestIds, allNodesById, detachedNodes} = await this.GetClosestIds();
|
||||||
console.debug("Generating preview, identicals are ",)
|
|
||||||
const preview: GeoJSONObject[] = closestIds.map((newId, i) => {
|
const preview: GeoJSONObject[] = closestIds.map((newId, i) => {
|
||||||
if (this.identicalTo[i] !== undefined) {
|
if (this.identicalTo[i] !== undefined) {
|
||||||
return undefined
|
return undefined
|
||||||
|
@ -116,13 +115,14 @@ export default class ReplaceGeometryAction extends OsmChangeAction {
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
|
||||||
for (const detachedNodeId of detachedNodeIds) {
|
detachedNodes.forEach(({reason}, id) => {
|
||||||
const origPoint = allNodesById.get(detachedNodeId).centerpoint()
|
const origPoint = allNodesById.get(id).centerpoint()
|
||||||
const feature = {
|
const feature = {
|
||||||
type: "Feature",
|
type: "Feature",
|
||||||
properties: {
|
properties: {
|
||||||
"detach": "yes",
|
"detach": "yes",
|
||||||
"id": "replace-geometry-detach-" + detachedNodeId
|
"id": "replace-geometry-detach-" + id,
|
||||||
|
"detach-reason":reason
|
||||||
},
|
},
|
||||||
geometry: {
|
geometry: {
|
||||||
type: "Point",
|
type: "Point",
|
||||||
|
@ -130,7 +130,7 @@ export default class ReplaceGeometryAction extends OsmChangeAction {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
preview.push(feature)
|
preview.push(feature)
|
||||||
}
|
})
|
||||||
|
|
||||||
|
|
||||||
return new StaticFeatureSource(Utils.NoNull(preview), false)
|
return new StaticFeatureSource(Utils.NoNull(preview), false)
|
||||||
|
@ -142,8 +142,13 @@ export default class ReplaceGeometryAction extends OsmChangeAction {
|
||||||
const allChanges: ChangeDescription[] = []
|
const allChanges: ChangeDescription[] = []
|
||||||
const actualIdsToUse: number[] = []
|
const actualIdsToUse: number[] = []
|
||||||
|
|
||||||
const {closestIds, osmWay, detachedNodeIds} = await this.GetClosestIds()
|
const nodeDb = this.state.featurePipeline.fullNodeDatabase;
|
||||||
|
if (nodeDb === undefined) {
|
||||||
|
throw "PANIC: replaceGeometryAction needs the FullNodeDatabase, which is undefined. This should be initialized by having the 'type_node'-layer enabled in your theme. (NB: the replacebutton has type_node as dependency)"
|
||||||
|
}
|
||||||
|
|
||||||
|
const {closestIds, osmWay, detachedNodes} = await this.GetClosestIds()
|
||||||
|
const detachedNodeIds = Array.from(detachedNodes.keys());
|
||||||
for (let i = 0; i < closestIds.length; i++) {
|
for (let i = 0; i < closestIds.length; i++) {
|
||||||
if (this.identicalTo[i] !== undefined) {
|
if (this.identicalTo[i] !== undefined) {
|
||||||
const j = this.identicalTo[i]
|
const j = this.identicalTo[i]
|
||||||
|
@ -211,10 +216,7 @@ export default class ReplaceGeometryAction extends OsmChangeAction {
|
||||||
// Some nodes might need to be deleted
|
// Some nodes might need to be deleted
|
||||||
if (detachedNodeIds.length > 0) {
|
if (detachedNodeIds.length > 0) {
|
||||||
|
|
||||||
const nodeDb = this.state.featurePipeline.fullNodeDatabase;
|
|
||||||
if (nodeDb === undefined) {
|
|
||||||
throw "PANIC: replaceGeometryAction needs the FullNodeDatabase, which is undefined. This should be initialized by having the 'type_node'-layer enabled in your theme. (NB: the replacebutton has type_node as dependency)"
|
|
||||||
}
|
|
||||||
for (const nodeId of detachedNodeIds) {
|
for (const nodeId of detachedNodeIds) {
|
||||||
const parentWays = nodeDb.GetParentWays(nodeId)
|
const parentWays = nodeDb.GetParentWays(nodeId)
|
||||||
const index = parentWays.data.map(w => w.id).indexOf(osmWay.id)
|
const index = parentWays.data.map(w => w.id).indexOf(osmWay.id)
|
||||||
|
@ -260,12 +262,18 @@ export default class ReplaceGeometryAction extends OsmChangeAction {
|
||||||
closestIds: number[],
|
closestIds: number[],
|
||||||
allNodesById: Map<number, OsmNode>,
|
allNodesById: Map<number, OsmNode>,
|
||||||
osmWay: OsmWay,
|
osmWay: OsmWay,
|
||||||
detachedNodeIds: number[]
|
detachedNodes: Map<number, {
|
||||||
|
reason: string
|
||||||
|
}>
|
||||||
}> {
|
}> {
|
||||||
// TODO FIXME: cap move length on points which are embedded into other ways (ev. disconnect them)
|
// TODO FIXME: cap move length on points which are embedded into other ways (ev. disconnect them)
|
||||||
// TODO FIXME: if a new point has to be created, snap to already existing ways
|
// TODO FIXME: if a new point has to be created, snap to already existing ways
|
||||||
|
|
||||||
|
const nodeDb = this.state.featurePipeline.fullNodeDatabase;
|
||||||
|
if (nodeDb === undefined) {
|
||||||
|
throw "PANIC: replaceGeometryAction needs the FullNodeDatabase, which is undefined. This should be initialized by having the 'type_node'-layer enabled in your theme. (NB: the replacebutton has type_node as dependency)"
|
||||||
|
}
|
||||||
|
|
||||||
let parsed: OsmObject[];
|
let parsed: OsmObject[];
|
||||||
{
|
{
|
||||||
// Gather the needed OsmObjects
|
// Gather the needed OsmObjects
|
||||||
|
@ -295,18 +303,27 @@ export default class ReplaceGeometryAction extends OsmChangeAction {
|
||||||
const distances = new Map<number /* osmId*/,
|
const distances = new Map<number /* osmId*/,
|
||||||
/** target coordinate index --> distance (or undefined if a duplicate)*/
|
/** target coordinate index --> distance (or undefined if a duplicate)*/
|
||||||
number[]>();
|
number[]>();
|
||||||
|
|
||||||
|
const nodeInfo = new Map<number /* osmId*/, {
|
||||||
|
distances :number[],
|
||||||
|
// Part of some other way then the one that should be replaced
|
||||||
|
partOfWay: boolean,
|
||||||
|
hasTags: boolean
|
||||||
|
}>()
|
||||||
|
|
||||||
for (const node of allNodes) {
|
for (const node of allNodes) {
|
||||||
const nodesWithAllParents = this.state.featurePipeline.fullNodeDatabase
|
|
||||||
if (nodesWithAllParents === undefined) {
|
const parentWays = nodeDb.GetParentWays(node.id)
|
||||||
throw "PANIC: replaceGeometryAction needs the FullNodeDatabase, which is undefined. This should be initialized by having the 'type_node'-layer enabled in your theme. (NB: the replacebutton has type_node as dependency)"
|
if(parentWays === undefined){
|
||||||
|
throw "PANIC: the way to replace has a node which has no parents at all. Is it deleted in the meantime?"
|
||||||
}
|
}
|
||||||
|
const parentWayIds = parentWays.data.map(w => w.type+"/"+w.id)
|
||||||
let parentWayIds = nodesWithAllParents.GetParentWays(node.id)
|
const idIndex = parentWayIds.indexOf(this.wayToReplaceId)
|
||||||
|
if(idIndex < 0){
|
||||||
|
throw "PANIC: the way to replace has a node, which is _not_ part of this was according to the node..."
|
||||||
|
}
|
||||||
|
parentWayIds.splice(idIndex, 1)
|
||||||
|
const partOfSomeWay = parentWayIds.length > 0
|
||||||
|
|
||||||
|
|
||||||
const nodeDistances = this.targetCoordinates.map(_ => undefined)
|
const nodeDistances = this.targetCoordinates.map(_ => undefined)
|
||||||
|
@ -319,10 +336,17 @@ export default class ReplaceGeometryAction extends OsmChangeAction {
|
||||||
nodeDistances[i] = GeoOperations.distanceBetween(targetCoordinate, [cp[1], cp[0]])
|
nodeDistances[i] = GeoOperations.distanceBetween(targetCoordinate, [cp[1], cp[0]])
|
||||||
}
|
}
|
||||||
distances.set(node.id, nodeDistances)
|
distances.set(node.id, nodeDistances)
|
||||||
|
nodeInfo.set(node.id, {
|
||||||
|
distances: nodeDistances,
|
||||||
|
partOfWay: partOfSomeWay,
|
||||||
|
hasTags: Object.keys(node.tags).length > 1
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const closestIds = this.targetCoordinates.map(_ => undefined)
|
const closestIds = this.targetCoordinates.map(_ => undefined)
|
||||||
const unusedIds = []
|
const unusedIds = new Map<number, {
|
||||||
|
reason: string
|
||||||
|
}>();
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Then, we search the node that has to move the least distance and add this as mapping.
|
* Then, we search the node that has to move the least distance and add this as mapping.
|
||||||
|
@ -372,7 +396,9 @@ export default class ReplaceGeometryAction extends OsmChangeAction {
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
// Seems like all the targetCoordinates have found a source point
|
// Seems like all the targetCoordinates have found a source point
|
||||||
unusedIds.push(candidate)
|
unusedIds.set(candidate,{
|
||||||
|
reason: "Unused by new way"
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (candidate !== undefined)
|
} while (candidate !== undefined)
|
||||||
|
@ -380,7 +406,9 @@ export default class ReplaceGeometryAction extends OsmChangeAction {
|
||||||
|
|
||||||
// If there are still unused values in 'distances', they are definitively unused
|
// If there are still unused values in 'distances', they are definitively unused
|
||||||
distances.forEach((_, nodeId) => {
|
distances.forEach((_, nodeId) => {
|
||||||
unusedIds.push(nodeId)
|
unusedIds.set(nodeId,{
|
||||||
|
reason: "Unused by new way"
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -393,7 +421,7 @@ export default class ReplaceGeometryAction extends OsmChangeAction {
|
||||||
for (const node of allNodes) {
|
for (const node of allNodes) {
|
||||||
allNodesById.set(node.id, <OsmNode>node)
|
allNodesById.set(node.id, <OsmNode>node)
|
||||||
}
|
}
|
||||||
return {closestIds, allNodesById, osmWay, detachedNodeIds: unusedIds};
|
return {closestIds, allNodesById, osmWay, detachedNodes: unusedIds};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ export class SubstitutedTranslation extends VariableUiElement {
|
||||||
return viz.func.constr(State.state, tagsSource, proto.special.args, DefaultGuiState.state).SetStyle(proto.special.style);
|
return viz.func.constr(State.state, tagsSource, proto.special.args, DefaultGuiState.state).SetStyle(proto.special.style);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("SPECIALRENDERING FAILED for", tagsSource.data?.id, e)
|
console.error("SPECIALRENDERING FAILED for", tagsSource.data?.id, e)
|
||||||
return new FixedUiElement(`Could not generate special rendering for ${viz.func}(${viz.args.join(", ")}) ${e}`).SetStyle("alert")
|
return new FixedUiElement(`Could not generate special rendering for ${viz.func.funcName}(${viz.args.join(", ")}) ${e}`).SetStyle("alert")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
|
|
253
test.ts
253
test.ts
|
@ -1,24 +1,239 @@
|
||||||
import BackgroundMapSwitch from "./UI/BigComponents/BackgroundMapSwitch";
|
import State from "./State";
|
||||||
import {UIEventSource} from "./Logic/UIEventSource";
|
import AllKnownLayers from "./Customizations/AllKnownLayers";
|
||||||
import Loc from "./Models/Loc";
|
|
||||||
import AvailableBaseLayersImplementation from "./Logic/Actors/AvailableBaseLayersImplementation";
|
import AvailableBaseLayersImplementation from "./Logic/Actors/AvailableBaseLayersImplementation";
|
||||||
import AvailableBaseLayers from "./Logic/Actors/AvailableBaseLayers";
|
import AvailableBaseLayers from "./Logic/Actors/AvailableBaseLayers";
|
||||||
import BaseLayer from "./Models/BaseLayer";
|
import MinimapImplementation from "./UI/Base/MinimapImplementation";
|
||||||
import {VariableUiElement} from "./UI/Base/VariableUIElement";
|
import {Utils} from "./Utils";
|
||||||
|
import * as grb from "./assets/themes/grb_import/grb.json";
|
||||||
|
import ReplaceGeometryAction from "./Logic/Osm/Actions/ReplaceGeometryAction";
|
||||||
|
import Minimap from "./UI/Base/Minimap";
|
||||||
|
import ShowDataLayer from "./UI/ShowDataLayer/ShowDataLayer";
|
||||||
|
import {AllKnownLayouts} from "./Customizations/AllKnownLayouts";
|
||||||
|
import {BBox} from "./Logic/BBox";
|
||||||
|
|
||||||
AvailableBaseLayers.implement(new AvailableBaseLayersImplementation())
|
AvailableBaseLayers.implement(new AvailableBaseLayersImplementation())
|
||||||
const state = {
|
MinimapImplementation.initialize()
|
||||||
currentBackground: new UIEventSource<BaseLayer>(AvailableBaseLayers.osmCarto),
|
|
||||||
locationControl: new UIEventSource<Loc>({
|
|
||||||
zoom: 19,
|
|
||||||
lat: 51.2,
|
|
||||||
lon: 3.2
|
|
||||||
})
|
|
||||||
}
|
|
||||||
const actualBackground = new UIEventSource(AvailableBaseLayers.osmCarto)
|
|
||||||
new BackgroundMapSwitch(state,
|
|
||||||
{
|
|
||||||
currentBackground: actualBackground
|
|
||||||
}).AttachTo("maindiv")
|
|
||||||
|
|
||||||
new VariableUiElement(actualBackground.map(bg => bg.id)).AttachTo("extradiv")
|
async function test() {
|
||||||
|
|
||||||
|
const coordinates = <[number, number][]>[
|
||||||
|
[
|
||||||
|
3.216690793633461,
|
||||||
|
51.21474084112525
|
||||||
|
],
|
||||||
|
[
|
||||||
|
3.2167256623506546,
|
||||||
|
51.214696737309964
|
||||||
|
],
|
||||||
|
[
|
||||||
|
3.2169999182224274,
|
||||||
|
51.214768983537674
|
||||||
|
],
|
||||||
|
[
|
||||||
|
3.2169650495052338,
|
||||||
|
51.21480720678671
|
||||||
|
],
|
||||||
|
[
|
||||||
|
3.2169368863105774,
|
||||||
|
51.21480090625335
|
||||||
|
],
|
||||||
|
[
|
||||||
|
3.2169489562511444,
|
||||||
|
51.21478074454077
|
||||||
|
],
|
||||||
|
[
|
||||||
|
3.216886594891548,
|
||||||
|
51.214765203214625
|
||||||
|
],
|
||||||
|
[
|
||||||
|
3.2168812304735184,
|
||||||
|
51.21477192378873
|
||||||
|
],
|
||||||
|
[
|
||||||
|
3.2168644666671753,
|
||||||
|
51.214768983537674
|
||||||
|
],
|
||||||
|
[
|
||||||
|
3.2168537378311157,
|
||||||
|
51.21478746511261
|
||||||
|
],
|
||||||
|
[
|
||||||
|
3.216690793633461,
|
||||||
|
51.21474084112525
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
const targetFeature = {
|
||||||
|
type: "Feature",
|
||||||
|
properties: {},
|
||||||
|
geometry: {
|
||||||
|
type: "Polygon",
|
||||||
|
coordinates: [coordinates]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
Utils.injectJsonDownloadForTests(
|
||||||
|
"https://www.openstreetmap.org/api/0.6/way/160909312/full",
|
||||||
|
{
|
||||||
|
"version": "0.6",
|
||||||
|
"generator": "CGImap 0.8.5 (920083 spike-06.openstreetmap.org)",
|
||||||
|
"copyright": "OpenStreetMap and contributors",
|
||||||
|
"attribution": "http://www.openstreetmap.org/copyright",
|
||||||
|
"license": "http://opendatacommons.org/licenses/odbl/1-0/",
|
||||||
|
"elements": [{
|
||||||
|
"type": "node",
|
||||||
|
"id": 1728823481,
|
||||||
|
"lat": 51.2146969,
|
||||||
|
"lon": 3.2167247,
|
||||||
|
"timestamp": "2017-07-18T22:52:45Z",
|
||||||
|
"version": 2,
|
||||||
|
"changeset": 50391526,
|
||||||
|
"user": "catweazle67",
|
||||||
|
"uid": 1976209
|
||||||
|
}, {
|
||||||
|
"type": "node",
|
||||||
|
"id": 1728823514,
|
||||||
|
"lat": 51.2147863,
|
||||||
|
"lon": 3.2168551,
|
||||||
|
"timestamp": "2017-07-18T22:52:45Z",
|
||||||
|
"version": 2,
|
||||||
|
"changeset": 50391526,
|
||||||
|
"user": "catweazle67",
|
||||||
|
"uid": 1976209
|
||||||
|
}, {
|
||||||
|
"type": "node",
|
||||||
|
"id": 1728823549,
|
||||||
|
"lat": 51.2147399,
|
||||||
|
"lon": 3.2168871,
|
||||||
|
"timestamp": "2017-07-18T22:52:46Z",
|
||||||
|
"version": 2,
|
||||||
|
"changeset": 50391526,
|
||||||
|
"user": "catweazle67",
|
||||||
|
"uid": 1976209
|
||||||
|
}, {
|
||||||
|
"type": "node",
|
||||||
|
"id": 4978288381,
|
||||||
|
"lat": 51.2147638,
|
||||||
|
"lon": 3.2168856,
|
||||||
|
"timestamp": "2017-07-18T22:52:21Z",
|
||||||
|
"version": 1,
|
||||||
|
"changeset": 50391526,
|
||||||
|
"user": "catweazle67",
|
||||||
|
"uid": 1976209
|
||||||
|
}, {
|
||||||
|
"type": "node",
|
||||||
|
"id": 4978289383,
|
||||||
|
"lat": 51.2147676,
|
||||||
|
"lon": 3.2169973,
|
||||||
|
"timestamp": "2017-07-18T22:52:21Z",
|
||||||
|
"version": 1,
|
||||||
|
"changeset": 50391526,
|
||||||
|
"user": "catweazle67",
|
||||||
|
"uid": 1976209
|
||||||
|
}, {
|
||||||
|
"type": "node",
|
||||||
|
"id": 4978289384,
|
||||||
|
"lat": 51.2147683,
|
||||||
|
"lon": 3.2168674,
|
||||||
|
"timestamp": "2017-07-18T22:52:21Z",
|
||||||
|
"version": 1,
|
||||||
|
"changeset": 50391526,
|
||||||
|
"user": "catweazle67",
|
||||||
|
"uid": 1976209
|
||||||
|
}, {
|
||||||
|
"type": "node",
|
||||||
|
"id": 4978289386,
|
||||||
|
"lat": 51.2147718,
|
||||||
|
"lon": 3.2168815,
|
||||||
|
"timestamp": "2017-07-18T22:52:21Z",
|
||||||
|
"version": 1,
|
||||||
|
"changeset": 50391526,
|
||||||
|
"user": "catweazle67",
|
||||||
|
"uid": 1976209
|
||||||
|
}, {
|
||||||
|
"type": "node",
|
||||||
|
"id": 4978289388,
|
||||||
|
"lat": 51.2147884,
|
||||||
|
"lon": 3.2169829,
|
||||||
|
"timestamp": "2017-07-18T22:52:21Z",
|
||||||
|
"version": 1,
|
||||||
|
"changeset": 50391526,
|
||||||
|
"user": "catweazle67",
|
||||||
|
"uid": 1976209
|
||||||
|
}, {
|
||||||
|
"type": "way",
|
||||||
|
"id": 160909312,
|
||||||
|
"timestamp": "2017-07-18T22:52:30Z",
|
||||||
|
"version": 2,
|
||||||
|
"changeset": 50391526,
|
||||||
|
"user": "catweazle67",
|
||||||
|
"uid": 1976209,
|
||||||
|
"nodes": [1728823483, 1728823514, 4978289384, 4978289386, 4978288381, 4978289388, 4978289383, 1728823549, 1728823481, 1728823483],
|
||||||
|
"tags": {
|
||||||
|
"addr:city": "Brugge",
|
||||||
|
"addr:country": "BE",
|
||||||
|
"addr:housenumber": "108",
|
||||||
|
"addr:postcode": "8000",
|
||||||
|
"addr:street": "Ezelstraat",
|
||||||
|
"building": "yes"
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
*/
|
||||||
|
const wayId = "way/160909312"
|
||||||
|
|
||||||
|
const layout = AllKnownLayouts.allKnownLayouts.get("grb")
|
||||||
|
const state = new State(layout)
|
||||||
|
State.state = state;
|
||||||
|
const bbox = new BBox(
|
||||||
|
[[
|
||||||
|
3.216193914413452,
|
||||||
|
51.214585847530635
|
||||||
|
],
|
||||||
|
[
|
||||||
|
3.217325806617737,
|
||||||
|
51.214585847530635
|
||||||
|
],
|
||||||
|
[
|
||||||
|
3.217325806617737,
|
||||||
|
51.21523102068533
|
||||||
|
],
|
||||||
|
[
|
||||||
|
3.216193914413452,
|
||||||
|
51.21523102068533
|
||||||
|
],
|
||||||
|
[
|
||||||
|
3.216193914413452,
|
||||||
|
51.214585847530635
|
||||||
|
]
|
||||||
|
])
|
||||||
|
const url = `https://www.openstreetmap.org/api/0.6/map.json?bbox=${bbox.minLon},${bbox.minLat},${bbox.maxLon},${bbox.maxLat}`
|
||||||
|
const data = await Utils.downloadJson(url)
|
||||||
|
|
||||||
|
state.featurePipeline.fullNodeDatabase.handleOsmJson(data, 0)
|
||||||
|
|
||||||
|
|
||||||
|
const action = new ReplaceGeometryAction(state, targetFeature, wayId, {
|
||||||
|
theme: "test"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
console.log(">>>>> ", action.GetClosestIds())
|
||||||
|
|
||||||
|
const map = Minimap.createMiniMap({
|
||||||
|
attribution: false,
|
||||||
|
})
|
||||||
|
const preview = await action.getPreview()
|
||||||
|
new ShowDataLayer({
|
||||||
|
layerToShow: AllKnownLayers.sharedLayers.get("conflation"),
|
||||||
|
features: preview,
|
||||||
|
leafletMap: map.leafletMap,
|
||||||
|
zoomToFeatures: true
|
||||||
|
})
|
||||||
|
map
|
||||||
|
.SetStyle("height: 75vh;")
|
||||||
|
.AttachTo("maindiv")
|
||||||
|
}
|
||||||
|
|
||||||
|
test()
|
|
@ -64,7 +64,7 @@ export default class ReplaceGeometrySpec extends T {
|
||||||
properties: {},
|
properties: {},
|
||||||
geometry: {
|
geometry: {
|
||||||
type: "Polygon",
|
type: "Polygon",
|
||||||
coordinates
|
coordinates: [coordinates]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue