1 |
|
2 | var RADIUS = 6371000.0;
|
3 | var GEO2METER = RADIUS * (Math.PI / 180)
|
4 |
|
5 | function newScene(sceneContent) {
|
6 | return {"X3D": {
|
7 | "@version": "3.0",
|
8 | "@profile": "Immersive",
|
9 | "@xmlns:xsd": "http://www.w3.org/2001/XMLSchema-instance",
|
10 | "@xsd:noNamespaceSchemaLocation": "http://www.web3d.org/specifications/x3d-3.0.xsd",
|
11 | "Scene": {
|
12 | "-children": sceneContent
|
13 | }
|
14 | }
|
15 | };
|
16 | }
|
17 |
|
18 | function newX3dJsonBld(id) {
|
19 | var result = {"Group": {
|
20 | "@class": "building",
|
21 | "@DEF": id,
|
22 | "@id": id,
|
23 | "-children": []
|
24 | }
|
25 | };
|
26 | // console.log('id: ' + JSON.stringify(id));
|
27 | // console.log('uuu: ' + JSON.stringify(result));
|
28 | return result;
|
29 | }
|
30 | function addBldPart(x3dJsonBld, x3dJsonBldPart) {
|
31 | var children = x3dJsonBld['Group']['-children'];
|
32 | // var children = [];
|
33 | // console.log('xxx: ' + JSON.stringify(children));
|
34 | // console.log('zzz: ' + JSON.stringify(JSON.parse(JSON.stringify(x3dJsonBldPart))));
|
35 | children[children.length] = JSON.parse(JSON.stringify(x3dJsonBldPart));
|
36 | }
|
37 |
|
38 | //function addBlock(x3dJsonBlockGroup, x3dJsonBlock) {
|
39 | // var x3dJsonBlocks = x3dJsonBlockGroup['Group']['-children'];
|
40 | //}
|
41 |
|
42 | function newX3dJsonBldPart(minHeight, color, transparency, points, height) {
|
43 | var result = {"Transform": {
|
44 | "@translation": [0, minHeight, 0],
|
45 | "-children": [{"Group": {"@class": "buildingPart",
|
46 | "-children": [{"Shape": {
|
47 | "-appearance": [{"Appearance": {
|
48 | "-material": [{"Material": {
|
49 | "@diffuseColor": color,
|
50 | "@transparency": transparency
|
51 | }}]
|
52 | }}],
|
53 | "-geometry": [{"Extrusion": {
|
54 | "@convex": false,
|
55 | "@creaseAngle": 0.785,
|
56 | "@crossSection": points,
|
57 | "@solid": false,
|
58 | "@endCap": false,
|
59 | "@spine": [0, 0, 0, 0, height, 0]
|
60 | }}]
|
61 | }}]
|
62 | }}]
|
63 | }
|
64 | };
|
65 | // console.log('result: ' + JSON.stringify(result));
|
66 | return result;
|
67 | }
|
68 | function newX3dJsonBldFloorPart(height, points) {
|
69 | // console.log("height: " + height);
|
70 | var result = {"Transform": {
|
71 | "@translation": [0, height, 0],
|
72 | "-children": [{"Transform": {"@rotation": '1 0 0 1.5708',
|
73 | "-children": [{"Group": {"@class": "buildingPart",
|
74 | "-children": [{"Shape": {
|
75 | "-appearance": [{"Appearance": {
|
76 | "-material": [{"Material": {
|
77 | "@diffuseColor": [1, 1, 1],
|
78 | "@transparency": 0
|
79 | }}]
|
80 | }}],
|
81 | "-geometry": [{"Polyline2D": {
|
82 | "@lineSegments": points}}]
|
83 | }}]
|
84 | }}]
|
85 | }}]
|
86 | }
|
87 | };
|
88 | // console.log('yyy: ' + result)
|
89 | return result;
|
90 | }
|
91 |
|
92 |
|
93 | // <Transform rotation='1 0 0 1.5708'>
|
94 |
|
95 |
|
96 |
|
97 |
|
98 | function getGeoJsonRoof(geoJson, id) {
|
99 | var result;
|
100 | for (var idx = 0; idx < geoJson.features.length; idx++) {
|
101 | if (geoJson.features[idx].properties.type === "geoRoof" && geoJson.features[idx].properties.id === id) {
|
102 | result = geoJson.features[idx];
|
103 | break;
|
104 | }
|
105 | }
|
106 | return result;
|
107 | }
|
108 |
|
109 | function geoToX3dColor(geoColor) {
|
110 | // console.log("geoColor: " + geoColor);
|
111 | // rgb(245, 245, 220)
|
112 | var regex = /^rgb\(([0-9]+), *([0-9]+), *([0-9]+)\)$/
|
113 | var result = geoColor.match(regex);
|
114 | return [
|
115 | Math.round(parseFloat(result[1], 10) / 2.56) / 100,
|
116 | Math.round(parseFloat(result[2], 10) / 2.56) / 100,
|
117 | Math.round(parseFloat(result[3], 10) / 2.56) / 100];
|
118 | }
|
119 | //Math.round(number * 100) / 100
|
120 | function isInside(geopoint, geobound) {
|
121 | return !(geopoint[0] < geobound.minbound[0]
|
122 | || geopoint[0] > geobound.maxbound[0]
|
123 | || geopoint[1] < geobound.minbound[1]
|
124 | || geopoint[1] > geobound.maxbound[1]);
|
125 | }
|
126 |
|
127 | /**
|
128 | * Process centroid of set of points.
|
129 | * e.g.: geonodes = [[x1,y1],[x2,y2]]
|
130 | */
|
131 | //function centroid(geonodes) {
|
132 | // var sumlon = 0;
|
133 | // var sumlat = 0;
|
134 | // for (var i = 0; i < geonodes.length; i++) {
|
135 | // sumlon += geonodes[i][0];
|
136 | // sumlat += geonodes[i][1];
|
137 | // }
|
138 | // return [
|
139 | // sumlon / geonodes.length,
|
140 | // sumlat / geonodes.length
|
141 | // ];
|
142 | //}
|
143 |
|
144 | var myOsmGround;
|
145 |
|
146 | /**
|
147 | *
|
148 | * +--------->
|
149 | * | X
|
150 | * |
|
151 | * |
|
152 | * lat ^ | Y
|
153 | * | v
|
154 | * |
|
155 | * | A B
|
156 | * | +-----+ lat=lat_A
|
157 | * | | |
|
158 | * | | | lon=lon_A
|
159 | * | +-----+
|
160 | * | D C
|
161 | * |
|
162 | * +----------------->
|
163 | * long
|
164 | *
|
165 | */
|
166 |
|
167 | /**
|
168 | * Create ground tile.
|
169 | * @param shift shift from origin
|
170 | * @param size ground size
|
171 | * @param tile tile url
|
172 | */
|
173 | function createTile(shift, size, tile) {
|
174 | var shape = {
|
175 | '-geometry': [{"Rectangle2D": {
|
176 | "@size": size
|
177 | }}]
|
178 | };
|
179 | if (tile) {
|
180 | shape['-appearance'] = [{"Appearance": {
|
181 | "-texture": [{"ImageTexture": {
|
182 | "@url": tile,
|
183 | }}]
|
184 | }}];
|
185 | }
|
186 | var result = {
|
187 | "Transform": {
|
188 | "@translation": [shift[0], -0.1, shift[1]],
|
189 | "@rotation": '1 0 0 -1.5708',
|
190 | "-children": [{"Group": {"@class": "tile",
|
191 | "-children": [{"Shape": shape}]
|
192 | }}]
|
193 | }
|
194 | };
|
195 | // if (tile) {
|
196 | // result["-children"][0]
|
197 | // }
|
198 | return result;
|
199 | }
|
200 | // <Transform translation='57.264285044396 -0.1 -43.3774179598869' rotation='1 0 0 -1.5708'>
|
201 | // <Group>
|
202 | // <Shape>
|
203 | // <Appearance>
|
204 | // <ImageTexture url='"http://a.tile.openstreetmap.org/20/308790/394107.png"'/>
|
205 | // </Appearance>
|
206 | // <Rectangle2D size='38.1757484360134 28.9212942252524'></Rectangle2D>
|
207 | // </Shape>
|
208 | // </Group>
|
209 |
|
210 | // <Transform translation='0 0 0'>
|
211 | // <Group class='tile'>
|
212 | // <Shape>
|
213 | // <Appearance>
|
214 | // <ImageTexture>
|
215 | // </ImageTexture>
|
216 | // </Appearance>
|
217 | // <Rectangle2D>
|
218 | // </Rectangle2D>
|
219 | // </Shape>
|
220 | // </Group>
|
221 | // </Transform>
|
222 | // <Group class='building'>
|
223 | // </Group>
|
224 | //
|
225 | // <Transform translation='-57.2629602636441 -0.1 -43.3774179598869' rotation='1 0 0 -1.5708'>
|
226 | // <Group>
|
227 | // <Shape>
|
228 | // <Appearance>
|
229 | // <ImageTexture url='"http://a.tile.openstreetmap.org/20/308787/394107.png"'/>
|
230 | // </Appearance>
|
231 | // <Rectangle2D size='38.1757484360133 28.9212942252524'></Rectangle2D>
|
232 | // </Shape>
|
233 | // </Group>
|
234 | // </Transform>
|
235 |
|
236 | /**
|
237 | * Convert GeoJSON data to x3dJson data
|
238 | * @param geoJson GeoJson buildings.
|
239 | * @param options Options.
|
240 | * @param onConvert callback at end of conversion
|
241 | */
|
242 | function convert(geoJson, options, onConvert) {
|
243 | var origin = (options && options.origin) ? options.origin : null;
|
244 | var loD = (options && options.loD) ? options.loD : 0;
|
245 | var tile = (options && options.tile) ? options.tile : null;
|
246 | var x3dJs = [];
|
247 | for (var idxGJ = 0; idxGJ < geoJson.length; idxGJ++) {
|
248 | switch (geoJson[idxGJ].type) {
|
249 | case "Feature":
|
250 | if (geoJson[idxGJ].properties.type === 'bounds') {
|
251 | var boundCoord = geoJson[idxGJ].geometry.coordinates[0];
|
252 | // console.log('boundCoord: ' + JSON.stringify(boundCoord));
|
253 | // boundCoord: [["-73.9862797","40.7481926"],["-73.9852939","40.7481926"],["-73.9852939","40.7486022"],["-73.9862797","40.7486022"]]
|
254 |
|
255 | if (!origin) {
|
256 | origin = boundCoord[0];
|
257 | }
|
258 | // 0:0,0--1:X,0
|
259 | // | |
|
260 | // | |
|
261 | // 3:0,Y--2:X,Y
|
262 | var size = [
|
263 | ((+boundCoord[2][0] - +boundCoord[0][0])) * GEO2METER,
|
264 | ((+boundCoord[2][1] - +boundCoord[0][1])) * GEO2METER];
|
265 | // console.log("size: " + JSON.stringify(size));
|
266 | // console.log("origin: " + JSON.stringify(origin));
|
267 | // console.log("boundCoord: " + JSON.stringify(boundCoord));
|
268 | x3dJs[x3dJs.length] = createTile(
|
269 | [((boundCoord[2][0] - origin[0]) * GEO2METER) / 2.0, ((+origin[1] - boundCoord[0][1]) * GEO2METER) / 2.0],
|
270 | size,
|
271 | tile);
|
272 | }
|
273 | break;
|
274 | case "FeatureCollection":
|
275 | var id = geoJson[idxGJ].properties.id;
|
276 | x3dJsonBlock = newX3dJsonBld(id);
|
277 | for (var i = 0; i < geoJson[idxGJ].features.length; i++) {
|
278 | var geoJsonBldPart = geoJson[idxGJ].features[i];
|
279 | // var my3dBldPart = {};
|
280 | points = [];
|
281 | perimeter = 0;
|
282 | if (geoJsonBldPart.geometry.coordinates[0].length > 0) {
|
283 | var pointRef = geoJsonBldPart.geometry.coordinates[0][geoJsonBldPart.geometry.coordinates[0].length - 1];
|
284 | for (var j = 0; j < geoJsonBldPart.geometry.coordinates[0].length; j++) {
|
285 | var node = geoJsonBldPart.geometry.coordinates[0][j];
|
286 | points[points.length] = [(node[0] - origin[0]) * GEO2METER, (origin[1] - node[1]) * GEO2METER];
|
287 | var z = (pointRef[1] - node[1]) * GEO2METER;
|
288 | var x = (node[0] - pointRef[0]) * GEO2METER;
|
289 | pointRef = node;
|
290 | perimeter += Math.sqrt(z * z + x * x);
|
291 | }
|
292 | }
|
293 |
|
294 | // if (geoJsonBldPart.properties.levels) {
|
295 | // my3dBldPart.levels = +geoJsonBldPart.properties.levels;
|
296 | // }
|
297 |
|
298 | // BldPart roof
|
299 | var roof = getGeoJsonRoof(geoJson[idxGJ], geoJsonBldPart.properties.id);
|
300 |
|
301 | // my3dBldPart.roof = {};
|
302 | // my3dBldPart.roof.shape = "flat";
|
303 | // my3dBldPart.roof.shape = (roof && roof.shape) ? roof.shape : "flat";
|
304 | // my3dBldPart.roof.elevation = ((geoJsonBldPart.properties.height) ? geoJsonBldPart.properties.height : 0)
|
305 | // - ((my3dBldPart.roof && my3dBldPart.roof.elevation) ? my3dBldPart.roof.elevation : 0);
|
306 | // my3dBldPart.roof.points = my3dBldPart.points;
|
307 | // my3dBldPart.roof.height = (roof && roof.height) ? roof.height : 0;
|
308 |
|
309 | var diffuseColor = (geoJsonBldPart.properties.color) ?
|
310 | geoToX3dColor(geoJsonBldPart.properties.color) :
|
311 | [
|
312 | (((13 * (1 + height)) % 100) / 100),
|
313 | (((17 * (1 + height)) % 100) / 100),
|
314 | (((23 * (1 + height)) % 100) / 100)];
|
315 | var minHeight = (geoJsonBldPart.properties.minHeight) ? +geoJsonBldPart.properties.minHeight : 0;
|
316 | var height = ((geoJsonBldPart.properties.height) ? geoJsonBldPart.properties.height : 0)
|
317 | - ((roof && roof.height) ? (roof.height) : 0)
|
318 | - minHeight;
|
319 | if (!height) {
|
320 | height = 9.99
|
321 | }
|
322 | var x3dPoints = [];
|
323 | for (var iP = 0; iP < points.length; iP++) {
|
324 | x3dPoints[x3dPoints.length] = points[iP][0];
|
325 | x3dPoints[x3dPoints.length] = points[iP][1];
|
326 | }
|
327 | addBldPart(x3dJsonBlock,
|
328 | newX3dJsonBldPart(
|
329 | minHeight,
|
330 | diffuseColor,
|
331 | geoJsonBldPart.properties.levels ? 0.6 : 0,
|
332 | x3dPoints,
|
333 | height));
|
334 |
|
335 | // Floors
|
336 | if (loD >= 4 && geoJsonBldPart.properties.levels && geoJsonBldPart.properties.height) {
|
337 | // console.log("geoJsonBldPart.properties.levels: " + geoJsonBldPart.properties.levels);
|
338 | // console.log("geoJsonBldPart.properties.height: " + geoJsonBldPart.properties.height);
|
339 | // console.log("geoJsonBldPart.properties.minLevel: " + geoJsonBldPart.properties.minLevel);
|
340 | // console.log("loD: " + loD);
|
341 | var floorHeight = (geoJsonBldPart.properties.height - minHeight) / (geoJsonBldPart.properties.levels - geoJsonBldPart.properties.minLevel);
|
342 | var level;
|
343 | console.log("geoJsonBldPart.properties.height: " + geoJsonBldPart.properties.height);
|
344 | console.log("geoJsonBldPart.properties.levels: " + geoJsonBldPart.properties.levels);
|
345 | console.log("geoJsonBldPart.properties.minLevel: " + geoJsonBldPart.properties.minLevel);
|
346 | console.log("floorHeight: " + floorHeight);
|
347 | console.log("minHeight: " + minHeight);
|
348 | for (level = +geoJsonBldPart.properties.minLevel; level < geoJsonBldPart.properties.levels; level++) {
|
349 | console.log("level: " + level);
|
350 | console.log("elevation processed: " + (+minHeight + (level - geoJsonBldPart.properties.minLevel) * floorHeight));
|
351 | addBldPart(x3dJsonBlock,
|
352 | newX3dJsonBldFloorPart(
|
353 | +minHeight + (level - geoJsonBldPart.properties.minLevel) * floorHeight,
|
354 | x3dPoints));
|
355 | }
|
356 | }
|
357 | }
|
358 | x3dJs[x3dJs.length] = JSON.parse(JSON.stringify(x3dJsonBlock));
|
359 | break;
|
360 | }
|
361 | }
|
362 | var scene = newScene(x3dJs);
|
363 | onConvert(scene);
|
364 | }
|
365 |
|
366 | exports.convert = convert;
|