Reputation: 1423
I have a TopoJSON file containing the boundaries of various districts in Uttar Pradesh, India. When you load the data on a map, you see only the outlines of the districts; the districts themselves are not filled.
I believe the problem is that each district is of type GeometryCollection
that has its own geometries
made up of a series of LineString
s.
Instead, I want each district to be of type Polygon
that just has arcs
.
For example, the first object is:
{
"type": "GeometryCollection",
"geometries": [{
"type": "GeometryCollection",
"properties": {
"district_number": 1,
"district_name": "Ghaziabad"
},
"geometries": [{
"type": "LineString",
"arcs": [0]
}, {
"type": "LineString",
"arcs": [1]
}, {
"type": "LineString",
"arcs": [2]
}, {
"type": "LineString",
"arcs": [3]
}, {
"type": "LineString",
"arcs": [4]
}, {
"type": "LineString",
"arcs": [5]
}]
}
I think I want to convert it, and every other object, to:
{
"type": "Polygon",
"properties": {
"district_number": 1,
"district_name": "Ghaziabad"
},
"arcs": [[0,1,2,3,4,5]]
}
I could fix it manually, but that seems insane. Is there a better way?
So I figured out how to convert the object into the result I thought I wanted, but I got some very wacky polygons. Here is my (very clunky) code. Thanks to Saeed Adel Mehraban for some guidance with this.
d3.json('map.topojson',function(error,data){ // get my json that needs to be converted
var arr = data.objects.collection.geometries; // this is the relevant array
var newArr = []; // in order to map each object, i need to put each one into a new array as a single-item array
arr.forEach(function(d,i){
var curr = [d];
newArr.push(curr);
})
newArr.forEach(function(e,i){ // now that i have my new array, i want to convert each object that contains a LineString into a Polygon
var output = e.map(function(d){
var arcsArr = []; // an empty array to push each single value of the LineString arcs into
return {
"type": "Polygon", // change the type to polygon
"properties": d.properties, // keep the properties
"arcs": d.geometries.map(function(g) { // a single key-value pair for arcs, made up of the individual arcs from the LineString
arcsArr.push(g.arcs[0]);
return [arcsArr]; // the array of arcs must be in another array
})
};
});
var output = output[0]; // get only the first item in the output array, which is the object i have modified
output.arcs = output.arcs[0]; // and change the arcs so we're only taking the first array (as we've duplicated the arrays)
$('body').append(JSON.stringify(output)+','); // append the whole thing to the body so I can copy it and paste it into the appropriate part of the JSON
});
});
This "worked" in the sense that my LineString
s were indeed converted to Polygon
s, retaining the original border. But the polygons themselves are a nightmare, with straight lines crisscrossing the map at all kinds of angles.
Is there something like a command line tool that can convert boundaries made of LineString
s into Polygon
s?
Upvotes: 1
Views: 1203
Reputation: 216
I believe I ran into the same problem being described.
This is Zambia drawn as a svg polyline foreach arc (red being the first arc listed, and magenta being the last):
However when attempting to create a polygon by concatenating the arcs:
What happened was the arcs for every object were listed clockwise, but the points in every individual arc were listed counterclockwise. Without seeing the topojson that OP is using I cannot 100% confirm this, but I suspect that this was the case.
I solved this by reversing the points in an arc before pushing them to the array of points to draw the polygon and now all is well:
Upvotes: 1
Reputation: 3324
Maybe a map function like below? (I write that with simplistic assumption about data schema. I can't guarantee that it works for complex linestrings since I'm not familiar with topojson format. But it works with your provided data)
var foo = [
{
"type": "GeometryCollection",
"geometries": [{
"type": "GeometryCollection",
"properties": {
"district_number": 1,
"district_name": "Ghaziabad"
},
"geometries": [{
"type": "LineString",
"arcs": [0]
}, {
"type": "LineString",
"arcs": [1]
}, {
"type": "LineString",
"arcs": [2]
}, {
"type": "LineString",
"arcs": [3]
}, {
"type": "LineString",
"arcs": [4]
}, {
"type": "LineString",
"arcs": [5]
}]
}]
}
];
var bar = foo.map(function(d) {
return {
"type": "Polygon",
"properties": d.geometries[0].properties,
"arc": d.geometries.map(function(g1) {
return g1.geometries.map(function(g) {
return g.arcs[0];
});
})
};
});
console.log(bar);
Upvotes: 0