All Downloads are FREE. Search and download functionalities are using the official Maven repository.

it.tidalwave.bluebill.mobile.observation.share.KMLReportGenerator Maven / Gradle / Ivy

There is a newer version: 1.0.15
Show newest version
/***********************************************************************************************************************
 *
 * 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