/*******************************************************************************
Copyright 2013 Johannes Mitlmeier
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 de.fub.agg2graph.agg;
import de.fub.agg2graph.input.CleaningOptions;
import de.fub.agg2graph.structs.CartesianCalc;
import de.fub.agg2graph.structs.GPSCalc;
import de.fub.agg2graph.structs.ILocation;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
/**
* Class for cleaning a path in the {@link AggContainer} using give
* {@link CleaningOptions}.
*
* @author Johannes Mitlmeier
*
*/
public class AggCleaner {
private static Logger logger = Logger.getLogger("agg2graph.clean");
private CleaningOptions co = new CleaningOptions();
public AggCleaner enableDefault() {
co.filterBySegmentLength = false;
co.filterByEdgeLength = true;
co.filterZigzag = true;
co.filterFakeCircle = true;
co.filterOutliers = true;
return this;
}
public void clean(List<? extends ILocation> pointList) {
List<ArrayList<ILocation>> result = new ArrayList<ArrayList<ILocation>>();
ArrayList<ILocation> currentSegment = new ArrayList<ILocation>();
for (int i = 0; i < pointList.size(); i++) {
ILocation point = pointList.get(i);
logger.fine("Examining point " + point);
// check edge length
if (co.filterByEdgeLength && currentSegment.size() > 0) {
ILocation lastPoint = currentSegment
.get(currentSegment.size() - 1);
double distance = GPSCalc.getDistance(lastPoint, point);
if (distance < co.minEdgeLength) {
logger.fine(String.format(
"edge length %s to %s: %.2f < %.2f", lastPoint,
point, distance, co.minEdgeLength));
logger.fine("short edge, dropping point " + point);
continue;
}
if (distance > co.maxEdgeLength) {
logger.fine(String.format(
"edge length %s to %s: %.2f > %.2f", lastPoint,
point, distance, co.maxEdgeLength));
logger.fine("long edge, still NOT dropping point " + point);
// make new segment
if (currentSegment.size() > co.minSegmentLength) {
result.add(currentSegment);
}
currentSegment = new ArrayList<ILocation>();
}
}
double angleHere = Double.MAX_VALUE;
double angleBefore = Double.MAX_VALUE;
// check zigzag
if (co.filterZigzag) {
if (currentSegment.size() > 1 && i < pointList.size() - 1) {
ILocation nextToLastPoint = currentSegment
.get(currentSegment.size() - 2);
ILocation lastPoint = currentSegment.get(currentSegment
.size() - 1);
ILocation nextPoint = pointList.get(i + 1);
angleHere = CartesianCalc.getAngleBetweenLines(lastPoint,
point, point, nextPoint);
angleBefore = CartesianCalc.getAngleBetweenLines(
nextToLastPoint, lastPoint, lastPoint, point);
if (!Double.isNaN(angleHere) && !Double.isNaN(angleBefore)) {
// is it zigzagged?
if (((angleHere > 180 - co.maxZigzagAngle) && (angleBefore < co.maxZigzagAngle))
|| ((angleHere < co.maxZigzagAngle) && (angleBefore > 180 - co.maxZigzagAngle))) {
logger.fine("found zigzag");
logger.fine(String.format("%.3f <- -> %.3f",
angleBefore, angleHere));
i++;
continue;
}
} else {
logger.fine("something bad");
}
}
}
// check fake circles
if (co.filterFakeCircle) {
if (currentSegment.size() > 1 && i < pointList.size() - 1) {
if (!co.filterZigzag) {
ILocation nextToLastPoint = currentSegment
.get(currentSegment.size() - 2);
ILocation lastPoint = currentSegment.get(currentSegment
.size() - 1);
ILocation nextPoint = pointList.get(i + 1);
angleHere = CartesianCalc.getAngleBetweenLines(
lastPoint, point, point, nextPoint);
angleBefore = CartesianCalc.getAngleBetweenLines(
nextToLastPoint, lastPoint, lastPoint, point);
}
if (!Double.isNaN(angleHere) && !Double.isNaN(angleBefore)) {
// is it a fake circle?
if ((angleHere > 180 - co.maxFakeCircleAngle)
&& (angleBefore > 180 - co.maxFakeCircleAngle)) {
logger.fine("found fake circle");
logger.fine(String.format("%.3f <- -> %.3f",
angleBefore, angleHere));
// insert as second but last element
ILocation oldLastPoint = currentSegment
.remove(currentSegment.size() - 1);
currentSegment.add(point);
currentSegment.add(oldLastPoint);
i++;
continue;
}
}
}
}
// segment length (split if necessary)
if (co.filterBySegmentLength
&& currentSegment.size() >= co.maxSegmentLength) {
// make new segment
if (currentSegment.size() > co.minSegmentLength) {
result.add(currentSegment);
}
currentSegment = new ArrayList<ILocation>();
}
logger.fine("adding point " + point);
currentSegment.add(point);
}
// save last segment
if (currentSegment.size() > co.minSegmentLength) {
result.add(currentSegment);
}
}
}