964 | | private int matchPoints(ArrayList<ImageEntry> dateImgLst, WayPoint prevWp, long prevDateWp, WayPoint curWp, long curDateWp) { |
965 | | double interval = prevDateWp > 0 ? ((int)Math.abs(curDateWp - prevDateWp)) : 1; |
| 964 | private int matchPoints(ArrayList<ImageEntry> dateImgLst, WayPoint prevWp, long prevDateWp, |
| 965 | WayPoint curWp, long curDateWp) { |
| 966 | // Time between the track point and the previous one, 5 sec if first point, i.e. photos take |
| 967 | // 5 sec before the first track point can be assumed to be take at the starting position |
| 968 | long interval = prevDateWp > 0 ? ((int)Math.abs(curDateWp - prevDateWp)) : 5; |
967 | | int i = getLastIndexOfListBefore(dateImgLst, curDateWp, interval); |
968 | | if (i >= 0 && i < dateImgLst.size() && dateImgLst.get(i).time.getTime()/1000+interval > prevDateWp) { |
969 | | Double speed = null; |
970 | | Double prevElevation = null; |
971 | | Double curElevation = null; |
972 | | if (prevWp != null) { |
973 | | double distance = getDistance(prevWp, curWp); |
974 | | speed = new Double((1000 * distance) / (curDateWp - prevDateWp)); |
975 | | try { |
976 | | prevElevation = new Double((String) prevWp.attr.get("ele")); |
977 | | } catch(Exception e) {} |
978 | | } |
| 970 | |
| 971 | // i is the index of the timewise last photo that has the same or earlier EXIF time |
| 972 | int i = getLastIndexOfListBefore(dateImgLst, curDateWp); |
| 973 | |
| 974 | // no photos match |
| 975 | if (i < 0) |
| 976 | return 0; |
| 977 | |
| 978 | Double speed = null; |
| 979 | Double prevElevation = null; |
| 980 | Double curElevation = null; |
| 981 | |
| 982 | if (prevWp != null) { |
| 983 | double distance = getDistance(prevWp, curWp); |
| 984 | // This is in km/h, 3.6 * m/s |
| 985 | if (curDateWp > prevDateWp) |
| 986 | speed = 3.6 * distance / (curDateWp - prevDateWp); |
980 | | curElevation = new Double((String) curWp.attr.get("ele")); |
981 | | } catch (Exception e) {} |
982 | | |
983 | | while(i >= 0 && inRadius(dateImgLst.get(i).time.getTime()/1000, curDateWp, interval)) { |
984 | | if(dateImgLst.get(i).coor == null) { |
| 988 | prevElevation = new Double((String) prevWp.attr.get("ele")); |
| 989 | } catch(Exception e) {} |
| 990 | } |
| 991 | |
| 992 | try { |
| 993 | curElevation = new Double((String) curWp.attr.get("ele")); |
| 994 | } catch (Exception e) {} |
| 995 | |
| 996 | // First trackpoint, then interval is set to five seconds, i.e. photos up to five seconds |
| 997 | // before the first point will be geotagged with the starting point |
| 998 | if(prevDateWp == 0 || curDateWp <= prevDateWp) { |
| 999 | while(i >= 0 && (dateImgLst.get(i).time.getTime()/1000) <= curDateWp |
| 1000 | && (dateImgLst.get(i).time.getTime()/1000) >= (curDateWp - interval)) { |
| 1001 | if(dateImgLst.get(i).coor == null) { |
994 | | if (prevDateWp != 0) { |
995 | | long imgDate; |
996 | | while(i >= 0 |
997 | | && (imgDate = dateImgLst.get(i).time.getTime()/1000) > prevDateWp) { |
998 | | if(dateImgLst.get(i).coor == null) { |
999 | | dateImgLst.get(i).pos = new EastNorth( |
1000 | | prevWp.eastNorth.east() + ((curWp.eastNorth.east() - prevWp.eastNorth.east()) * (imgDate - prevDateWp)) / (curDateWp - prevDateWp), |
1001 | | prevWp.eastNorth.north() + ((curWp.eastNorth.north() - prevWp.eastNorth.north()) * (imgDate - prevDateWp)) / (curDateWp - prevDateWp)); |
1002 | | dateImgLst.get(i).coor = Main.proj.eastNorth2latlon(dateImgLst.get(i).pos); |
1003 | | dateImgLst.get(i).speed = speed; |
1004 | | if (curElevation != null && prevElevation != null) { |
1005 | | dateImgLst.get(i).elevation = prevElevation + ((curElevation - prevElevation) * (imgDate - prevDateWp)) / (curDateWp - prevDateWp); |
1006 | | } |
1007 | | ret++; |
1008 | | } |
1009 | | i--; |
1010 | | } |
| 1013 | // This code gives a simple linear interpolation of the coordinates between current and |
| 1014 | // previous track point assuming a constant speed in between |
| 1015 | long imgDate; |
| 1016 | while(i >= 0 && (imgDate = dateImgLst.get(i).time.getTime()/1000) >= prevDateWp) { |
| 1017 | |
| 1018 | if(dateImgLst.get(i).coor == null) { |
| 1019 | // The values of timeDiff are between 0 and 1, it is not seconds but a dimensionless |
| 1020 | // variable |
| 1021 | double timeDiff = (double)(imgDate - prevDateWp) / interval; |
| 1022 | dateImgLst.get(i).pos = new EastNorth( |
| 1023 | interpolate(prevWp.eastNorth.east(), curWp.eastNorth.east(), timeDiff), |
| 1024 | interpolate(prevWp.eastNorth.north(), curWp.eastNorth.north(), timeDiff)); |
| 1025 | dateImgLst.get(i).coor = Main.proj.eastNorth2latlon(dateImgLst.get(i).pos); |
| 1026 | dateImgLst.get(i).speed = speed; |
| 1027 | |
| 1028 | if (curElevation != null && prevElevation != null) |
| 1029 | dateImgLst.get(i).elevation = interpolate(prevElevation, curElevation, timeDiff); |
| 1030 | |
| 1031 | ret++; |
1016 | | private int getLastIndexOfListBefore(ArrayList<ImageEntry> dateImgLst, long searchedDate, double interval) { |
1017 | | int lstSize = dateImgLst.size(); |
1018 | | if (lstSize == 0 || searchedDate < dateImgLst.get(0).time.getTime()/1000) { |
| 1038 | private double interpolate(double val1, double val2, double time) { |
| 1039 | return val1 + (val2 - val1) * time; |
| 1040 | } |
| 1041 | |
| 1042 | private int getLastIndexOfListBefore(ArrayList<ImageEntry> dateImgLst, long searchedDate) { |
| 1043 | int lstSize= dateImgLst.size(); |
| 1044 | |
| 1045 | // No photos or the first photo taken is later than the search period |
| 1046 | if(lstSize == 0 || searchedDate < dateImgLst.get(0).time.getTime()/1000) |
1020 | | } else if (searchedDate-interval > dateImgLst.get(lstSize - 1).time.getTime()/1000) { |
1021 | | return lstSize; |
1022 | | } else if (inRadius(searchedDate, dateImgLst.get(lstSize - 1).time.getTime()/1000, interval)) { |
1023 | | return lstSize - 1; |
1024 | | } else if (inRadius(searchedDate , dateImgLst.get(0).time.getTime()/1000, interval)) { |
1025 | | int curIndex = 0; |
1026 | | while (curIndex + 1 < lstSize |
1027 | | && inRadius(dateImgLst.get(curIndex + 1).time.getTime()/1000, searchedDate, interval)) { |
1028 | | curIndex++; |
1029 | | } |
1030 | | return curIndex; |
1031 | | } |
| 1048 | |
| 1049 | // The search period is later than the last photo |
| 1050 | if (searchedDate > dateImgLst.get(lstSize - 1).time.getTime() / 1000) |
| 1051 | return lstSize-1; |
1033 | | int curIndex = 0; |
1034 | | int startIndex=0; |
1035 | | int endIndex = lstSize - 1; |
1036 | | while (endIndex - startIndex > 1) { |
1037 | | curIndex = (endIndex + startIndex) / 2; |
1038 | | long curDate = dateImgLst.get(curIndex).time.getTime()/1000; |
1039 | | if (curDate-interval < searchedDate) { |
1040 | | startIndex = curIndex; |
1041 | | } else if (curDate+interval > searchedDate) { |
1042 | | endIndex = curIndex; |
1043 | | } else { |
1044 | | // Check that there is no image _after_ that one that have exactly the same date. |
1045 | | while (curIndex + 1 < lstSize |
1046 | | && inRadius(dateImgLst.get(curIndex + 1).time.getTime()/1000, searchedDate, interval)) { |
1047 | | curIndex++; |
1048 | | } |
1049 | | return curIndex; |
1050 | | } |
| 1053 | // The searched index is somewhere in the middle, do a binary search from the beginning |
| 1054 | int curIndex= 0; |
| 1055 | int startIndex= 0; |
| 1056 | int endIndex= lstSize-1; |
| 1057 | while (endIndex - startIndex > 1) { |
| 1058 | curIndex= (int) Math.round((double)(endIndex + startIndex)/2); |
| 1059 | if (searchedDate > dateImgLst.get(curIndex).time.getTime()/1000) |
| 1060 | startIndex= curIndex; |
| 1061 | else |
| 1062 | endIndex= curIndex; |