From f6fcc770cbbfa1c55a3d3a6f2f2daaca9be5b0ff Mon Sep 17 00:00:00 2001 From: Jean-Francois Remacle <jean-francois.remacle@uclouvain.be> Date: Mon, 12 Jan 2009 11:59:39 +0000 Subject: [PATCH] -add an option in GSHHS Plugin to remove narrow straits (almost complete rewrite of GSHHS plugin) -complete the doc of the GSHHS Plugin -compile GSHHS plugin even if matheval is not present --- Plugin/GSHHS.cpp | 1346 +++++++++++++++++++++++++------------- Plugin/GSHHS.h | 12 - Plugin/PluginManager.cpp | 4 +- 3 files changed, 909 insertions(+), 453 deletions(-) diff --git a/Plugin/GSHHS.cpp b/Plugin/GSHHS.cpp index c01cc0c62e..4bfc93a0f5 100644 --- a/Plugin/GSHHS.cpp +++ b/Plugin/GSHHS.cpp @@ -1,413 +1,835 @@ -// Gmsh - Copyright (C) 1997-2009 C. Geuzaine, J.-F. Remacle -// -// See the LICENSE.txt file for license information. Please report all -// bugs and problems to <gmsh@geuz.org>. - -#include "GSHHS.h" +#include <string> +#include <stdio.h> +#include <stdlib.h> +#include <math.h> #include "Field.h" -#include "GModel.h" #include <sstream> #include <fstream> -/*static void projectInvStereo(Point &pplan,Point3D &psphere){ - double rp2=pplan.x*pplan.x+pplan.y*pplan.y; - psphere.z= (4-rp2)/(4+rp2); - psphere.x= (1+psphere.z)/2*pplan.x; - psphere.y= (1+psphere.z)/2*pplan.y; - psphere.zone_id=pplan.zone_id; -} -static void projectStereo(Point3D &psphere,Point &pplan){ - pplan.x=2*psphere.x/(psphere.z+1); - pplan.y=2*psphere.y/(psphere.z+1); - pplan.zone_id=psphere.zone_id; -}*/ -// ************** Coordinate Systems ************* -class coordinate_system{ - public: - virtual void to_cartesian(const SPoint3 coord, SPoint3 &cartesian)=0; - virtual void from_cartesian(const SPoint3 cartesian, SPoint3 &coord)=0; -}; -// ************** Longitude Latitude *************** -class coordinate_lonlat:public coordinate_system{ - public: - void to_cartesian(const SPoint3 ll, SPoint3 &xyz){ - double clat = cos(ll.y()); - xyz.setPosition( clat * cos(ll.x()), clat * sin(ll.x()), sin(ll.y())); - } - void from_cartesian(const SPoint3 xyz, SPoint3 &ll){ - double r=sqrt(xyz.x()*xyz.x()+xyz.y()*xyz.y()+xyz.z()*xyz.z()); - ll.setPosition( atan2(xyz.y(),xyz.x()), asin(xyz.z()/r), 0); - } -}; -// ************** Longitude Latitude (degrees) *************** -class coordinate_lonlat_degrees:public coordinate_system{ - coordinate_lonlat cll; - SPoint3 llradian; - public: - void to_cartesian(const SPoint3 ll, SPoint3 &xyz){ - llradian.setPosition(ll.x()*M_PI/180,ll.y()*M_PI/180,0); - cll.to_cartesian(llradian,xyz); - } - void from_cartesian(const SPoint3 xyz, SPoint3 &ll){ - cll.from_cartesian(xyz,llradian); - ll.setPosition(llradian.x()*180/M_PI,llradian.y()*180/M_PI,0); - } -}; +#include "SPoint2.h" +#include "GSHHS.h" +#include "GModel.h" -// ************** UTM ************** -class coordinate_utm :public coordinate_system{ - int zone; - coordinate_lonlat ll_conv; - SPoint3 ll; - double a, b, n, n2, n3, n4, n5, e, e2, e1, e12, e13, e14, J1, J2, J3, J4, - Ap, Bp, Cp, Dp, Ep, e4, e6, ep, ep2, ep4, k0, mu_fact; - public: - static int get_zone_from_longitude(double lon){ - return (int)ceil((lon / M_PI + 1) * 30); - } - double meridionalarc(double lon, double lat){ - return Ap * lat + Bp * sin(2 * lat) + Cp * sin(4 * lat) + - Dp * sin(6 * lat) + Ep; - } - void from_cartesian(const SPoint3 xyz,SPoint3 &utm) { - ll_conv.from_cartesian(xyz,ll); - double S = meridionalarc(ll.x(),ll.y()); - double slat = sin(ll.y()); - double clat = cos(ll.y()); - double slat2 = slat * slat; - double clat2 = clat * clat; - double clat3 = clat2 * clat; - double clat4 = clat3 * clat; - double tlat2 = slat2 / clat2; - double nu = a / sqrt(1 - e * e * slat2); - double p = ll.x() - ((zone - 0.5) / 30 - 1) * M_PI; - double p2 = p * p; - double p3 = p * p2; - double p4 = p2 * p2; - utm.setPosition( - k0 * nu * clat * p + (k0 * nu * clat3 / 6) - * (1 - tlat2 + ep2 * clat2) * p3 + 5e5, - S * k0 + k0 * nu * slat * clat / 2 * p2 - + k0 * nu * slat * clat3 / 24 - * (5 - tlat2 + 9 * ep2 * clat2 + 4 * ep4 * clat4) * p4, - 0); - } - void to_cartesian(const SPoint3 utm, SPoint3 &xyz){ - double mu = utm.y() * mu_fact; - double fp = - mu + J1 * sin(2 * mu) + J2 * sin(4 * mu) + J3 * sin(6 * mu) + - J4 * sin(8 * mu); - double cfp = cos(fp); - double cfp2 = cfp * cfp; - double sfp = sin(fp); - double sfp2 = sfp * sfp; - double c1 = ep2 * cfp2; - double c12 = c1 * c1; - double t1 = sfp2 / cfp2; - double t12 = t1 * t1; - double r1 = a * (1 - e2) / pow((1 - e2 * sfp2), 1.5); - double n1 = a / sqrt(1 - e2 * sfp2); - double d = (utm.x() - 5e5) / (n1 * k0); - double d2 = d * d; - double d3 = d2 * d; - double d4 = d2 * d2; - double d5 = d4 * d; - double d6 = d4 * d2; - ll.setPosition( - ((zone - 0.5) / 30 - 1) * M_PI + (d - (1 + 2 * t1 + c1) * d3 / 6 + - (5 - 2 * c1 + 28 * t1 - 3 * c12 + - 8 * ep2 + - 24 * t12) * d5 / 120) / cfp, - fp - n1 * sfp / cfp / r1 - * (d2 / 2 - (5 + 3 * t1 + 10 * c1 - 4 * c12 - 9 * ep2) * d4 / 24 - + (61 + 90 * t1 + 298 * c1 + 45 * t12 - 3 * c12 - 252 * ep2) * d6 / 720), - 0); - ll_conv.to_cartesian(ll,xyz); - } - coordinate_utm(int _zone, double _a = 6378137, double _b = 6356752.3142) { - /* see http://www.uwgb.edu/dutchs/UsefulData/UTMFormulas.HTM */ - a = _a; /* Equatorial Radius*/ - b = _b; /* Rayon Polar Radius*/ - zone=_zone; - n = (a - b) / (a + b); - n2 = n * n; - n3 = n * n * n; - n4 = n * n * n * n; - n5 = n * n * n * n * n; - e = sqrt(1 - b * b / a / a); - e2 = e * e; - e1 = (1 - sqrt(1 - e2)) / (1 + sqrt(1 - e2)); - e12 = e1 * e1; - e13 = e1 * e1 * e1; - e14 = e1 * e1 * e1 * e1; - J1 = (3 * e1 / 2 - 27 * e13 / 32); - J2 = (21 * e12 / 16 - 55 * e14 / 32); - J3 = 151 * e13 / 96; - J4 = 1097 * e14 / 512; - Ap = a * (1 - n + (5. / 4.) * (n2 - n3) + (81. / 64.) * (n4 - n5)); - Bp = -3 * a * n / 2 * (1 - n + (7. / 8.) * (n2 - n3) + - (55. / 64.) * (n4 - n5)); - Cp = 14 * a * n2 / 16 * (1 - n + (3. / 4) * (n2 - n3)); - Dp = -35 * a * n3 / 48 * (1 - n + 11. / 16. * (n2 - n3)); - Ep = +315 * a * n4 / 51 * (1 - n); - e4 = e2 * e2; - e6 = e2 * e2 * e2; - ep = e * a / b; - ep2 = ep * ep; - ep4 = ep2 * ep2; - k0 = 0.9996; - mu_fact = 1 / (k0 * a * (1 - e2 / 4 - 3 * e4 / 64 - 5 * e6 / 256)); - } -}; -class GeoEarthImport +class GMSH_GSHHSPlugin:public GMSH_Post_Plugin { - Field *size_field; - std::ostringstream loop_buff, surface_buff;; - std::string filename; - std::ofstream *file; - int il, ip, is, ill, ifi; - int first_point_in_loop, first_point_in_surface,first_point_in_attractor; - bool empty_surface,closed_loop; - SPoint3 lastpoint; - coordinate_system *c_syst; - void new_attractor(){ - first_point_in_attractor = ip; - } - void new_surface() { - surface_buff.str(""); - surface_buff << "Plane Surface( IS + " << is++ << " ) = { "; - first_point_in_surface = ip; - empty_surface = true; - } - void new_loop(){ - loop_buff.str(""); - first_point_in_loop = ip; - closed_loop=true; - } - public: - void set_coordinate_system(coordinate_system *_c_syst){ - c_syst=_c_syst; - } - GeoEarthImport(const std::string _filename, bool write_polar_sphere){ - c_syst=NULL; - filename = _filename; - file=new std::ofstream(filename.c_str()); - size_field = NULL; - loop_buff.precision(16); - std::ostringstream buff; - il = ip = ill = is = ifi = 0; - buff << "IP = newp;\n"; - buff << "IL = newl;\n"; - buff << "ILL = newll;\n"; - buff << "IS = news;\n"; - buff << "IFI = newf;\n"; - if(write_polar_sphere){ - buff << "Point ( IP + " << ip++ << " ) = {0, 0, 0 };\n"; - buff << "Point ( IP + " << ip++ <<" ) = {0, 0, 6.371e6 };\n"; - buff << "PolarSphere ( IS + " << is++ << " ) = {IP , IP+1};\n"; - } - *file << buff.str(); - new_surface(); - new_attractor(); - new_loop(); - } - ~GeoEarthImport(){ - //file << "Euclidian Coordinates;"; - file->close(); - } - void set_size_field(Field * _size_field){ - size_field = _size_field; - } - void add_point(SPoint3 point){ - if(c_syst) - c_syst->to_cartesian(point,point); - double lc=0; - if(size_field){ - double d=(*size_field)(point[0]* 6361e3,point[1]* 6361e3,point[2]* 6361e3); - if(d<0){ - if(first_point_in_loop!=ip){ - closed_loop=false; - end_loop(); - closed_loop=false; + // ************** Inputs (readers) ************* + class reader{ + public: + virtual int next_loop(bool &closed)=0; + virtual bool next_point(SPoint3 &point)=0; + }; + class reader_loops2:public reader{ + FILE *fp; + int npoints_in_loop; + int ipoint; + std::string filename; + public: + reader_loops2(std::string _filename){ + filename=_filename; + fp=fopen(filename.c_str(),"r"); + } + ~reader_loops2(){ + fclose(fp); + } + int next_loop(bool & closed){ + ipoint=0; + npoints_in_loop=-1; + int i_closed; + if(fscanf(fp, "%d %d", &npoints_in_loop,&i_closed) != 2) + return 0; + closed = i_closed; + return npoints_in_loop; + } + bool next_point(SPoint3 &point){ + if(ipoint>=npoints_in_loop) + return false; + point[2]=0; + ipoint++; + if(fscanf(fp, "%le %le", &point[0], &point[1]) != 2) + Msg::Error("gshhs: Error reading loops2 file.\n"); + return true; + } + }; + class reader_gshhs:public reader{ + /* $Id: GSHHS.cpp,v 1.19 2009-01-12 11:59:39 remacle Exp $ + * + * Include file defining structures used in gshhs.c + * + * Paul Wessel, SOEST + * + * Copyright (c) 1996-2008 by P. Wessel and W. H. F. Smith + * See COPYING file for copying and redistribution conditions. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License for more details. + * + * Contact info: www.soest.hawaii.edu/pwessel + * + * 14-SEP-2004. PW: Version 1.3. Header is now n * 8 bytes (n = 5) + * For use with version 1.3 of GSHHS + * 2-MAY-2006. PW: Version 1.4. Header is now 32 bytes (all int 4) + * For use with version 1.4 of GSHHS + * 31-MAR-2007. PW: Version 1.5. no format change + * For use with version 1.5 of GSHHS + * 28-AUG-2007. PW: Version 1.6. no format change + * For use with version 1.6 of GSHHS which now has WDBII + * borders and rivers. + */ + static const int GSHHS_DATA_VERSION=6; // For v1.5 data set + //define GSHHS_PROG_VERSION "1.9" + static const double GSHHS_SCL=1.0e-6; // COnvert micro-degrees to degrees + inline unsigned int swabi4(unsigned int i4){ // For byte swapping on little-endian systems (GSHHS is defined to be bigendian) + return (((i4) >> 24) + (((i4) >> 8) & 65280) + (((i4) & 65280) << 8) + (((i4) & 255) << 24)); + } + class POINT { /* Each lon, lat pair is stored in micro-degrees in 4-byte integer format */ + public: + int x; + int y; + }; + class GSHHS { /* Global Self-consistent Hierarchical High-resolution Shorelines */ + public: + int id; /* Unique polygon id number, starting at 0 */ + int n; /* Number of points in this polygon */ + int flag; /* = level + version << 8 + greenwich << 16 + source << 24 */ + /* flag contains 4 items, one in each byte, as follows: + * low byte: level = flag & 255: Values: 1 land, 2 lake, 3 island_in_lake, 4 pond_in_island_in_lake + * 2nd byte: version = (flag >> 8) & 255: Values: Should be 4 for GSHHS version 1.4 + * 3rd byte: greenwich = (flag >> 16) & 255: Values: Greenwich is 1 if Greenwich is crossed + * 4th byte: source = (flag >> 24) & 255: Values: 0 = CIA WDBII, 1 = WVS + */ + int west, east, south, north; /* min/max extent in micro-degrees */ + int area; /* Area of polygon in 1/10 km^2 */ + }; + GSHHS h; + POINT p; + FILE *fp; + int max_east,flip,ip,greenwich; + bool first_loop; + public: + reader_gshhs(std::string filename){ + fp=fopen(filename.c_str(),"r"); + max_east = 270000000; + first_loop=true; + } + ~reader_gshhs(){ + fclose(fp); + } + int next_loop(bool &closed){ + closed=true; + int level=0; + ip=0; + while(level!=1){ + int n_read = fread ((void *)&h, (size_t)sizeof (struct GSHHS), (size_t)1, fp); + if(n_read!=1 || feof(fp)) + return 0; + level = h.flag & 255; + int version = (h.flag >> 8) & 255; + flip = (version != GSHHS_DATA_VERSION); /* Take as sign that byte-swabbing is needed */ + if (flip) { + h.id = swabi4 ((unsigned int)h.id); + h.n = swabi4 ((unsigned int)h.n); + h.west = swabi4 ((unsigned int)h.west); + h.east = swabi4 ((unsigned int)h.east); + h.south = swabi4 ((unsigned int)h.south); + h.north = swabi4 ((unsigned int)h.north); + h.area = swabi4 ((unsigned int)h.area); + h.flag = swabi4 ((unsigned int)h.flag); + } + if(level!=1) + fseek(fp, (size_t)(h.n * sizeof(struct POINT)), SEEK_CUR); + if(first_loop) + first_loop=false; + else + max_east = 180000000; /* Only Eurasiafrica needs 270 */ } - return; + greenwich = (h.flag >> 16) & 255; + int src = (h.flag >> 24) & 255; + double w = h.west * GSHHS_SCL; /* Convert from microdegrees to degrees */ + double e = h.east * GSHHS_SCL; + double s = h.south * GSHHS_SCL; + double n = h.north * GSHHS_SCL; + char source = (src == 1) ? 'W' : 'C'; /* Either WVS or CIA (WDBII) pedigree */ + int line = (h.area) ? 0 : 1; /* Either Polygon (0) or Line (1) (if no area) */ + double area = 0.1 * h.area; /* Now im km^2 */ + return h.n; + } + bool next_point(SPoint3 &point){ + if(ip>=h.n) + return false; + if (fread ((void *)&p, (size_t)sizeof(struct POINT), (size_t)1, fp) != 1) { + printf ("gshhs: Error reading gshhs file.\n"); + exit(1); + } + if (flip) { + p.x = swabi4 ((unsigned int)p.x); + p.y = swabi4 ((unsigned int)p.y); + } + double lon = p.x * GSHHS_SCL; + if (greenwich && p.x > max_east) + lon -= 360.0; + double lat = p.y * GSHHS_SCL; + point[0]=lon*M_PI/180; + point[1]=lat*M_PI/180; + point[2]=0; + ip++; + return true; + } + }; + + // ************** Coordinate Systems ************* + class coordinate_system{ + public: + virtual void to_cartesian(const SPoint3 coord, SPoint3 &cartesian)=0; + virtual void from_cartesian(const SPoint3 cartesian, SPoint3 &coord)=0; + }; + // ************** Longitude Latitude *************** + class coordinate_lonlat:public coordinate_system{ + double radius; + public: + coordinate_lonlat(double r){ + radius=r; + } + void to_cartesian(const SPoint3 ll, SPoint3 &xyz){ + double clat = cos(ll.y()); + xyz.setPosition( clat * cos(ll.x())*radius, clat * sin(ll.x())*radius, sin(ll.y())*radius); + } + void from_cartesian(const SPoint3 xyz, SPoint3 &ll){ + double r=sqrt(xyz.x()*xyz.x()+xyz.y()*xyz.y()+xyz.z()*xyz.z()); + ll.setPosition( atan2(xyz.y(),xyz.x()), asin(xyz.z()/r), r); + } + }; + // ************** Longitude Latitude (degrees) *************** + class coordinate_lonlat_degrees:public coordinate_system{ + coordinate_lonlat cll; + SPoint3 llradian; + public: + coordinate_lonlat_degrees(double r):cll(r){}; + void to_cartesian(const SPoint3 ll, SPoint3 &xyz){ + llradian.setPosition(ll.x()*M_PI/180,ll.y()*M_PI/180,0); + cll.to_cartesian(llradian,xyz); } - lc=std::min(d, (*size_field) (lastpoint[0],lastpoint[1],lastpoint[2])); + void from_cartesian(const SPoint3 xyz, SPoint3 &ll){ + cll.from_cartesian(xyz,llradian); + ll.setPosition(llradian.x()*180/M_PI,llradian.y()*180/M_PI,0); + } + }; + + // ************** UTM ************** + class coordinate_utm :public coordinate_system{ + int zone; + coordinate_lonlat ll_conv; + SPoint3 ll; + double a, b, n, n2, n3, n4, n5, e, e2, e1, e12, e13, e14, J1, J2, J3, J4, + Ap, Bp, Cp, Dp, Ep, e4, e6, ep, ep2, ep4, k0, mu_fact; + public: + static int get_zone_from_longitude(double lon){ + return (int)ceil((lon / M_PI + 1) * 30); + } + double meridionalarc(double lon, double lat){ + return Ap * lat + Bp * sin(2 * lat) + Cp * sin(4 * lat) + + Dp * sin(6 * lat) + Ep; + } + void from_cartesian(const SPoint3 xyz,SPoint3 &utm) { + ll_conv.from_cartesian(xyz,ll); + double S = meridionalarc(ll.x(),ll.y()); + double slat = sin(ll.y()); + double clat = cos(ll.y()); + double slat2 = slat * slat; + double clat2 = clat * clat; + double clat3 = clat2 * clat; + double clat4 = clat3 * clat; + double tlat2 = slat2 / clat2; + double nu = a / sqrt(1 - e * e * slat2); + double p = ll.x() - ((zone - 0.5) / 30 - 1) * M_PI; + double p2 = p * p; + double p3 = p * p2; + double p4 = p2 * p2; + utm.setPosition( + k0 * nu * clat * p + (k0 * nu * clat3 / 6) + * (1 - tlat2 + ep2 * clat2) * p3 + 5e5, + S * k0 + k0 * nu * slat * clat / 2 * p2 + + k0 * nu * slat * clat3 / 24 + * (5 - tlat2 + 9 * ep2 * clat2 + 4 * ep4 * clat4) * p4, + 0); + } + void to_cartesian(const SPoint3 utm, SPoint3 &xyz){ + double mu = utm.y() * mu_fact; + double fp = + mu + J1 * sin(2 * mu) + J2 * sin(4 * mu) + J3 * sin(6 * mu) + + J4 * sin(8 * mu); + double cfp = cos(fp); + double cfp2 = cfp * cfp; + double sfp = sin(fp); + double sfp2 = sfp * sfp; + double c1 = ep2 * cfp2; + double c12 = c1 * c1; + double t1 = sfp2 / cfp2; + double t12 = t1 * t1; + double r1 = a * (1 - e2) / pow((1 - e2 * sfp2), 1.5); + double n1 = a / sqrt(1 - e2 * sfp2); + double d = (utm.x() - 5e5) / (n1 * k0); + double d2 = d * d; + double d3 = d2 * d; + double d4 = d2 * d2; + double d5 = d4 * d; + double d6 = d4 * d2; + ll.setPosition( + ((zone - 0.5) / 30 - 1) * M_PI + (d - (1 + 2 * t1 + c1) * d3 / 6 + + (5 - 2 * c1 + 28 * t1 - 3 * c12 + + 8 * ep2 + + 24 * t12) * d5 / 120) / cfp, + fp - n1 * sfp / cfp / r1 + * (d2 / 2 - (5 + 3 * t1 + 10 * c1 - 4 * c12 - 9 * ep2) * d4 / 24 + + (61 + 90 * t1 + 298 * c1 + 45 * t12 - 3 * c12 - 252 * ep2) * d6 / 720), + 0); + ll_conv.to_cartesian(ll,xyz); + } + coordinate_utm(int _zone,double ll_radius, double _a = 6378137, double _b = 6356752.3142) :ll_conv(ll_radius){ + /* see http://www.uwgb.edu/dutchs/UsefulData/UTMFormulas.HTM */ + a = _a; /* Equatorial Radius*/ + b = _b; /* Rayon Polar Radius*/ + zone=_zone; + n = (a - b) / (a + b); + n2 = n * n; + n3 = n * n * n; + n4 = n * n * n * n; + n5 = n * n * n * n * n; + e = sqrt(1 - b * b / a / a); + e2 = e * e; + e1 = (1 - sqrt(1 - e2)) / (1 + sqrt(1 - e2)); + e12 = e1 * e1; + e13 = e1 * e1 * e1; + e14 = e1 * e1 * e1 * e1; + J1 = (3 * e1 / 2 - 27 * e13 / 32); + J2 = (21 * e12 / 16 - 55 * e14 / 32); + J3 = 151 * e13 / 96; + J4 = 1097 * e14 / 512; + Ap = a * (1 - n + (5. / 4.) * (n2 - n3) + (81. / 64.) * (n4 - n5)); + Bp = -3 * a * n / 2 * (1 - n + (7. / 8.) * (n2 - n3) + + (55. / 64.) * (n4 - n5)); + Cp = 14 * a * n2 / 16 * (1 - n + (3. / 4) * (n2 - n3)); + Dp = -35 * a * n3 / 48 * (1 - n + 11. / 16. * (n2 - n3)); + Ep = +315 * a * n4 / 51 * (1 - n); + e4 = e2 * e2; + e6 = e2 * e2 * e2; + ep = e * a / b; + ep2 = ep * ep; + ep4 = ep2 * ep2; + k0 = 0.9996; + mu_fact = 1 / (k0 * a * (1 - e2 / 4 - 3 * e4 / 64 - 5 * e6 / 256)); + } + }; + + /********** classes and functions to ensure minimal distance and angle between points **********/ + class box; + class loop; + class point{ + public: + SPoint3 v; + std::list<point>::iterator it_loop; + std::list<point*>::iterator it_box; + box *b; + double min_dist; + loop *l; + point(double _x,double _y,double _z,Field *f,double straits_factor){ + v[0]=_x; v[1]=_y; v[2]=_z; + if(f) + min_dist=(*f)(v[0],v[1],v[2])*straits_factor; + } + point(double _x,double _y,double _z,double _min_dist){ + v[0]=_x; v[1]=_y; v[2]=_z; + min_dist=_min_dist; + } + double dist(point p){ + return sqrt( + (v[0]-p.v[0])*(v[0]-p.v[0]) + +(v[1]-p.v[1])*(v[1]-p.v[1]) + +(v[2]-p.v[2])*(v[2]-p.v[2])); + } + void to_stereo(double &xp,double &yp,bool inverse_stereo=false){ + if(inverse_stereo){ + yp=v[1]/(1-v[2]); + xp=v[0]/(1-v[2]); + }else{ + xp=-v[1]/(1+v[2]); + yp=-v[0]/(1+v[2]); + } + } + void to_latlon(double &lat,double &lon){ + lat=asin(v[2]); + lon=atan2(v[1],v[0]); + if(lon<-15*M_PI/16)lon+=2*M_PI; + } + }; + class box{ + public: + box *sub_boxes[2]; + point min,max; + int max_n; + double min_size,size; + bool splitted; + std::list<point*> list; + int cut_dim,ndim; + int n; + box(point _min,point _max,int _max_n=100,double _min_size=0,int _cut_dim=0):min(_min),max(_max),max_n(_max_n){ + n=0; + min_size=_min_size; + size=0; + ndim=3; + for(int i=0;i<ndim;i++) + size=std::max(size,fabs(max.v[i]-min.v[i])); + splitted=false; + cut_dim=_cut_dim; + } + void add( point &p){ + if(!splitted){ + list.push_back(&p); + p.it_box=list.end(); + p.it_box--; + p.b=this; + n++; + if(n>max_n && size>=min_size){ + point mid0(min); + point mid1(max); + mid1.v[cut_dim]=mid0.v[cut_dim]=(min.v[cut_dim]+max.v[cut_dim])/2; + int newdim=(cut_dim+1)%ndim; + sub_boxes[0]=new box(min,mid1,max_n,min_size,newdim); + sub_boxes[1]=new box(mid0,max,max_n,min_size,newdim); + splitted=true; + for(std::list<point*>::iterator it=list.begin();it!=list.end();it++) + add(**it); + list.clear(); + } + }else{ + int ix=(p.v[cut_dim]-min.v[cut_dim])>(max.v[cut_dim]-min.v[cut_dim])/2; + sub_boxes[ix]->add(p); + } + } + void remove(point *p){ + if(p->b!=this) + p->b->remove(p); + else{ + list.erase(p->it_box); + n--; + } + } + void find_closest(point p,int nc,double *d,point **cp){ + int i=(cut_dim+ndim-1)%ndim; + if(p.v[i]<min.v[i]-d[nc-1] || p.v[i]>max.v[i]+d[nc-1]) + return; + if(splitted){ + for(int i=0;i<2;i++) + sub_boxes[i]->find_closest(p,nc,d,cp); + }else for(std::list<point*>::iterator it=list.begin();it!=list.end();it++){ + double dd=p.dist(**it); + if(dd<d[nc-1]){ + int j; + for(j=nc-2;j>=0;j--){ + if(dd>d[j])break; + d[j+1]=d[j]; + cp[j+1]=cp[j]; + } + d[j+1]=dd; + cp[j+1]=*it; + } + } + } + }; + static double get_angle(double x0,double y0,double x1,double y1,double x2,double y2){ + double dx0=x1-x0; + double dx1=x2-x1; + double dy0=y1-y0; + double dy1=y2-y1; + return atan2(dx0*dy1-dx1*dy0,dx1*dx0+dy1*dy0); } - lc/=6361e3; - if(ip == first_point_in_loop || point.distance(lastpoint) >lc){ - SPoint2 stereo(-point.x() / (1 + point.z()), -point.y() / (1 + point.z())); - loop_buff << "Point ( IP + " << ip++ << " ) = {" << stereo. - x() << ", " << stereo.y() << ", " << 0 << " };\n"; - lastpoint = point; + static double get_angle(point &p0,point &p1,point &p2){ + double dx0=p1.v[0]-p0.v[0]; + double dy0=p1.v[1]-p0.v[1]; + double dz0=p1.v[2]-p0.v[2]; + double dx1=p2.v[0]-p1.v[0]; + double dy1=p2.v[1]-p1.v[1]; + double dz1=p2.v[2]-p1.v[2]; + double scalar=dx0*dx1+dy0*dy1+dz0*dz1; + double vectx=dy0*dz1-dy1*dz0; + double vecty=dz0*dx1-dz1*dx0; + double vectz=dx0*dy1-dx1*dy0; + int sign=vectx*p1.v[0]+vecty*p1.v[1]+vectz*p1.v[2]<0?-1:1; + double vect=sqrt(vectx*vectx+vecty*vecty+vectz*vectz); + return atan2(-vect*sign,scalar); } - } - void end_loop(bool closed=true) { - closed&=closed_loop; - if(ip - first_point_in_loop > 3) { - loop_buff<<"LoopStart"<<il<<" = IP + "<< first_point_in_loop<<";\n"; - loop_buff<<"LoopEnd"<<il<<" = IP + "<< ip - 1<<";\n"; - loop_buff << "BSpline ( IL + " << il++ << " ) = { IP + " << - first_point_in_loop << " : IP + " << ip - 1 ; - if(closed) loop_buff<< ", IP + " << first_point_in_loop; - loop_buff<< " };\n"; - if(closed){ - loop_buff << "Line Loop ( ILL + " << ill++ << " ) = { IL + " << il - - 1 << " };"; - } - *file << loop_buff.str(); - if(closed){ - if(!empty_surface) - surface_buff << ", "; - surface_buff << "ILL + " << ill - 1; - empty_surface = false; - } + // angle (01,12) + class loop:public std::list<point>{ + public: + bool closed; + loop(){ + closed=true; + } + inline iterator next(iterator i){ + ++i; + if(i==end()){ + i=begin(); + } + return i; + } + inline iterator prev(iterator i){ + if(i==begin()) + i=end(); + --i; + return i; + } + iterator remove_range(loop::iterator i0,loop::iterator i1){ //remove [id0, id1] and replace it by a single point at (id0+id1)/2; + for(int i=0;i<3;i++) + i1->v[i]=(i0->v[i]+i1->v[i])/2; + while(i0!=i1){ + if(i0->b) + i0->b->remove(&*i0); + i0=erase(i0); + if(i0==end()) + i0=begin(); + } + return i1; + } + int orientation(iterator i0, iterator i1,bool reverse_stereo){ + if(next(i0)==i1) + return 0; + double alpha=0; + double x[3],y[3]; + i1->to_stereo(x[0],y[0],reverse_stereo); + i0->to_stereo(x[1],y[1],reverse_stereo); + iterator p=i0; + do{ + p=next(p); + p->to_stereo(x[2],y[2],reverse_stereo); + alpha+=get_angle(x[0],y[0],x[1],y[1],x[2],y[2]); + x[0]=x[1];y[0]=y[1]; + x[1]=x[2];y[1]=y[2]; + }while(p!=i1); + i0->to_stereo(x[2],y[2],reverse_stereo); + alpha+=get_angle(x[0],y[0],x[1],y[1],x[2],y[2]); + return rint(alpha/(M_PI*2)); + } + int length(iterator i0,iterator i1){ + int l=1; + while(i0!=i1){ + i0=next(i0); + l++; + } + return l; + } + void insert_range(iterator i,iterator j0,iterator j1){ + iterator n=j0; + do{ + j0=n; + iterator is=insert(i,*j0); + is->it_loop=is; + is->l=this; + *(j0->it_box)=&*is; + n=j0->l->next(j0); + }while(j0!=j1); + } + }; + + class loops:public std::list<loop>{ + public: + void print_gnuplot(std::ostream &stream){ + double lat,lon; + for(iterator il=begin();il!=end();il++){ + stream<<"\n"; + for(loop::iterator ip=il->begin();ip!=il->end();ip++){ + ip->to_latlon(lat,lon); + stream<<lon*180/M_PI<<" "<<lat*180/M_PI<<"\n"; + } + il->front().to_latlon(lat,lon); + stream<<lon*180/M_PI<<" "<<lat*180/M_PI<<"\n"; + } + } + }; + + double stereo_cross_product(point p00,point p01, point p10,point p11){ + double x[4],y[4]; + p00.to_stereo(x[0],y[0]); + p01.to_stereo(x[1],y[1]); + p10.to_stereo(x[2],y[2]); + p11.to_stereo(x[3],y[3]); + return (x[1]-x[0])*(y[3]-y[2])-(y[1]-y[0])*(x[3]-x[2]); } - else { - ip = first_point_in_loop; + bool is_intersected(point p00,point p01, point p10,point p11){ + if(stereo_cross_product(p00,p01,p00,p10)*stereo_cross_product(p00,p01,p00,p11)>0) + return false; + if(stereo_cross_product(p10,p11,p10,p00)*stereo_cross_product(p10,p11,p10,p01)>0) + return false; + return true; } - new_loop(); - } - void end_surface(){ - if(!empty_surface) { - surface_buff << "};\n"; - surface_buff.str(""); - *file << surface_buff.str()<<"\n"; + void loop_fill_box(loop *l,box &b){ + int i=0; + for(loop::iterator ip=l->begin();ip!=l->end();ip++){ + ip->l=l; + ip->it_loop=ip; + b.add(*ip); + } + } + bool loop_check_intersections(loop *l,box &b){ + // Check for intersections + bool result=false; + for(loop::iterator i00=l->begin();i00!=l->end();++i00){ + loop::iterator i01=l->next(i00); + if(i01==l->begin() && !l->closed) + break; + double length0=i00->dist(*i01); +#define NP 5 + double d[NP*2]={length0*1.0001}; + for(int i=0;i<NP*2;i++) + d[i]=DBL_MAX; + point *cp[NP*2]; + b.find_closest(*i00,NP,d,cp); + b.find_closest(*i01,NP,d+NP,cp+NP); + for(int i=0;i<NP*2;i++){ + if(d[i]>length0) + break; + if(i00!=cp[i]->it_loop && i01!=cp[i]->it_loop){ + loop::iterator i10=cp[i]->it_loop; + loop::iterator i11=l->next(i10); + if((i11!=l->begin() || l->closed) &&(i11 != i00 && i11 != i01)) + if(is_intersected(*i00,*i01,*i10,*i11)){ + if(l->length(i11,i00)<l->length(i01,i10)) + i00=l->remove_range(i11,i00); + else + i00=l->remove_range(i01,i10); + result=true; + if(i00!=l->begin()) + i00--; + break; + } + i11=i10; + i10=l->prev(i11); + if((i11!=l->begin() || l->closed) &&(i10 != i00 && i10 != i01)) + if(is_intersected(*i00,*i01,*i10,*i11)){ + if(l->length(i11,i00)<l->length(i01,i10)) + i00=l->remove_range(i11,i00); + else + i00=l->remove_range(i01,i10); + result=true; + if(i00!=l->begin()) + i00--; + break; + } + } + } + } + return result; } - new_surface(); - } - void end_attractor(){ - *file << "Field [ IFI + " << ifi << "] = Attractor;\n"; - *file << "Field [ IFI + " << ifi++ << "].NodesList = { IP + " << - first_point_in_attractor << " : IP + " << ip - 1 << " };"; - new_attractor(); - } -}; - -/* $Id: GSHHS.cpp,v 1.18 2008-12-29 09:43:39 geuzaine Exp $ - * - * Include file defining structures used in gshhs.c - * - * Paul Wessel, SOEST - * - * Copyright (c) 1996-2008 by P. Wessel and W. H. F. Smith - * See COPYING file for copying and redistribution conditions. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program 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 General Public License for more details. - * - * Contact info: www.soest.hawaii.edu/pwessel - * - * 14-SEP-2004. PW: Version 1.3. Header is now n * 8 bytes (n = 5) - * For use with version 1.3 of GSHHS - * 2-MAY-2006. PW: Version 1.4. Header is now 32 bytes (all int 4) - * For use with version 1.4 of GSHHS - * 31-MAR-2007. PW: Version 1.5. no format change - * For use with version 1.5 of GSHHS - * 28-AUG-2007. PW: Version 1.6. no format change - * For use with version 1.6 of GSHHS which now has WDBII - * borders and rivers. - */ -#include <stdio.h> -#include <stdlib.h> -#include <math.h> + bool loop_check_close_points_self(loop *l,box &b){ + bool result=false; + bool reverse_stereo=(l->orientation(l->begin(),--l->end(),false)<0); + for(loop::iterator i=l->begin();i!=l->end();){ + double d[2]={i->min_dist*1.001,i->min_dist*1.001}; + point *cp[2]; + b.find_closest(*i,2,d,cp); + if(d[1]<i->min_dist){ + loop::iterator id1=cp[1]->it_loop; + int not_a_loop=-1; + if(!l->closed){ + loop::iterator ii; + for(ii=i;ii!=l->end() && ii!=id1;ii++); + not_a_loop= ii==l->end()?0:1; + } + if(not_a_loop!=0 && (l->orientation(i,id1,reverse_stereo)==-1 || l->length(i,id1)<3)){ + i=l->remove_range(i,id1); + result=true; + } + if(not_a_loop!=1 &&(l->orientation(id1,i,reverse_stereo)==-1 || l->length(id1,i)<3)){ + i=l->remove_range(id1,i); + result=true; + }else + i++; + }else + i++; + } + return result; + } -#define GSHHS_DATA_VERSION 6 /* For v1.5 data set */ -#define GSHHS_PROG_VERSION "1.9" + bool loop_check_small_angles(loop *l){ + bool removed=false; + for(loop::iterator i=l->begin();i!=l->end();++i){ + loop::iterator i1=l->next(i); + loop::iterator i2=l->next(i1); + if((!l->closed) && i2==l->begin()) + break; + double alpha=get_angle(*i,*i1,*i2); + if(alpha>3*M_PI/4){ + i1->b->remove(&*i1); + i=l->erase(i1); + removed=true; + } + } + return removed; + } -#define GSHHS_SCL 1.0e-6 /* COnvert micro-degrees to degrees */ + bool loop_check_close_points(loop *l,box &b){ +#define NPD 10 + for(loop::iterator i=l->begin();i!=l->end();){ + double d[NPD]; + point *cp[NPD]; + for(int j=0;j<NPD;j++){ + d[j]=i->min_dist*1.001; + cp[j]=NULL; + } + b.find_closest(*i,NPD,d,cp); + bool merged=false; + for(int j=0;j<NPD;j++){ + if(!cp[j])break; + if(i->l!=cp[j]->l){ + double lat,lon; + i->to_latlon(lat,lon); + loop::iterator f0=i; + loop::iterator f1=cp[j]->it_loop; + double newx[3],dx[3],crossx[3]; + for(int k=0;k<3;k++){ + newx[k]=(f0->v[k]+f1->v[k])/2; + dx[k]=(f1->v[k]-f0->v[k])/2; + } + for(int k=0;k<3;k++){ + int k1=(k+1)%3; + int k2=(k+2)%3; + crossx[k]=newx[k1]*dx[k2]-newx[k2]*dx[k1]; + } + double norm=sqrt(crossx[0]*crossx[0]+crossx[1]*crossx[1]+crossx[2]*crossx[2]); + for(int k=0;k<3;k++){ + crossx[k]*=i->min_dist*0.1/norm; + f0->v[k]=newx[k]-crossx[k]; + f1->v[k]=newx[k]+crossx[k]; + } -/* For byte swapping on little-endian systems (GSHHS is defined to be bigendian) */ + l->insert_range(++f0,f1->l->next(f1),f1); + cp[j]->l->clear(); + merged=true; + break; + } + } + if(!merged) + i++; + } + } + class GeoEarthImport + { + std::ostringstream loop_buff, surface_buff;; + std::string filename; + std::ofstream *file; + int il, ip, is, ill, ifi; + int first_point_in_loop, first_point_in_surface,first_point_in_attractor; + bool empty_surface; + void new_attractor(){ + first_point_in_attractor = ip; + } + void new_surface() { + surface_buff.str(""); + surface_buff << "Plane Surface( IS + " << is++ << " ) = { "; + first_point_in_surface = ip; + empty_surface = true; + } + void new_loop(){ + loop_buff.str(""); + first_point_in_loop = ip; + } + coordinate_lonlat cll; + public: + GeoEarthImport(const std::string _filename, bool write_polar_sphere,double radius): + cll(radius) + { + filename = _filename; + file=new std::ofstream(filename.c_str()); + loop_buff.precision(16); + std::ostringstream buff; + il = ip = ill = is = ifi = 0; + buff << "IP = newp;\n"; + buff << "IL = newl;\n"; + buff << "ILL = newll;\n"; + buff << "IS = news;\n"; + buff << "IFI = newf;\n"; + if(write_polar_sphere){ + buff << "Point ( IP + " << ip++ << " ) = {0, 0, 0 };\n"; + buff << "Point ( IP + " << ip++ <<" ) = {0, 0,"<<radius<<"};\n"; + buff << "PolarSphere ( IS + " << is++ << " ) = {IP , IP+1};\n"; + } + *file << buff.str(); + new_surface(); + new_attractor(); + new_loop(); + } + ~GeoEarthImport(){ + //file << "Euclidian Coordinates;"; + file->close(); + } + void add_point(SPoint3 point){ + SPoint3 pll; + cll.from_cartesian(point,pll); + SPoint2 stereo(-pll.x() / (1 + pll.z()), -pll.y() / (1 + pll.z())); + loop_buff << "Point ( IP + " << ip++ << " ) = {" << stereo. + x() << ", " << stereo.y() << ", " << 0 << " };\n"; + } + void end_loop(bool closed) { + if(ip - first_point_in_loop > 3) { + loop_buff<<"LoopStart"<<il<<" = IP + "<< first_point_in_loop<<";\n"; + loop_buff<<"LoopEnd"<<il<<" = IP + "<< ip - 1<<";\n"; + loop_buff << "Spline ( IL + " << il++ << " ) = { IP + " << + first_point_in_loop << " : IP + " << ip - 1 ; + if(closed) loop_buff<< ", IP + " << first_point_in_loop; + loop_buff<< " };\n"; + if(closed){ + loop_buff << "Line Loop ( ILL + " << ill++ << " ) = { IL + " << il - + 1 << " };"; + } + *file << loop_buff.str(); + if(closed){ + if(!empty_surface) + surface_buff << ", "; + surface_buff << "ILL + " << ill - 1; + empty_surface = false; + } + } + else { + ip = first_point_in_loop; + } + new_loop(); + } + void end_surface(){ + if(!empty_surface) { + surface_buff << "};\n"; + surface_buff.str(""); + *file << surface_buff.str()<<"\n"; + } + new_surface(); + } + void end_attractor(){ + *file << "Field [ IFI + " << ifi << "] = Attractor;\n"; + *file << "Field [ IFI + " << ifi++ << "].NodesList = { IP + " << + first_point_in_attractor << " : IP + " << ip - 1 << " };"; + new_attractor(); + } + }; + void getName(char *name) const; + void getInfos(char *author, char *copyright, char *help_text) const; + void catchErrorMessage(char *errorMessage) const; + int getNbOptions() const; + int getNbOptionsStr() const; + StringXNumber *getOption(int iopt); + StringXString *getOptionStr(int iopt); + PView *execute(PView *); +}; -#define swabi4(i4) (((i4) >> 24) + (((i4) >> 8) & 65280) + (((i4) & 65280) << 8) + (((i4) & 255) << 24)) -struct GSHHS { /* Global Self-consistent Hierarchical High-resolution Shorelines */ - int id; /* Unique polygon id number, starting at 0 */ - int n; /* Number of points in this polygon */ - int flag; /* = level + version << 8 + greenwich << 16 + source << 24 */ - /* flag contains 4 items, one in each byte, as follows: - * low byte: level = flag & 255: Values: 1 land, 2 lake, 3 island_in_lake, 4 pond_in_island_in_lake - * 2nd byte: version = (flag >> 8) & 255: Values: Should be 4 for GSHHS version 1.4 - * 3rd byte: greenwich = (flag >> 16) & 255: Values: Greenwich is 1 if Greenwich is crossed - * 4th byte: source = (flag >> 24) & 255: Values: 0 = CIA WDBII, 1 = WVS - */ - int west, east, south, north; /* min/max extent in micro-degrees */ - int area; /* Area of polygon in 1/10 km^2 */ -}; -struct POINT { /* Each lon, lat pair is stored in micro-degrees in 4-byte integer format */ - int x; - int y; -}; -void import_gshhs(FILE * fp, GeoEarthImport & geo_import) -{ - double w, e, s, n; - char source; - int k, max_east = 270000000, n_read, flip; - struct POINT p; - struct GSHHS h; - n_read = fread ((void *)&h, (size_t)sizeof (struct GSHHS), (size_t)1, fp); - int version = (h.flag >> 8) & 255; - flip = (version != GSHHS_DATA_VERSION); /* Take as sign that byte-swabbing is needed */ - - while (n_read == 1 && ! feof(fp)) { - if (flip) { - h.id = swabi4 ((unsigned int)h.id); - h.n = swabi4 ((unsigned int)h.n); - h.west = swabi4 ((unsigned int)h.west); - h.east = swabi4 ((unsigned int)h.east); - h.south = swabi4 ((unsigned int)h.south); - h.north = swabi4 ((unsigned int)h.north); - h.area = swabi4 ((unsigned int)h.area); - h.flag = swabi4 ((unsigned int)h.flag); - } - int level = h.flag & 255; - version = (h.flag >> 8) & 255; - int greenwich = (h.flag >> 16) & 255; - int src = (h.flag >> 24) & 255; - w = h.west * GSHHS_SCL; /* Convert from microdegrees to degrees */ - e = h.east * GSHHS_SCL; - s = h.south * GSHHS_SCL; - n = h.north * GSHHS_SCL; - source = (src == 1) ? 'W' : 'C'; /* Either WVS or CIA (WDBII) pedigree */ - int line = (h.area) ? 0 : 1; /* Either Polygon (0) or Line (1) (if no area) */ - double area = 0.1 * h.area; /* Now im km^2 */ - if(level != 1) { // Skip data (lake,island,pond) - fseek(fp, (size_t)(h.n * sizeof(struct POINT)), SEEK_CUR); - }else{ - for (k = 0; k < h.n; k++) { - if (fread ((void *)&p, (size_t)sizeof(struct POINT), (size_t)1, fp) != 1) { - Msg::Error ("gshhs: Error reading gshhs file.\n"); - return; - } - if (flip) { - p.x = swabi4 ((unsigned int)p.x); - p.y = swabi4 ((unsigned int)p.y); - } - double lon = p.x * GSHHS_SCL; - if (greenwich && p.x > max_east) lon -= 360.0; - double lat = p.y * GSHHS_SCL; - geo_import.add_point(SPoint3(M_PI/180*lon,M_PI/180*lat,0)); - } - geo_import.end_loop(); - } - max_east = 180000000; /* Only Eurasiafrica needs 270 */ - n_read = fread((void *)&h, (size_t)sizeof (struct GSHHS), (size_t)1, fp); - } - geo_import.end_surface(); - geo_import.end_attractor(); -} // ************** MAIN PLUGIN ************** @@ -416,10 +838,9 @@ StringXNumber GSHHSOptions_Number[] = { {GMSH_FULLRC, "UTMZone", NULL, 0}, {GMSH_FULLRC, "UTMEquatorialRadius", NULL, 6378137}, {GMSH_FULLRC, "UTMPolarRadius", NULL, 6356752.3142}, - {GMSH_FULLRC, "UTMScale", NULL, 1}, - {GMSH_FULLRC, "UTMShiftX", NULL, 0}, - {GMSH_FULLRC, "UTMShiftY", NULL, 0}, - {GMSH_FULLRC, "WritePolarSphere",NULL,1} + {GMSH_FULLRC, "radius", NULL,6371009}, + {GMSH_FULLRC, "WritePolarSphere",NULL,1}, + {GMSH_FULLRC, "MinStraitsFactor",NULL,1} }; StringXString GSHHSOptions_String[] = { {GMSH_FULLRC, "InFileName", NULL, "gshhs_c.b"}, @@ -442,22 +863,35 @@ void GMSH_GSHHSPlugin::getName(char *name) const } void GMSH_GSHHSPlugin::getInfos(char *author, char *copyright, - char *help_text) const + char *help_text) const { strcpy(author, "J. Lambrechts"); strcpy(copyright, "C. Geuzaine, J.-F. Remacle"); - strcpy(help_text, "Plugin(GSHHS) read differenct kind of contour lines data and write a .geo file.\n" - "Valid values for \"Format\" are :\n" - " -\"gshhs\" : open GSHHS file\n" - " -\"loops2\" : import 2D contour lines in simple text format :\n" - " NB_POINTS_IN_FIRST_LOOP\n" - " COORD1 COORD2\n" - " COORD1 COORD2\n" - " ... ...\n" - " NB_POINTS_IN_SECOND_LOOP\n" - " ...\n" - ); - + strcpy(help_text, + "Plugin(GSHHS) read different kind of contour lines data and write a .geo file on the surface of a sphere (the Earth).\n" + "The principal application is to load GSHHS data\n (see http://www.soest.hawaii.edu/wessel/gshhs/gshhs.html).\n" + "Valid values for \"Format\" are ):\n" + " -\"gshhs\" : open GSHHS file\n" + " -\"loops2\" : import 2D contour lines in simple text format :\n" + " NB_POINTS_IN_FIRST_LOOP FIRST_LOOP_IS_CLOSED\n" + " COORD1 COORD2\n" + " COORD1 COORD2\n" + " ... ...\n" + " NB_POINTS_IN_SECOND_LOOP SECOND_LOOP_IS_CLOSED\n" + " ...\n" + " (LOOP_IS_CLOSED specify if this coast line describe a closed curve (0=no, 1=yes).\n" + "In the case of \"loops2\" format, you can specify the the coordinate system used in the input file with the" + "\"Coordinate\" option, valid values are\n" + " -\"lonlat\" for longitude-latidute radian,\n" + " -\"lonlat_degrees\" for longitude-latitude degrees,\n" + " -\"UTM\" for universal transverse mercartor (\"UTMZone\" option should be specified)\n" + " -\"cartesian\" for full 3D coordinates\n" + "\"radius\" specify the earth radius.\n" + "If the \"iField\" option is set, consecutive points closer than the value of the field iField (in meters) will not be added.\n" + "If \"MinStraitsFactor\" >0 and if a field iField is provided, coastlines closer than MinStraitsFactor*field(IField) are merged and inner corners which form an angle < pi/3 are removed.\n" + "The output is always in stereographic coordinates, if the \"WritePolarSphere\" option is not 0, a sphere is added to the geo file.\n" + "WARNING : this plugin is still experimental and need polishing and error-handling. In particular, it will probably crash if an inexistant field id is given or if the input/output cannot be open." + ); } int GMSH_GSHHSPlugin::getNbOptions() const @@ -493,26 +927,26 @@ PView *GMSH_GSHHSPlugin::execute(PView * v) char *outfilename = (char *)GSHHSOptions_String[1].def; std::string format(GSHHSOptions_String[2].def); std::string coordinate_name(GSHHSOptions_String[3].def); - double scale = GSHHSOptions_Number[4].def; - double shiftx = GSHHSOptions_Number[5].def; - double shifty = GSHHSOptions_Number[6].def; - bool write_polar_sphere = (bool)GSHHSOptions_Number[7].def; int utm_zone=(int)GSHHSOptions_Number[1].def; double utm_equatorial_radius=(double)GSHHSOptions_Number[2].def; double utm_polar_radius=(double)GSHHSOptions_Number[3].def; - coordinate_lonlat lonlat; - coordinate_lonlat_degrees lonlat_degrees; - coordinate_utm utm(utm_zone, utm_equatorial_radius, utm_polar_radius); - GeoEarthImport geo_import(outfilename,write_polar_sphere); + double radius=(double)GSHHSOptions_Number[4].def; + bool write_polar_sphere = (bool)GSHHSOptions_Number[5].def; + double straits_factor = (double)GSHHSOptions_Number[6].def; + coordinate_lonlat lonlat(radius); + coordinate_lonlat_degrees lonlat_degrees(radius); + coordinate_utm utm(utm_zone, radius,utm_equatorial_radius, utm_polar_radius); + GeoEarthImport geo_import(outfilename,write_polar_sphere,radius); + coordinate_system *c_syst=NULL; if(coordinate_name == "lonlat") - geo_import.set_coordinate_system(&lonlat); + c_syst=&lonlat; else if(coordinate_name == "lonlat_degrees") - geo_import.set_coordinate_system(&lonlat_degrees); + c_syst=&lonlat_degrees; else if(coordinate_name == "utm") - geo_import.set_coordinate_system(&utm); + c_syst=&utm; else if(coordinate_name != "cartesian"){ Msg::Error("gshhs: Unknown coordinate system %s.\n", - coordinate_name.c_str()); + coordinate_name.c_str()); return NULL; } Field *field = NULL; @@ -521,35 +955,69 @@ PView *GMSH_GSHHSPlugin::execute(PView * v) if(!field){ Msg::Error("Field[%d] does not exist", iField); return NULL; - }else{ - geo_import.set_size_field(field); } } - FILE *fp; - if ((fp = fopen (filename, "rb")) == NULL ) { - Msg::Error("gshhs: Could not find file %s.\n", filename); - return NULL; - } double x,y,z; - if(format == "gshhs") { - geo_import.set_coordinate_system(&lonlat); - import_gshhs(fp, geo_import); + SPoint3 p; + reader *read; + if(format == "loops2") { + read=new reader_loops2(filename); + }else if(format == "gshhs") { + c_syst=&lonlat; + read=new reader_gshhs(filename); } - else if(format == "loops2") { - int npoints_in_loop; - int closed; - while(fscanf(fp, "%d %d", &npoints_in_loop,&closed) == 2) { - for(int i = 0; i < npoints_in_loop; i++) { - if(fscanf(fp, "%le %le", &x, &y) != 2) { - Msg::Error("gshhs: Error reading loops2 file \'%s\'.\n", filename); - return NULL; - } - geo_import.add_point(SPoint3(x,y,0)); + loops ll; + bool closed; + while(read->next_loop(closed)!=0){ + loop l; + l.closed=closed; + point oldp(0,0,0,0.); + while(read->next_point(p)){ + if(c_syst) + c_syst->to_cartesian(p,p); + point newp(p[0],p[1],p[2],field,straits_factor); + if(newp.min_dist<0){ + while(!l.empty() && l.back().dist(l.front())<l.back().min_dist) + l.pop_back(); + l.closed=false; + if(l.size()>=3) + ll.push_back(l); + l.clear(); + } else if (l.empty() || oldp.dist(newp)>newp.min_dist){ + l.push_back(newp); + oldp=newp; } - geo_import.end_loop(closed); } - geo_import.end_surface(); - geo_import.end_attractor(); - } + while(!l.empty() && l.back().dist(l.front())<l.back().min_dist) + l.pop_back(); + if(l.size()>=3) + ll.push_back(l); + } + delete read; + if(straits_factor>0 && iField !=0){ + box *b=new box(point(-radius,-radius,-radius,0.),point(radius,radius,radius,0.)); + for(loops::iterator il=ll.begin();il!=ll.end();il++) + loop_fill_box(&*il,*b); + for(loops::iterator il=ll.begin();il!=ll.end();il++) + loop_check_close_points(&*il,*b); + delete b; + for(loops::iterator il=ll.begin();il!=ll.end();il++){ + box b(point(-radius,-radius,-radius,0.),point(radius,radius,radius,0.)); + loop_fill_box(&*il,b); + while(false + || loop_check_small_angles(&*il) + || loop_check_close_points_self(&*il,b) + || loop_check_intersections(&*il,b) + ); + } + } + for(std::list<loop>::iterator l=ll.begin();l!=ll.end();l++){ + for(loop::iterator p=l->begin();p!=l->end();p++) + geo_import.add_point(p->v); + geo_import.end_loop(l->closed); + } + geo_import.end_surface(); + geo_import.end_attractor(); + return NULL; } diff --git a/Plugin/GSHHS.h b/Plugin/GSHHS.h index be23327f01..cfb67fb954 100644 --- a/Plugin/GSHHS.h +++ b/Plugin/GSHHS.h @@ -13,17 +13,5 @@ extern "C" GMSH_Plugin *GMSH_RegisterGSHHSPlugin(); } -class GMSH_GSHHSPlugin:public GMSH_Post_Plugin -{ -public: - void getName(char *name) const; - void getInfos(char *author, char *copyright, char *help_text) const; - void catchErrorMessage(char *errorMessage) const; - int getNbOptions() const; - int getNbOptionsStr() const; - StringXNumber *getOption(int iopt); - StringXString *getOptionStr(int iopt); - PView *execute(PView *); -}; #endif diff --git a/Plugin/PluginManager.cpp b/Plugin/PluginManager.cpp index d6f9ab9464..77dd4b64de 100644 --- a/Plugin/PluginManager.cpp +++ b/Plugin/PluginManager.cpp @@ -217,13 +217,13 @@ void GMSH_PluginManager::registerDefaultPlugins() ("FieldView", GMSH_RegisterFieldViewPlugin())); allPlugins.insert(std::pair<const char*, GMSH_Plugin*> ("Triangulate", GMSH_RegisterTriangulatePlugin())); + allPlugins.insert(std::pair<const char*, GMSH_Plugin*> + ("GSHHS", GMSH_RegisterGSHHSPlugin())); #if defined(HAVE_MATH_EVAL) allPlugins.insert(std::pair<const char*, GMSH_Plugin*> ("Evaluate", GMSH_RegisterEvaluatePlugin())); allPlugins.insert(std::pair<const char*, GMSH_Plugin*> ("CutParametric", GMSH_RegisterCutParametricPlugin())); - allPlugins.insert(std::pair<const char*, GMSH_Plugin*> - ("GSHHS", GMSH_RegisterGSHHSPlugin())); #endif } -- GitLab