r381 - in trunk: sammoa-application/src/main/java/fr/ulr/sammoa/application sammoa-application/src/main/java/fr/ulr/sammoa/application/map sammoa-application/src/test/java/fr/ulr/sammoa/application/map sammoa-persistence/src/main/java/fr/ulr/sammoa/persistence src/site/rst
Author: tchemit Date: 2012-08-09 19:53:27 +0200 (Thu, 09 Aug 2012) New Revision: 381 Url: http://forge.codelutin.com/repositories/revision/sammoa/381 Log: refs #1203: Export SHP Modified: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/FlightService.java trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/map/ExportMapService.java trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/map/LegStatus.java trunk/sammoa-application/src/test/java/fr/ulr/sammoa/application/map/ExportMapServiceTest.java trunk/sammoa-persistence/src/main/java/fr/ulr/sammoa/persistence/Observations.java trunk/sammoa-persistence/src/main/java/fr/ulr/sammoa/persistence/Routes.java trunk/src/site/rst/import-export.rst Modified: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/FlightService.java =================================================================== --- trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/FlightService.java 2012-08-09 17:26:32 UTC (rev 380) +++ trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/FlightService.java 2012-08-09 17:53:27 UTC (rev 381) @@ -25,6 +25,7 @@ package fr.ulr.sammoa.application; import com.google.common.base.Preconditions; +import com.google.common.base.Predicate; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; @@ -57,6 +58,7 @@ import org.nuiton.topia.TopiaContext; import org.nuiton.topia.TopiaException; import org.nuiton.topia.TopiaRuntimeException; +import org.nuiton.util.PeriodDates; import org.nuiton.util.TimeLog; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -96,6 +98,8 @@ public List<Flight> getFlights(Campaign campaign) { + Preconditions.checkNotNull(campaign); + long start = TimeLog.getTime(); List<Flight> result; @@ -119,9 +123,65 @@ return result; } - + + public Iterable<Flight> getFlights(Campaign campaign, + Date beginDate, + Date endDate) { + + TopiaContext transaction = persistence.beginTransaction(); + try { + + Iterable<Flight> result = getFlights(transaction, campaign, beginDate, endDate); + return result; + + } finally { + persistence.endTransaction(transaction); + } + + } + + public Iterable<Flight> getFlights(TopiaContext transaction, + Campaign campaign, + Date beginDate, + Date endDate) { + + Preconditions.checkNotNull(campaign); + Preconditions.checkNotNull(beginDate); + Preconditions.checkNotNull(endDate); + + long start = TimeLog.getTime(); + + List<Flight> campaignFlights; + try { + + FlightDAO dao = SammoaDAOHelper.getFlightDAO(transaction); + + campaignFlights = dao.findAllByCampaign(campaign); + Collections.sort(campaignFlights, Flights.onDate()); + + } catch (TopiaException e) { + throw new TopiaRuntimeException(e); + + } + + // Filter on period + final PeriodDates period = new PeriodDates(beginDate, endDate); + Iterable<Flight> result = Iterables.filter(campaignFlights, new Predicate<Flight>() { + + @Override + public boolean apply(Flight input) { + return period.between(input.getBeginDate()); + } + }); + + timeLog.log(start, "getFlights(" + campaign.getCode() + ")"); + + return result; + } + public Flight getFlight(String flightId) { + Preconditions.checkNotNull(flightId); long start = TimeLog.getTime(); Flight result; @@ -129,15 +189,15 @@ TopiaContext transaction = persistence.beginTransaction(); try { FlightDAO dao = SammoaDAOHelper.getFlightDAO(transaction); - + result = dao.findByTopiaId(flightId); - Preconditions.checkArgument(result != null, + Preconditions.checkArgument(result != null, String.format("%s doesn't exist", flightId)); if (logger.isInfoEnabled()) { - logger.info(String.format("Loading flight %d [%s]", - result.getFlightNumber(), - result.getTopiaId()) + logger.info("Loading flight {} [{}]", + result.getFlightNumber(), + result.getTopiaId() ); } @@ -173,7 +233,7 @@ TopiaContext transaction = persistence.beginTransaction(); try { FlightDAO dao = SammoaDAOHelper.getFlightDAO(transaction); - + String systemId = config.getSystemId(); int startNumber = config.getFlightNumber(); @@ -181,11 +241,11 @@ result = dao.createByNaturalId(systemId, flightNumber, campaign); result.setPlatformType(PlatformType.SIMPLE); - + if (logger.isInfoEnabled()) { - logger.info(String.format("Create new flight %d for campaign %s", - flightNumber, - campaign.getCode()) + logger.info("Create new flight {} for campaign {}", + flightNumber, + campaign.getCode() ); } @@ -207,8 +267,8 @@ * * @param flight Flight where observers are retrieved * @return the List of allowed Observer + * @see ObserverPosition * @since 0.3 - * @see ObserverPosition */ public List<Observer> getFlightObserverForPositions(Flight flight) { @@ -228,10 +288,22 @@ public List<GeoPoint> getFlightGeoPoints(Flight flight) { - List<GeoPoint> result; TopiaContext transaction = persistence.beginTransaction(); try { + List<GeoPoint> result = getFlightGeoPoints(transaction, flight); + return result; + } finally { + persistence.endTransaction(transaction); + } + + } + + public List<GeoPoint> getFlightGeoPoints(TopiaContext transaction, Flight flight) { + + List<GeoPoint> result; + + try { GeoPointDAO dao = SammoaDAOHelper.getGeoPointDAO(transaction); result = dao.findAllByFlightOrderedByRecordTime(flight); @@ -239,8 +311,6 @@ } catch (TopiaException e) { throw new TopiaRuntimeException(e); - } finally { - persistence.endTransaction(transaction); } return result; } @@ -288,7 +358,7 @@ * necessary. Note that all {@link TransectFlight} have link with * {@link AutoSaveListener} to manage modifications. * - * @param flight The flight + * @param flight The flight * @param fromIndex Index where transects will be added * @param transects The list of transect to add * @return the resulting TransectFlight added @@ -296,7 +366,7 @@ public List<TransectFlight> addTransects(Flight flight, int fromIndex, Iterable<Transect> transects) { List<TransectFlight> result = Lists.newArrayList(); - + TopiaContext transaction = persistence.beginTransaction(); try { @@ -312,7 +382,7 @@ // referential.persistTransectIfNecessary(transaction, transect); TransectFlight transectFlight = createTransectFlight( - transaction, transect, flight); + transaction, transect, flight); logger.debug("Add transect {} to the flight {}", transect.getName(), flight.getFlightNumber()); @@ -333,7 +403,7 @@ Collections.reverse(result); return result; } - + public Map<Transect, Long> getTransectRealNbTimes(Collection<Transect> transects) { Map<Transect, Long> result; @@ -366,20 +436,35 @@ */ public List<Route> getRoutes(Flight flight) { - List<Route> result; TopiaContext transaction = persistence.beginTransaction(); try { + List<Route> result = getRoutes(transaction, flight); + return result; + } finally { + persistence.endTransaction(transaction); + } + } + + /** + * Retrieve the list of {@link Route} associated to the given {@code flight}. + * + * @param flight Flight + * @return the List of Route matching the {@code flight} + */ + public List<Route> getRoutes(TopiaContext transaction, Flight flight) { + + List<Route> result; + try { + RouteDAO dao = SammoaDAOHelper.getRouteDAO(transaction); result = dao.findAllByFlightOrderedByBeginTime(flight); } catch (TopiaException e) { throw new TopiaRuntimeException(e); + } - } finally { - persistence.endTransaction(transaction); - } return result; } @@ -407,7 +492,7 @@ } return result; } - + public TransectFlight getLastTransectDone(Flight flight) { TransectFlight result; @@ -416,7 +501,7 @@ RouteDAO dao = SammoaDAOHelper.getRouteDAO(transaction); - Route route = dao.findLastByFlightAndType(flight, RouteType.LEG); + Route route = dao.findLastByFlightAndType(flight, RouteType.LEG); if (route != null) { result = route.getTransectFlight(); @@ -436,10 +521,20 @@ public List<Observation> getObservations(Flight flight) { - List<Observation> result; TopiaContext transaction = persistence.beginTransaction(); try { + List<Observation> result = getObservations(transaction, flight); + return result; + } finally { + persistence.endTransaction(transaction); + } + } + public List<Observation> getObservations(TopiaContext transaction, Flight flight) { + + List<Observation> result; + try { + ObservationDAO dao = SammoaDAOHelper.getObservationDAO(transaction); result = dao.findAllByFlightOrderedByObservationTime(flight); @@ -447,12 +542,10 @@ } catch (TopiaException e) { throw new TopiaRuntimeException(e); - } finally { - persistence.endTransaction(transaction); } return result; } - + public void setRouteObserverByPosition(Route route, Observer observer, Position position) { @@ -463,7 +556,7 @@ ObserverPositionDAO observerPositionDAO = SammoaDAOHelper.getObserverPositionDAO(transaction); - + ObserverPosition observerPosition = Iterables.find(observerPositions, ObserverPositions.withPosition(position)); @@ -489,12 +582,12 @@ } } } - + observerPosition.setObserver(observer); observerPositionDAO.update(observerPosition); debugObserverPositions("Update", observerPositions); - + transaction.commitTransaction(); } catch (TopiaException e) { @@ -567,18 +660,18 @@ Route previousRoute, TransectFlight transectFlight) throws TopiaException { - + Preconditions.checkArgument(transectFlight != null, "You can't create a leg without any transect"); Route result = createRoute(transaction, flight, beginTime, RouteType.LEG, previousRoute, transectFlight); RouteDAO dao = SammoaDAOHelper.getRouteDAO(transaction); - + result.setTransectFlight(transectFlight); int effortNumber = dao.getLastEffortNumber(flight); result.setEffortNumber(effortNumber); - + return result; } @@ -588,7 +681,7 @@ Route previousRoute, Observation circleBackCause) throws TopiaException { - + Preconditions.checkArgument(circleBackCause != null, "You can't create a route without any observation cause"); Route result = createRoute(transaction, flight, beginTime, RouteType.CIRCLE_BACK, previousRoute, null); @@ -626,21 +719,21 @@ } // Prepare observer positions - Collection<ObserverPosition> observerPositions = + Collection<ObserverPosition> observerPositions = createRouteObserverPositions(transaction, previousRoute, transectFlight, flight); result.setObserverPosition(observerPositions); return result; } - + protected Collection<ObserverPosition> createRouteObserverPositions(TopiaContext transaction, Route previousRoute, TransectFlight transectFlight, - Flight flight) + Flight flight) throws TopiaException { - + Collection<ObserverPosition> result; - + if (previousRoute != null) { // Prepare position depends on transect change @@ -662,20 +755,20 @@ } result = copyObserverPositions(transaction, previousRoute.getObserverPosition()); - } - } else { + } + } else { if (logger.isDebugEnabled()) { logger.debug("Create default observerPositions from flight"); } result = createObserverPositions(transaction, flight); - } - return result; + } + return result; } - protected Collection<ObserverPosition> createObserverPositions(TopiaContext transaction, - Flight flight) + protected Collection<ObserverPosition> createObserverPositions(TopiaContext transaction, + Flight flight) throws TopiaException { Collection<ObserverPosition> result = Lists.newArrayList(); @@ -712,10 +805,10 @@ } debugObserverPositions("Create", result); - + return result; } - + protected Collection<ObserverPosition> copyObserverPositions(TopiaContext transaction, Collection<ObserverPosition> observerPositions) throws TopiaException { @@ -723,10 +816,10 @@ Collection<ObserverPosition> result = Lists.newArrayList(); debugObserverPositions("Copy", observerPositions); - + ObserverPositionDAO observerPositionDAO = SammoaDAOHelper.getObserverPositionDAO(transaction); - + for (ObserverPosition source : observerPositions) { ObserverPosition target = observerPositionDAO.create(); @@ -736,10 +829,10 @@ } debugObserverPositions("Result of copy", result); - - return result; + + return result; } - + protected void debugObserverPositions(String title, Iterable<ObserverPosition> observerPositions) { if (logger.isTraceEnabled()) { Modified: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/map/ExportMapService.java =================================================================== --- trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/map/ExportMapService.java 2012-08-09 17:26:32 UTC (rev 380) +++ trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/map/ExportMapService.java 2012-08-09 17:53:27 UTC (rev 381) @@ -30,17 +30,28 @@ import com.bbn.openmap.omGraphics.OMGraphic; import com.bbn.openmap.omGraphics.OMPoint; import com.google.common.base.Preconditions; -import com.google.common.base.Predicate; -import com.google.common.collect.Iterables; import com.google.common.collect.Maps; +import fr.ulr.sammoa.application.FlightService; import fr.ulr.sammoa.application.SammoaConfig; import fr.ulr.sammoa.application.SammoaContext; import fr.ulr.sammoa.persistence.Campaign; import fr.ulr.sammoa.persistence.Flight; import fr.ulr.sammoa.persistence.GeoPoint; +import fr.ulr.sammoa.persistence.GeoPoints; +import fr.ulr.sammoa.persistence.Observation; +import fr.ulr.sammoa.persistence.Observations; +import fr.ulr.sammoa.persistence.ObserverPosition; +import fr.ulr.sammoa.persistence.Position; import fr.ulr.sammoa.persistence.Region; +import fr.ulr.sammoa.persistence.Route; +import fr.ulr.sammoa.persistence.RouteType; +import fr.ulr.sammoa.persistence.Routes; import fr.ulr.sammoa.persistence.SammoaPersistence; -import org.nuiton.util.PeriodDates; +import fr.ulr.sammoa.persistence.Species; +import fr.ulr.sammoa.persistence.Strate; +import fr.ulr.sammoa.persistence.Transect; +import fr.ulr.sammoa.persistence.TransectFlight; +import org.nuiton.topia.TopiaContext; import org.nuiton.util.TimeLog; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -48,6 +59,8 @@ import java.io.File; import java.text.DateFormat; import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Iterator; import java.util.List; import java.util.Map; @@ -89,15 +102,14 @@ dataModel.getExportDirectory(), dataModel.getExportFilename()); } + long startTime = TimeLog.getTime(); - Campaign campaign = dataModel.getCampaign(); - Region region = campaign.getRegion(); // * uniquement pour un parcours de type LEG, sinon la cellule sera vide // ** uniquement pour un parcours de type CIRCLE_BACK, sinon la cellule sera vide DbfTableModelBuilder builder = new DbfTableModelBuilder() - .stringColumn("REGION") // (campaign.region.code) + .stringColumn("REGION") // (region.code) .stringColumn("CAMPAIGN") // (campaign.code) .integerColumn("SECTOR") // * (route.transectFlight.transect.strate.sector.sectorNumber) .stringColumn("STRATE_TYPE") // * (route.transectFlight.transect.strate.strateType.code) @@ -107,9 +119,9 @@ .integerColumn("FLIGHT") // (route.flight.flightNumber) .stringColumn("COMPUTER") // (route.flight.systemId) .stringColumn("ROUTE_TYPE") // (route.routeType.name) - .stringColumn("EFFORT_GROUP") // * () - .stringColumn("EFFORT") // * () - .stringColumn("STATUS") // * (LegStatus.name) + .stringColumn("EFFORT_GROUP") // * (voir doc) + .stringColumn("EFFORT") // * (voir doc) + .stringColumn("STATUS") // * (voir doc) .dateColumn("DATE") // (route.beginTime) .stringColumn("HHMMSS") // (format(route.beginTime, "HHmmss")) .integerColumn("SEA_STATE") // (route.seaState) @@ -133,73 +145,160 @@ .doubleColumn("SPEED", 19, 11) // (geoPoint.speed) .doubleColumn("ALTITUDE", 19, 11) // (geoPoint.altitude) .stringColumn("GPS_TIME") // (format(geoPoint.recordTime, "HHmmss")) - .stringColumn("AIRCRAFT") // (route.flight.planeImmatriculation) + .stringColumn("AIRCRAFT") // (route.flight.immatriculation) .stringColumn("COMMENT") // (route.comment) .build(); EsriGraphicList graphicList = new EsriPointList(); - List<Flight> campaignFlights = context.getFlightService().getFlights(dataModel.getCampaign()); - // Filter on period - final PeriodDates period = new PeriodDates(dataModel.getBeginDate(), dataModel.getEndDate()); - Iterable<Flight> flights = Iterables.filter(campaignFlights, new Predicate<Flight>() { + FlightService flightService = context.getFlightService(); - @Override - public boolean apply(Flight input) { - return period.between(input.getBeginDate()); - } - }); + Campaign campaign = dataModel.getCampaign(); + Region region = campaign.getRegion(); - // Export for each flight - for (Flight flight : flights) { + List<RouteType> routeTypes = dataModel.getRouteTypes(); + List<Strate> strates = dataModel.getStrates(); - if (logger.isInfoEnabled()) { - logger.info("Export GeoPoints from flight {} - {} - {} - {}", - new Object[]{flight.getFlightNumber(), - flight.getSystemId(), - campaign.getCode(), - region.getCode()} - ); - } + TopiaContext tx = context.getPersistence().beginTransaction(); - List<GeoPoint> geoPoints = context.getFlightService().getFlightGeoPoints(flight); + try { + // get flights for campaign (and between begin - end date) + Iterable<Flight> flights = flightService.getFlights( + tx, + campaign, + dataModel.getBeginDate(), + dataModel.getEndDate()); - // One record by GeoPoint - for (GeoPoint geoPoint : geoPoints) { + // Export for each flight + for (Flight flight : flights) { - Map<String, Object> record = Maps.newHashMap(); + if (logger.isInfoEnabled()) { + logger.info("Export Efforts from flight {} - {} - {} - {}", + new Object[]{flight.getFlightNumber(), + flight.getSystemId(), + campaign.getCode(), + region.getCode()} + ); + } - record.put("REGION", region.getCode()); - record.put("CAMPAIGN", campaign.getCode()); - record.put("FLIGHT", flight.getFlightNumber()); - record.put("COMPUTER", flight.getSystemId()); - record.put("DATE", geoPoint.getRecordTime()); - record.put("HHMMSS", timeFormat.format(geoPoint.getRecordTime())); - record.put("LAT", geoPoint.getLatitude()); - record.put("LON", geoPoint.getLongitude()); - record.put("SPEED", geoPoint.getSpeed()); - record.put("ALTITUDE", geoPoint.getAltitude()); + // common properties for the flight + Map<String, Object> commonRecord = Maps.newHashMap(); + fillFlightRecord(campaign, region, flight, commonRecord); - builder.addValues(record); + // get all routes of this flight + List<Route> routes = flightService.getRoutes(tx, flight); - if (logger.isTraceEnabled()) { - logger.trace("Record={}", record); + // get all geo points for this flight + List<GeoPoint> geoPoints = flightService.getFlightGeoPoints(tx, flight); + + // get best geo points for each route + Iterable<GeoPoint> routeGeoPoints = + GeoPoints.getClosestPoints(geoPoints, Routes.toDates(routes)); + + // to iterate on geoPoints + Iterator<GeoPoint> geoPointIterator = routeGeoPoints.iterator(); + + // to keep current effort group identifier + String effortGroup = null; + + for (Route route : routes) { + + if (logger.isTraceEnabled()) { + logger.trace("Export Efforts from route {} - {}", + new Object[]{route.getBeginTime(), + route.getRouteType()} + ); + } + + // get geoPoint associated with this route + GeoPoint geoPoint = geoPointIterator.next(); + + // is current route a leg ? + boolean routeIsLeg = Routes.isRouteLeg(route); + + if (!routeIsLeg) { + + if (effortGroup != null) { + + // previous route was a leg + // need to create a end row (to close the group) + + Map<String, Object> record = Maps.newHashMap(); + record.putAll(commonRecord); + + // add route data + fillRouteRecord(flight, + route, + effortGroup, + LegStatus.END, + record); + + // add geoPoint data and flush + fillGeoPointRecordAndFlush(geoPoint, + record, + builder, + graphicList); + } + + // reset effort group + // will be recomputed by first next leg route + effortGroup = null; + } + + boolean routeIsValid = Routes.isRouteAccepted(route, + routeTypes, + strates); + + if (routeIsValid) { + + // selected route = one row on dbf + + Map<String, Object> record = Maps.newHashMap(); + record.putAll(commonRecord); + + LegStatus legStatus = null; + + if (routeIsLeg) { + + if (effortGroup == null) { + + // this is the first route of the leg group + legStatus = LegStatus.BEGIN; + + // compute the unique effortGroup for this group + effortGroup = computeEffortGroup(flight, route); + } else { + + // group already began, just add a route to it + legStatus = LegStatus.ADD; + } + + } + + // add route data + fillRouteRecord(flight, route, effortGroup, legStatus, record); + + + // add geoPoint data and flush + fillGeoPointRecordAndFlush(geoPoint, + record, + builder, + graphicList); + } } - - OMGraphic graphic = new OMPoint(geoPoint.getLatitude(), geoPoint.getLongitude()); - graphicList.add(graphic); } - } - startTime = timeLog.log(startTime, "exportGeoPointsMap", "after building EsriGraphicList and DbfTableModel"); + startTime = timeLog.log( + startTime, + "exportEffortsMap", + "after building EsriGraphicList and DbfTableModel"); - // Execute export with EsriShapeExport - DbfTableModel tableModel = builder.getModel(); - String pathFile = new File(dataModel.getExportDirectory(), dataModel.getExportFilename()).getAbsolutePath(); - EsriShapeExport shapeExport = new EsriShapeExport(graphicList, tableModel, pathFile); - shapeExport.export(); + flushExport(builder, dataModel, graphicList); - timeLog.log(startTime, "exportEffortsMap", "after EsriShapeExport execution"); + timeLog.log(startTime, "exportEffortsMap", "after EsriShapeExport execution"); + } finally { + context.getPersistence().endTransaction(tx); + } } public void exportObservationsMap(ExportMapModel dataModel) { @@ -214,11 +313,7 @@ } long startTime = TimeLog.getTime(); - Campaign campaign = dataModel.getCampaign(); - Region region = campaign.getRegion(); - // * uniquement pour un parcours de type LEG, sinon la cellule sera vide - // ** uniquement pour un parcours de type CIRCLE_BACK, sinon la cellule sera vide DbfTableModelBuilder builder = new DbfTableModelBuilder() .stringColumn("REGION") // (campaign.region.code) .stringColumn("CAMPAIGN") // (campaign.code) @@ -230,9 +325,9 @@ .integerColumn("FLIGHT") // (route.flight.flightNumber) .stringColumn("COMPUTER") // (route.flight.systemId) .stringColumn("ROUTE_TYPE") // (route.routeType.name) - .stringColumn("EFFORT_GROUP") // * () - .stringColumn("EFFORT") // * () - .stringColumn("OBSERVATION") // () + .stringColumn("EFFORT_GROUP") // * (voir doc) + .stringColumn("EFFORT") // * (voir doc) + .stringColumn("OBSERVATION") // (voir doc) .dateColumn("DATE") // (observation.beginTime) .stringColumn("HHMMSS") // (format(observation.beginTime, "HHmmss")) .stringColumn("TAXON") // (observation.species.type) @@ -248,7 +343,7 @@ .stringColumn("BEHAVIOUR") // (observation.behaviour) .integerColumn("SWIM_DIR") // (observation.swimDir) .stringColumn("CALVES") // (observation.calves) - .stringColumn("PHOTO") // (observation.photo) + .booleanColumn("PHOTO") // (observation.photo) .stringColumn("OBSERVER") // (observation.observerPosition.observer.initials) .stringColumn("SIDE") // (observation.observerPosition.observer.position.name) .stringColumn("STATUS") // (observation.observationStatus.name) @@ -258,77 +353,179 @@ .doubleColumn("SPEED", 19, 11) // (geoPoint.speed) .doubleColumn("ALTITUDE", 19, 11) // (geoPoint.altitude) .stringColumn("GPS_TIME") // (format(geoPoint.recordTime, "HHmmss")) - .stringColumn("AIRCRAFT") // (observation.flight.planeImmatriculation) + .stringColumn("AIRCRAFT") // (flight.immatriculation) .stringColumn("COMMENT") // (observation.comment) .build(); EsriGraphicList graphicList = new EsriPointList(); - List<Flight> campaignFlights = context.getFlightService().getFlights(dataModel.getCampaign()); - // Filter on period - final PeriodDates period = new PeriodDates(dataModel.getBeginDate(), dataModel.getEndDate()); - Iterable<Flight> flights = Iterables.filter(campaignFlights, new Predicate<Flight>() { + Campaign campaign = dataModel.getCampaign(); + Region region = campaign.getRegion(); + List<RouteType> routeTypes = dataModel.getRouteTypes(); + List<Strate> strates = dataModel.getStrates(); - @Override - public boolean apply(Flight input) { - return period.between(input.getBeginDate()); - } - }); + TopiaContext tx = context.getPersistence().beginTransaction(); - // Export for each flight + try { + FlightService flightService = context.getFlightService(); - for (Flight flight : flights) { + // get flights for campaign (and between begin - end date) + Iterable<Flight> flights = flightService.getFlights( + tx, + campaign, + dataModel.getBeginDate(), + dataModel.getEndDate()); - if (logger.isInfoEnabled()) { - logger.info("Export GeoPoints from flight {} - {} - {} - {}", - new Object[]{flight.getFlightNumber(), - flight.getSystemId(), - campaign.getCode(), - region.getCode()} - ); - } + // Export for each flight - List<GeoPoint> geoPoints = context.getFlightService().getFlightGeoPoints(flight); + for (Flight flight : flights) { - // One record by GeoPoint - for (GeoPoint geoPoint : geoPoints) { + if (logger.isInfoEnabled()) { + logger.info("Export Observations from flight {} - {} - {} - {}", + new Object[]{flight.getFlightNumber(), + flight.getSystemId(), + campaign.getCode(), + region.getCode()} + ); + } - Map<String, Object> record = Maps.newHashMap(); + // get all observations for this flight + List<Observation> observations = + flightService.getObservations(tx, flight); - record.put("REGION", region.getCode()); - record.put("CAMPAIGN", campaign.getCode()); - record.put("FLIGHT", flight.getFlightNumber()); - record.put("COMPUTER", flight.getSystemId()); - record.put("DATE", geoPoint.getRecordTime()); - record.put("HHMMSS", timeFormat.format(geoPoint.getRecordTime())); - record.put("LAT", geoPoint.getLatitude()); - record.put("LON", geoPoint.getLongitude()); - record.put("SPEED", geoPoint.getSpeed()); - record.put("ALTITUDE", geoPoint.getAltitude()); + // apply species filter + Observations.removeOtherSpecies(observations, + dataModel.getSpecies()); - builder.addValues(record); + // get all routes of this flight + List<Route> routes = flightService.getRoutes(tx, flight); - if (logger.isTraceEnabled()) { - logger.trace("Record={}", record); + // get all geo points for this flight + List<GeoPoint> routeGeoPoints = + flightService.getFlightGeoPoints(tx, flight); + + Map<String, Object> flightRecord = Maps.newHashMap(); + fillFlightRecord(campaign, region, flight, flightRecord); + + int nextRouteIndex = 0; + int nbRoutes = routes.size(); + String effortGroup = null; + + for (Route route : routes) { + + nextRouteIndex++; + + boolean routeIsLeg = Routes.isRouteLeg(route); + + if (!routeIsLeg) { + + // new group will be computed at next leg route + effortGroup = null; + } + + if (!Routes.isRouteAccepted(route, routeTypes, strates)) { + + // not selected route + continue; + } + + Map<String, Object> routeRecord = Maps.newHashMap(); + routeRecord.putAll(flightRecord); + + if (routeIsLeg && effortGroup == null) { + + // compute effort group id + effortGroup = computeEffortGroup(flight, route); + } + + fillRouteTypeRecord(flight, route, effortGroup, routeRecord); + + // get routeEndTime + Date routeEndTime; + + if (nextRouteIndex < nbRoutes) { + + // use next route begin time + Route nextRoute = routes.get(nextRouteIndex); + routeEndTime = nextRoute.getBeginTime(); + } else { + + // use flight end date + routeEndTime = flight.getEndDate(); + } + + // Get observations for this route + List<Observation> routeObservations = + Observations.getObservations(observations, + route.getBeginTime(), + routeEndTime); + + // get best geo points for each observation + Iterable<GeoPoint> observationGeoPoints = + GeoPoints.getClosestPoints( + routeGeoPoints, + Observations.toDates(routeObservations)); + + // to iterate on geoPoints + Iterator<GeoPoint> geoPointIterator = + observationGeoPoints.iterator(); + + for (Observation observation : routeObservations) { + + Map<String, Object> record = Maps.newHashMap(); + record.putAll(routeRecord); + + String observationId = computeObservationId(flight, observation); + record.put("OBSERVATION", observationId); + + fillDateRecord(observation.getObservationTime(), record); + + Species species = observation.getSpecies(); + if (species != null) { + record.put("TAXON", species.getType()); + record.put("GROUP", species.getGroupName()); + record.put("FAMILY", species.getFamily()); + record.put("SPECIES", species.getCode()); + record.put("SPECIES_NAME", species.getCommonName()); + record.put("SPECIES_LATIN", species.getLatinName()); + } + record.put("POD_SIZE", observation.getPodSize()); + record.put("AGE", observation.getAge()); + record.put("DEC_ANGLE", observation.getDecAngle()); + record.put("CUE", observation.getCue()); + record.put("BEHAVIOUR", observation.getBehaviour()); + record.put("SWIM_DIR", observation.getSwimDir()); + record.put("CALVES", observation.getCalves()); + record.put("PHOTO", observation.isPhoto()); + record.put("OBSERVER", observation.getObserverPosition().getObserver().getInitials()); + record.put("SIDE", observation.getObserverPosition().getPosition().getName()); + record.put("STATUS", observation.getObservationStatus().getName()); + record.put("COMMENT", observation.getComment()); + + GeoPoint geoPoint = geoPointIterator.next(); + + // add geoPoint data and flush + fillGeoPointRecordAndFlush(geoPoint, + record, + builder, + graphicList); + + } } - - OMGraphic graphic = new OMPoint(geoPoint.getLatitude(), geoPoint.getLongitude()); - graphicList.add(graphic); } - } - startTime = timeLog.log(startTime, "exportObservationsMap", "after building EsriGraphicList and DbfTableModel"); + startTime = timeLog.log(startTime, "exportObservationsMap", "after building EsriGraphicList and DbfTableModel"); - // Execute export with EsriShapeExport - DbfTableModel tableModel = builder.getModel(); - String pathFile = new File(dataModel.getExportDirectory(), dataModel.getExportFilename()).getAbsolutePath(); - EsriShapeExport shapeExport = new EsriShapeExport(graphicList, tableModel, pathFile); - shapeExport.export(); + flushExport(builder, dataModel, graphicList); - timeLog.log(startTime, "exportObservationsMap", "after EsriShapeExport execution"); + timeLog.log(startTime, "exportObservationsMap", "after EsriShapeExport execution"); + } finally { + context.getPersistence().endTransaction(tx); + } } public void exportGeoPointsMap(ExportMapModel dataModel) { + Preconditions.checkNotNull(dataModel.getCampaign()); Preconditions.checkNotNull(dataModel.getBeginDate()); Preconditions.checkNotNull(dataModel.getEndDate()); @@ -341,14 +538,12 @@ long startTime = TimeLog.getTime(); - Campaign campaign = dataModel.getCampaign(); - Region region = campaign.getRegion(); - DbfTableModelBuilder builder = new DbfTableModelBuilder() .stringColumn("REGION") .stringColumn("CAMPAIGN") .integerColumn("FLIGHT") .stringColumn("COMPUTER") + .stringColumn("AIRCRAFT") .dateColumn("DATE") .stringColumn("HHMMSS") .doubleColumn("LAT", 19, 11) @@ -357,68 +552,214 @@ .doubleColumn("ALTITUDE", 19, 11) .build(); - EsriGraphicList graphicList = new EsriPointList(); - List<Flight> campaignFlights = context.getFlightService().getFlights(dataModel.getCampaign()); + Campaign campaign = dataModel.getCampaign(); + Region region = campaign.getRegion(); - // Filter on period - final PeriodDates period = new PeriodDates(dataModel.getBeginDate(), dataModel.getEndDate()); - Iterable<Flight> flights = Iterables.filter(campaignFlights, new Predicate<Flight>() { + FlightService flightService = context.getFlightService(); - @Override - public boolean apply(Flight input) { - return period.between(input.getBeginDate()); - } - }); + // get flights for campaign (and between begin - end date) + Iterable<Flight> flights = flightService.getFlights(campaign, + dataModel.getBeginDate(), + dataModel.getEndDate()); + EsriGraphicList graphicList = new EsriPointList(); + // Export for each flight for (Flight flight : flights) { if (logger.isInfoEnabled()) { - logger.info(String.format("Export GeoPoints from flight %d - %s - %s - %s", - flight.getFlightNumber(), - flight.getSystemId(), - campaign.getCode(), - region.getCode()) + logger.info("Export GeoPoints from flight {} - {} - {} - {}", + new Object[]{flight.getFlightNumber(), + flight.getSystemId(), + campaign.getCode(), + region.getCode()} ); } - List<GeoPoint> geoPoints = context.getFlightService().getFlightGeoPoints(flight); + List<GeoPoint> geoPoints = + flightService.getFlightGeoPoints(flight); + Map<String, Object> commonRecord = Maps.newHashMap(); + fillFlightRecord(campaign, region, flight, commonRecord); + // One record by GeoPoint for (GeoPoint geoPoint : geoPoints) { Map<String, Object> record = Maps.newHashMap(); + record.putAll(commonRecord); - record.put("REGION", region.getCode()); - record.put("CAMPAIGN", campaign.getCode()); - record.put("FLIGHT", flight.getFlightNumber()); - record.put("COMPUTER", flight.getSystemId()); - record.put("DATE", geoPoint.getRecordTime()); - record.put("HHMMSS", timeFormat.format(geoPoint.getRecordTime())); - record.put("LAT", geoPoint.getLatitude()); - record.put("LON", geoPoint.getLongitude()); - record.put("SPEED", geoPoint.getSpeed()); - record.put("ALTITUDE", geoPoint.getAltitude()); + fillDateRecord(geoPoint.getRecordTime(), record); - builder.addValues(record); - - if (logger.isTraceEnabled()) { - logger.trace("Record={}", record); - } - - OMGraphic graphic = new OMPoint(geoPoint.getLatitude(), geoPoint.getLongitude()); - graphicList.add(graphic); + // add geoPoint data and flush + fillGeoPointRecordAndFlush(geoPoint, + record, + builder, + graphicList); } } - startTime = timeLog.log(startTime, "exportGeoPointsMap", "after building EsriGraphicList and DbfTableModel"); + startTime = timeLog.log(startTime, "exportGeoPointsMap", + "after building EsriGraphicList and DbfTableModel"); - // Execute export with EsriShapeExport + flushExport(builder, dataModel, graphicList); + + timeLog.log(startTime, "exportGeoPointsMap", + "after EsriShapeExport execution"); + } + + protected void flushExport(DbfTableModelBuilder builder, + ExportMapModel dataModel, + EsriGraphicList graphicList) { + DbfTableModel tableModel = builder.getModel(); - String pathFile = new File(dataModel.getExportDirectory(), dataModel.getExportFilename()).getAbsolutePath(); + String pathFile = new File(dataModel.getExportDirectory(), + dataModel.getExportFilename()).getAbsolutePath(); EsriShapeExport shapeExport = new EsriShapeExport(graphicList, tableModel, pathFile); shapeExport.export(); + } - timeLog.log(startTime, "exportGeoPointsMap", "after EsriShapeExport execution"); + protected void fillDateRecord(Date date, Map<String, Object> record) { + record.put("DATE", date); + record.put("HHMMSS", timeFormat.format(date)); } + + protected void fillGeoPointRecordAndFlush(GeoPoint geoPoint, + Map<String, Object> record, + DbfTableModelBuilder builder, + EsriGraphicList graphicList) { + + record.put("LAT", geoPoint.getLatitude()); + record.put("LON", geoPoint.getLongitude()); + record.put("SPEED", geoPoint.getSpeed()); + record.put("ALTITUDE", geoPoint.getAltitude()); + + builder.addValues(record); + + if (logger.isTraceEnabled()) { + logger.trace("Record={}", record); + } + + OMGraphic graphic = new OMPoint(geoPoint.getLatitude(), + geoPoint.getLongitude()); + graphicList.add(graphic); + } + + protected void fillFlightRecord(Campaign campaign, + Region region, + Flight flight, + Map<String, Object> record) { + + record.put("REGION", region.getCode()); + record.put("CAMPAIGN", campaign.getCode()); + record.put("FLIGHT", flight.getFlightNumber()); + record.put("AIRCRAFT", flight.getImmatriculation()); + record.put("COMPUTER", flight.getSystemId()); + } + + protected void fillRouteRecord(Flight flight, + Route route, + String effortGroup, + LegStatus legStatus, + Map<String, Object> record) { + + if (logger.isTraceEnabled()) { + logger.trace("Create Route record for route {} - {}", + new Object[]{route.getBeginTime(), + route.getRouteType()} + ); + } + + fillDateRecord(route.getBeginTime(), record); + fillRouteTypeRecord(flight, route, effortGroup, record); + + if (legStatus != null) { + record.put("STATUS", LegStatus.END); + } + record.put("COMMENT", route.getComment()); + record.put("SEA_STATE", route.getSeaState()); + record.put("SWELL", route.getSwell()); + record.put("TURBIDITY", route.getTurbidity()); + record.put("SKY_GLINT", route.getSkyGlint()); + record.put("GLARE_FROM", route.getGlareFrom()); + record.put("GLARE_TO", route.getGlareTo()); + record.put("GLARE_SEVERITY", route.getGlareSeverity()); + record.put("GLARE_UNDER", route.isGlareUnder()); + record.put("CLOUD_COVER", route.getCloudCover()); + record.put("SUBJECTIVE", route.getSubjectiveConditions()); + record.put("UNEXP_LEFT", route.getUnexpectedLeft()); + record.put("UNEXP_RIGHT", route.getUnexpectedRight()); + + ObserverPosition observerPositionByPosition = + route.getObserverPositionByPosition(Position.FRONT_LEFT); + if (observerPositionByPosition != null) { + record.put("LEFT_REAR", observerPositionByPosition.getObserver().getInitials()); + } + observerPositionByPosition = + route.getObserverPositionByPosition(Position.FRONT_RIGHT); + if (observerPositionByPosition != null) { + record.put("RIGHT_REAR", observerPositionByPosition.getObserver().getInitials()); + } + observerPositionByPosition = + route.getObserverPositionByPosition(Position.NAVIGATOR); + if (observerPositionByPosition != null) { + record.put("CENTER", observerPositionByPosition.getObserver().getInitials()); + } + } + + protected void fillRouteTypeRecord(Flight flight, + Route route, + String effortGroup, + Map<String, Object> record) { + + record.put("ROUTE_TYPE", route.getRouteType().getName()); + if (Routes.isRouteLeg(route)) { + fillLegRouteRecord(route, effortGroup, record); + } + + if (Routes.isRouteCircleBack(route)) { + + // compute circle back cause + String circleBackCause = computeObservationId(flight, route.getCircleBackCause()); + record.put("CB_CAUSE", circleBackCause); + } + } + + protected void fillLegRouteRecord(Route route, + String effortGroup, + Map<String, Object> record) { + + TransectFlight transectFlight = route.getTransectFlight(); + Transect transect = transectFlight.getTransect(); + Strate strate = transect.getStrate(); + + String effort = computeEffort(route); + + record.put("SECTOR", strate.getSector().getSectorNumber()); + record.put("STRATE_TYPE", strate.getStrateType().getCode()); + record.put("STRATE", strate.getCode()); + record.put("TRANSECT", transect.getName()); + record.put("PASSAGE", transectFlight.getCrossingNumber()); + record.put("EFFORT_GROUP", effortGroup); + record.put("EFFORT", effort); + } + + protected String computeEffort(Route route) { + String result = "L" + route.getEffortNumber() + "-" + + route.getFlight().getFlightNumber() + "-" + + route.getFlight().getSystemId(); + return result; + } + + protected String computeEffortGroup(Flight flight, Route route) { + String result = "G" + route.getEffortNumber() + "-" + + flight.getFlightNumber() + "-" + + flight.getSystemId(); + return result; + } + + protected String computeObservationId(Flight flight, Observation observation) { + return "O" + observation.getObservationNumber() + "-" + + flight.getFlightNumber() + "-" + + flight.getSystemId(); + } } Modified: trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/map/LegStatus.java =================================================================== --- trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/map/LegStatus.java 2012-08-09 17:26:32 UTC (rev 380) +++ trunk/sammoa-application/src/main/java/fr/ulr/sammoa/application/map/LegStatus.java 2012-08-09 17:53:27 UTC (rev 381) @@ -7,7 +7,7 @@ * @since 0.5 */ public enum LegStatus { - BEAGIN, + BEGIN, ADD, END; public String getName() { Modified: trunk/sammoa-application/src/test/java/fr/ulr/sammoa/application/map/ExportMapServiceTest.java =================================================================== --- trunk/sammoa-application/src/test/java/fr/ulr/sammoa/application/map/ExportMapServiceTest.java 2012-08-09 17:26:32 UTC (rev 380) +++ trunk/sammoa-application/src/test/java/fr/ulr/sammoa/application/map/ExportMapServiceTest.java 2012-08-09 17:53:27 UTC (rev 381) @@ -183,6 +183,7 @@ public Iterable<ImportableColumn<GeoPoint, Object>> getColumnsForImport() { ModelBuilder builder = new ModelBuilder(); builder.newMandatoryColumn("REGION", "flight.campaign.region.code"); + builder.newMandatoryColumn("AIRCRAFT", "flight.immatriculation"); builder.newMandatoryColumn("CAMPAIGN", "flight.campaign.code"); builder.newMandatoryColumn("FLIGHT", "flight.flightNumber", new DoubleToIntegerValueParser()); builder.newMandatoryColumn("COMPUTER", "flight.systemId"); Modified: trunk/sammoa-persistence/src/main/java/fr/ulr/sammoa/persistence/Observations.java =================================================================== --- trunk/sammoa-persistence/src/main/java/fr/ulr/sammoa/persistence/Observations.java 2012-08-09 17:26:32 UTC (rev 380) +++ trunk/sammoa-persistence/src/main/java/fr/ulr/sammoa/persistence/Observations.java 2012-08-09 17:53:27 UTC (rev 381) @@ -2,8 +2,8 @@ /* * #%L * SAMMOA :: Persistence - * $Id:$ - * $HeadURL:$ + * $Id$ + * $HeadURL$ * %% * Copyright (C) 2012 UMS 3462, Code Lutin * %% @@ -26,9 +26,15 @@ import com.google.common.base.Function; import com.google.common.base.Preconditions; import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import org.apache.commons.collections.CollectionUtils; import org.nuiton.util.DateUtil; +import org.nuiton.util.PeriodDates; import java.util.Date; +import java.util.Iterator; +import java.util.List; /** * Created: 16/07/12 @@ -36,15 +42,19 @@ * @author fdesbois <desbois@codelutin.com> */ public final class Observations { - + private Observations() { // static class do not have instanciation } + public static Iterable<Date> toDates(Iterable<Observation> observations) { + return Iterables.transform(observations, toDate()); + } + public static Function<Observation, Date> toDate() { return TO_DATE_FUNCTION; } - + public static boolean inRoute(Observation observation, Route route, Route nextRoute) { Date begin = route.getBeginTime(); @@ -59,6 +69,21 @@ return new ObservationInRoutePredicate(route, nextRoute); } + public static void removeOtherSpecies(List<Observation> observations, + List<Species> species) { + if (CollectionUtils.isNotEmpty(species)) { + + // filter by species + Iterator<Observation> itr = observations.iterator(); + while (itr.hasNext()) { + Observation observation = itr.next(); + if (!species.contains(observation.getSpecies())) { + itr.remove(); + } + } + } + } + protected static Function<Observation, Date> TO_DATE_FUNCTION = new Function<Observation, Date>() { @Override @@ -66,11 +91,27 @@ return input.getObservationTime(); } }; - + + public static List<Observation> getObservations(List<Observation> observations, + Date beginTime, + Date endTime) { + + PeriodDates periodDate = new PeriodDates(beginTime, endTime); + + List<Observation> result = Lists.newArrayList(); + for (Observation observation : observations) { + Date observationTime = observation.getObservationTime(); + if (periodDate.between(observationTime)) { + result.add(observation); + } + } + return result; + } + protected static class ObservationInRoutePredicate implements Predicate<Observation> { - + protected Route route; - + protected Route nextRoute; public ObservationInRoutePredicate(Route route, Route nextRoute) { @@ -84,5 +125,5 @@ return Observations.inRoute(input, route, nextRoute); } } - + } Modified: trunk/sammoa-persistence/src/main/java/fr/ulr/sammoa/persistence/Routes.java =================================================================== --- trunk/sammoa-persistence/src/main/java/fr/ulr/sammoa/persistence/Routes.java 2012-08-09 17:26:32 UTC (rev 380) +++ trunk/sammoa-persistence/src/main/java/fr/ulr/sammoa/persistence/Routes.java 2012-08-09 17:53:27 UTC (rev 381) @@ -2,8 +2,8 @@ /* * #%L * SAMMOA :: Persistence - * $Id:$ - * $HeadURL:$ + * $Id$ + * $HeadURL$ * %% * Copyright (C) 2012 UMS 3462, Code Lutin * %% @@ -23,8 +23,14 @@ * #L% */ +import com.google.common.base.Function; import com.google.common.base.Objects; +import com.google.common.collect.Iterables; +import org.apache.commons.collections.CollectionUtils; +import java.util.Date; +import java.util.List; + /** * Created: 16/07/12 * @@ -36,6 +42,50 @@ // static class do not have instanciation } + public static boolean isRouteLeg(Route route) { + return route != null && RouteType.LEG == route.getRouteType(); + } + + public static boolean isRouteCircleBack(Route route) { + return route != null && RouteType.CIRCLE_BACK == route.getRouteType(); + } + + public static Iterable<Date> toDates(Iterable<Route> routes) { + return Iterables.transform(routes, toDate()); + } + + public static boolean isRouteAccepted(Route route, + List<RouteType> routeTypes, + List<Strate> strates) { + boolean result = false; + + if (CollectionUtils.isEmpty(routeTypes) || + routeTypes.contains(route.getRouteType())) { + + TransectFlight transectFlight = route.getTransectFlight(); + + if (CollectionUtils.isEmpty(strates) || + transectFlight == null || + strates.contains(transectFlight.getTransect().getStrate())) { + result = true; + } + } + + return result; + } + + public static Function<Route, Date> toDate() { + return TO_DATE_FUNCTION; + } + + protected static Function<Route, Date> TO_DATE_FUNCTION = new Function<Route, Date>() { + + @Override + public Date apply(Route input) { + return input.getBeginTime(); + } + }; + public static boolean equal(Route o1, Route o2) { boolean result = Objects.equal(o1.getRouteType(), o2.getRouteType()); Modified: trunk/src/site/rst/import-export.rst =================================================================== --- trunk/src/site/rst/import-export.rst 2012-08-09 17:26:32 UTC (rev 380) +++ trunk/src/site/rst/import-export.rst 2012-08-09 17:53:27 UTC (rev 381) @@ -172,6 +172,8 @@ geoPoint.flight.flightNumber - COMPUTER : Identifiant du système geoPoint.flight.systemId +- AIRCRAFT : Immatriculation de l'avion + geoPoint.flight.planeImmatriculation - DATE : Date d'enregistrement du poin geoPoint.recordTime - HHMMSS : Heure d'enregistrement du point @@ -487,7 +489,7 @@ * observation.calves -- PHOTO : Des photos ont été prises +- PHOTO : Des photos ont été prises (L) * observation.photo
participants (1)
-
tchemit@users.forge.codelutin.com