TreeGenerator.java 7.21 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package de.hft.stuttgart.citygml.green.osm;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Polygon;
import org.xmlobjects.gml.model.geometry.aggregates.MultiSurface;
import org.xmlobjects.gml.model.geometry.primitives.SurfaceProperty;

public class TreeGenerator {
	
	private static final double TRUNK_INCREASE_FACTOR = 1.2;
	public static MultiSurface generateTree(Coordinate point, double trunkRadius, double trunkHeight,
			double crownXRadius, double crownYRadius, double crownHeight) {

		List<Coordinate> trunkWestCoordinateList = new ArrayList<>();
		trunkWestCoordinateList.add(new Coordinate(point.x - trunkRadius, point.y - trunkRadius, 0));
		double drawTrunkHeight = trunkHeight * TRUNK_INCREASE_FACTOR;
		trunkWestCoordinateList.add(new Coordinate(point.x - trunkRadius, point.y - trunkRadius, drawTrunkHeight));
		trunkWestCoordinateList.add(new Coordinate(point.x - trunkRadius, point.y + trunkRadius, drawTrunkHeight));
		trunkWestCoordinateList.add(new Coordinate(point.x - trunkRadius, point.y + trunkRadius, 0));
		trunkWestCoordinateList.add(new Coordinate(point.x - trunkRadius, point.y - trunkRadius, 0));
		Polygon trunkWestPolygon = convertPolygon(trunkWestCoordinateList);
		var trunkWestConvertedPolygon = GreenEnricher.convertToCityGmlPoly(trunkWestPolygon);
		MultiSurface ms = new MultiSurface();
		ms.getSurfaceMember().add(new SurfaceProperty(trunkWestConvertedPolygon));

		List<Coordinate> trunkEastCoordinateList = new ArrayList<>();
		trunkEastCoordinateList.add(new Coordinate(point.x + trunkRadius, point.y - trunkRadius, 0));
		trunkEastCoordinateList.add(new Coordinate(point.x + trunkRadius, point.y + trunkRadius, 0));
		trunkEastCoordinateList.add(new Coordinate(point.x + trunkRadius, point.y + trunkRadius, drawTrunkHeight));
		trunkEastCoordinateList.add(new Coordinate(point.x + trunkRadius, point.y - trunkRadius, drawTrunkHeight));
		trunkEastCoordinateList.add(new Coordinate(point.x + trunkRadius, point.y - trunkRadius, 0));
		Polygon trunkEastPolygon = convertPolygon(trunkEastCoordinateList);
		var trunkEastConvertedPolygon = GreenEnricher.convertToCityGmlPoly(trunkEastPolygon);
		ms.getSurfaceMember().add(new SurfaceProperty(trunkEastConvertedPolygon));

		List<Coordinate> trunkSouthCoordinateList = new ArrayList<>();
		trunkSouthCoordinateList.add(new Coordinate(point.x - trunkRadius, point.y - trunkRadius, 0));
		trunkSouthCoordinateList.add(new Coordinate(point.x + trunkRadius, point.y - trunkRadius, 0));
		trunkSouthCoordinateList.add(new Coordinate(point.x + trunkRadius, point.y - trunkRadius, drawTrunkHeight));
		trunkSouthCoordinateList.add(new Coordinate(point.x - trunkRadius, point.y - trunkRadius, drawTrunkHeight));
		trunkSouthCoordinateList.add(new Coordinate(point.x - trunkRadius, point.y - trunkRadius, 0));
		Polygon trunkSouthPolygon = convertPolygon(trunkSouthCoordinateList);
		var trunkSouthConvertedPolygon = GreenEnricher.convertToCityGmlPoly(trunkSouthPolygon);
		ms.getSurfaceMember().add(new SurfaceProperty(trunkSouthConvertedPolygon));

		List<Coordinate> trunkNorthCoordinateList = new ArrayList<>();
		trunkNorthCoordinateList.add(new Coordinate(point.x - trunkRadius, point.y + trunkRadius, 0));
		trunkNorthCoordinateList.add(new Coordinate(point.x - trunkRadius, point.y + trunkRadius, drawTrunkHeight));
		trunkNorthCoordinateList.add(new Coordinate(point.x + trunkRadius, point.y + trunkRadius, drawTrunkHeight));
		trunkNorthCoordinateList.add(new Coordinate(point.x + trunkRadius, point.y + trunkRadius, 0));
		trunkNorthCoordinateList.add(new Coordinate(point.x - trunkRadius, point.y + trunkRadius, 0));
		Polygon trunkNorthPolygon = convertPolygon(trunkNorthCoordinateList);
		var trunkNorthConvertedPolygon = GreenEnricher.convertToCityGmlPoly(trunkNorthPolygon);
		ms.getSurfaceMember().add(new SurfaceProperty(trunkNorthConvertedPolygon));

		/*-
		 * Spheroid formula:
		 * x = a * sin(thetha) * cos(phi)
		 * y = b * sin(thetha) * sin(phi)
		 * z = c * cos(thetha)
		 * 
		 * 0 <= theta <= pi
		 * 0 <= phi	 < 2 pi
		 */

		// create crown
		// divide by 2 to get radius, height is diameter
		double c = crownHeight / 2D;

		double a = crownXRadius;
		double b = crownYRadius;

		int numberOfThetaRings = 5;
		int numberOfPhiRings = 10;

		double thetaDelta = Math.PI / (numberOfThetaRings - 1);
		double phiDelta = Math.PI * 2 / numberOfPhiRings;

		List<List<Coordinate>> ringCoordinates = new ArrayList<>();

		// top point triangles
		Coordinate topPoint = new Coordinate(point.x, point.y, point.z + c + trunkHeight + c);
		ringCoordinates.add(Collections.singletonList(topPoint));
		for (int i = 1; i < numberOfThetaRings - 1; i++) {
			double theta = i * thetaDelta;
			List<Coordinate> coords = new ArrayList<>();
			ringCoordinates.add(coords);
			for (int j = 0; j < numberOfPhiRings; j++) {
				double phi = j * phiDelta;
				double x = a * Math.sin(theta) * Math.cos(phi) + point.x;
				double y = b * Math.sin(theta) * Math.sin(phi) + point.y;
				double z = c * Math.cos(theta) + point.z + trunkHeight + c;
				Coordinate p1 = new Coordinate(x, y, z);
				coords.add(p1);
			}
		}
		Coordinate bottomPoint = new Coordinate(point.x, point.y, point.z + trunkHeight);
		ringCoordinates.add(Collections.singletonList(bottomPoint));
		
		List<Coordinate> secondRing = ringCoordinates.get(1);
		for (int i = 0; i < secondRing.size(); i++) {
			Coordinate[] coordArray = new Coordinate[] { topPoint, secondRing.get(i), secondRing.get((i + 1) % secondRing.size()), topPoint };
			Polygon polygon = GreenEnricher.geomFactory.createPolygon(coordArray);
			var convertedPoly = GreenEnricher.convertToCityGmlPoly(polygon);
			ms.getSurfaceMember().add(new SurfaceProperty(convertedPoly));
		}
		for (int i = 1; i < ringCoordinates.size() - 2; i++) {
			List<Coordinate> topRing = ringCoordinates.get(i);
			List<Coordinate> bottomRing = ringCoordinates.get(i + 1);
			for (int j = 0; j < topRing.size(); j++) {
				int nextRingIndex = (j + 1) % topRing.size();
				Coordinate p1 = topRing.get(j);
				Coordinate p2 = topRing.get(nextRingIndex);
				Coordinate p3 = bottomRing.get(j);
				Coordinate p4 = bottomRing.get(nextRingIndex);
				Coordinate[] coordArray = new Coordinate[] { p1, p3, p4, p2, p1 };
				Polygon polygon = GreenEnricher.geomFactory.createPolygon(coordArray);
				var convertedPoly = GreenEnricher.convertToCityGmlPoly(polygon);
				ms.getSurfaceMember().add(new SurfaceProperty(convertedPoly));
			}
		}
		
		// bottom point triangles
		List<Coordinate> bottomRing = ringCoordinates.get(ringCoordinates.size() - 2);
		for (int i = 0; i < bottomRing.size(); i++) {
			int nextRingIndex = (i + 1) % bottomRing.size();
			Coordinate p1 = bottomRing.get(i);
			Coordinate p2 = bottomRing.get(nextRingIndex);
			Coordinate[] coordArray = new Coordinate[] { p2, p1, bottomPoint, p2 };
			Polygon polygon = GreenEnricher.geomFactory.createPolygon(coordArray);
			var convertedPoly = GreenEnricher.convertToCityGmlPoly(polygon);
			ms.getSurfaceMember().add(new SurfaceProperty(convertedPoly));
		}

		return ms;
	}

	private static Polygon convertPolygon(List<Coordinate> trunkWestCoordinateList) {
		return GreenEnricher.geomFactory
				.createPolygon(trunkWestCoordinateList.toArray(new Coordinate[trunkWestCoordinateList.size()]));
	}

}