it.tidalwave.bluebill.mobile.observation.share.KMLReportGenerator Maven / Gradle / Ivy
/***********************************************************************************************************************
*
* blueBill Mobile - open source birdwatching
* ==========================================
*
* Copyright (C) 2009, 2010 by Tidalwave s.a.s. (http://www.tidalwave.it)
* http://bluebill.tidalwave.it/mobile/
*
***********************************************************************************************************************
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
***********************************************************************************************************************
*
* $Id: KMLReportGenerator.java,v f0193565de42 2010/06/12 00:06:53 fabrizio $
*
**********************************************************************************************************************/
package it.tidalwave.bluebill.mobile.observation.share;
import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.TreeSet;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import it.tidalwave.util.AsException;
import it.tidalwave.util.NotFoundException;
import it.tidalwave.netbeans.util.Locator;
import it.tidalwave.geo.Coordinate;
import it.tidalwave.geo.Range;
import it.tidalwave.bluebill.observation.Location;
import it.tidalwave.bluebill.observation.Observation;
import it.tidalwave.bluebill.observation.ObservationItem;
import it.tidalwave.bluebill.observation.ObservationSet;
import it.tidalwave.bluebill.taxonomy.Taxon;
import it.tidalwave.bluebill.mobile.GeneralPreferences;
import it.tidalwave.bluebill.mobile.observation.ObservationPreferences;
import it.tidalwave.bluebill.mobile.taxonomy.TaxonomyPreferences;
import static it.tidalwave.bluebill.mobile.observation.ObservationPreferences.Extra.*;
import static it.tidalwave.bluebill.taxonomy.Taxon.Taxon;
/***********************************************************************************************************************
*
* @author Fabrizio Giudici
* @version $Id: $
*
**********************************************************************************************************************/
public class KMLReportGenerator extends ReportGenerator
{
private static final Class Range = Range.class; // FIXME: move to Range
private static final double RADIUS_THRESHOLD_FOR_RANGE_CIRCLE = 10.0;
@Nonnull
private ObservationPreferences observationPreferences = Locator.find(ObservationPreferences.class);
@Nonnull
private TaxonomyPreferences taxonomyPreferences = Locator.find(TaxonomyPreferences.class);
@Nonnull
private final GeneralPreferences generalPreferences = Locator.find(GeneralPreferences.class);
private boolean ignore = false;
private final List names = new ArrayList();
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
public void begin (final @Nonnull ObservationSet observationSet)
{
buffer.append("\n"
+ "\n"
+ " \n"
+ " blueBill Report \n"
+ " blueBill Report. \n"
+ " \n");
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
public void end (final @Nonnull ObservationSet observationSet)
{
buffer.append(" \n \n");
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
public void beginVisit (final @Nonnull Observation observation)
{
try
{
final Location location = observation.getLocation();
final Range range = location.as(Range); // can be not present, test before producing any output
buffer.append(" \n");
buffer.append(" \n");
buffer.append(" ").append(formatCoordinate(range.getCoordinate())).append(" \n");
buffer.append(" \n");
final DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss'Z'");
buffer.append(" \n");
buffer.append(" ").append(df.format(observation.getDate())).append(" \n");
buffer.append(" \n");
names.clear();
final Set taxonNames = new TreeSet();
final Locale primaryLocale = taxonomyPreferences.getTaxonomyLocales().get(0);
for (final ObservationItem item : observation.findObservationItems().results())
{
final Taxon taxon = item.getObservable().as(Taxon);
try
{
taxonNames.add(taxon.getDisplayName(primaryLocale));
}
catch (NotFoundException e)
{
taxonNames.add(taxon.getScientificName());
}
}
final StringBuilder name = new StringBuilder();
String separator = "";
int n = 0;
for (final String taxonName : taxonNames)
{
if (++n >= 5)
{
name.append("...");
break;
}
name.append(separator).append(taxonName);
separator = ", ";
}
buffer.append(String.format(" %s \n", name.toString()));
ignore = false;
}
catch (AsException e)
{
// Range not available, can't place on a map
ignore = true;
}
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
public void visit (final @Nonnull ObservationItem item)
{
if (!ignore)
{
names.add(observationPreferences.formatAsHtml(item, CARDINALITY, GENDER, MODE, NOTE_FULL).toString());
}
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
public void endVisit (final @Nonnull Observation observation)
{
if (!ignore)
{
Collections.sort(names);
buffer.append(" \n");
buffer.append(" %s
\n",
generalPreferences.formatDateAndTime(observation.getDate())));
buffer.append(String.format(" %s
\n",
observation.getLocation().getDisplayName()));
buffer.append(" \n");
for (int i = 0; i < names.size(); i++)
{
buffer.append(String.format(" - %s
\n", names.get(i)));
}
buffer.append("
\n");
buffer.append(" ]]>\n");
buffer.append(" \n");
buffer.append(" \n");
final Location location = observation.getLocation();
final Range range = location.as(Range);
if (range.getRadius() > RADIUS_THRESHOLD_FOR_RANGE_CIRCLE)
{
outputRangeCircle(range, buffer);
}
}
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
private void outputRangeCircle (final @Nonnull Range range, final @Nonnull StringBuilder buffer)
{
final Coordinate coordinate = range.getCoordinate();
final StringBuilder path = new StringBuilder();
final int n = 20;
for (double angle = 0; angle < 360; angle += 360 / n)
{
path.append(formatCoordinate(x(coordinate, range.getRadius(), angle))).append(" ");
}
buffer.append(" \n");
buffer.append(" #defaultStyles \n");
buffer.append(" \n");
buffer.append(" \n");
buffer.append(" \n");
buffer.append(" \n");
buffer.append(" ").append(path).append(" \n");
buffer.append(" \n");
buffer.append(" \n");
buffer.append(" \n");
buffer.append(" \n");
names.clear();
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
@Nonnull
private static Coordinate x (final @Nonnull Coordinate from, final double range, final double bearing)
{
final double EARTH_RADIUS_EQUATOR = 6378140.0;
final double b = Math.toRadians(bearing);
final double lon = Math.toRadians(from.getLongitude());
final double lat = Math.toRadians(from.getLatitude());
// final double f = 1/298.257;
final double e = 0.08181922;
final double R = EARTH_RADIUS_EQUATOR * (1 - e * e) / Math.pow((1 - e * e * Math.pow(Math.sin(lat), 2)), 1.5);
final double psi = range / R;
final double phi = Math.PI / 2 - lat;
final double arccos = Math.cos(psi) * Math.cos(phi) + Math.sin(psi) * Math.sin(phi) * Math.cos(b);
final double latA = Math.toDegrees(Math.PI / 2 - Math.acos(arccos));
final double arcsin = Math.sin(b) * Math.sin(psi) / Math.sin(phi);
final double longA = Math.toDegrees(lon - Math.asin(arcsin));
return new Coordinate(latA, longA, from.getAltitude());
}
@Nonnull
private static String formatCoordinate (final @Nonnull Coordinate c)
{
return String.format(Locale.UK, "%f, %f, %f", c.getLongitude(), c.getLatitude(), c.getAltitude());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy