Revision 5f5cfe6a
Added by Andreas Kohlbecker about 4 years ago
.gitignore | ||
---|---|---|
50 | 50 |
!cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/database/data/.settings |
51 | 51 |
!cdmlib-persistence/src/main/java/eu/etaxonomy/cdm/database/update/v35_36/.settings |
52 | 52 |
workbench.xmi |
53 |
cdmlib-ext/KmlJaxbMarshallerTest.kml |
cdmlib-ext/src/main/java/eu/etaxonomy/cdm/ext/geo/EditGeoService.java | ||
---|---|---|
28 | 28 |
import org.springframework.stereotype.Service; |
29 | 29 |
import org.springframework.transaction.annotation.Transactional; |
30 | 30 |
|
31 |
import de.micromata.opengis.kml.v_2_2_0.Kml; |
|
31 | 32 |
import eu.etaxonomy.cdm.api.service.DistributionTree; |
32 | 33 |
import eu.etaxonomy.cdm.api.service.dto.CondensedDistribution; |
33 | 34 |
import eu.etaxonomy.cdm.api.service.dto.DistributionInfoDTO; |
34 | 35 |
import eu.etaxonomy.cdm.api.service.dto.DistributionInfoDTO.InfoPart; |
35 | 36 |
import eu.etaxonomy.cdm.api.utility.DescriptionUtility; |
36 | 37 |
import eu.etaxonomy.cdm.api.utility.DistributionOrder; |
38 |
import eu.etaxonomy.cdm.ext.geo.kml.KMLDocumentBuilder; |
|
37 | 39 |
import eu.etaxonomy.cdm.model.common.CdmBase; |
38 | 40 |
import eu.etaxonomy.cdm.model.common.Language; |
39 | 41 |
import eu.etaxonomy.cdm.model.common.MarkerType; |
... | ... | |
181 | 183 |
} |
182 | 184 |
|
183 | 185 |
@Override |
184 |
public OccurrenceServiceRequestParameterDto getOccurrenceServiceRequestParameterString(
|
|
185 |
List<SpecimenOrObservationBase> specimensOrObersvations,
|
|
186 |
public OccurrenceServiceRequestParameterDto getOccurrenceServiceRequestParameters(
|
|
187 |
List<SpecimenOrObservationBase> specimensOrObservations,
|
|
186 | 188 |
Map<SpecimenOrObservationType, Color> specimenOrObservationTypeColors) { |
187 | 189 |
|
188 | 190 |
List<Point> fieldUnitPoints = new ArrayList<>(); |
189 | 191 |
List<Point> derivedUnitPoints = new ArrayList<>(); |
190 | 192 |
|
191 |
for (SpecimenOrObservationBase<?> specimenOrObservationBase : specimensOrObersvations) {
|
|
192 |
SpecimenOrObservationBase<?> specimenOrObservation = occurrenceDao |
|
193 |
for (SpecimenOrObservationBase<?> specimenOrObservationBase : specimensOrObservations) {
|
|
194 |
SpecimenOrObservationBase<?> specimensOrObservation = occurrenceDao
|
|
193 | 195 |
.load(specimenOrObservationBase.getUuid()); |
194 | 196 |
|
195 |
if (specimenOrObservation instanceof FieldUnit) { |
|
196 |
GatheringEvent gatherEvent = ((FieldUnit) specimenOrObservation).getGatheringEvent(); |
|
197 |
if (specimensOrObservation instanceof FieldUnit) {
|
|
198 |
GatheringEvent gatherEvent = ((FieldUnit) specimensOrObservation).getGatheringEvent();
|
|
197 | 199 |
if (gatherEvent != null && gatherEvent.getExactLocation() != null){ |
198 | 200 |
fieldUnitPoints.add(gatherEvent.getExactLocation()); |
199 | 201 |
} |
200 | 202 |
} |
201 |
if (specimenOrObservation instanceof DerivedUnit) { |
|
202 |
registerDerivedUnitLocations((DerivedUnit) specimenOrObservation, derivedUnitPoints); |
|
203 |
if (specimensOrObservation instanceof DerivedUnit) {
|
|
204 |
registerDerivedUnitLocations((DerivedUnit) specimensOrObservation, derivedUnitPoints);
|
|
203 | 205 |
} |
204 | 206 |
} |
205 | 207 |
|
206 | 208 |
return EditGeoServiceUtilities.getOccurrenceServiceRequestParameterString(fieldUnitPoints, |
207 | 209 |
derivedUnitPoints, specimenOrObservationTypeColors); |
208 | 210 |
} |
211 |
|
|
212 |
@Override |
|
213 |
public Kml occurrencesToKML( |
|
214 |
List<SpecimenOrObservationBase> specimensOrObservations, |
|
215 |
Map<SpecimenOrObservationType, Color> specimenOrObservationTypeColors) { |
|
216 |
|
|
217 |
KMLDocumentBuilder builder = new KMLDocumentBuilder(); |
|
218 |
|
|
219 |
for (SpecimenOrObservationBase<?> specimenOrObservationBase : specimensOrObservations) { |
|
220 |
builder.addSpecimenOrObservationBase(occurrenceDao.load(specimenOrObservationBase.getUuid())); |
|
221 |
} |
|
222 |
|
|
223 |
Kml kml = builder.build(); |
|
224 |
|
|
225 |
return kml; |
|
226 |
} |
|
209 | 227 |
|
210 | 228 |
public CondensedDistribution getCondensedDistribution(List<TaxonDescription> taxonDescriptions, |
211 | 229 |
boolean statusOrderPreference, |
cdmlib-ext/src/main/java/eu/etaxonomy/cdm/ext/geo/IEditGeoService.java | ||
---|---|---|
22 | 22 |
|
23 | 23 |
import org.springframework.transaction.annotation.Transactional; |
24 | 24 |
|
25 |
import de.micromata.opengis.kml.v_2_2_0.Kml; |
|
25 | 26 |
import eu.etaxonomy.cdm.api.service.dto.CondensedDistribution; |
26 | 27 |
import eu.etaxonomy.cdm.api.service.dto.DistributionInfoDTO; |
27 | 28 |
import eu.etaxonomy.cdm.api.utility.DescriptionUtility; |
... | ... | |
131 | 132 |
List<Language> langs); |
132 | 133 |
|
133 | 134 |
|
134 |
public OccurrenceServiceRequestParameterDto getOccurrenceServiceRequestParameterString(
|
|
135 |
public OccurrenceServiceRequestParameterDto getOccurrenceServiceRequestParameters(
|
|
135 | 136 |
List<SpecimenOrObservationBase> specimensOrObersvations, |
136 | 137 |
Map<SpecimenOrObservationType,Color> specimenOrObservationTypeColors |
137 | 138 |
); |
... | ... | |
222 | 223 |
CondensedDistributionRecipe recipe, |
223 | 224 |
List<Language> langs); |
224 | 225 |
|
226 |
|
|
227 |
public Kml occurrencesToKML(List<SpecimenOrObservationBase> specimensOrObersvations, |
|
228 |
Map<SpecimenOrObservationType, Color> specimenOrObservationTypeColors); |
|
229 |
|
|
225 | 230 |
} |
cdmlib-ext/src/main/java/eu/etaxonomy/cdm/ext/geo/kml/GeometryBuilder.java | ||
---|---|---|
1 |
/** |
|
2 |
* Copyright (C) 2020 EDIT |
|
3 |
* European Distributed Institute of Taxonomy |
|
4 |
* http://www.e-taxonomy.eu |
|
5 |
* |
|
6 |
* The contents of this file are subject to the Mozilla Public License Version 1.1 |
|
7 |
* See LICENSE.TXT at the top of this package for the full license terms. |
|
8 |
*/ |
|
9 |
|
|
10 |
package eu.etaxonomy.cdm.ext.geo.kml; |
|
11 |
|
|
12 |
import java.awt.geom.Point2D; |
|
13 |
|
|
14 |
import javax.measure.Quantity; |
|
15 |
import javax.measure.Unit; |
|
16 |
import javax.measure.UnitConverter; |
|
17 |
import javax.measure.quantity.Length; |
|
18 |
|
|
19 |
import org.apache.log4j.Logger; |
|
20 |
import org.geotools.data.DataUtilities; |
|
21 |
import org.geotools.feature.SchemaException; |
|
22 |
import org.geotools.feature.simple.SimpleFeatureBuilder; |
|
23 |
import org.geotools.geometry.jts.JTS; |
|
24 |
import org.geotools.geometry.jts.JTSFactoryFinder; |
|
25 |
import org.geotools.referencing.CRS; |
|
26 |
import org.geotools.referencing.GeodeticCalculator; |
|
27 |
import org.geotools.referencing.crs.DefaultGeographicCRS; |
|
28 |
import org.locationtech.jts.geom.Coordinate; |
|
29 |
import org.locationtech.jts.geom.CoordinateSequence; |
|
30 |
import org.locationtech.jts.geom.Geometry; |
|
31 |
import org.locationtech.jts.geom.GeometryFactory; |
|
32 |
import org.locationtech.jts.geom.Point; |
|
33 |
import org.locationtech.jts.geom.Polygon; |
|
34 |
import org.locationtech.jts.util.GeometricShapeFactory; |
|
35 |
import org.opengis.feature.GeometryAttribute; |
|
36 |
import org.opengis.feature.simple.SimpleFeature; |
|
37 |
import org.opengis.feature.simple.SimpleFeatureType; |
|
38 |
import org.opengis.geometry.MismatchedDimensionException; |
|
39 |
import org.opengis.referencing.FactoryException; |
|
40 |
import org.opengis.referencing.NoSuchAuthorityCodeException; |
|
41 |
import org.opengis.referencing.crs.CoordinateReferenceSystem; |
|
42 |
import org.opengis.referencing.crs.ProjectedCRS; |
|
43 |
import org.opengis.referencing.operation.MathTransform; |
|
44 |
import org.opengis.referencing.operation.TransformException; |
|
45 |
|
|
46 |
import si.uom.SI; |
|
47 |
import tec.uom.se.quantity.Quantities; |
|
48 |
|
|
49 |
/** |
|
50 |
* See : |
|
51 |
* |
|
52 |
* https://gis.stackexchange.com/questions/311272/create-dynamic-circle-polygon-from-specific-lat-long-using-geotools |
|
53 |
* https://gis.stackexchange.com/questions/283183/using-geometricshapefactory-to-create-circle-with-radius-in-miles |
|
54 |
* |
|
55 |
* https://stackoverflow.com/questions/36481651/how-do-i-create-a-circle-with-latitude-longitude-and-radius-with-geotools#36528805 |
|
56 |
* |
|
57 |
* |
|
58 |
* Another great library for creating shapes is https://github.com/locationtech/spatial4j |
|
59 |
* |
|
60 |
* @author Andreas Kohlbecker |
|
61 |
* @since Apr 21, 2020 |
|
62 |
*/ |
|
63 |
public class GeometryBuilder { |
|
64 |
|
|
65 |
private final static Logger logger = Logger.getLogger(GeometryBuilder.class); |
|
66 |
|
|
67 |
public enum CircleMethod { |
|
68 |
circle, simpleCircleSmall, simpleCircle, reprojectedCircle; |
|
69 |
} |
|
70 |
|
|
71 |
/** |
|
72 |
* Fails with javax.measure.IncommensurableException: m is not compatible with |
|
73 |
* deg |
|
74 |
* |
|
75 |
* see |
|
76 |
* https://gis.stackexchange.com/questions/283183/using-geometricshapefactory-to-create-circle-with-radius-in-miles |
|
77 |
* |
|
78 |
* @param radius |
|
79 |
* @param latitude |
|
80 |
* @param longitude |
|
81 |
* @return |
|
82 |
* @throws NoSuchAuthorityCodeException |
|
83 |
* @throws FactoryException |
|
84 |
*/ |
|
85 |
public Polygon circle(Double radius, Double latitude, Double longitude) |
|
86 |
throws NoSuchAuthorityCodeException, FactoryException { |
|
87 |
|
|
88 |
Quantity<Length> radiusMeter = Quantities.getQuantity(radius, SI.METRE); |
|
89 |
Unit<Length> origUnit = (Unit<Length>) DefaultGeographicCRS.WGS84.getCoordinateSystem().getAxis(0).getUnit(); //// (Unit<Length>) |
|
90 |
//// //// |
|
91 |
//// origCRS.getCoordinateSystem().getAxis(0).getUnit(); |
|
92 |
|
|
93 |
GeometricShapeFactory shapeFactory = new GeometricShapeFactory(); |
|
94 |
shapeFactory.setNumPoints(32); |
|
95 |
shapeFactory.setCentre(new Coordinate(latitude, longitude)); |
|
96 |
shapeFactory.setSize(radiusMeter.to(origUnit).getValue().doubleValue() * 2); |
|
97 |
|
|
98 |
Polygon circlePolygon = shapeFactory.createCircle(); |
|
99 |
circlePolygon.setSRID(4326); |
|
100 |
|
|
101 |
return circlePolygon; |
|
102 |
} |
|
103 |
|
|
104 |
/** |
|
105 |
* Only suitable for small radius (> 1000 m) as the circles are heavily |
|
106 |
* distorted otherwise. |
|
107 |
* |
|
108 |
* @param radius |
|
109 |
* @param latitude |
|
110 |
* @param longitude |
|
111 |
* @return |
|
112 |
*/ |
|
113 |
public Geometry simpleCircleSmall(Double radius, Double latitude, Double longitude) { |
|
114 |
|
|
115 |
double diameterInMeters = radius * 2.0d; |
|
116 |
GeometricShapeFactory shapeFactory = new GeometricShapeFactory(); |
|
117 |
shapeFactory.setNumPoints(64); // adjustable |
|
118 |
shapeFactory.setCentre(new Coordinate(longitude, latitude)); |
|
119 |
// Length in meters of 1° of latitude = always 111.32 km |
|
120 |
shapeFactory.setWidth(diameterInMeters / 111320d); |
|
121 |
// Length in meters of 1° of longitude = 40075 km * cos( latitude ) / 360 |
|
122 |
shapeFactory.setHeight(diameterInMeters / (40075000 * Math.cos(Math.toRadians(latitude)) / 360)); |
|
123 |
|
|
124 |
Polygon circle = shapeFactory.createEllipse(); |
|
125 |
return circle; |
|
126 |
} |
|
127 |
|
|
128 |
/** |
|
129 |
* Creates perfect circles which are looking good but might be projected |
|
130 |
* incorrectly for the resulting map |
|
131 |
* |
|
132 |
* @param distance |
|
133 |
* @param latitude |
|
134 |
* @param longitude |
|
135 |
* @return |
|
136 |
*/ |
|
137 |
public Geometry simpleCircle(Quantity<Length> distance, Double latitude, Double longitude) { |
|
138 |
|
|
139 |
GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null); |
|
140 |
CoordinateSequence coordinateSequence = geometryFactory.getCoordinateSequenceFactory() |
|
141 |
.create(new Coordinate[] { new Coordinate(longitude, latitude) }); |
|
142 |
Point point = new Point(coordinateSequence, geometryFactory); |
|
143 |
|
|
144 |
GeodeticCalculator calc = new GeodeticCalculator(DefaultGeographicCRS.WGS84); |
|
145 |
calc.setStartingGeographicPoint(longitude, latitude); |
|
146 |
UnitConverter converter = distance.getUnit().getConverterTo(SI.METRE); |
|
147 |
double d = converter.convert(distance.getValue()).doubleValue(); |
|
148 |
calc.setDirection(0.0, d); |
|
149 |
Point2D p2 = calc.getDestinationGeographicPoint(); |
|
150 |
calc.setDirection(90.0, d); |
|
151 |
Point2D p3 = calc.getDestinationGeographicPoint(); |
|
152 |
|
|
153 |
double dy = p2.getY() - latitude; |
|
154 |
double dx = p3.getX() - longitude; |
|
155 |
double dist = (dy + dx) / 2.0; |
|
156 |
Polygon p1 = (Polygon) point.buffer(dist); |
|
157 |
return p1; |
|
158 |
} |
|
159 |
|
|
160 |
/** |
|
161 |
* This Method should produces the best circles. |
|
162 |
* |
|
163 |
* The code is based on an example published by Ian Turton on stackoverflow: |
|
164 |
* |
|
165 |
* https://stackoverflow.com/questions/36481651/how-do-i-create-a-circle-with-latitude-longitude-and-radius-with-geotools#36528805 |
|
166 |
* |
|
167 |
* see https://gist.github.com/ianturton/973563fe5004985ba35a6e2247f7d823 and |
|
168 |
* https://gitlab.com/snippets/17558 |
|
169 |
* |
|
170 |
* @param feature |
|
171 |
* @param distance |
|
172 |
* @return |
|
173 |
*/ |
|
174 |
public Geometry bufferFeature(SimpleFeature feature, Double radius) { |
|
175 |
|
|
176 |
// replacment for Measure<Double, Length> distance: |
|
177 |
Quantity<Length> radiusMeter = Quantities.getQuantity(radius, SI.METRE); |
|
178 |
|
|
179 |
// extract the geometry |
|
180 |
GeometryAttribute gProp = feature.getDefaultGeometryProperty(); |
|
181 |
CoordinateReferenceSystem origCRS = gProp.getDescriptor().getCoordinateReferenceSystem(); |
|
182 |
|
|
183 |
Geometry geom = (Geometry) feature.getDefaultGeometry(); |
|
184 |
Geometry pGeom = geom; |
|
185 |
MathTransform toTransform, fromTransform = null; |
|
186 |
|
|
187 |
// reproject the geometry to a local projection |
|
188 |
if (!(origCRS instanceof ProjectedCRS)) { |
|
189 |
|
|
190 |
double x = geom.getCoordinate().x; |
|
191 |
double y = geom.getCoordinate().y; |
|
192 |
|
|
193 |
String code = "AUTO:42001," + x + "," + y; |
|
194 |
// System.out.println(code); |
|
195 |
CoordinateReferenceSystem auto; |
|
196 |
try { |
|
197 |
auto = CRS.decode(code); |
|
198 |
toTransform = CRS.findMathTransform(DefaultGeographicCRS.WGS84, auto); |
|
199 |
fromTransform = CRS.findMathTransform(auto, DefaultGeographicCRS.WGS84); |
|
200 |
pGeom = JTS.transform(geom, toTransform); |
|
201 |
|
|
202 |
} catch (MismatchedDimensionException | TransformException | FactoryException e) { |
|
203 |
logger.error(e); |
|
204 |
} |
|
205 |
|
|
206 |
} |
|
207 |
|
|
208 |
// create a buffer around the geometry, assumes the geometry is in the same |
|
209 |
// units as the distance variable. |
|
210 |
Geometry out = pGeom.buffer(radiusMeter.getValue().doubleValue()); |
|
211 |
Geometry retGeom = out; |
|
212 |
// reproject the geometry to the original projection |
|
213 |
if (!(origCRS instanceof ProjectedCRS)) { |
|
214 |
try { |
|
215 |
retGeom = JTS.transform(out, fromTransform); |
|
216 |
|
|
217 |
} catch (MismatchedDimensionException | TransformException e) { |
|
218 |
logger.error(e); |
|
219 |
} |
|
220 |
} |
|
221 |
|
|
222 |
return retGeom; |
|
223 |
} |
|
224 |
|
|
225 |
public static SimpleFeature createSimplePointFeature(Double longitude, Double latitude) throws SchemaException { |
|
226 |
SimpleFeatureType schema = DataUtilities.createType("", "Location", "locations:Point:srid=4326,id:Integer" // a |
|
227 |
// number |
|
228 |
// attribute |
|
229 |
); |
|
230 |
SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(schema); |
|
231 |
|
|
232 |
GeometryFactory geometryFactory = new GeometryFactory(); |
|
233 |
/* Longitude (= x coord) first ! */ |
|
234 |
Point point = geometryFactory.createPoint(new Coordinate(longitude, latitude)); |
|
235 |
featureBuilder.add(point); |
|
236 |
SimpleFeature feature = featureBuilder.buildFeature(null); |
|
237 |
return feature; |
|
238 |
} |
|
239 |
|
|
240 |
} |
cdmlib-ext/src/main/java/eu/etaxonomy/cdm/ext/geo/kml/KMLDocumentBuilder.java | ||
---|---|---|
1 |
/** |
|
2 |
* Copyright (C) 2020 EDIT |
|
3 |
* European Distributed Institute of Taxonomy |
|
4 |
* http://www.e-taxonomy.eu |
|
5 |
* |
|
6 |
* The contents of this file are subject to the Mozilla Public License Version 1.1 |
|
7 |
* See LICENSE.TXT at the top of this package for the full license terms. |
|
8 |
*/ |
|
9 |
|
|
10 |
package eu.etaxonomy.cdm.ext.geo.kml; |
|
11 |
|
|
12 |
import java.util.ArrayList; |
|
13 |
import java.util.Arrays; |
|
14 |
import java.util.Collection; |
|
15 |
import java.util.HashMap; |
|
16 |
import java.util.HashSet; |
|
17 |
import java.util.List; |
|
18 |
import java.util.Map; |
|
19 |
import java.util.Optional; |
|
20 |
import java.util.Set; |
|
21 |
|
|
22 |
import org.apache.log4j.Logger; |
|
23 |
import org.geotools.feature.SchemaException; |
|
24 |
import org.locationtech.jts.geom.Coordinate; |
|
25 |
import org.opengis.feature.simple.SimpleFeature; |
|
26 |
import org.opengis.referencing.FactoryException; |
|
27 |
|
|
28 |
import de.micromata.opengis.kml.v_2_2_0.AltitudeMode; |
|
29 |
import de.micromata.opengis.kml.v_2_2_0.Document; |
|
30 |
import de.micromata.opengis.kml.v_2_2_0.ExtendedData; |
|
31 |
import de.micromata.opengis.kml.v_2_2_0.Feature; |
|
32 |
import de.micromata.opengis.kml.v_2_2_0.Kml; |
|
33 |
import de.micromata.opengis.kml.v_2_2_0.KmlFactory; |
|
34 |
import de.micromata.opengis.kml.v_2_2_0.LineStyle; |
|
35 |
import de.micromata.opengis.kml.v_2_2_0.LinearRing; |
|
36 |
import de.micromata.opengis.kml.v_2_2_0.Placemark; |
|
37 |
import de.micromata.opengis.kml.v_2_2_0.PolyStyle; |
|
38 |
import de.micromata.opengis.kml.v_2_2_0.Polygon; |
|
39 |
import de.micromata.opengis.kml.v_2_2_0.Style; |
|
40 |
import eu.etaxonomy.cdm.model.location.Point; |
|
41 |
import eu.etaxonomy.cdm.model.occurrence.DerivedUnit; |
|
42 |
import eu.etaxonomy.cdm.model.occurrence.FieldUnit; |
|
43 |
import eu.etaxonomy.cdm.model.occurrence.GatheringEvent; |
|
44 |
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase; |
|
45 |
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationType; |
|
46 |
import eu.etaxonomy.cdm.model.term.DefinedTerm; |
|
47 |
import eu.etaxonomy.cdm.model.term.TermType; |
|
48 |
import si.uom.SI; |
|
49 |
import tec.uom.se.quantity.Quantities; |
|
50 |
|
|
51 |
/** |
|
52 |
* |
|
53 |
* @author Andreas Kohlbecker |
|
54 |
* @since Apr 21, 2020 |
|
55 |
*/ |
|
56 |
public class KMLDocumentBuilder { |
|
57 |
|
|
58 |
private final static Logger logger = Logger.getLogger(KMLDocumentBuilder.class); |
|
59 |
|
|
60 |
private Set<SpecimenOrObservationBase> occSet = new HashSet<>(); |
|
61 |
|
|
62 |
private Map<String, Style> styles = new HashMap<>(); |
|
63 |
|
|
64 |
private static final DefinedTerm KIND_OF_UNIT_UNSET = DefinedTerm.NewInstance(TermType.KindOfUnit); |
|
65 |
|
|
66 |
public KMLDocumentBuilder addSpecimenOrObservationBase(SpecimenOrObservationBase occurrence) { |
|
67 |
occSet.add(occurrence); |
|
68 |
return this; |
|
69 |
} |
|
70 |
|
|
71 |
public Kml build() { |
|
72 |
|
|
73 |
Kml kml = KmlFactory.createKml(); |
|
74 |
List<Feature> documentFeatures = new ArrayList<>(); |
|
75 |
|
|
76 |
for (SpecimenOrObservationBase sob : occSet) { |
|
77 |
if (sob instanceof FieldUnit) { |
|
78 |
GatheringEvent gatherEvent = ((FieldUnit) sob).getGatheringEvent(); |
|
79 |
if (gatherEvent != null && isValidPoint(gatherEvent.getExactLocation())) { |
|
80 |
createFieldUnitPlacemarks(documentFeatures, sob, gatherEvent, LocationType.FIELD_UNIT, sob.getKindOfUnit()); |
|
81 |
} |
|
82 |
} |
|
83 |
if (sob instanceof DerivedUnit) { |
|
84 |
walkDerivationPath((DerivedUnit) sob, (DerivedUnit) sob, documentFeatures, null); |
|
85 |
} |
|
86 |
} |
|
87 |
|
|
88 |
Document doc = kml.createAndSetDocument(); |
|
89 |
doc.getFeature().addAll(documentFeatures); |
|
90 |
doc.getStyleSelector().addAll(styles.values()); |
|
91 |
return kml; |
|
92 |
} |
|
93 |
|
|
94 |
/** |
|
95 |
* @param derivedUnit |
|
96 |
* @param documentFeatures |
|
97 |
* @param kindOfUnit |
|
98 |
*/ |
|
99 |
private void walkDerivationPath(DerivedUnit derivedUnit, DerivedUnit unitOfInterest, List<Feature> documentFeatures, |
|
100 |
DefinedTerm kindOfUnit) { |
|
101 |
|
|
102 |
if (kindOfUnit == null) { |
|
103 |
if (derivedUnit.getKindOfUnit() != null) { |
|
104 |
kindOfUnit = derivedUnit.getKindOfUnit(); |
|
105 |
} else { |
|
106 |
kindOfUnit = KIND_OF_UNIT_UNSET; |
|
107 |
} |
|
108 |
} |
|
109 |
|
|
110 |
Set<SpecimenOrObservationBase> originals = derivedUnit.getOriginals(); |
|
111 |
if (originals != null) { |
|
112 |
for (SpecimenOrObservationBase<?> original : originals) { |
|
113 |
if (original instanceof FieldUnit) { |
|
114 |
GatheringEvent gatherEvent = ((FieldUnit) original).getGatheringEvent(); |
|
115 |
if (gatherEvent != null && isValidPoint(gatherEvent.getExactLocation())) { |
|
116 |
createFieldUnitPlacemarks(documentFeatures, unitOfInterest, gatherEvent, LocationType.DERIVED_UNIT, kindOfUnit); |
|
117 |
} |
|
118 |
} else { |
|
119 |
walkDerivationPath((DerivedUnit) original, unitOfInterest, documentFeatures, kindOfUnit); |
|
120 |
} |
|
121 |
} |
|
122 |
} |
|
123 |
} |
|
124 |
|
|
125 |
/** |
|
126 |
* @param documentFeatures |
|
127 |
* @param sob |
|
128 |
* @param gatherEvent |
|
129 |
*/ |
|
130 |
private void createFieldUnitPlacemarks(List<Feature> documentFeatures, SpecimenOrObservationBase sob, |
|
131 |
GatheringEvent gatherEvent, LocationType locationType, DefinedTerm kindOfUnit) { |
|
132 |
Placemark mapMarker = fieldUnitLocationMarker(gatherEvent.getExactLocation(), |
|
133 |
gatherEvent.getAbsoluteElevation(), locationType, kindOfUnit); |
|
134 |
documentFeatures.add(mapMarker); |
|
135 |
addExtendedData(mapMarker, sob, gatherEvent); |
|
136 |
errorRadiusPlacemark(gatherEvent.getExactLocation()).ifPresent(pm -> documentFeatures.add(pm)); |
|
137 |
} |
|
138 |
|
|
139 |
|
|
140 |
/** |
|
141 |
* @param exactLocation |
|
142 |
* @param altitude |
|
143 |
* @param locationType |
|
144 |
* @param kindOfUnit |
|
145 |
* @return |
|
146 |
*/ |
|
147 |
private Placemark fieldUnitLocationMarker(Point exactLocation, Integer altitude, LocationType locationType, |
|
148 |
DefinedTerm kindOfUnit) { |
|
149 |
|
|
150 |
Placemark mapMarker = KmlFactory.createPlacemark(); |
|
151 |
de.micromata.opengis.kml.v_2_2_0.Point point = KmlFactory.createPoint(); |
|
152 |
point.setAltitudeMode(AltitudeMode.ABSOLUTE); |
|
153 |
if (altitude != null) { |
|
154 |
point.setCoordinates(Arrays.asList(KmlFactory.createCoordinate(exactLocation.getLongitude(), |
|
155 |
exactLocation.getLatitude(), altitude.doubleValue()))); |
|
156 |
} else { |
|
157 |
point.setCoordinates(Arrays |
|
158 |
.asList(KmlFactory.createCoordinate(exactLocation.getLongitude(), exactLocation.getLatitude()))); |
|
159 |
} |
|
160 |
mapMarker.setGeometry(point); |
|
161 |
mapMarker.setStyleUrl(styleURL(locationType, kindOfUnit)); |
|
162 |
|
|
163 |
return mapMarker; |
|
164 |
} |
|
165 |
|
|
166 |
private Optional<Placemark> errorRadiusPlacemark(Point exactLocation) { |
|
167 |
|
|
168 |
// exactLocation.setErrorRadius(25 * 1000); // METER // uncomment for debugging |
|
169 |
|
|
170 |
Placemark errorRadiusCicle = null; |
|
171 |
if (exactLocation.getErrorRadius() != null && exactLocation.getErrorRadius() > 0) { |
|
172 |
errorRadiusCicle = KmlFactory.createPlacemark(); |
|
173 |
LinearRing cirle = createKMLCircle(exactLocation.getLongitude(), exactLocation.getLatitude(), |
|
174 |
exactLocation.getErrorRadius()); |
|
175 |
Polygon polygon = errorRadiusCicle.createAndSetPolygon(); |
|
176 |
polygon.createAndSetOuterBoundaryIs().setLinearRing(cirle); |
|
177 |
polygon.setExtrude(true); |
|
178 |
errorRadiusCicle.setStyleUrl(errorRadiusStyleURL()); |
|
179 |
} |
|
180 |
|
|
181 |
return Optional.ofNullable(errorRadiusCicle); |
|
182 |
} |
|
183 |
|
|
184 |
|
|
185 |
/** |
|
186 |
* @param longitude |
|
187 |
* @param latitude |
|
188 |
* @param errorRadiusMeter |
|
189 |
* @return |
|
190 |
*/ |
|
191 |
private LinearRing createKMLCircle(Double longitude, Double latitude, Integer errorRadiusMeter) { |
|
192 |
|
|
193 |
GeometryBuilder.CircleMethod method = GeometryBuilder.CircleMethod.reprojectedCircle; |
|
194 |
LinearRing lineString = KmlFactory.createLinearRing(); |
|
195 |
lineString.setAltitudeMode(AltitudeMode.RELATIVE_TO_GROUND); |
|
196 |
|
|
197 |
org.locationtech.jts.geom.Geometry polygonGeom = null; |
|
198 |
GeometryBuilder gb = new GeometryBuilder(); |
|
199 |
try { |
|
200 |
switch (method) { |
|
201 |
case simpleCircle: |
|
202 |
// this is the best method so far !!!! |
|
203 |
polygonGeom = gb.simpleCircle(Quantities.getQuantity(errorRadiusMeter.doubleValue(), SI.METRE), |
|
204 |
latitude, longitude); |
|
205 |
break; |
|
206 |
case simpleCircleSmall: |
|
207 |
// Only suitable for small radius (> 1000 m) as the circles are heavily distorted |
|
208 |
// otherwise. |
|
209 |
polygonGeom = gb.simpleCircleSmall(errorRadiusMeter.doubleValue(), latitude, longitude); |
|
210 |
break; |
|
211 |
case circle: |
|
212 |
// fails |
|
213 |
polygonGeom = gb.circle(errorRadiusMeter.doubleValue(), latitude, longitude); |
|
214 |
break; |
|
215 |
case reprojectedCircle: |
|
216 |
// incomplete |
|
217 |
SimpleFeature pointFeature = gb.createSimplePointFeature(longitude, latitude); |
|
218 |
polygonGeom = gb.bufferFeature(pointFeature, errorRadiusMeter.doubleValue()); |
|
219 |
break; |
|
220 |
} |
|
221 |
for (Coordinate coordinate : polygonGeom.getCoordinates()) { |
|
222 |
lineString.addToCoordinates(coordinate.getX(), coordinate.getY()); |
|
223 |
} |
|
224 |
} catch (FactoryException e) { |
|
225 |
logger.error("Polygon creation for error radius failed", e); |
|
226 |
} catch (SchemaException e) { |
|
227 |
logger.error("SimplePointFeature creation failed", e); |
|
228 |
} |
|
229 |
return lineString; |
|
230 |
} |
|
231 |
|
|
232 |
private void addExtendedData(Placemark mapMarker, SpecimenOrObservationBase sob, GatheringEvent gatherEvent) { |
|
233 |
|
|
234 |
String name = ""; |
|
235 |
if(sob.getRecordBasis() != null) { |
|
236 |
name = sob.getRecordBasis().name(); |
|
237 |
} else { |
|
238 |
name = SpecimenOrObservationType.Unknown.name(); |
|
239 |
} |
|
240 |
String titleCache = sob.getTitleCache(); |
|
241 |
String locationString = null; |
|
242 |
if(gatherEvent.getExactLocation() != null) { |
|
243 |
locationString = gatherEvent.getExactLocation().toSexagesimalString(false, true); |
|
244 |
titleCache = titleCache.replace(locationString + ", ", ""); |
|
245 |
} |
|
246 |
String description = "<p class=\"title-cache\">" + titleCache |
|
247 |
+ " <a class=\"specimen-link\" href=\"${specimen-link-base-url}/" + sob.getUuid() + "\">${specimen-link-text}</a>" |
|
248 |
+ "</p>"; |
|
249 |
if(locationString != null) { |
|
250 |
// see https://www.mediawiki.org/wiki/GeoHack |
|
251 |
description += "<p class=\"exact-location\"><a target=\"geohack\" href=\"https://tools.wmflabs.org/geohack/en/" + |
|
252 |
gatherEvent.getExactLocation().getLatitude() + ";" + gatherEvent.getExactLocation().getLongitude() +"?pagename=" + name + "\">" + locationString + "</a></p>"; |
|
253 |
} |
|
254 |
// mapMarker.setName(name); |
|
255 |
mapMarker.setDescription(description); |
|
256 |
|
|
257 |
ExtendedData extendedData = mapMarker.createAndSetExtendedData(); |
|
258 |
extendedData.createAndAddData(sob.getTitleCache()).setName("titleCache"); |
|
259 |
if(mapMarker.getGeometry() != null && mapMarker.getGeometry() instanceof de.micromata.opengis.kml.v_2_2_0.Point) { |
|
260 |
extendedData.createAndAddData(((de.micromata.opengis.kml.v_2_2_0.Point)mapMarker.getGeometry()).getCoordinates().toString()).setName("Location"); |
|
261 |
} |
|
262 |
|
|
263 |
} |
|
264 |
|
|
265 |
|
|
266 |
private String styleURL(LocationType locationType, DefinedTerm kindOfUnit) { |
|
267 |
String key = ""; |
|
268 |
if (locationType != null) { |
|
269 |
key += locationType.name(); |
|
270 |
} |
|
271 |
if (kindOfUnit != null) { |
|
272 |
key += kindOfUnit.getUuid(); |
|
273 |
} |
|
274 |
if (!styles.containsKey(key)) { |
|
275 |
Style style = KmlFactory.createStyle().withIconStyle(MapMarkerIcons.red_blank.asIconStyle()); |
|
276 |
style.setId(key); |
|
277 |
styles.put(key, style); |
|
278 |
} |
|
279 |
return "#" + key; |
|
280 |
} |
|
281 |
|
|
282 |
private String errorRadiusStyleURL() { |
|
283 |
String key = "ERROR_RADIUS"; |
|
284 |
if (!styles.containsKey(key)) { |
|
285 |
Style style = KmlFactory.createStyle(); |
|
286 |
PolyStyle polyStyle = style.createAndSetPolyStyle(); |
|
287 |
polyStyle.setColor("100000ee"); // aabbggrr, where aa=alpha (00 to ff); bb=blue (00 to ff); gg=green (00 to ff); rr=red (00 to ff). |
|
288 |
polyStyle.setFill(true); |
|
289 |
polyStyle.setOutline(true); |
|
290 |
style.setId(key); |
|
291 |
LineStyle lineStyle = style.createAndSetLineStyle(); |
|
292 |
// lineStyle.setColor("ff880088"); // aabbggrr, where aa=alpha (00 to ff); |
|
293 |
// bb=blue (00 to ff); gg=green (00 to ff); rr=red (00 to ff). |
|
294 |
lineStyle.setWidth(1); |
|
295 |
styles.put(key, style); |
|
296 |
} |
|
297 |
return "#" + key; |
|
298 |
} |
|
299 |
|
|
300 |
|
|
301 |
// TODO use also for .EditGeoService.registerDerivedUnitLocations(DerivedUnit |
|
302 |
// derivedUnit, List<Point> derivedUnitPoints) !!!!!!!!! |
|
303 |
public boolean isValidPoint(Point point) { |
|
304 |
|
|
305 |
if (point == null) { |
|
306 |
return false; |
|
307 |
} |
|
308 |
// points with no longitude or latitude should not exist |
|
309 |
// see #4173 ([Rule] Longitude and Latitude in Point must not be null) |
|
310 |
if (point.getLatitude() == null || point.getLongitude() == null) { |
|
311 |
return false; |
|
312 |
} |
|
313 |
// FIXME: remove next statement after |
|
314 |
// DerivedUnitFacade or ABCD import is fixed |
|
315 |
// |
|
316 |
if (point.getLatitude() == 0.0 || point.getLongitude() == 0.0) { |
|
317 |
return false; |
|
318 |
} |
|
319 |
return true; |
|
320 |
} |
|
321 |
|
|
322 |
public enum LocationType { |
|
323 |
FIELD_UNIT, DERIVED_UNIT; |
|
324 |
} |
|
325 |
} |
cdmlib-ext/src/main/java/eu/etaxonomy/cdm/ext/geo/kml/MapMarkerIcons.java | ||
---|---|---|
1 |
/** |
|
2 |
* Copyright (C) 2020 EDIT |
|
3 |
* European Distributed Institute of Taxonomy |
|
4 |
* http://www.e-taxonomy.eu |
|
5 |
* |
|
6 |
* The contents of this file are subject to the Mozilla Public License Version 1.1 |
|
7 |
* See LICENSE.TXT at the top of this package for the full license terms. |
|
8 |
*/ |
|
9 |
|
|
10 |
package eu.etaxonomy.cdm.ext.geo.kml; |
|
11 |
|
|
12 |
import java.net.MalformedURLException; |
|
13 |
import java.net.URL; |
|
14 |
|
|
15 |
import de.micromata.opengis.kml.v_2_2_0.ColorMode; |
|
16 |
import de.micromata.opengis.kml.v_2_2_0.IconStyle; |
|
17 |
import de.micromata.opengis.kml.v_2_2_0.KmlFactory; |
|
18 |
import de.micromata.opengis.kml.v_2_2_0.Units; |
|
19 |
import de.micromata.opengis.kml.v_2_2_0.Vec2; |
|
20 |
|
|
21 |
/** |
|
22 |
* |
|
23 |
* MOre icons at http://kml4earth.appspot.com/icons.html |
|
24 |
* |
|
25 |
* @author Andreas Kohlbecker |
|
26 |
* @since Apr 21, 2020 |
|
27 |
*/ |
|
28 |
public enum MapMarkerIcons { |
|
29 |
|
|
30 |
blu_blank("http://maps.google.com/mapfiles/kml/paddle/blu-blank.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
31 |
blu_circle("http://maps.google.com/mapfiles/kml/paddle/blu-circle.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
32 |
blu_diamond("http://maps.google.com/mapfiles/kml/paddle/blu-diamond.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
33 |
blu_square("http://maps.google.com/mapfiles/kml/paddle/blu-sqare.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
34 |
blu_stars("http://maps.google.com/mapfiles/kml/paddle/blu-stars.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
35 |
|
|
36 |
grn_blank("http://maps.google.com/mapfiles/kml/paddle/grn-blank.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
37 |
grn_circle("http://maps.google.com/mapfiles/kml/paddle/grn-circle.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
38 |
grn_diamond("http://maps.google.com/mapfiles/kml/paddle/grn-diamond.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
39 |
grn_square("http://maps.google.com/mapfiles/kml/paddle/grn-sqare.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
40 |
grn_stars("http://maps.google.com/mapfiles/kml/paddle/grn-stars.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
41 |
|
|
42 |
ltblu_blank("http://maps.google.com/mapfiles/kml/paddle/ltblu-blank.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
43 |
ltblu_circle("http://maps.google.com/mapfiles/kml/paddle/ltblu-circle.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
44 |
ltblu_diamond("http://maps.google.com/mapfiles/kml/paddle/ltblu-diamond.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
45 |
ltblu_square("http://maps.google.com/mapfiles/kml/paddle/ltblu-sqare.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
46 |
ltblu_stars("http://maps.google.com/mapfiles/kml/paddle/ltblu-stars.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
47 |
|
|
48 |
pink_blank("http://maps.google.com/mapfiles/kml/paddle/pink-blank.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
49 |
pink_circle("http://maps.google.com/mapfiles/kml/paddle/pink-circle.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
50 |
pink_diamond("http://maps.google.com/mapfiles/kml/paddle/pink-diamond.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
51 |
pink_square("http://maps.google.com/mapfiles/kml/paddle/pink-sqare.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
52 |
pink_stars("http://maps.google.com/mapfiles/kml/paddle/pink-stars.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
53 |
|
|
54 |
purple_blank("http://maps.google.com/mapfiles/kml/paddle/purple-blank.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
55 |
purple_circle("http://maps.google.com/mapfiles/kml/paddle/purple-circle.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
56 |
purple_diamond("http://maps.google.com/mapfiles/kml/paddle/purple-diamond.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
57 |
purple_square("http://maps.google.com/mapfiles/kml/paddle/purple-sqare.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
58 |
purple_stars("http://maps.google.com/mapfiles/kml/paddle/purple-stars.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
59 |
|
|
60 |
red_blank("http://maps.google.com/mapfiles/kml/paddle/red-blank.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
61 |
red_circle("http://maps.google.com/mapfiles/kml/paddle/red-circle.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
62 |
red_diamond("http://maps.google.com/mapfiles/kml/paddle/red-diamond.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
63 |
red_square("http://maps.google.com/mapfiles/kml/paddle/red-sqare.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
64 |
red_stars("http://maps.google.com/mapfiles/kml/paddle/red-stars.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
65 |
|
|
66 |
ylw_blank("http://maps.google.com/mapfiles/kml/paddle/ylw-blank.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
67 |
ylw_circle("http://maps.google.com/mapfiles/kml/paddle/ylw-circle.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
68 |
ylw_diamond("http://maps.google.com/mapfiles/kml/paddle/ylw-diamond.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
69 |
ylw_square("http://maps.google.com/mapfiles/kml/paddle/ylw-sqare.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
70 |
ylw_stars("http://maps.google.com/mapfiles/kml/paddle/ylw-stars.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
71 |
|
|
72 |
orange_blank("http://maps.google.com/mapfiles/kml/paddle/orange-blank.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
73 |
orange_circle("http://maps.google.com/mapfiles/kml/paddle/orange-circle.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
74 |
orange_diamond("http://maps.google.com/mapfiles/kml/paddle/orange-diamond.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
75 |
orange_square("http://maps.google.com/mapfiles/kml/paddle/orange-sqare.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
76 |
orange_stars("http://maps.google.com/mapfiles/kml/paddle/orange-stars.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
77 |
|
|
78 |
wht_blank("http://maps.google.com/mapfiles/kml/paddle/wht-blank.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
79 |
wht_circle("http://maps.google.com/mapfiles/kml/paddle/wht-circle.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
80 |
wht_diamond("http://maps.google.com/mapfiles/kml/paddle/wht-diamond.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
81 |
wht_square("http://maps.google.com/mapfiles/kml/paddle/wht-sqare.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
82 |
wht_stars("http://maps.google.com/mapfiles/kml/paddle/wht-stars.png", KmlFactory.createVec2().withX(0.5).withY(0).withXunits(Units.FRACTION).withYunits(Units.FRACTION)), |
|
83 |
|
|
84 |
sunny("http://maps.google.com/mapfiles/kml/shapes/sunny.png", null); |
|
85 |
|
|
86 |
URL url; |
|
87 |
Vec2 hotspot; |
|
88 |
|
|
89 |
MapMarkerIcons(String ulr, Vec2 hotspot) { |
|
90 |
try { |
|
91 |
this.url = new URL(ulr); |
|
92 |
if(hotspot != null) { |
|
93 |
this.hotspot = hotspot; |
|
94 |
} |
|
95 |
} catch (MalformedURLException e) { |
|
96 |
throw new RuntimeException(e); |
|
97 |
} |
|
98 |
} |
|
99 |
|
|
100 |
@Override |
|
101 |
public String toString() { |
|
102 |
return url.toString(); |
|
103 |
} |
|
104 |
|
|
105 |
public Vec2 hotSpot() { |
|
106 |
return hotspot; |
|
107 |
} |
|
108 |
|
|
109 |
public IconStyle asIconStyle() { |
|
110 |
IconStyle iconStyle = KmlFactory.createIconStyle().withIcon( |
|
111 |
KmlFactory.createIcon().withHref(this.toString()) |
|
112 |
); |
|
113 |
iconStyle.setScale(1); |
|
114 |
iconStyle.setHotSpot(hotspot); |
|
115 |
return iconStyle; |
|
116 |
} |
|
117 |
|
|
118 |
} |
cdmlib-ext/src/test/java/eu/etaxonomy/cdm/ext/kml/KmlJaxbMarshallerTest.java | ||
---|---|---|
1 |
package eu.etaxonomy.cdm.ext.kml; |
|
2 |
|
|
3 |
import static org.junit.Assert.assertTrue; |
|
4 |
|
|
5 |
import java.io.File; |
|
6 |
import java.io.FileWriter; |
|
7 |
import java.io.IOException; |
|
8 |
import java.io.StringWriter; |
|
9 |
|
|
10 |
import javax.xml.bind.JAXBContext; |
|
11 |
import javax.xml.bind.JAXBException; |
|
12 |
import javax.xml.bind.Marshaller; |
|
13 |
|
|
14 |
import org.apache.commons.io.FileUtils; |
|
15 |
import org.apache.log4j.Level; |
|
16 |
import org.apache.log4j.Logger; |
|
17 |
import org.junit.Before; |
|
18 |
import org.junit.Test; |
|
19 |
|
|
20 |
import de.micromata.opengis.kml.v_2_2_0.Kml; |
|
21 |
import eu.etaxonomy.cdm.ext.geo.kml.KMLDocumentBuilder; |
|
22 |
import eu.etaxonomy.cdm.model.location.Point; |
|
23 |
import eu.etaxonomy.cdm.model.occurrence.FieldUnit; |
|
24 |
import eu.etaxonomy.cdm.model.occurrence.GatheringEvent; |
|
25 |
|
|
26 |
public class KmlJaxbMarshallerTest { |
|
27 |
|
|
28 |
Kml kml; |
|
29 |
|
|
30 |
Logger logger; |
|
31 |
|
|
32 |
@Before |
|
33 |
public void makeKML() { |
|
34 |
FieldUnit fu = FieldUnit.NewInstance(); |
|
35 |
fu.setGatheringEvent(GatheringEvent.NewInstance()); |
|
36 |
fu.getGatheringEvent().setExactLocation(Point.NewInstance(-112.292238941097, 36.09520916122063, null, null)); |
|
37 |
|
|
38 |
KMLDocumentBuilder builder = new KMLDocumentBuilder(); |
|
39 |
builder.addSpecimenOrObservationBase(fu); |
|
40 |
kml = builder.build(); |
|
41 |
|
|
42 |
logger = Logger.getLogger(this.getClass()); |
|
43 |
logger.setLevel(Level.DEBUG); |
|
44 |
} |
|
45 |
|
|
46 |
|
|
47 |
@Test |
|
48 |
public void marshallTest() throws JAXBException, IOException { |
|
49 |
|
|
50 |
JAXBContext jaxbContext = JAXBContext.newInstance(Kml.class); |
|
51 |
Marshaller marshaller = jaxbContext.createMarshaller(); |
|
52 |
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); |
|
53 |
StringWriter sw = new StringWriter(); |
|
54 |
marshaller.marshal(kml, sw); |
|
55 |
String kml = sw.toString(); |
|
56 |
if(logger.isDebugEnabled()) { |
|
57 |
logger.debug("kml:\n" + kml); |
|
58 |
FileUtils.write(new File("KmlJaxbMarshallerTest.kml"), kml); |
|
59 |
} |
|
60 |
assertTrue(kml.contains("<kml:Document>")); |
|
61 |
assertTrue(kml.contains("<kml:Point>")); |
|
62 |
assertTrue(kml.contains("<kml:coordinates>-112.292238941097,36.09520916122063</kml:coordinates>")); |
|
63 |
assertTrue(kml.contains("<kml:altitudeMode>absolute</kml:altitudeMode>")); |
|
64 |
} |
|
65 |
|
|
66 |
} |
cdmlib-remote-webapp/src/main/java/eu/etaxonomy/cdm/remote/config/CdmSpringMVCConfig.java | ||
---|---|---|
107 | 107 |
|
108 | 108 |
} |
109 | 109 |
|
110 |
@Bean |
|
111 |
@DependsOn({"requestMappingHandlerAdapter"}) |
|
112 |
public XmlViewResolver getOaiXmlViewResolver() { |
|
113 |
XmlViewResolver resolver = new XmlViewResolver(); |
|
114 |
resolver.setOrder(1); |
|
115 |
resolver.setLocation(new ServletContextResource(servletContext,"/WEB-INF/oai-views.xml")); |
|
116 |
resolver.setCache(XML_VIEW_CACHING); |
|
117 |
return resolver; |
|
118 |
} |
|
119 |
|
|
120 |
|
|
121 |
|
|
110 |
@Bean |
|
111 |
@DependsOn({ "requestMappingHandlerAdapter" }) |
|
112 |
public XmlViewResolver getOaiXmlViewResolver() { |
|
113 |
XmlViewResolver resolver = new XmlViewResolver(); |
|
114 |
resolver.setOrder(1); |
|
115 |
resolver.setLocation(new ServletContextResource(servletContext, "/WEB-INF/oai-views.xml")); |
|
116 |
resolver.setCache(XML_VIEW_CACHING); |
|
117 |
return resolver; |
|
118 |
} |
|
119 |
|
|
120 |
@Bean |
|
121 |
@DependsOn({ "requestMappingHandlerAdapter" }) |
|
122 |
public XmlViewResolver kmlXmlViewResolver() { |
|
123 |
XmlViewResolver resolver = new PatternViewResolver(); |
|
124 |
resolver.setOrder(1); |
|
125 |
resolver.setLocation(new ServletContextResource(servletContext, "/WEB-INF/kml-views.xml")); |
|
126 |
resolver.setCache(XML_VIEW_CACHING); |
|
127 |
return resolver; |
|
128 |
} |
|
122 | 129 |
|
123 | 130 |
/* (non-Javadoc) |
124 | 131 |
* @see org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration#addInterceptors(org.springframework.web.servlet.config.annotation.InterceptorRegistry) |
cdmlib-remote-webapp/src/main/webapp/WEB-INF/kml-views.xml | ||
---|---|---|
1 |
<?xml version="1.0" encoding="UTF-8"?> |
|
2 |
<beans xmlns="http://www.springframework.org/schema/beans" |
|
3 |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|
4 |
xsi:schemaLocation="http://www.springframework.org/schema/beans |
|
5 |
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> |
|
6 |
|
|
7 |
<!-- |
|
8 |
=============================================================== |
|
9 |
This is the configuration file for a |
|
10 |
eu.etaxonomy.cdm.remote.view.XMLViewResolver |
|
11 |
=============================================================== |
|
12 |
--> |
|
13 |
<bean name="**/kml/** **/kml/*" class="org.springframework.web.servlet.view.xml.MarshallingView"> |
|
14 |
<property name="contentType" value="text/xml; charset=UTF-8"/> |
|
15 |
<property name="marshaller" ref="kmlMarshaller"/><!-- see /cdmlib-remote/src/main/resources/eu/etaxonomy/cdm/remote.xml --> |
|
16 |
</bean> |
|
17 |
</beans> |
cdmlib-remote/src/main/java/eu/etaxonomy/cdm/remote/controller/OptionsController.java | ||
---|---|---|
1 |
package eu.etaxonomy.cdm.remote.controller; |
|
2 |
|
|
3 |
import org.springframework.http.HttpStatus; |
|
4 |
import org.springframework.http.ResponseEntity; |
|
5 |
import org.springframework.stereotype.Controller; |
|
6 |
import org.springframework.web.bind.annotation.CrossOrigin; |
|
7 |
import org.springframework.web.bind.annotation.RequestMapping; |
|
8 |
import org.springframework.web.bind.annotation.RequestMethod; |
|
9 |
|
|
10 |
@CrossOrigin(origins = "*", maxAge = 3600) |
|
11 |
@Controller |
|
12 |
public class OptionsController { |
|
13 |
|
|
14 |
@RequestMapping( |
|
15 |
value = "/**", |
|
16 |
method = RequestMethod.OPTIONS |
|
17 |
) |
|
18 |
public ResponseEntity handle() { |
|
19 |
return new ResponseEntity(HttpStatus.OK); |
|
20 |
} |
|
21 |
|
|
22 |
} |
cdmlib-remote/src/main/java/eu/etaxonomy/cdm/remote/controller/ext/ExternalGeoController.java | ||
---|---|---|
24 | 24 |
|
25 | 25 |
import org.apache.log4j.Logger; |
26 | 26 |
import org.springframework.beans.factory.annotation.Autowired; |
27 |
import org.springframework.http.HttpStatus; |
|
28 |
import org.springframework.http.ResponseEntity; |
|
27 | 29 |
import org.springframework.stereotype.Controller; |
28 | 30 |
import org.springframework.web.bind.WebDataBinder; |
31 |
import org.springframework.web.bind.annotation.CrossOrigin; |
|
29 | 32 |
import org.springframework.web.bind.annotation.InitBinder; |
30 | 33 |
import org.springframework.web.bind.annotation.PathVariable; |
31 | 34 |
import org.springframework.web.bind.annotation.RequestMapping; |
32 | 35 |
import org.springframework.web.bind.annotation.RequestMethod; |
33 | 36 |
import org.springframework.web.bind.annotation.RequestParam; |
37 |
import org.springframework.web.bind.annotation.RestController; |
|
34 | 38 |
import org.springframework.web.servlet.ModelAndView; |
35 | 39 |
|
36 | 40 |
import eu.etaxonomy.cdm.api.service.IDescriptionService; |
... | ... | |
80 | 84 |
* @since 18.06.2009 |
81 | 85 |
* |
82 | 86 |
*/ |
87 |
|
|
83 | 88 |
@Controller |
84 | 89 |
@Api(value="mapServiceParameters") |
85 | 90 |
@RequestMapping(value = { "ext/edit/mapServiceParameters/" }) |
... | ... | |
194 | 199 |
* @throws IOException TODO write controller method documentation |
195 | 200 |
*/ |
196 | 201 |
@RequestMapping(value = { "taxonOccurrencesFor/{uuid}" }, method = RequestMethod.GET) |
197 |
public ModelAndView doGetOccurrenceMapUriParams(
|
|
202 |
public OccurrenceServiceRequestParameterDto doGetOccurrenceMapUriParams(
|
|
198 | 203 |
@PathVariable("uuid") UUID uuid, |
199 | 204 |
@RequestParam(value = "relationships", required = false) UuidList relationshipUuids, |
200 | 205 |
@RequestParam(value = "relationshipsInvers", required = false) UuidList relationshipInversUuids, |
... | ... | |
203 | 208 |
HttpServletResponse response) |
204 | 209 |
throws IOException { |
205 | 210 |
|
206 |
Map<SpecimenOrObservationType, Color> specimenOrObservationTypeColors = null; |
|
207 | 211 |
|
208 | 212 |
logger.info("doGetOccurrenceMapUriParams() " + requestPathAndQuery(request)); |
209 |
ModelAndView mv = new ModelAndView(); |
|
210 | 213 |
|
211 |
Set<TaxonRelationshipEdge> includeRelationships = ControllerUtils.loadIncludeRelationships( |
|
214 |
Map<SpecimenOrObservationType, Color> specimenOrObservationTypeColors = null; |
|
215 |
|
|
216 |
List<SpecimenOrObservationBase> specimensOrObersvations = occurencesForTaxon(uuid, relationshipUuids, |
|
217 |
relationshipInversUuids, maxDepth, response); |
|
218 |
|
|
219 |
OccurrenceServiceRequestParameterDto dto = geoservice.getOccurrenceServiceRequestParameters(specimensOrObersvations, |
|
220 |
specimenOrObservationTypeColors ); |
|
221 |
|
|
222 |
return dto; |
|
223 |
} |
|
224 |
|
|
225 |
private List<SpecimenOrObservationBase> occurencesForTaxon(UUID taxonUuid, UuidList relationshipUuids, |
|
226 |
UuidList relationshipInversUuids, Integer maxDepth, HttpServletResponse response) throws IOException { |
|
227 |
Set<TaxonRelationshipEdge> includeRelationships = ControllerUtils.loadIncludeRelationships( |
|
212 | 228 |
relationshipUuids, relationshipInversUuids, termService); |
213 | 229 |
|
214 |
Taxon taxon = getCdmBaseInstance(Taxon.class, uuid, response, (List<String>)null);
|
|
230 |
Taxon taxon = getCdmBaseInstance(Taxon.class, taxonUuid, response, (List<String>)null);
|
|
215 | 231 |
|
216 | 232 |
List<OrderHint> orderHints = new ArrayList<OrderHint>(); |
217 | 233 |
orderHints.add(new OrderHint("titleCache", SortOrder.DESCENDING)); |
218 | 234 |
|
219 | 235 |
List<SpecimenOrObservationBase> specimensOrObersvations = occurrenceService.listByAssociatedTaxon( |
220 | 236 |
null, includeRelationships, taxon, maxDepth, null, null, orderHints, null); |
221 |
|
|
222 |
OccurrenceServiceRequestParameterDto dto = geoservice.getOccurrenceServiceRequestParameterString(specimensOrObersvations, |
|
223 |
specimenOrObservationTypeColors ); |
|
224 |
mv.addObject(dto); |
|
225 |
return mv; |
|
226 |
} |
|
237 |
return specimensOrObersvations; |
|
238 |
} |
|
227 | 239 |
|
228 | 240 |
/** |
229 | 241 |
* Assembles and returns URI parameter Strings for the EDIT Map Service. The distribution areas for the |
cdmlib-remote/src/main/java/eu/etaxonomy/cdm/remote/controller/ext/KmlController.java | ||
---|---|---|
1 |
/** |
|
2 |
* Copyright (C) 2009 EDIT |
|
3 |
* European Distributed Institute of Taxonomy |
|
4 |
* http://www.e-taxonomy.eu |
|
5 |
* |
|
6 |
* The contents of this file are subject to the Mozilla Public License Version 1.1 |
|
7 |
* See LICENSE.TXT at the top of this package for the full license terms. |
|
8 |
*/ |
|
9 |
package eu.etaxonomy.cdm.remote.controller.ext; |
|
10 |
|
|
11 |
import java.awt.Color; |
|
12 |
import java.io.IOException; |
|
13 |
import java.util.ArrayList; |
|
14 |
import java.util.List; |
|
15 |
import java.util.Map; |
|
16 |
import java.util.Set; |
|
17 |
import java.util.UUID; |
|
18 |
|
|
19 |
import javax.servlet.http.HttpServletRequest; |
|
20 |
import javax.servlet.http.HttpServletResponse; |
|
21 |
|
|
22 |
import org.apache.log4j.Logger; |
|
23 |
import org.springframework.beans.factory.annotation.Autowired; |
|
24 |
import org.springframework.stereotype.Controller; |
|
25 |
import org.springframework.web.bind.WebDataBinder; |
|
26 |
import org.springframework.web.bind.annotation.CrossOrigin; |
|
27 |
import org.springframework.web.bind.annotation.InitBinder; |
|
28 |
import org.springframework.web.bind.annotation.PathVariable; |
|
29 |
import org.springframework.web.bind.annotation.RequestMapping; |
|
30 |
import org.springframework.web.bind.annotation.RequestMethod; |
|
31 |
import org.springframework.web.bind.annotation.RequestParam; |
|
32 |
|
|
33 |
import de.micromata.opengis.kml.v_2_2_0.Kml; |
|
34 |
import eu.etaxonomy.cdm.api.service.IOccurrenceService; |
|
35 |
import eu.etaxonomy.cdm.api.service.ITaxonService; |
|
36 |
import eu.etaxonomy.cdm.api.service.ITermService; |
|
37 |
import eu.etaxonomy.cdm.api.service.util.TaxonRelationshipEdge; |
|
38 |
import eu.etaxonomy.cdm.database.UpdatableRoutingDataSource; |
|
39 |
import eu.etaxonomy.cdm.ext.geo.IEditGeoService; |
|
40 |
import eu.etaxonomy.cdm.model.common.MarkerType; |
|
41 |
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase; |
|
42 |
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationType; |
|
43 |
import eu.etaxonomy.cdm.model.taxon.Taxon; |
|
44 |
import eu.etaxonomy.cdm.model.taxon.TaxonBase; |
|
45 |
import eu.etaxonomy.cdm.persistence.query.OrderHint; |
|
46 |
import eu.etaxonomy.cdm.persistence.query.OrderHint.SortOrder; |
|
47 |
import eu.etaxonomy.cdm.remote.controller.BaseController; |
|
48 |
import eu.etaxonomy.cdm.remote.controller.util.ControllerUtils; |
|
49 |
import eu.etaxonomy.cdm.remote.editor.DefinedTermBaseList; |
|
50 |
import eu.etaxonomy.cdm.remote.editor.TermBaseListPropertyEditor; |
|
51 |
import eu.etaxonomy.cdm.remote.editor.UUIDListPropertyEditor; |
|
52 |
import eu.etaxonomy.cdm.remote.editor.UuidList; |
|
53 |
import io.swagger.annotations.Api; |
|
54 |
|
|
55 |
/** |
|
56 |
* The ExternalGeoController class is a Spring MVC Controller. |
|
57 |
* <p> |
|
58 |
* The syntax of the mapped service URIs contains the the {datasource-name} path element. |
|
59 |
* The available {datasource-name}s are defined in a configuration file which |
|
60 |
* is loaded by the {@link UpdatableRoutingDataSource}. If the |
|
61 |
* UpdatableRoutingDataSource is not being used in the actual application |
|
62 |
* context any arbitrary {datasource-name} may be used. |
|
63 |
* <p> |
|
64 |
* @author a.kohlbecker |
|
65 |
* @since 18.06.2009 |
|
66 |
* |
|
67 |
*/ |
|
68 |
@CrossOrigin(origins = "*") |
|
69 |
@Controller |
|
70 |
@Api(value="mapServiceParameters") |
|
71 |
@RequestMapping(value = { "kml" }) |
|
72 |
public class KmlController extends BaseController<TaxonBase, ITaxonService> { |
|
73 |
|
|
74 |
public static final Logger logger = Logger.getLogger(KmlController.class); |
|
75 |
|
|
76 |
@Autowired |
|
77 |
private IEditGeoService geoservice; |
|
78 |
|
|
79 |
@Autowired |
|
80 |
private IOccurrenceService occurrenceService; |
|
81 |
|
|
82 |
@Autowired |
|
83 |
private ITermService termService; |
|
84 |
|
|
85 |
@InitBinder |
|
86 |
@Override |
|
87 |
public void initBinder(WebDataBinder binder) { |
|
88 |
super.initBinder(binder); |
|
89 |
binder.registerCustomEditor(UuidList.class, new UUIDListPropertyEditor()); |
|
90 |
binder.registerCustomEditor(DefinedTermBaseList.class, new TermBaseListPropertyEditor<MarkerType>(termService)); |
|
91 |
} |
|
92 |
|
|
93 |
@Autowired |
|
94 |
@Override |
|
95 |
public void setService(ITaxonService service) { |
|
96 |
this.service = service; |
|
97 |
} |
|
98 |
|
|
99 |
/** |
|
100 |
* Assembles and returns URI parameter Strings for the EDIT Map Service. The distribution areas for the |
|
101 |
* {@link Taxon} instance identified by the <code>{taxon-uuid}</code> are found and are translated into |
|
102 |
* an valid URI parameter String. Higher level distribution areas are expanded in order to include all |
|
103 |
* nested sub-areas. |
|
104 |
* <p> |
|
105 |
* URI: <b>/{datasource-name}/geo/map/distribution/{taxon-uuid}</b> |
|
106 |
* |
|
107 |
* @param request |
|
108 |
* @param response |
|
109 |
* @return URI parameter Strings for the EDIT Map Service |
|
110 |
* @throws IOException TODO write controller method documentation |
|
111 |
*/ |
|
112 |
@RequestMapping(value = { "taxonOccurrencesFor/{uuid}" }, method = RequestMethod.GET) |
|
113 |
public Kml doGetOccurrenceKml( |
|
114 |
@PathVariable("uuid") UUID uuid, |
|
115 |
@RequestParam(value = "relationships", required = false) UuidList relationshipUuids, |
|
116 |
@RequestParam(value = "relationshipsInvers", required = false) UuidList relationshipInversUuids, |
|
117 |
@RequestParam(value = "maxDepth", required = false) Integer maxDepth, |
|
118 |
HttpServletRequest request, |
|
119 |
HttpServletResponse response) |
|
120 |
throws IOException { |
|
121 |
|
|
122 |
|
|
123 |
logger.info("doGetOccurrenceKml() " + requestPathAndQuery(request)); |
|
124 |
|
|
125 |
Map<SpecimenOrObservationType, Color> specimenOrObservationTypeColors = null; |
|
126 |
|
|
127 |
List<SpecimenOrObservationBase> specimensOrObersvations = occurencesForTaxon(uuid, relationshipUuids, |
|
128 |
relationshipInversUuids, maxDepth, response); |
|
129 |
|
|
130 |
Kml kml = geoservice.occurrencesToKML(specimensOrObersvations, specimenOrObservationTypeColors); |
|
131 |
|
|
132 |
return kml; |
|
133 |
} |
|
134 |
|
|
135 |
private List<SpecimenOrObservationBase> occurencesForTaxon(UUID taxonUuid, UuidList relationshipUuids, |
|
136 |
UuidList relationshipInversUuids, Integer maxDepth, HttpServletResponse response) throws IOException { |
|
137 |
Set<TaxonRelationshipEdge> includeRelationships = ControllerUtils.loadIncludeRelationships( |
|
138 |
relationshipUuids, relationshipInversUuids, termService); |
|
139 |
|
|
140 |
Taxon taxon = getCdmBaseInstance(Taxon.class, taxonUuid, response, (List<String>)null); |
|
141 |
|
|
142 |
List<OrderHint> orderHints = new ArrayList<OrderHint>(); |
|
143 |
orderHints.add(new OrderHint("titleCache", SortOrder.DESCENDING)); |
|
144 |
|
|
145 |
List<SpecimenOrObservationBase> specimensOrObersvations = occurrenceService.listByAssociatedTaxon( |
|
146 |
null, includeRelationships, taxon, maxDepth, null, null, orderHints, null); |
|
147 |
return specimensOrObersvations; |
|
148 |
} |
|
149 |
|
|
150 |
|
|
151 |
} |
cdmlib-remote/src/main/java/eu/etaxonomy/cdm/remote/view/XmlView.java | ||
---|---|---|
6 | 6 |
import javax.servlet.http.HttpServletResponse; |
7 | 7 |
import javax.xml.transform.stream.StreamResult; |
8 | 8 |
|
9 |
import org.springframework.beans.factory.annotation.Autowired; |
|
10 |
import org.springframework.beans.factory.annotation.Qualifier; |
|
11 | 9 |
import org.springframework.oxm.Marshaller; |
12 | 10 |
import org.springframework.web.servlet.view.AbstractView; |
13 | 11 |
|
14 | 12 |
import eu.etaxonomy.cdm.model.common.IdentifiableEntity; |
15 | 13 |
|
16 | 14 |
/** |
17 |
* View class which takes a serializes a cdm object as xml |
|
15 |
* View class which serializes objects as xml |
|
16 |
* |
|
18 | 17 |
* @author ben |
19 | 18 |
* @see javax.xml.transform.Source |
20 | 19 |
* @see com.ibm.lsid.MetadataResponse |
20 |
* @deprecated use {@link org.springframework.web.servlet.view.xml.MarshallingView} instead |
|
21 | 21 |
*/ |
22 |
@Deprecated |
|
22 | 23 |
public class XmlView extends AbstractView { |
23 | 24 |
|
24 | 25 |
private Marshaller marshaller; |
... | ... | |
39 | 40 |
|
40 | 41 |
} |
41 | 42 |
|
42 |
@Autowired |
|
43 |
@Qualifier("marshaller") |
|
44 | 43 |
public void setMarshaller(Marshaller marshaller) { |
45 | 44 |
this.marshaller = marshaller; |
46 | 45 |
} |
47 | 46 |
|
48 | 47 |
|
49 |
|
|
50 | 48 |
@Override |
51 | 49 |
protected void renderMergedOutputModel(Map model, HttpServletRequest request, HttpServletResponse response) |
52 | 50 |
throws Exception { |
cdmlib-remote/src/main/resources/eu/etaxonomy/cdm/remote.xml | ||
---|---|---|
47 | 47 |
</map> |
48 | 48 |
</property> |
49 | 49 |
</bean> |
50 |
|
|
51 |
<bean id="kmlMarshaller" name="kmlMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller"> |
|
52 |
<property name="classesToBeBound"> |
|
53 |
<list> |
|
54 |
<value>de.micromata.opengis.kml.v_2_2_0.Kml</value> |
|
55 |
</list> |
|
56 |
</property> |
|
57 |
<property name="checkForXmlRootElement" value="false" /> |
|
58 |
<property name="marshallerProperties"> |
|
59 |
<map> |
|
60 |
<entry key="jaxb.formatted.output"><value type="java.lang.Boolean">true</value></entry> |
|
61 |
</map> |
|
62 |
</property> |
|
63 |
</bean> |
|
50 | 64 |
|
51 | 65 |
<bean id="dozerMapper" class="eu.etaxonomy.cdm.remote.dto.assembler.DozerBeanMapperFactoryBean"> |
52 | 66 |
<property name="mappingFiles"> |
Also available in: Unified diff
ref #6113 producing more complete kml for DerivedUnits & general controller for HTTP OPTIONS requests