OSDN Git Service

直近のtrkpt からmagver(進行方向) を算出。ただし、exifへは未反映
[importpicture/importpicture.git] / importPicture / src / osm / jp / gpx / ImportPicture.java
1 package osm.jp.gpx;\r
2 import java.io.*;\r
3 import java.text.DecimalFormat;\r
4 import java.text.ParseException;\r
5 import java.text.SimpleDateFormat;\r
6 import java.util.ArrayList;\r
7 import java.util.Arrays;\r
8 import java.util.Calendar;\r
9 import java.util.Comparator;\r
10 import java.util.Date;\r
11 import java.util.GregorianCalendar;\r
12 import java.util.HashMap;\r
13 import java.util.Iterator;\r
14 import java.util.Set;\r
15 import java.util.TimeZone;\r
16 import java.util.logging.LogManager;\r
17 import java.util.logging.Logger;\r
18 \r
19 import javax.xml.parsers.*;\r
20 import javax.xml.transform.OutputKeys;\r
21 import javax.xml.transform.Transformer;\r
22 import javax.xml.transform.TransformerFactory;\r
23 import javax.xml.transform.dom.DOMSource;\r
24 import javax.xml.transform.stream.StreamResult;\r
25 \r
26 import org.apache.commons.imaging.ImageReadException;\r
27 import org.apache.commons.imaging.ImageWriteException;\r
28 import org.apache.commons.imaging.Imaging;\r
29 import org.apache.commons.imaging.common.ImageMetadata;\r
30 import org.apache.commons.imaging.common.RationalNumber;\r
31 import org.apache.commons.imaging.formats.jpeg.JpegImageMetadata;\r
32 import org.apache.commons.imaging.formats.jpeg.exif.ExifRewriter;\r
33 import org.apache.commons.imaging.formats.tiff.TiffImageMetadata;\r
34 import org.apache.commons.imaging.formats.tiff.constants.ExifTagConstants;\r
35 import org.apache.commons.imaging.formats.tiff.constants.GpsTagConstants;\r
36 import org.apache.commons.imaging.formats.tiff.write.TiffOutputDirectory;\r
37 import org.apache.commons.imaging.formats.tiff.write.TiffOutputSet;\r
38 import org.w3c.dom.*;\r
39 \r
40 public class ImportPicture {\r
41         public static File gpxDir = new File(".");\r
42         public static File outDir = null;\r
43         \r
44     /**\r
45          * ログ設定プロパティファイルのファイル内容\r
46          */\r
47         protected static final String LOGGING_PROPERTIES_DATA\r
48             = "handlers=java.util.logging.ConsoleHandler\n"\r
49             + ".level=FINEST\n"\r
50             + "java.util.logging.ConsoleHandler.level=INFO\n"\r
51             + "java.util.logging.ConsoleHandler.formatter=osm.jp.gpx.YuuLogFormatter";\r
52 \r
53         /**\r
54          * static initializer によるログ設定の初期化\r
55          */\r
56     public static final Logger logger = Logger.getLogger("CommandLogging");\r
57     static {\r
58         InputStream inStream = null;\r
59         try {\r
60             inStream = new ByteArrayInputStream(LOGGING_PROPERTIES_DATA.getBytes("UTF-8"));\r
61             try {\r
62                 LogManager.getLogManager().readConfiguration(inStream);\r
63                 logger.config("ログ設定: LogManagerを設定しました。");\r
64             }\r
65             catch (IOException e) {\r
66                 logger.warning("ログ設定: LogManager設定の際に例外が発生しました。:" + e.toString());\r
67             }\r
68         }\r
69         catch (UnsupportedEncodingException e) {\r
70             logger.severe("ログ設定: UTF-8エンコーディングがサポートされていません。:" + e.toString());\r
71         }\r
72         finally {\r
73             try {\r
74                 if (inStream != null) {\r
75                         inStream.close();\r
76                 }\r
77             } catch (IOException e) {\r
78                 logger.warning("ログ設定: ログ設定プロパティファイルのストリームクローズ時に例外が発生しました。:"+ e.toString());\r
79             }\r
80         }\r
81     }\r
82 \r
83     /** メイン\r
84      * 画像ファイルをGPXファイルに取り込みます。\r
85      * \r
86      * ・画像ファイルの更新日付をその画像の撮影日時とします。(Exi情報は無視します)\r
87      *    ※ 対象とするファイルは'*.jpg'のみ\r
88      * ・精確な時刻との時差を入力することで、撮影日時を補正します。\r
89      * ・画像ファイルの更新日付リストをCSV形式のファイルとして出力する。\r
90      * ・・結果は、取り込み元のGPXファイルとは別に、元ファイル名にアンダーバー「_」を付加した.ファイルに出力します。\r
91      *\r
92      * @param argv\r
93      * argv[-] = dummy\r
94      * argv[0] = 画像ファイルが格納されているディレクトリ\r
95      * argv[1] = 時刻補正の基準とする画像ファイル\r
96      * argv[2] = 基準画像ファイルの精確な撮影日時 "yyyy-MM-dd'T'HH:mm:ss"\r
97      * argv[3] = [EXIF] EXIF情報の書き換えを行う / [not] EXIF情報の書き換えを行わない\r
98      * argv[4] = 撮影位置をロギングしたGPXファイル\r
99      * \r
100      * @throws IOException\r
101      * @throws ImageReadException \r
102      */\r
103     public static void main(String[] argv) throws Exception\r
104     {\r
105         Date jptime;\r
106 \r
107         if (argv.length > 0) {\r
108             gpxDir = new File(argv[0]);\r
109         }\r
110 \r
111         if (argv.length < 4) {\r
112             System.out.println("!!! Illigal command call. !!!");\r
113             System.out.println("> java -cp .:AdjustTime.jar:commons-imaging-1.0-SNAPSHOT.jar <targetDir> <time base image> <time> {EXIF/not} (gpx)");\r
114             System.out.println("> java -cp .:AdjustTime.jar:commons-imaging-1.0-SNAPSHOT.jar. IMG_01234.JPG 2012-06-15T12:52:22 EXIF");\r
115             System.out.println("> java -cp .:AdjustTime.jar . IMG_01234.JPG 2012-06-15T12:52:22 not");\r
116             System.out.println();\r
117             return;\r
118         }\r
119 \r
120         // 基準時刻ファイルの「更新日時」を使って時刻合わせを行う。\r
121         File baseFile = new File(gpxDir, argv[1]);\r
122         jptime = new Date(baseFile.lastModified());\r
123 \r
124         // \r
125         boolean exif = false;\r
126         if (argv[3].toUpperCase().equals("EXIF")) {\r
127             exif = true;\r
128         }\r
129 \r
130         // 第6引数が指定されなければ、指定されたディレクトリ内のGPXファイルすべてを対象とする\r
131         ArrayList<File> gpxFiles = new ArrayList<>();\r
132         if (argv.length > 4) {\r
133             gpxFiles.add(new File(gpxDir, argv[4]));\r
134         }\r
135         else {\r
136             File[] files = gpxDir.listFiles();\r
137             for (File file : files) {\r
138                 if (file.isFile()) {\r
139                     String filename = file.getName().toUpperCase();\r
140                     if (filename.endsWith(".GPX")) {\r
141                         if (!filename.endsWith("_.GPX")) {\r
142                             gpxFiles.add(file);\r
143                         }\r
144                     }\r
145                 }\r
146             }\r
147         }\r
148 \r
149 \r
150         /**\r
151          *\r
152                 <wpt lat="35.25714922" lon="139.15490497">\r
153                         <ele>62.099998474121094</ele>\r
154                         <time>2012-06-11T00:44:38Z</time>\r
155                         <hdop>0.75</hdop>\r
156                         <name><![CDATA[写真]]></name>\r
157                         <cmt><![CDATA[精度: 3.0m]]></cmt>\r
158                         <link href="2012-06-11_09-44-38.jpg">\r
159                                 <text>2012-06-11_09-44-38.jpg</text>\r
160                         </link>\r
161                         <sat>9</sat>\r
162                 </wpt>\r
163          */\r
164         DocumentBuilderFactory factory;\r
165         DocumentBuilder        builder;\r
166         Node gpx;\r
167 \r
168         for (File gpxFile : gpxFiles) {\r
169             String fileName = gpxFile.getName();\r
170             String iStr = fileName.substring(0, fileName.length() - 4);\r
171 \r
172             File outputFile = new File(gpxFile.getParent(), iStr +"_.gpx");\r
173             System.out.println(iStr + " => "+ outputFile.getName());\r
174 \r
175             factory = DocumentBuilderFactory.newInstance();\r
176             builder = factory.newDocumentBuilder();\r
177             factory.setIgnoringElementContentWhitespace(true);\r
178             factory.setIgnoringComments(true);\r
179             factory.setValidating(true);\r
180 \r
181             // GPX file --> Node root\r
182             DOMImplementation domImpl = builder.getDOMImplementation();\r
183             document = domImpl.createDocument("", "gpx", null);\r
184 \r
185             /*\r
186             <gpx>\r
187             <trk>\r
188             <name><![CDATA[Tracked with OSMTracker for Android?]]></name>\r
189             <cmt><![CDATA[警告: HDOP values aren't the HDOP as returned by the GPS device. They're approximated from the location accuracy in meters.]]></cmt>\r
190             <trkseg>\r
191             <trkpt lat="35.32123832" lon="139.56965631">\r
192             <ele>47.20000076293945</ele>\r
193             <time>2012-06-15T03:00:29Z</time>\r
194             <hdop>0.5</hdop>\r
195             </trkpt>\r
196             </trkseg>\r
197             </trk>\r
198             <wpt lat="35.2564461" lon="139.15437809">\r
199             </wpt>\r
200             </gpx>\r
201             */\r
202             HashMap<Long,Element> map = new HashMap<>();\r
203             Element trk = null;\r
204             gpx    = builder.parse(gpxFile).getFirstChild();\r
205             NodeList nodes = gpx.getChildNodes();\r
206             for (int i=0; i < nodes.getLength(); i++) {\r
207                 Node node2 = nodes.item(i);\r
208                 if (node2.getNodeName().equals("trk")) {\r
209                     trk = (Element) node2;\r
210                     trkptMap(trk, map);\r
211                 }\r
212             }\r
213 \r
214             if (trk != null) {\r
215                 dfjp.setTimeZone(TimeZone.getTimeZone("JST"));\r
216                 String timeStr = argv[2];\r
217                 try {\r
218                     Date t = dfjp.parse(timeStr);\r
219                     long delta = t.getTime() - jptime.getTime();\r
220 \r
221                     /*\r
222                     * GPXへ割りつける開始時刻と終了時刻を求める\r
223                     */\r
224                     long gpxStartTime = (new Date()).getTime();         // 対象とする開始時刻(現在時刻)\r
225                     long gpxEndTime = 0L;                                                       // 対象とする終了時刻\r
226                     Set<Long> keySet = map.keySet();  //すべてのキー値を取得\r
227                     for (Long timeLong : keySet) {\r
228                         long gpxTime = timeLong;\r
229                         if (gpxStartTime > gpxTime) {\r
230                             gpxStartTime = gpxTime;\r
231                         }\r
232                         if (gpxEndTime < gpxTime) {\r
233                             gpxEndTime = gpxTime;\r
234                         }\r
235                     }\r
236 \r
237                     System.out.println("           時差: "+ (delta / 1000) +"(sec)");\r
238                     System.out.println("    Target GPX: ["+ gpxFile.getName() +"]");\r
239                     System.out.println("GPX start time: "+ dfjp.format(new Date(gpxStartTime)) + "\t[GMT " + dfuk.format(new Date(gpxStartTime))+"]");\r
240                     System.out.println("  GPX end time: "+ dfjp.format(new Date(gpxEndTime)) + "\t[GMT " + dfuk.format(new Date(gpxEndTime))+"]");\r
241                     System.out.println();\r
242                     System.out.println("------------|--------------------|--------------------|------------|------------|--------|------|");\r
243                     System.out.println(" name       | UpdateTime         | GPStime            | Latitude   | Longitude  | ele    |magvar|");\r
244                     System.out.println("------------|--------------------|--------------------|------------|------------|--------|------|");\r
245                     proc(gpxDir, delta, gpxStartTime, gpxEndTime, map, exif, gpx);\r
246                     System.out.println("------------|--------------------|--------------------|------------|------------|--------|------|");\r
247                 }\r
248                 catch (ParseException e) {\r
249                     System.out.println("'"+ timeStr +"' の書式が違います("+ TIME_FORMAT_STRING +")");\r
250                 }\r
251             }\r
252 \r
253             // 出力\r
254             DOMSource source = new DOMSource(gpx);\r
255             FileOutputStream os = new FileOutputStream(outputFile);\r
256             StreamResult result = new StreamResult(os);\r
257             TransformerFactory transFactory = TransformerFactory.newInstance();\r
258             Transformer transformer = transFactory.newTransformer();\r
259             transformer.setOutputProperty(OutputKeys.INDENT, "yes");\r
260             transformer.setOutputProperty(OutputKeys.METHOD, "xml");\r
261             transformer.transform(source, result);\r
262         }\r
263     }\r
264         \r
265     /**\r
266      * 再帰メソッド\r
267      * @throws ParseException \r
268      * @throws IOException \r
269      * @throws ImageReadException \r
270      * @throws ImageWriteException \r
271      */\r
272     static void proc(File dir, long delta, long gpxStartTime, long gpxEndTime, HashMap<Long,Element> map, boolean exifWrite, Node gpx) throws ParseException, ImageReadException, IOException, ImageWriteException {\r
273         DecimalFormat yearFormatter = new DecimalFormat("0000");\r
274         DecimalFormat monthFormatter = new DecimalFormat("00");\r
275         DecimalFormat dayFormatter = new DecimalFormat("00");\r
276 \r
277         File[] files = dir.listFiles();\r
278         Arrays.sort(files, new FileSort());\r
279         for (File image : files) {\r
280             if (image.isDirectory()) {\r
281                 proc(image, delta, gpxStartTime, gpxEndTime, map, exifWrite, gpx);\r
282             }\r
283             else {\r
284                 String imageName = image.getName();\r
285                 if (checkFile(imageName)) {\r
286                     Date itime = new Date(image.lastModified());\r
287                     Date uktime = new Date(itime.getTime() + delta);\r
288                     if ((uktime.getTime() >= gpxStartTime) && (uktime.getTime() <= gpxEndTime)) {\r
289                         Element trkpt = trkpt(map, uktime);\r
290                         if (trkpt != null) {\r
291                             System.out.print(String.format("%12s|", image.getName()));\r
292                             System.out.print(String.format("%20s ", dfjp.format(itime)));\r
293                             System.out.print(String.format("%20s|", dfjp.format(uktime)));\r
294 \r
295                             Element wpt = createWptTag(image, uktime.getTime(), trkpt);\r
296                             String latStr = wpt.getAttribute("lat");\r
297                             String lonStr = wpt.getAttribute("lon");\r
298                             System.out.print(String.format("%12s %12s|", latStr, lonStr));\r
299                             double latitude = Double.parseDouble(latStr);\r
300                             double longitude = Double.parseDouble(lonStr);\r
301 \r
302                             String eleStr = null;\r
303                             String magvarStr = null;\r
304                             NodeList nodes = wpt.getChildNodes();      // 子ノードを取得\r
305                             for (int i4=0; i4< nodes.getLength(); i4++) {\r
306                                 Node node = nodes.item(i4);\r
307                                 if (node != null) {\r
308                                     if (node.getNodeName().equals("ele")) {\r
309                                         eleStr = node.getFirstChild().getNodeValue();\r
310                                         System.out.println(String.format("%8s|", eleStr));\r
311                                         break;\r
312                                     }\r
313                                     if (node.getNodeName().equals("magvar")) {\r
314                                         magvarStr = node.getFirstChild().getNodeValue();\r
315                                         System.out.println(String.format("%6s|", magvarStr));\r
316                                         break;\r
317                                     }\r
318                                 }\r
319                                 else {\r
320                                     System.out.println("-");\r
321                                     break;\r
322                                 }\r
323                             }\r
324 \r
325                             if (exifWrite) {\r
326                                 TiffOutputSet outputSet = null;\r
327                                 FileOutputStream fos = null;\r
328 \r
329                                 ImageMetadata meta = Imaging.getMetadata(image);\r
330                                 JpegImageMetadata jpegMetadata = (JpegImageMetadata)meta;\r
331                                 if (jpegMetadata != null) {\r
332                                     TiffImageMetadata exif = jpegMetadata.getExif();\r
333                                     if (exif != null) {\r
334                                         outputSet = exif.getOutputSet();\r
335                                     }\r
336                                 }\r
337 \r
338                                 if (outputSet == null) {\r
339                                     System.out.println("added : new tiff output set");\r
340                                     outputSet = new TiffOutputSet();\r
341                                 }\r
342 \r
343                                 //---- EXIF_TAG_DATE_TIME_ORIGINAL / 「撮影日時/オリジナル画像の生成日時」----\r
344                                 TiffOutputDirectory exifDir = outputSet.getOrCreateExifDirectory();\r
345                                 {\r
346                                     Calendar cal = GregorianCalendar.getInstance();\r
347                                     cal.setTime(uktime);\r
348                                     exifDir.removeField(ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL);\r
349                                     exifDir.add(ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL, new SimpleDateFormat("yyyy:MM:dd HH:mm:ss").format(cal.getTime()));\r
350                                 }\r
351 \r
352                                 //---- EXIF GPS_TIME_STAMP ----\r
353                                 TiffOutputDirectory gpsDir = outputSet.getOrCreateGPSDirectory();\r
354                                 {\r
355                                     Calendar cal = GregorianCalendar.getInstance(TimeZone.getTimeZone("UTC"));\r
356                                     cal.setTime(uktime);\r
357                                     final String yearStr = yearFormatter.format(cal.get(Calendar.YEAR));\r
358                                     final String monthStr = monthFormatter.format(cal.get(Calendar.MONTH) + 1);\r
359                                     final String dayStr = dayFormatter.format(cal.get(Calendar.DAY_OF_MONTH));\r
360                                     final String dateStamp = yearStr +":"+ monthStr +":"+ dayStr;\r
361 \r
362                                     gpsDir.removeField(GpsTagConstants.GPS_TAG_GPS_TIME_STAMP);\r
363                                     gpsDir.add(GpsTagConstants.GPS_TAG_GPS_TIME_STAMP,\r
364                                             RationalNumber.valueOf(cal.get(Calendar.HOUR_OF_DAY)),\r
365                                             RationalNumber.valueOf(cal.get(Calendar.MINUTE)),\r
366                                             RationalNumber.valueOf(cal.get(Calendar.SECOND)));\r
367                                     gpsDir.removeField(GpsTagConstants.GPS_TAG_GPS_DATE_STAMP);\r
368                                     gpsDir.add(GpsTagConstants.GPS_TAG_GPS_DATE_STAMP, dateStamp);\r
369                                 }\r
370 \r
371                                 //---- EXIF GPS elevation/ALTITUDE ----\r
372                                 if (eleStr != null) {\r
373                                     final double altitude = Double.parseDouble(eleStr);\r
374                                     gpsDir.removeField(GpsTagConstants.GPS_TAG_GPS_ALTITUDE);\r
375                                     gpsDir.add(GpsTagConstants.GPS_TAG_GPS_ALTITUDE, RationalNumber.valueOf(altitude));\r
376                                 }\r
377 \r
378                                 //---- EXIF GPS_ ----\r
379                                 final String longitudeRef = (longitude < 0 ? "W" : "E");\r
380                                 longitude = Math.abs(longitude);\r
381                                 final String latitudeRef = (latitude < 0 ? "S" : "N");\r
382                                 latitude = Math.abs(latitude);\r
383 \r
384                                 gpsDir.removeField(GpsTagConstants.GPS_TAG_GPS_LONGITUDE_REF);\r
385                                 gpsDir.add(GpsTagConstants.GPS_TAG_GPS_LONGITUDE_REF, longitudeRef);\r
386                                 gpsDir.removeField(GpsTagConstants.GPS_TAG_GPS_LATITUDE_REF);\r
387                                 gpsDir.add(GpsTagConstants.GPS_TAG_GPS_LATITUDE_REF, latitudeRef);\r
388                                 {\r
389                                     double value = longitude;\r
390                                     final double longitudeDegrees = (long) value;\r
391                                     value %= 1;\r
392                                     value *= 60.0;\r
393                                     final double longitudeMinutes = (long) value;\r
394                                     value %= 1;\r
395                                     value *= 60.0;\r
396                                     final double longitudeSeconds = value;\r
397                                     gpsDir.removeField(GpsTagConstants.GPS_TAG_GPS_LONGITUDE);\r
398                                     gpsDir.add(GpsTagConstants.GPS_TAG_GPS_LONGITUDE,\r
399                                             RationalNumber.valueOf(longitudeDegrees),\r
400                                             RationalNumber.valueOf(longitudeMinutes),\r
401                                             RationalNumber.valueOf(longitudeSeconds));\r
402                                 }\r
403                                 {\r
404                                     double value = latitude;\r
405                                     final double latitudeDegrees = (long) value;\r
406                                     value %= 1;\r
407                                     value *= 60.0;\r
408                                     final double latitudeMinutes = (long) value;\r
409                                     value %= 1;\r
410                                     value *= 60.0;\r
411                                     final double latitudeSeconds = value;\r
412                                     gpsDir.removeField(GpsTagConstants.GPS_TAG_GPS_LATITUDE);\r
413                                     gpsDir.add(GpsTagConstants.GPS_TAG_GPS_LATITUDE,\r
414                                             RationalNumber.valueOf(latitudeDegrees),\r
415                                             RationalNumber.valueOf(latitudeMinutes),\r
416                                             RationalNumber.valueOf(latitudeSeconds));\r
417                                 }\r
418 \r
419                                 ExifRewriter rewriter = new ExifRewriter();\r
420                                 try {\r
421                                     if (outDir == null) {\r
422                                         outDir = new File(dir, "converted");\r
423                                         outDir.mkdir();\r
424                                     }\r
425                                     fos = new FileOutputStream(new File(outDir, imageName));\r
426                                     rewriter.updateExifMetadataLossy(image, fos, outputSet);\r
427                                 }\r
428                                 finally {\r
429                                     if (fos != null) {\r
430                                         fos.close();\r
431                                     }\r
432                                 }\r
433                             }\r
434 \r
435                             Element temp = getCopy(gpx.getOwnerDocument(), wpt);\r
436                             gpx.appendChild(temp);\r
437                         }\r
438                     }\r
439                 }\r
440             }\r
441         }\r
442     }\r
443         \r
444     static Document document;\r
445 \r
446     /**\r
447      * 2012-06-10T05:09:46Z  (日本時間の'2012-06-10T14:09:46')\r
448      */\r
449     public static final String TIME_FORMAT_STRING = "yyyy-MM-dd'T'HH:mm:ss";\r
450     public static SimpleDateFormat dfjp = new SimpleDateFormat(TIME_FORMAT_STRING);\r
451     public static SimpleDateFormat dfuk = new SimpleDateFormat(TIME_FORMAT_STRING +"'Z'");\r
452 \r
453     /**\r
454      * XMLエレメント<trkpt>をTIMEでキー付したHashMapを生成する<br>\r
455      * \r
456      *  <trk><trkseg><trkpt><time>2014-01-01T00:59:09Z</time></trkpt></trkseg></trk>\r
457      * \r
458      * @param trk\r
459      * @param map\r
460      * @throws ParseException\r
461      */\r
462     public static void trkptMap(Element trk, HashMap<Long,Element> map) throws ParseException {\r
463         dfuk.setTimeZone(TimeZone.getTimeZone("GMT"));\r
464 \r
465         NodeList nodes1 = trk.getChildNodes();\r
466         for (int i1=0; i1 < nodes1.getLength(); i1++) {\r
467             Node node2 = nodes1.item(i1);\r
468             if (node2.getNodeName().equals("trkseg")) {\r
469                 Element trkseg = (Element) node2;\r
470                 NodeList nodes2 = trkseg.getChildNodes();\r
471                 for (int i2=0; i2 < nodes2.getLength(); i2++) {\r
472                     Node node3 = nodes2.item(i2);\r
473                     if (node3.getNodeName().equals("trkpt")) {\r
474                         Element trkpt = (Element) node3;\r
475 \r
476                         NodeList nodes3 = trkpt.getChildNodes();\r
477                         for (int i3=0; i3 < nodes3.getLength(); i3++) {\r
478                             Node node4 = nodes3.item(i3);\r
479                             if (node4.getNodeName().equals("time")) {\r
480                                 Element time = (Element) node4;\r
481                                 NodeList nodes4 = time.getChildNodes();      // 子ノードを取得\r
482                                 for (int i4=0; i4< nodes4.getLength(); i4++) {\r
483                                     Node node5 = nodes4.item(i4);\r
484                                     if (node5 != null) {\r
485                                         if (node5.getNodeType() == Node.TEXT_NODE) {\r
486                                             String timeStr = node5.getNodeValue();\r
487                                             long t = dfuk.parse(timeStr).getTime();\r
488                                             map.put(t, getCopy(trk.getOwnerDocument(), trkpt));\r
489                                         }\r
490                                     }\r
491                                 }\r
492                             }\r
493                         }\r
494                     }\r
495                 }\r
496             }\r
497         }\r
498     }\r
499 \r
500     /**\r
501      *  < lat="35.32123832" lon="139.56965631">\r
502      *          <ele>47.20000076293945</ele>\r
503      *          <time>2012-06-15T03:00:29Z</time>\r
504      *  </trkpt>\r
505      * @return\r
506      * @param map\r
507      * @param jptime\r
508      * @throws ParseException\r
509      */\r
510     public static Element trkpt(HashMap<Long,Element> map, Date jptime) throws ParseException {\r
511         Double R = 20000000 / Math.PI;                  // 地球の半径(m)\r
512         long sa = 2L * 3600000L;\r
513         long jpt = jptime.getTime();\r
514         Element ret = null;\r
515         Element mae = null;\r
516 \r
517         Set<Long> keySet = map.keySet();  //すべてのキー値を取得\r
518         Iterator<Long> keyIte = keySet.iterator();\r
519         while (keyIte.hasNext()) {    //ループ。反復子iteratorによる キー 取得\r
520             Long time = keyIte.next();\r
521             long t = time;\r
522             if (Math.abs(jpt - t) < sa) {\r
523                 sa = Math.abs(jpt - t);\r
524                 ret = map.get(time);\r
525 \r
526                 // <MAGVAR>がなければ、\r
527                 // 直前の位置と、現在地から進行方向を求める\r
528                 NodeList nodes3 = ret.getChildNodes();\r
529                 Element magvar = null;\r
530                 for (int i3=0; i3 < nodes3.getLength(); i3++) {\r
531                     Node node4 = nodes3.item(i3);\r
532                     if (node4.getNodeName().toLowerCase().equals("magvar")) {\r
533                         magvar = (Element) node4;\r
534                         break;\r
535                     }\r
536                 }\r
537                 if (magvar == null) {\r
538                     if (mae != null) {\r
539                         Double maeLAT = null;\r
540                         Double maeLON = null;\r
541                         Double imaLAT = null;\r
542                         Double imaLON =null;\r
543 \r
544                         // 経度(longitude)と経度から進行方向を求める\r
545                         NamedNodeMap nodeMap = mae.getAttributes();\r
546                         if (null != nodeMap) {\r
547                             for (int j=0; j < nodeMap.getLength(); j++ ) {\r
548                                 switch (nodeMap.item(j).getNodeName()) {\r
549                                     case "lat":\r
550                                         String latStr = nodeMap.item(j).getNodeValue();\r
551                                         maeLAT = new Double(latStr);\r
552                                         break;\r
553                                     case "lon":\r
554                                         String lonStr = nodeMap.item(j).getNodeValue();\r
555                                         maeLON = new Double(lonStr);\r
556                                         break;\r
557                                 }\r
558                             }\r
559                             nodeMap = ret.getAttributes();\r
560                             for (int j=0; j < nodeMap.getLength(); j++ ) {\r
561                                 switch (nodeMap.item(j).getNodeName()) {\r
562                                     case "lat":\r
563                                         String latStr = nodeMap.item(j).getNodeValue();\r
564                                         imaLAT = new Double(latStr);\r
565                                         break;\r
566                                     case "lon":\r
567                                         String lonStr = nodeMap.item(j).getNodeValue();\r
568                                         imaLON = new Double(lonStr);\r
569                                         break;\r
570                                 }\r
571                             }\r
572                             Double dLON = imaLON - maeLON;\r
573                             Double dLAT = imaLAT - maeLAT;\r
574                             Double r = Math.cos(Math.toRadians((imaLAT + maeLAT) * 2)) * R;\r
575                             Double x = Math.toRadians(imaLON - maeLON) * r;\r
576                             Double y = Math.toRadians(imaLAT - maeLAT) * R;\r
577                             double rad = Math.toDegrees(Math.atan(y / x));\r
578                             System.out.println("magvar = " + rad);\r
579                             magvar = ret.getOwnerDocument().createElement("magvar");\r
580                             magvar.setTextContent(Double.toString(rad));\r
581                             ret.appendChild(magvar);\r
582                         }\r
583                     }\r
584                 }\r
585             }\r
586             mae = map.get(time);\r
587         }\r
588 \r
589         if (sa < (60000L * 10L)) {\r
590             // System.out.println(dfuk.format(jpt) +" ("+ sa +")");\r
591             return ret;\r
592         }\r
593         return null;\r
594     }\r
595 \r
596     /**\r
597      * 対象は '*.JPG' のみ対象とする\r
598      * @return \r
599      * @param name\r
600      */\r
601     public static boolean checkFile(String name) {\r
602         return ((name != null) && name.toUpperCase().endsWith(".JPG"));\r
603     }\r
604 \r
605     /**\r
606      *  <wpt lat="35.25714922" lon="139.15490497">\r
607      *          <ele>62.099998474121094</ele>\r
608      *          <time>2012-06-11T00:44:38Z</time>\r
609      *          <name><![CDATA[写真]]></name>\r
610      *          <link href="2012-06-11_09-44-38.jpg">\r
611      *                  <text>2012-06-11_09-44-38.jpg</text>\r
612      *          </link>\r
613      *  </wpt>\r
614      *\r
615      *  <trkpt lat="35.32123832" lon="139.56965631">\r
616      *          <ele>47.20000076293945</ele>\r
617      *          <time>2012-06-15T03:00:29Z</time>\r
618      *  </trkpt>\r
619      *\r
620      * @return\r
621      * @param iFile\r
622      * @param timestamp\r
623      * @param trkpt\r
624      */\r
625     public static Element createWptTag(File iFile, long timestamp, Element trkpt) {\r
626         Element wpt = document.createElement("wpt");\r
627 \r
628         NamedNodeMap nodeMap = trkpt.getAttributes();\r
629         if (null != nodeMap) {\r
630             for (int j=0; j < nodeMap.getLength(); j++ ) {\r
631                 switch (nodeMap.item(j).getNodeName()) {\r
632                 case "lat":\r
633                     String lat = nodeMap.item(j).getNodeValue();\r
634                     wpt.setAttribute("lat", lat);\r
635                     break;\r
636                 case "lon":\r
637                     String lon = nodeMap.item(j).getNodeValue();\r
638                     wpt.setAttribute("lon", lon);\r
639                     break;\r
640                 }\r
641             }\r
642         }\r
643 \r
644         NodeList nodes1 = trkpt.getChildNodes();\r
645         for (int i1=0; i1 < nodes1.getLength(); i1++) {\r
646             Node node1 = nodes1.item(i1);\r
647             NodeList nodes2 = node1.getChildNodes();\r
648             switch (node1.getNodeName()) {\r
649             case "ele":\r
650                 for (int i2=0; i2 < nodes2.getLength(); i2++) {\r
651                     Node node2 = nodes2.item(i2);\r
652                     if (node2 != null) {\r
653                         if (node2.getNodeType() == Node.TEXT_NODE) {\r
654                             String eleStr = node2.getNodeValue();\r
655                             Element eleE = document.createElement("ele");\r
656                             eleE.setTextContent(eleStr);\r
657                             wpt.appendChild(eleE);\r
658                         }\r
659                     }\r
660                 }\r
661                 break;\r
662             case "time":\r
663                 for (int i2=0; i2 < nodes2.getLength(); i2++) {\r
664                     Node node2 = nodes2.item(i2);\r
665                     if (node2 != null) {\r
666                         if (node2.getNodeType() == Node.TEXT_NODE) {\r
667                             String timeStr = node2.getNodeValue();\r
668                             Element timeE = document.createElement("time");\r
669                             timeE.setTextContent(timeStr);\r
670                             wpt.appendChild(timeE);\r
671                         }\r
672                     }\r
673                 }\r
674                 break;\r
675             case "magvar":\r
676                 for (int i2=0; i2 < nodes2.getLength(); i2++) {\r
677                     Node node2 = nodes2.item(i2);\r
678                     if (node2 != null) {\r
679                         if (node2.getNodeType() == Node.TEXT_NODE) {\r
680                             String magvarStr = node2.getNodeValue();\r
681                             Element magvarE = document.createElement("magvar");\r
682                             magvarE.setTextContent(magvarStr);\r
683                             wpt.appendChild(magvarE);\r
684                         }\r
685                     }\r
686                 }\r
687                 break;\r
688             }\r
689         }\r
690 \r
691         Element name = document.createElement("name");\r
692         name.appendChild(document.createCDATASection("写真"));\r
693         wpt.appendChild(name);\r
694 \r
695         Element link = document.createElement("link");\r
696         link.setAttribute("href", getShortPathName(gpxDir, iFile));\r
697         Element text = document.createElement("text");\r
698         text.setTextContent(iFile.getName());\r
699         link.appendChild(text);\r
700         wpt.appendChild(link);\r
701 \r
702         return wpt;\r
703     }\r
704         \r
705     static String getShortPathName(File dir, File iFile) {\r
706         String dirPath = dir.getAbsolutePath();\r
707         String filePath = iFile.getAbsolutePath();\r
708         if (filePath.startsWith(dirPath)) {\r
709             return filePath.substring(dirPath.length()+1);\r
710         }\r
711         else {\r
712             return filePath;\r
713         }\r
714     }\r
715 \r
716     public static Element getCopy(Document doc, Node node) {\r
717         Element root = doc.createElement(node.getNodeName());\r
718 \r
719         NamedNodeMap nodeMap = node.getAttributes();\r
720         if (null != nodeMap) {\r
721             for (int j=0; j < nodeMap.getLength(); j++ ) {\r
722                 root.setAttribute(nodeMap.item(j).getNodeName(), nodeMap.item(j).getNodeValue());\r
723             }\r
724         }\r
725 \r
726         NodeList nodes = node.getChildNodes();\r
727         for (int i=0; i < nodes.getLength(); i++) {\r
728             Node node2 = nodes.item(i);\r
729             if (node2.getNodeType() == Node.ELEMENT_NODE) {\r
730                 root.appendChild(getCopy(doc, node2));\r
731             }\r
732             else if (node2.getNodeType() == Node.TEXT_NODE) {\r
733                 String str = node2.getNodeValue();\r
734                 Text textContents = doc.createTextNode(str);\r
735                 root.appendChild(textContents);\r
736             }\r
737             else if (node2.getNodeType() == Node.CDATA_SECTION_NODE) {\r
738                 String str = node2.getNodeValue();\r
739                 CDATASection cdataSection = doc.createCDATASection(str);\r
740                 root.appendChild(cdataSection);\r
741             }\r
742         }\r
743         return root;\r
744     }\r
745         \r
746     /**\r
747      * ファイル名の順序に並び替えるためのソートクラス\r
748      * \r
749      * @author hayashi\r
750      */\r
751     static class FileSort implements Comparator<File>{\r
752         @Override\r
753         public int compare(File src, File target){\r
754             int diff = src.getName().compareTo(target.getName());\r
755             return diff;\r
756         }\r
757     }\r
758 \r
759 }