From 1c7437d6de01fffbe3f69853717808b1790413fd Mon Sep 17 00:00:00 2001 From: Abyss777 Date: Fri, 19 Aug 2016 10:45:33 +0500 Subject: - Added trips report - Refactored reports models - Added tests for ReportUtils - Added speed to test-generator.py - Other changes --- src/org/traccar/reports/Trips.java | 160 +++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 src/org/traccar/reports/Trips.java (limited to 'src/org/traccar/reports/Trips.java') diff --git a/src/org/traccar/reports/Trips.java b/src/org/traccar/reports/Trips.java new file mode 100644 index 000000000..068c47b8f --- /dev/null +++ b/src/org/traccar/reports/Trips.java @@ -0,0 +1,160 @@ +/* + * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com) + * Copyright 2016 Andrey Kunitsyn (abyss@fox5.ru) + * + * 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. + */ +package org.traccar.reports; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; + +import javax.json.Json; +import javax.json.JsonArrayBuilder; + +import org.traccar.Context; +import org.traccar.model.Position; +import org.traccar.reports.model.TripReport; +import org.traccar.web.CsvBuilder; +import org.traccar.web.JsonConverter; + +public final class Trips { + + private Trips() { + } + + private static TripReport calculateTrip(ArrayList positions, int startIndex, int endIndex) { + Position startTrip = positions.get(startIndex); + Position endTrip = positions.get(endIndex); + + double speedMax = 0.0; + double speedSum = 0.0; + for (int i = startIndex; i <= endIndex; i++) { + double speed = positions.get(i).getSpeed(); + speedSum += speed; + if (speed > speedMax) { + speedMax = speed; + } + } + + TripReport trip = new TripReport(); + long tripDuration = endTrip.getFixTime().getTime() - positions.get(startIndex).getFixTime().getTime(); + long deviceId = startTrip.getDeviceId(); + trip.setDeviceId(deviceId); + String deviceName = Context.getDeviceManager().getDeviceById(deviceId).getName(); + trip.setDeviceName(deviceName); + trip.setStartPositionId(startTrip.getId()); + trip.setStartTime(startTrip.getFixTime()); + trip.setStartAddress(startTrip.getAddress()); + trip.setEndPositionId(endTrip.getId()); + trip.setEndTime(endTrip.getFixTime()); + trip.setEndAddress(endTrip.getAddress()); + trip.setDistance(ReportUtils.calculateDistance(startTrip, endTrip)); + trip.setDuration(tripDuration); + trip.setAverageSpeed(speedSum / (endIndex - startIndex)); + trip.setMaxSpeed(speedMax); + trip.setSpentFuel(ReportUtils.calculateSpentFuel(startTrip, endTrip)); + + return trip; + } + + private static Collection detectTrips(long deviceId, Date from, Date to) throws SQLException { + double speedThreshold = Context.getConfig().getDouble("event.motion.speedThreshold", 0.01); + long minimalTripDuration = Context.getConfig().getLong("report.trip.minimalTripDuration", 300) * 1000; + double minimalTripDistance = Context.getConfig().getLong("report.trip.minimalTripDistance", 500); + long minimalParkingDuration = Context.getConfig().getLong("report.trip.minimalParkingDuration", 300) * 1000; + Collection result = new ArrayList<>(); + + ArrayList positions = new ArrayList<>(Context.getDataManager().getPositions(deviceId, from, to)); + if (positions != null && !positions.isEmpty()) { + int previousStartParkingIndex = 0; + int startParkingIndex = -1; + int previousEndParkingIndex = 0; + int endParkingIndex = 0; + + boolean isMoving = false; + boolean isLast = false; + boolean skipped = false; + boolean tripFiltered = false; + + for (int i = 0; i < positions.size(); i++) { + isMoving = positions.get(i).getSpeed() > speedThreshold; + isLast = i == positions.size() - 1; + + if ((isMoving || isLast) && startParkingIndex != -1) { + if (!skipped || previousEndParkingIndex == 0) { + previousEndParkingIndex = endParkingIndex; + } + endParkingIndex = i; + } + if (!isMoving && startParkingIndex == -1) { + long tripDuration = positions.get(i).getFixTime().getTime() + - positions.get(endParkingIndex).getFixTime().getTime(); + double tripDistance = ReportUtils.calculateDistance(positions.get(endParkingIndex), + positions.get(i), false); + tripFiltered = tripDuration < minimalTripDuration && tripDistance < minimalTripDistance; + if (tripFiltered) { + startParkingIndex = previousStartParkingIndex; + endParkingIndex = previousEndParkingIndex; + tripFiltered = false; + } else { + previousStartParkingIndex = i; + startParkingIndex = i; + } + + } + if (startParkingIndex != -1 && (endParkingIndex > startParkingIndex || isLast)) { + long parkingDuration = positions.get(endParkingIndex).getFixTime().getTime() + - positions.get(startParkingIndex).getFixTime().getTime(); + if ((parkingDuration >= minimalParkingDuration || isLast) + && previousEndParkingIndex < startParkingIndex) { + if (!tripFiltered) { + result.add(calculateTrip(positions, previousEndParkingIndex, startParkingIndex)); + } + previousEndParkingIndex = endParkingIndex; + skipped = false; + } else { + skipped = true; + } + startParkingIndex = -1; + } + } + } + return result; + } + + public static String getJson(long userId, Collection deviceIds, Collection groupIds, + Date from, Date to) throws SQLException { + JsonArrayBuilder json = Json.createArrayBuilder(); + for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { + Context.getPermissionsManager().checkDevice(userId, deviceId); + for (TripReport tripReport : detectTrips(deviceId, from, to)) { + json.add(JsonConverter.objectToJson(tripReport)); + } + } + return json.build().toString(); + } + + public static String getCsv(long userId, Collection deviceIds, Collection groupIds, + Date from, Date to) throws SQLException { + CsvBuilder csv = new CsvBuilder(); + csv.addHeaderLine(new TripReport()); + for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { + Context.getPermissionsManager().checkDevice(userId, deviceId); + csv.addArray(detectTrips(deviceId, from, to)); + } + return csv.build(); + } +} -- cgit v1.2.3