/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2006-2008, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
*/
package org.geotools.data;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.geotools.geometry.DirectPosition2D;
import org.geotools.referencing.CRS;
import org.geotools.referencing.operation.builder.AffineTransformBuilder;
import org.geotools.referencing.operation.builder.MappedPosition;
import org.geotools.resources.i18n.ErrorKeys;
import org.geotools.resources.i18n.Errors;
import org.opengis.geometry.DirectPosition;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;
/**
* Reader for Mapinfo .TAB files
* Finds control points and CRS in .TAB file and parses them accordingly and builds a mathtransform and CRS
*
* @author Niels Charlier, Scitus Development
*
*/
public class MapInfoFileReader {
/**
* Logger for this class.
*/
private final static Logger LOGGER = org.geotools.util.logging.Logging
.getLogger("org.geotools.data.MapInfoFileReader");
/**
* Projection mappings Mapinfo -> WKT
*/
private static Map<Integer, String> PROJECTIONS = new HashMap<Integer, String>();
/**
* Datum mappings Mapinfo -> WKT
*/
private static Map<Integer, String> DATUMS = new HashMap<Integer, String>();
/**
* Unit mappings Mapinfo -> WKT
*/
private static Map<String, String> UNITS = new HashMap<String, String>();
/**
* List of parameters
*/
private final static String[] PARAMETERS1 = new String[] { "central_meridian", "latitude_of_origin", "standard_parallel_1", "standard_parallel_2", "false_easting", "false_northing"};
private final static String[] PARAMETERS2 = new String[] { "central_meridian", "latitude_of_origin", "scale_factor", "false_easting", "false_northing"};
static {
PROJECTIONS.put(2, "Cylindrical_Equal_Area");
PROJECTIONS.put(3, "Lambert_Conformal_Conic_2SP");
PROJECTIONS.put(4, "Lambert_Azimuthal_Equal_Area");
PROJECTIONS.put(7, "Hotine_Oblique_Mercator");
PROJECTIONS.put(8, "Transverse_Mercator");
PROJECTIONS.put(9, "Albers_Conic_Equal_Area");
PROJECTIONS.put(10, "Mercator_1SP");
PROJECTIONS.put(18, "New_Zealand_Map_Grid");
PROJECTIONS.put(19, "Lambert_Conformal_Conic_2SP_Belgium");
PROJECTIONS.put(26, "Mercator_1SP");
PROJECTIONS.put(27, "Polyconic");
PROJECTIONS.put(28, "Lambert_Azimuthal_Equal_Area");
PROJECTIONS.put(30, "Cassini_Soldner");
PROJECTIONS.put(32, "Krovak");
DATUMS.put(1, "GEOGCS[\"Adindan\", DATUM[\"Adindan\", SPHEROID[\"Clarke 1880 (RGS)\",6378249.145,293.465], TOWGS84[-166,-15,204,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(2, "GEOGCS[\"Afgooye\", DATUM[\"Afgooye\", SPHEROID[\"Krassowsky 1940\",6378245,298.3], TOWGS84[-43,-163,45,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(3, "GEOGCS[\"Ain el Abd\", DATUM[\"Ain_el_Abd_1970\", SPHEROID[\"International 1924\",6378388,297], TOWGS84[-143,-236,7,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(5, "GEOGCS[\"Arc 1950\", DATUM[\"Arc_1950\", SPHEROID[\"Clarke 1880 (Arc)\",6378249.145,293.4663077], TOWGS84[-143,-90,-294,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(6, "GEOGCS[\"Arc 1960\", DATUM[\"Arc_1960\", SPHEROID[\"Clarke 1880 (RGS)\",6378249.145,293.465], TOWGS84[-160,-6,-302,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(12, "GEOGCS[\"AGD66\", DATUM[\"Australian_Geodetic_Datum_1966\", SPHEROID[\"Australian National Spheroid\",6378160,298.25], TOWGS84[-117.808,-51.536,137.784,0.303,0.446,0.234,-0.29]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(13, "GEOGCS[\"AGD84\", DATUM[\"Australian_Geodetic_Datum_1984\", SPHEROID[\"Australian National Spheroid\",6378160,298.25], TOWGS84[-134,-48,149,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(15, "GEOGCS[\"Bermuda 1957\", DATUM[\"Bermuda_1957\", SPHEROID[\"Clarke 1866\",6378206.4,294.9786982139006], TOWGS84[-73,213,296,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(16, "GEOGCS[\"Bogota 1975\", DATUM[\"Bogota_1975\", SPHEROID[\"International 1924\",6378388,297], TOWGS84[307,304,-318,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(17, "GEOGCS[\"Campo Inchauspe\", DATUM[\"Campo_Inchauspe\", SPHEROID[\"International 1924\",6378388,297], TOWGS84[-148,136,90,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(19, "GEOGCS[\"Cape\", DATUM[\"Cape\", SPHEROID[\"Clarke 1880 (Arc)\",6378249.145,293.4663077], TOWGS84[-136,-108,-292,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(20, "GEOGCS[\"Cape Canaveral\", DATUM[\"Cape_Canaveral\", SPHEROID[\"Clarke 1866\",6378206.4,294.9786982139006], TOWGS84[-2,151,181,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(21, "GEOGCS[\"Carthage\", DATUM[\"Carthage\", SPHEROID[\"Clarke 1880 (IGN)\",6378249.2,293.4660212936265], TOWGS84[-263,6,431,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(22, "GEOGCS[\"Chatham Islands 1971\", DATUM[\"Chatham_Islands_Datum_1971\", SPHEROID[\"International 1924\",6378388,297], TOWGS84[175,-38,113,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(23, "GEOGCS[\"Chua\", DATUM[\"Chua\", SPHEROID[\"International 1924\",6378388,297], TOWGS84[-134,229,-29,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(24, "GEOGCS[\"Corrego Alegre 1970-72\", DATUM[\"Corrego_Alegre_1970_72\", SPHEROID[\"International 1924\",6378388,297], TOWGS84[-206,172,-6,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(25, "GEOGCS[\"Batavia\", DATUM[\"Batavia\", SPHEROID[\"Bessel 1841\",6377397.155,299.1528128], TOWGS84[-377,681,-50,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(27, "GEOGCS[\"Easter Island 1967\", DATUM[\"Easter_Island_1967\", SPHEROID[\"International 1924\",6378388,297], TOWGS84[211,147,111,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(28, "GEOGCS[\"ED50\", DATUM[\"European_Datum_1950\", SPHEROID[\"International 1924\",6378388,297], TOWGS84[-87,-98,-121,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(29, "GEOGCS[\"ED79\", DATUM[\"European_Datum_1979\", SPHEROID[\"International 1924\",6378388,297], TOWGS84[-86,-98,-119,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(30, "GEOGCS[\"Gandajika 1970\", DATUM[\"Gandajika_1970\", SPHEROID[\"International 1924\",6378388,297], TOWGS84[-133,-321,50,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(31, "GEOGCS[\"NZGD49\", DATUM[\"New_Zealand_Geodetic_Datum_1949\", SPHEROID[\"International 1924\",6378388,297], TOWGS84[59.47,-5.04,187.44,0.47,-0.1,1.024,-4.5993]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(34, "GEOGCS[\"Guam 1963\", DATUM[\"Guam_1963\", SPHEROID[\"Clarke 1866\",6378206.4,294.9786982139006], TOWGS84[-100,-248,259,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(36, "GEOGCS[\"Hito XVIII 1963\", DATUM[\"Hito_XVIII_1963\", SPHEROID[\"International 1924\",6378388,297], TOWGS84[16,196,93,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(37, "GEOGCS[\"Hjorsey 1955\", DATUM[\"Hjorsey_1955\", SPHEROID[\"International 1924\",6378388,297], TOWGS84[-73,46,-86,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(38, "GEOGCS[\"Hong Kong 1963\", DATUM[\"Hong_Kong_1963\", SPHEROID[\"Clarke 1858\",6378293.645208759,294.2606763692569]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(39, "GEOGCS[\"Hu Tzu Shan 1950\", DATUM[\"Hu_Tzu_Shan_1950\", SPHEROID[\"International 1924\",6378388,297], TOWGS84[-637,-549,-203,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(44, "GEOGCS[\"Johnston Island 1961\", DATUM[\"Johnston_Island_1961\", SPHEROID[\"International 1924\",6378388,297], TOWGS84[189,-79,-202,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(45, "GEOGCS[\"Kandawala\", DATUM[\"Kandawala\", SPHEROID[\"Everest 1830 (1937 Adjustment)\",6377276.345,300.8017], TOWGS84[-97,787,86,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(47, "GEOGCS[\"Kertau 1968\", DATUM[\"Kertau_1968\", SPHEROID[\"Everest 1830 Modified\",6377304.063,300.8017], TOWGS84[-11,851,5,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(49, "GEOGCS[\"Liberia 1964\", DATUM[\"Liberia_1964\", SPHEROID[\"Clarke 1880 (RGS)\",6378249.145,293.465], TOWGS84[-90,40,88,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(52, "GEOGCS[\"Mahe 1971\", DATUM[\"Mahe_1971\", SPHEROID[\"Clarke 1880 (RGS)\",6378249.145,293.465], TOWGS84[41,-220,-134,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(54, "GEOGCS[\"Massawa\", DATUM[\"Massawa\", SPHEROID[\"Bessel 1841\",6377397.155,299.1528128], TOWGS84[639,405,60,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(55, "GEOGCS[\"Merchich\", DATUM[\"Merchich\", SPHEROID[\"Clarke 1880 (IGN)\",6378249.2,293.4660212936265], TOWGS84[31,146,47,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(57, "GEOGCS[\"Minna\", DATUM[\"Minna\", SPHEROID[\"Clarke 1880 (RGS)\",6378249.145,293.465], TOWGS84[-92,-93,122,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(61, "GEOGCS[\"Naparima 1972\", DATUM[\"Naparima_1972\", SPHEROID[\"International 1924\",6378388,297], TOWGS84[-10,375,165,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(62, "GEOGCS[\"NAD27\", DATUM[\"North_American_Datum_1927\", SPHEROID[\"Clarke 1866\",6378206.4,294.9786982139006]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(74, "GEOGCS[\"NAD83\", DATUM[\"North_American_Datum_1983\", SPHEROID[\"GRS 1980\",6378137,298.257222101], TOWGS84[0,0,0,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(77, "GEOGCS[\"Old Hawaiian\", DATUM[\"Old_Hawaiian\", SPHEROID[\"Clarke 1866\",6378206.4,294.9786982139006], TOWGS84[61,-285,-181,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(79, "GEOGCS[\"OSGB 1936\", DATUM[\"OSGB_1936\", SPHEROID[\"Airy 1830\",6377563.396,299.3249646], TOWGS84[446.448,-125.157,542.06,0.15,0.247,0.842,-20.489]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(81, "GEOGCS[\"Pitcairn 1967\", DATUM[\"Pitcairn_1967\", SPHEROID[\"International 1924\",6378388,297], TOWGS84[185,165,42,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(82, "GEOGCS[\"PSAD56\", DATUM[\"Provisional_South_American_Datum_1956\", SPHEROID[\"International 1924\",6378388,297], TOWGS84[-288,175,-376,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(83, "GEOGCS[\"Puerto Rico\", DATUM[\"Puerto_Rico\", SPHEROID[\"Clarke 1866\",6378206.4,294.9786982139006], TOWGS84[11,72,-101,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(84, "GEOGCS[\"QND95\", DATUM[\"Qatar_National_Datum_1995\", SPHEROID[\"International 1924\",6378388,297], TOWGS84[-119.425,-303.659,-11.0006,1.1643,0.174458,1.09626,3.65706]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(85, "GEOGCS[\"Qornoq\", DATUM[\"Qornoq\", SPHEROID[\"International 1924\",6378388,297], TOWGS84[164,138,-189,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(86, "GEOGCS[\"RGR92\", DATUM[\"Reseau_Geodesique_de_la_Reunion_1992\", SPHEROID[\"GRS 1980\",6378137,298.257222101], TOWGS84[0,0,0,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(87, "GEOGCS[\"Monte Mario\", DATUM[\"Monte_Mario\", SPHEROID[\"International 1924\",6378388,297], TOWGS84[-104.1,-49.1,-9.9,0.971,-2.917,0.714,-11.68]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(90, "GEOGCS[\"Sapper Hill 1943\", DATUM[\"Sapper_Hill_1943\", SPHEROID[\"International 1924\",6378388,297], TOWGS84[-355,21,72,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(91, "GEOGCS[\"Schwarzeck\", DATUM[\"Schwarzeck\", SPHEROID[\"Bessel Namibia (GLM)\",6377483.865280419,299.1528128], TOWGS84[616,97,-251,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(92, "GEOGCS[\"SAD69\", DATUM[\"South_American_Datum_1969\", SPHEROID[\"GRS 1967\",6378160,298.247167427], TOWGS84[-57,1,-41,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(92, "GEOGCS[\"SAD69\", DATUM[\"South_American_Datum_1969\", SPHEROID[\"GRS 1967 Modified\",6378160,298.25], TOWGS84[-57,1,-41,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(96, "GEOGCS[\"Timbalai 1948\", DATUM[\"Timbalai_1948\", SPHEROID[\"Everest 1830 (1967 Definition)\",6377298.556,300.8017], TOWGS84[-679,669,-48,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(97, "GEOGCS[\"Tokyo\", DATUM[\"Tokyo\", SPHEROID[\"Bessel 1841\",6377397.155,299.1528128], TOWGS84[-146.414,507.337,680.507,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(99, "GEOGCS[\"Viti Levu 1916\", DATUM[\"Viti_Levu_1916\", SPHEROID[\"Clarke 1880 (RGS)\",6378249.145,293.465], TOWGS84[51,391,-36,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(102, "GEOGCS[\"WGS 66\", DATUM[\"World_Geodetic_System_1966\", SPHEROID[\"NWL 9D\",6378145,298.25]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(103, "GEOGCS[\"WGS 72\", DATUM[\"WGS_1972\", SPHEROID[\"WGS 72\",6378135,298.26], TOWGS84[0,0,4.5,0,0,0.554,0.2263]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(104, "GEOGCS[\"WGS 84\", DATUM[\"WGS_1984\", SPHEROID[\"WGS 84\",6378137,298.257223563]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(105, "GEOGCS[\"Yacare\", DATUM[\"Yacare\", SPHEROID[\"International 1924\",6378388,297], TOWGS84[-155,171,37,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(106, "GEOGCS[\"Zanderij\", DATUM[\"Zanderij\", SPHEROID[\"International 1924\",6378388,297], TOWGS84[-265,120,-358,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(108, "GEOGCS[\"ED87\", DATUM[\"European_Datum_1987\", SPHEROID[\"International 1924\",6378388,297], TOWGS84[-83.11,-97.38,-117.22,0.00569291,-0.0446976,0.0442851,0.1218]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(112, "GEOGCS[\"RT90\", DATUM[\"Rikets_koordinatsystem_1990\", SPHEROID[\"Bessel 1841\",6377397.155,299.1528128], TOWGS84[414.1,41.3,603.1,-0.855,2.141,-7.023,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(117, "GEOGCS[\"NZGD2000\", DATUM[\"New_Zealand_Geodetic_Datum_2000\", SPHEROID[\"GRS 1980\",6378137,298.257222101], TOWGS84[0,0,0,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(118, "GEOGCS[\"American Samoa 1962\", DATUM[\"American_Samoa_1962\", SPHEROID[\"Clarke 1866\",6378206.4,294.9786982139006], TOWGS84[-115,118,426,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(120, "GEOGCS[\"Ayabelle Lighthouse\", DATUM[\"Ayabelle_Lighthouse\", SPHEROID[\"Clarke 1880 (RGS)\",6378249.145,293.465], TOWGS84[-79,-129,145,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(121, "GEOGCS[\"Bukit Rimpah\", DATUM[\"Bukit_Rimpah\", SPHEROID[\"Bessel 1841\",6377397.155,299.1528128], TOWGS84[-384,664,-48,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(123, "GEOGCS[\"Dabola 1981\", DATUM[\"Dabola_1981\", SPHEROID[\"Clarke 1880 (IGN)\",6378249.2,293.4660212936265], TOWGS84[-83,37,124,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(124, "GEOGCS[\"Deception Island\", DATUM[\"Deception_Island\", SPHEROID[\"Clarke 1880 (RGS)\",6378249.145,293.465], TOWGS84[260,12,-147,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(127, "GEOGCS[\"Herat North\", DATUM[\"Herat_North\", SPHEROID[\"International 1924\",6378388,297], TOWGS84[-333,-222,114,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(129, "GEOGCS[\"Indian 1975\", DATUM[\"Indian_1975\", SPHEROID[\"Everest 1830 (1937 Adjustment)\",6377276.345,300.8017], TOWGS84[210,814,289,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(130, "GEOGCS[\"Indian 1954\", DATUM[\"Indian_1954\", SPHEROID[\"Everest 1830 (1937 Adjustment)\",6377276.345,300.8017], TOWGS84[217,823,299,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(131, "GEOGCS[\"Indian 1960\", DATUM[\"Indian_1960\", SPHEROID[\"Everest 1830 (1937 Adjustment)\",6377276.345,300.8017], TOWGS84[198,881,317,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(133, "GEOGCS[\"ID74\", DATUM[\"Indonesian_Datum_1974\", SPHEROID[\"Indonesian National Spheroid\",6378160,298.247], TOWGS84[-24,-15,5,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(136, "GEOGCS[\"Leigon\", DATUM[\"Leigon\", SPHEROID[\"Clarke 1880 (RGS)\",6378249.145,293.465], TOWGS84[-130,29,364,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(138, "GEOGCS[\"M'poraloko\", DATUM[\"M_poraloko\", SPHEROID[\"Clarke 1880 (IGN)\",6378249.2,293.4660212936265], TOWGS84[-74,-130,42,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(141, "GEOGCS[\"Point 58\", DATUM[\"Point_58\", SPHEROID[\"Clarke 1880 (RGS)\",6378249.145,293.465], TOWGS84[-106,-129,165,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(142, "GEOGCS[\"Pointe Noire\", DATUM[\"Congo_1960_Pointe_Noire\", SPHEROID[\"Clarke 1880 (IGN)\",6378249.2,293.4660212936265], TOWGS84[-148,51,-291,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(143, "GEOGCS[\"Porto Santo\", DATUM[\"Porto_Santo_1936\", SPHEROID[\"International 1924\",6378388,297], TOWGS84[-499,-249,314,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(144, "GEOGCS[\"Selvagem Grande\", DATUM[\"Selvagem_Grande\", SPHEROID[\"International 1924\",6378388,297], TOWGS84[-289,-124,60,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(146, "GEOGCS[\"S-JTSK\", DATUM[\"System_Jednotne_Trigonometricke_Site_Katastralni\", SPHEROID[\"Bessel 1841\",6377397.155,299.1528128], TOWGS84[589,76,480,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(147, "GEOGCS[\"Tananarive\", DATUM[\"Tananarive_1925\", SPHEROID[\"International 1924\",6378388,297], TOWGS84[-189,-242,-91,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(150, "GEOGCS[\"Hartebeesthoek94\", DATUM[\"Hartebeesthoek94\", SPHEROID[\"WGS 84\",6378137,298.257223563], TOWGS84[0,0,0,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(151, "GEOGCS[\"ATS77\", DATUM[\"Average_Terrestrial_System_1977\", SPHEROID[\"Average Terrestrial System 1977\",6378135,298.257]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(152, "GEOGCS[\"JGD2000\", DATUM[\"Japanese_Geodetic_Datum_2000\", SPHEROID[\"GRS 1980\",6378137,298.257222101], TOWGS84[0,0,0,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(1001, "GEOGCS[\"Pulkovo 1942\", DATUM[\"Pulkovo_1942\", SPHEROID[\"Krassowsky 1940\",6378245,298.3], TOWGS84[23.92,-141.27,-80.9,-0,0.35,0.82,-0.12]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(1002, "GEOGCS[\"NTF\", DATUM[\"Nouvelle_Triangulation_Francaise\", SPHEROID[\"Clarke 1880 (IGN)\",6378249.2,293.4660212936265], TOWGS84[-168,-60,320,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(1004, "GEOGCS[\"HD72\", DATUM[\"Hungarian_Datum_1972\", SPHEROID[\"GRS 1967\",6378160,298.247167427], TOWGS84[52.17,-71.82,-14.9,0,0,0,0]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(1017, "GEOGCS[\"Xian 1980\", DATUM[\"Xian_1980\", SPHEROID[\"IAG 1975\",6378140,298.257]], PRIMEM[\"Greenwich\",0], UNIT[\"degree\",0.0174532925199433]]");
DATUMS.put(1020, "GEOGCS[\"S-JTSK (Ferro)\", DATUM[\"System_Jednotne_Trigonometricke_Site_Katastralni_Ferro\", SPHEROID[\"Bessel 1841\",6377397.155,299.1528128], TOWGS84[589,76,480,0,0,0,0]], PRIMEM[\"Ferro\",-17.66666666666667], UNIT[\"degree\",0.0174532925199433]]");
UNITS.put("m", "UNIT[\"Meter\",1]");
UNITS.put("ft", "UNIT[\"foot\",0.3048]");
UNITS.put("li", "UNIT[\"link\",0.201168]");
UNITS.put("survey ft", "UNIT[\"US survey foot\",0.3048006096012192]");
}
/**
* The transform builder
*/
private List<MappedPosition> controlPoints = new ArrayList<MappedPosition> ();
/**
* The Coordinate Reference System
*/
private CoordinateReferenceSystem coordinateReferenceSystem;
/**
* Constructor for a {@link MapInfoFileReader}.
*
* @param tabfile holds the location where to read from.
* @param bufferSize to buffer when reading.
* @throws IOException in case something bad happens.
*/
public MapInfoFileReader(final File tabfile) throws IOException {
if (tabfile == null) {
throw new IllegalArgumentException(Errors.format(ErrorKeys.NULL_ARGUMENT_$1, "tabfile"));
}
if (!tabfile.isFile() || !tabfile.canRead()) {
throw new IllegalArgumentException(Errors.format(ErrorKeys.FILE_DOES_NOT_EXIST_$1,
tabfile));
}
parseTabFile(new BufferedReader(new FileReader(tabfile)));
}
/**
* Constructor for a {@link MapInfoFileReader}.
*
* @param tabfile {@link URL} where to read from.
* @param bufferSize to buffer when reading.
* @throws IOException in case something bad happens.
*/
public MapInfoFileReader(final URL tabfile) throws IOException {
if (tabfile == null) {
throw new IllegalArgumentException(Errors.format(ErrorKeys.NULL_ARGUMENT_$1, "inFile"));
}
parseTabFile(new BufferedReader(new InputStreamReader(tabfile.openStream())));
}
/**
* Parse Tab File
*
* @param bufferedreader the buffered reader
* @throws IOException
* @throws DataSourceException
*/
private void parseTabFile(final BufferedReader bufferedreader) throws IOException,
DataSourceException {
String str;
Pattern patternPoint = Pattern.compile(" *\\(([0-9\\.]*),([0-9\\.]*)\\) *\\(([0-9\\.]*),([0-9\\.]*)\\).*");
Pattern patternCoordSys = Pattern.compile("CoordSys *Earth *Projection *([0-9]*) *, *([0-9]*) *,?(.*)");
Pattern patternUnit = Pattern.compile(" *\"([^\"]*)\" *,?(.*)");
try {
while ((str = bufferedreader.readLine()) != null) {
Matcher matcherPoint = patternPoint.matcher(str);
if (matcherPoint.find()) {
double d1 = Double.parseDouble(matcherPoint.group(1));
double d2 = Double.parseDouble(matcherPoint.group(2));
double d3 = Double.parseDouble(matcherPoint.group(3));
double d4 = Double.parseDouble(matcherPoint.group(4));
DirectPosition p1 = new DirectPosition2D(null, d1, d2);
DirectPosition p2 = new DirectPosition2D(null, d3, d4);
controlPoints.add(new MappedPosition(p2, p1));
} else {
Matcher matcherCoordSys = patternCoordSys.matcher(str);
if (matcherCoordSys.find()) {
try {
int projectionType = Integer.parseInt(matcherCoordSys.group(1));
int datum = Integer.parseInt(matcherCoordSys.group(2));
String rest = matcherCoordSys.group(3);
String unit = "m";
Matcher matcherUnit = patternUnit.matcher(rest);
if (matcherUnit.find()){
unit = matcherUnit.group(1);
rest = matcherUnit.group(2);
}
String s = "PROJCS[\"Unnamed\", " + DATUMS.get(datum) + ",";
String proj = PROJECTIONS.get(projectionType);
if (proj != null) {
s += " PROJECTION[\"" + proj +"\"], ";
}
String[] parts = rest.split(",");
final String[] PARAMETERS;
if (parts.length > 5) {
PARAMETERS = PARAMETERS1;
} else {
PARAMETERS = PARAMETERS2;
}
boolean flag = false;
for (int i=0; i < parts.length && i < PARAMETERS.length; i++) {
String n = parts[i].trim();
int space = n.indexOf(" ");
if (space > 0) {
n = n.substring(0, space);
}
double d = Double.parseDouble(n);
if (i==3 && flag) {
s += " PARAMETER[\"scale_factor\"," + d + "],";
} else if (i==2 && d==0) {
flag = true;
}
else {
s += " PARAMETER[\"" + PARAMETERS[i] + "\"," + d + "],";
}
}
s += " " + UNITS.get(unit);
s += "]";
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.log(Level.FINE, "Mapinfo converted CRS: " + s);
}
coordinateReferenceSystem = CRS.parseWKT(s);
}
catch (Exception e) {
LOGGER.log(Level.WARNING, "Failed to parse and encode mapinfo crs: " + e.getLocalizedMessage(), e);
//ignore coordinate reference system
}
}
}
}
} catch (Exception e) {
throw new DataSourceException(e);
} finally {
try {
bufferedreader.close();
} catch (Throwable t) {
if (LOGGER.isLoggable(Level.FINE)){
LOGGER.log(Level.FINE, t.getLocalizedMessage(), t);
}
}
}
// did we find all we were looking for?
if (controlPoints.size() < 3) {
throw new DataSourceException("Didn't find a minimum of three control points in the .tab file.");
}
}
/**
* Get Control Points
*
* @return Control Points
*/
public synchronized List<MappedPosition> getControlPoints() {
return controlPoints;
}
/**
* Get Math Transform based on control points
*
* @return MathTransform
*/
public synchronized MathTransform getTransform() {
AffineTransformBuilder builder = new AffineTransformBuilder(controlPoints);
try {
return builder.getMathTransform();
} catch (FactoryException e) {
LOGGER.log(Level.WARNING, e.getLocalizedMessage(), e);
return null;
}
}
/**
* Get CoordinateReferenceSysten
*
* @return Coordinate Reference System
*/
public synchronized CoordinateReferenceSystem getCRS() {
return coordinateReferenceSystem;
}
}