summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRafael Laboissière <rafael@debian.org>2020-05-26 05:27:24 -0300
committerRafael Laboissière <rafael@debian.org>2020-05-26 05:27:24 -0300
commit4ec814108766d2234a019b929916b6426ec8e7c5 (patch)
tree027dcceae0d4c91400020b4e535d8afc1eb91278
parentba2211591577cbb78f4067fe426287a37aeb1f2c (diff)
New upstream version 2.0.1
-rw-r--r--DESCRIPTION9
-rw-r--r--NEWS15
-rw-r--r--doc/octclip.pdfbin206232 -> 212089 bytes
-rw-r--r--doc/octclip.tex159
-rw-r--r--inst/oc_polybool.m301
-rw-r--r--src/Makefile9
-rw-r--r--src/_oc_polybool.cc111
-rw-r--r--src/arco.c910
-rw-r--r--[-rwxr-xr-x]src/compilador.c0
-rw-r--r--src/dpeucker.c520
-rw-r--r--src/dpeuckera.c204
-rw-r--r--src/dpeuckere.c1495
-rw-r--r--src/dpeuckerp.c1114
-rw-r--r--[-rwxr-xr-x]src/errores.c0
-rw-r--r--[-rwxr-xr-x]src/eucli.c0
-rw-r--r--[-rwxr-xr-x]src/fgeneral.c26
-rw-r--r--[-rwxr-xr-x]src/geocnan.c0
-rw-r--r--[-rwxr-xr-x]src/greiner.c106
-rw-r--r--src/libgeoc/arco.h617
-rw-r--r--[-rwxr-xr-x]src/libgeoc/compilador.h0
-rw-r--r--[-rwxr-xr-x]src/libgeoc/constantes.h0
-rw-r--r--src/libgeoc/dpeucker.h348
-rw-r--r--src/libgeoc/dpeuckera.h210
-rw-r--r--src/libgeoc/dpeuckere.h1002
-rw-r--r--src/libgeoc/dpeuckerp.h774
-rw-r--r--[-rwxr-xr-x]src/libgeoc/errores.h0
-rw-r--r--[-rwxr-xr-x]src/libgeoc/eucli.h0
-rw-r--r--[-rwxr-xr-x]src/libgeoc/fgeneral.h146
-rw-r--r--[-rwxr-xr-x]src/libgeoc/general.h0
-rw-r--r--[-rwxr-xr-x]src/libgeoc/geocnan.h0
-rw-r--r--[-rwxr-xr-x]src/libgeoc/geom.h0
-rw-r--r--[-rwxr-xr-x]src/libgeoc/greiner.h66
-rw-r--r--src/libgeoc/mate.h482
-rw-r--r--[-rwxr-xr-x]src/libgeoc/polig.h206
-rw-r--r--[-rwxr-xr-x]src/libgeoc/polil.h93
-rw-r--r--src/libgeoc/posmatvec.h512
-rw-r--r--src/libgeoc/proyecaux.h90
-rw-r--r--[-rwxr-xr-x]src/libgeoc/ptopol.h618
-rw-r--r--[-rwxr-xr-x]src/libgeoc/recpolil.h29
-rw-r--r--[-rwxr-xr-x]src/libgeoc/segmento.h140
-rw-r--r--[-rwxr-xr-x]src/libgeoc/ventorno.h0
-rw-r--r--src/mate.c813
-rw-r--r--[-rwxr-xr-x]src/polig.c329
-rw-r--r--[-rwxr-xr-x]src/polil.c112
-rw-r--r--src/posmatvec.c292
-rw-r--r--src/proyecaux.c92
-rw-r--r--[-rwxr-xr-x]src/ptopol.c489
-rw-r--r--[-rwxr-xr-x]src/recpolil.c21
-rw-r--r--[-rwxr-xr-x]src/segmento.c278
-rw-r--r--[-rwxr-xr-x]src/ventorno.c0
50 files changed, 11543 insertions, 1195 deletions
diff --git a/DESCRIPTION b/DESCRIPTION
index 28b5ad2..0f11518 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -1,13 +1,12 @@
Name: OctCLIP
-Version: 1.0.8
-Date: 2015-06-16
+Version: 2.0.1
+Date: 2020-05-16
Author: José Luis García Pallero <jgpallero@gmail.com>
Maintainer: José Luis García Pallero <jgpallero@gmail.com>
Title: GNU Octave clipping polygons tool
Description: This package allows to do boolean operations with polygons using
the Greiner-Hormann algorithm.
-Depends: Octave (>= 2.9.7)
-Url: http://davis.wpi.edu/~matt/courses/clipping/
- https://bitbucket.org/jgpallero/octclip
+Depends: Octave (>= 3.6.0)
+Url: https://bitbucket.org/jgpallero/octclip
Autoload: no
License: GPLv3+, modified BSD
diff --git a/NEWS b/NEWS
index 25596af..3c40549 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,18 @@
+Summary of important user-visible changes for version 2.0.1:
+------------------------------------------------------------
+
+** Minor changes in src/Makefile
+
+Summary of important user-visible changes for version 2.0.0:
+------------------------------------------------------------
+
+** API changed, added XOR operation, and help strings rewritten
+
+Summary of important user-visible changes for version 1.0.9:
+------------------------------------------------------------
+
+** Minor changes due to http://wiki.octave.org/Remove_class_of_function_from_documentation_strings
+
Summary of important user-visible changes for version 1.0.8:
------------------------------------------------------------
diff --git a/doc/octclip.pdf b/doc/octclip.pdf
index 7059395..c0afbef 100644
--- a/doc/octclip.pdf
+++ b/doc/octclip.pdf
Binary files differ
diff --git a/doc/octclip.tex b/doc/octclip.tex
index 5b0247c..c39623c 100644
--- a/doc/octclip.tex
+++ b/doc/octclip.tex
@@ -6,13 +6,19 @@
\newcommand{\octclip}{\texttt{OctCLIP}}
\newcommand{\octave}{GNU Octave}
-\title{Clipping polygons from \octave\footnote{This document is distributed
+\title{Clipping polygons in \octave\footnote{This document is distributed
under the terms of the GNU Free Documentation License. Please, see
\url{http://www.gnu.org/licenses/}}}
\author{Jos\'e Luis Garc\'ia Pallero\footnote{ETSI en Topograf\'ia, Geodesia y
Cartograf\'ia, Universidad Polit\'ecnica de Madrid.
\texttt{jlg.pallero@upm.es}, \texttt{jgpallero@gmail.com}}}
-\date{February 13, 2015 (version 1.0.6)\\
+\date{May 16, 2020 (version 2.0.1)\\
+ May 11, 2020 (version 2.0.0)\\
+ May 9, 2020 (version 1.1.0)\\
+ May 9, 2020 (version 1.0.9)\\
+ June 16, 2015 (version 1.0.8)\\
+ April 28, 2015 (version 1.0.7)\\
+ February 13, 2015 (version 1.0.6)\\
June 20, 2013 (version 1.0.5)\\
October 1, 2012 (version 1.0.2)\\
November 21, 2011 (version 1.0.1)\\
@@ -22,9 +28,6 @@
\maketitle
% \tableofcontents
-\nocite{eat-om}
-\nocite{kim2006a}
-
\begin{abstract}
This is a small introduction to using the \octclip{} package. In this text, you
can overview the basic usage of the functions in
@@ -37,12 +40,10 @@ description about the Greiner-Hormann implemented algorithm, please read
The \octclip{} package allows you to perform boolean operations (intersection,
union, difference and exclusive or) between two polygons in \octave{} using the
-Greiner-Hormann algorithm\footnote{\cite{greiner1998} and
-\url{http://davis.wpi.edu/~matt/courses/clipping/}}.
-
-Greiner-Hormann is an efficient algorithm for clipping arbitrary 2D polygons.
-The algorithm can handle arbitrary closed polygons, specifically where the
-subject and clip polygons may self-intersect.
+Greiner-Hormann algorithm as presented in \cite{greiner1998}. This method is an
+efficient algorithm for clipping arbitrary 2D polygons. The algorithm can handle
+arbitrary closed polygons included the cases when the subject and/or clipper
+polygons contain self-intersections.
\section{Installation}
@@ -116,132 +117,30 @@ allocation.
To do.
-\section{Examples}
-
-To do.
-
\section{Notes}
Apart from \url{http://octave.sourceforge.net/octclip/index.html}, an up to date
version of \octclip{} can be downloaded from
\url{https://bitbucket.org/jgpallero/octclip/}.
-% \subsection{Geodetic to geocentric and vice versa}
-%
-% \begin{verbatim}
-% lon=-6*pi/180;lat=43*pi/180;h=1000;
-% [x,y,z]=op_geod2geoc(lon,lat,h,6378388,1/297)
-% x = 4647300.72326257
-% y = -488450.988568138
-% z = 4328259.36425774
-%
-% [lon,lat,h]=op_geoc2geod(x,y,z,6378388,1/297);
-% lon*=180/pi,lat*=180/pi,h
-% lon = -6
-% lat = 43
-% h = 1000.00000000074
-% \end{verbatim}
-%
-% \subsection{Forward and inverse projection}
-%
-% \begin{verbatim}
-% lon=-6*pi/180;lat=43*pi/180;
-% [x,y]=op_fwd(lon,lat,'+proj=utm +lon_0=3w +ellps=GRS80')
-% x = 255466.980547577
-% y = 4765182.93268401
-%
-% [lon,lat]=op_inv(x,y,'+proj=utm +lon_0=3w +ellps=GRS80');
-% lon*=180/pi,lat*=180/pi
-% lon = -6.00000000003597
-% lat = 42.9999999999424
-% \end{verbatim}
-%
-% \subsection{Forward and inverse projection: \texttt{op\_transform}}
-%
-% \subsubsection{With altitude}
-%
-% \begin{verbatim}
-% lon=-6*pi/180;lat=43*pi/180;h=1000;
-% [x,y,h]=op_transform(lon,lat,h,'+proj=latlong +ellps=GRS80',...
-% '+proj=utm +lon_0=3w +ellps=GRS80')
-% x = 255466.980547577
-% y = 4765182.93268401
-% h = 1000
-%
-% [lon,lat,h]=op_transform(x,y,h,...
-% '+proj=utm +lon_0=3w +ellps=GRS80',...
-% '+proj=latlong +ellps=GRS80');
-% lon*=180/pi,lat*=180/pi,h
-% lon = -6.00000000003597
-% lat = 42.9999999999424
-% h = 1000
-% \end{verbatim}
-%
-% \subsubsection{Without altitude}
-%
-% \begin{verbatim}
-% lon=-6*pi/180;lat=43*pi/180;
-% [x,y]=op_transform(lon,lat,'+proj=latlong +ellps=GRS80',...
-% '+proj=utm +lon_0=3w +ellps=GRS80')
-% x = 255466.980547577
-% y = 4765182.93268401
-%
-% [lon,lat]=op_transform(x,y,'+proj=utm +lon_0=3w +ellps=GRS80',...
-% '+proj=latlong +ellps=GRS80');
-% lon*=180/pi,lat*=180/pi
-% lon = -6.00000000003597
-% lat = 42.9999999999424
-% \end{verbatim}
-%
-% \subsection{Error due to an erroneous parameter}
-%
-% \begin{verbatim}
-% lon=-6*pi/180;lat=43*pi/180;
-% [x,y]=op_fwd(lon,lat,'+proj=utm +lon_0=3w +ellps=GRS8')
-% error:
-% In function op_fwd:
-% In function _op_fwd:
-% Projection parameters
-% unknown elliptical parameter name
-% +proj=utm +lon_0=3w +ellps=GRS8
-% \end{verbatim}
-%
-% \subsection{Error due to latitude too big}
-%
-% \begin{verbatim}
-% lon=[-6*pi/180;-6*pi/180];lat=[43*pi/180;43];
-% [x,y]=op_fwd(lon,lat,'+proj=utm +lon_0=3w +ellps=GRS80')
-% warning: _op_fwd:
-%
-% warning: Projection error in point 2 (index starts at 1)
-% x =
-%
-% 255466.980547577
-% Inf
-%
-% y =
-%
-% 4765182.93268401
-% Inf
-% \end{verbatim}
-
-\begin{thebibliography}{99}
-\bibitem{eat-om} \textsc{Eaton}, John W.; \textsc{Bateman}, David, and
- \textsc{Hauberg}, S\o{}ren; \textit{GNU Octave. A high-level
- interactive language for numerical computations}; Edition 3 for
- Octave version 3.2.3; July 2007; Permanently updated at
- \url{http://www.gnu.org/software/octave/docs.html}.
+\begin{thebibliography}{9}
+\bibitem{eat-om} \textsc{Eaton}, John W.; \textsc{Bateman}, David;
+ \textsc{Hauberg}, S\o{}ren; and \textsc{Wehbring}, Rik;
+ GNU Octave. A high-level interactive language for numerical
+ computations; Edition 5 for Octave version 5.2.0, January 2020;
+ \url{https://www.gnu.org/software/octave/octave.pdf};
+ Permanently updated at
+ \url{https://www.gnu.org/software/octave/support.html}.
+
\bibitem{greiner1998} \textsc{Greiner}, G\"unter, and \textsc{Hormann}, Kai;
- \textit{Efficient clipping of arbitrary polygons};
- ACM Transactions on Graphics; Volume 17(2), April 1998;
- Pages 71--83.
- There is a web link with some example code at
- \url{http://davis.wpi.edu/~matt/courses/clipping/}.
-\bibitem{kim2006a} \textsc{Kim}, Dae Hyun, and \textsc{Kim}, Myoung-Jun;
- \textit{An Extension of Polygon Clipping To Resolve
- Degenerate Cases};
- Computer-Aided Design \& Applications; Vol. 3; Numbers 1--4,
- 2006; Pages 447--456.
+ \textit{Efficient clipping of arbitrary polygons}; ACM
+ Transactions on Graphics; Volume 17(2), April 1998;
+ Pages 71--83. There is a web link with some example code
+ at \url{http://davis.wpi.edu/~matt/courses/clipping/}.
\end{thebibliography}
\end{document}
+
+%Copyright (C) 2011-2020, José Luis García Pallero, <jgpallero@gmail.com>
+%This document is distributed under the terms of the GNU Free Documentation
+%License. Please, see http://www.gnu.org/licenses/
diff --git a/inst/oc_polybool.m b/inst/oc_polybool.m
index 2ed1608..92b85af 100644
--- a/inst/oc_polybool.m
+++ b/inst/oc_polybool.m
@@ -1,4 +1,4 @@
-## Copyright (C) 2011-2015, José Luis García Pallero, <jgpallero@gmail.com>
+## Copyright (C) 2011-2020, José Luis García Pallero, <jgpallero@gmail.com>
##
## This file is part of OctCLIP.
##
@@ -17,61 +17,88 @@
## <http://www.gnu.org/licenses/>.
## -*- texinfo -*-
-## @deftypefn{Function File}{[@var{X},@var{Y},@var{nPol},@var{nInt},@var{nPert}] =}oc_polybool(@var{sub},@var{clip},@var{op})
-## @deftypefnx{Function File}{[@var{X},@var{Y},@var{nPol},@var{nInt},@var{nPert}] =}oc_polybool(@var{sub},@var{clip})
+## @deftypefn {}{[@var{p},@var{details}] =}_oc_polybool(@var{sub},@var{clip})
+## @deftypefnx {}{[@var{p},@var{details}] =}_oc_polybool(@var{sub},@var{clip},@var{op})
+## @deftypefnx {}{[@var{p},@var{details}] =}_oc_polybool(@var{sub},@var{clip},@var{op},@var{hor})
+##
+## @cindex Performs boolean operations between two polygons.
##
## This function performs boolean operations between two polygons using the
-## Greiner-Hormann algorithm (http://davis.wpi.edu/~matt/courses/clipping/).
+## Greiner-Hormann algorithm as it is presented in
+## http://davis.wpi.edu/~matt/courses/clipping/
##
## @var{sub} is a two column matrix containing the X and Y coordinates of the
-## vertices for the subject polygon.
+## vertices for the subject polygon (it must be unique, although
+## self-intersections are permitted).
##
## @var{clip} is a two column matrix containing the X and Y coordinates of the
-## vertices for the clipper polygon.
+## vertices for the clipper polygon(it must be unique, although
+## self-intersections are permitted).
##
## @var{op} is a text string containing the operation to perform between
## @var{sub} and @var{clip}. Possible values are:
##
## @itemize @bullet
## @item @var{'AND'}
-## Intersection of @var{sub} and @var{clip} (value by default).
+## Intersection of @var{sub} and @var{clip}. This value is set by default.
## @item @var{'OR'}
-## Union of @var{subt} and @var{clip}.
+## Union of @var{sub} and @var{clip}.
## @item @var{'AB'}
## Operation @var{sub} - @var{clip}.
## @item @var{'BA'}
## Operation of @var{clip} - @var{sub}.
+## @item @var{'XOR'}
+## Exclusive disjunction between @var{clip} and @var{sub}. This operation is
+## performed as the joining of 'AB' and 'BA' consecutively applied
## @end itemize
##
+## @var{hor} is an identifier for performing (value 1, by default) or not
+## (value 0) the searching for holes in the result of the operation OR. When OR
+## is applied with non convex entities some of the resulting polygons can be
+## actually holes. Activating this argument the possible holes are identified.
+## If the operation is other than OR the value of this argument is irrelevant
+##
## For the matrices @var{sub} and @var{clip}, the first point is not needed to
## be repeated at the end (but is permitted). Pairs of (NaN,NaN) coordinates in
## @var{sub} and/or @var{clip} are omitted, so they are treated as if each one
-## stored a single polygon.
+## stored a single polygon, i.e., this function does not admit boolean
+## operations between multiple polygons of between polygons with holes, although
+## polygons containing self-intersections are permitted
##
-## @var{X} is a column vector containing the X coordinates of the vertices of
-## the resultant polygon(s).
+## @var{p} is a two column matrix containing the X and Y coordinates of the
+## vertices of the resultant polygon(s). If the result consist of multiple
+## polygons they are separated by rows os (NaN,NaN) values.
##
-## @var{Y} is a column vector containing the Y coordinates of the vertices of
-## the resultant polygon(s).
+## @var{details} is a struct containing details of the computation. Its fields
+## (IN LOWERCASE!) are:
##
-## @var{nPol} is the number of output polygons.
+## @itemize @bullet
+## @item @var{poly}
+## Three-column matrix with a number of rows equal to the number of polygons
+## stored in the matrix @var{p}. The first column stores the row of @var{p}
+## where the corresponding polygon starts, the second column the row of @var{p}
+## where the polygon end, and the third colum is a mark identifying if the
+## polygon is a hole (value 0) or not (value 1). The values of the third column
+## are relevant only in the case of the OR operation
+## @item @var{nint}
+## Number of intersections between @var{sub} and @var{clip}.
+## @item @var{npert}
+## Number of perturbed points of the @var{clip} polygon if any particular case
+## (points in the border of the other polygon) occurs see
+## http://davis.wpi.edu/~matt/courses/clipping/ for details.
+## @end itemize
##
-## @var{nInt} is the number of intersections between @var{sub} and @var{clip}.
+## This function does not check if the dimensions of @var{sub} and @var{clip}
+## are correct.
##
-## @var{nPert} is the number of perturbed points of the @var{clip} polygon in
-## any particular case (points in the oborder of the other polygon) occurs see
-## http://davis.wpi.edu/~matt/courses/clipping/ for details.
## @end deftypefn
-
-
-
-function [X,Y,nPol,nInt,nPert] = oc_polybool(sub,clip,op)
+function [p,details] = oc_polybool(sub,clip,op,hor)
try
functionName = 'oc_polybool';
minArg = 2;
- maxArg = 3;
+ maxArg = 4;
%*******************************************************************************
%NUMBER OF INPUT ARGUMENTS CHECKING
@@ -83,10 +110,18 @@ try
'Correct number of input arguments = %d or %d'],...
nargin,minArg,maxArg);
end
- %check if we omit the op argument
- if nargin==minArg
- %by default, use AND
- op = 'AND';
+ %values by default
+ opDef = 'AND';
+ horDef = 1;
+ %check if we omit some input arguments
+ if nargin<maxArg
+ %hor by default
+ hor = horDef;
+ %check for op
+ if nargin==minArg
+ %op by default
+ op = opDef;
+ end
end
%*******************************************************************************
@@ -106,7 +141,11 @@ end
try
%calling oct function
- [X,Y,nPol,nInt,nPert] = _oc_polybool(sub,clip,op);
+ [p,pp,nInt,nPert] = _oc_polybool(sub,clip,op,hor);
+ %creation of the output struct
+ details.poly = pp;
+ details.nint = nInt;
+ details.npert = nPert;
catch
%error message
error('\n\tIn function %s:\n\tIn function %s ',functionName,lasterr);
@@ -147,10 +186,10 @@ if ~ischar(inOp)
error('The third input argument is not a text string');
else
%upper case
- outOp = toupper(inOp);
+ outOp = upper(inOp);
%check values
if (~strcmp(outOp,'AND'))&&(~strcmp(outOp,'OR'))&& ...
- (~strcmp(outOp,'AB'))&&(~strcmp(outOp,'BA'))
+ (~strcmp(outOp,'AB'))&&(~strcmp(outOp,'BA'))&&(~strcmp(outOp,'XOR'))
error('The third input argument is not correct');
end
end
@@ -170,7 +209,8 @@ end
%tests for input arguments
%!error(oc_polybool)
-%!error(oc_polybool(1,2,3,4))
+%!error(oc_polybool(1))
+%!error(oc_polybool(1,2,3,4,5))
%!error(oc_polybool('string',2,3))
%!error(oc_polybool(1,'string',3))
%!error(oc_polybool(1,2,3))
@@ -208,56 +248,207 @@ end
%! clXLim = [1.5 11.75];
%! clYLim = [0.5 8.50];
%! %compute intersection
-%! [clXI,clYI] = oc_polybool(clSub,clClip,'and');
+%! [pI,detI] = oc_polybool(clSub,clClip,'and');
%! %compute union
-%! [clXU,clYU] = oc_polybool(clSub,clClip,'or');
+%! [pU,detU] = oc_polybool(clSub,clClip,'or',1);
%! %compute A-B
-%! [clXA,clYA] = oc_polybool(clSub,clClip,'ab');
+%! [pA,detA] = oc_polybool(clSub,clClip,'ab');
%! %compute B-A
-%! [clXB,clYB] = oc_polybool(clSub,clClip,'ba');
+%! [pB,detB] = oc_polybool(clSub,clClip,'ba');
+%! %compute XOR
+%! [pX,detX] = oc_polybool(clSub,clClip,'xor');
+%! %plotting
+%! figure(1);
+%! %plot window for original data
+%! subplot(3,2,1);
+%! plot(clSub(:,1),clSub(:,2),clClip(:,1),clClip(:,2));
+%! axis('equal');
+%! xlim(clXLim);
+%! ylim(clYLim);
+%! title('Original polygons');
+%! legend('Subject polygon','Clipper polygon','location','southeast');
%! %plot window for intersection
-%! subplot(2,2,1);
-%! plot(clXI,clYI,'r.-','markersize',10,'linewidth',3,clSub(:,1),clSub(:,2),...
-%! clClip(:,1),clClip(:,2));
+%! subplot(3,2,2);
+%! hold('on');
+%! for i=1:size(detI.poly,1)
+%! pS = detI.poly(i,1);
+%! pE = detI.poly(i,2);
+%! fill(pI(pS:pE,1),pI(pS:pE,2),'r');
+%! end
+%! hold('off');
%! axis('equal');
%! xlim(clXLim);
%! ylim(clYLim);
%! title('OctCLIP intersection');
-%! legend('Intersection','Subject polygon','Clipper polygon',...
-%! 'location','southeast');
%! %plot window for union
-%! subplot(2,2,2);
-%! plot(clXU,clYU,'r.-','markersize',10,'linewidth',3,clSub(:,1),clSub(:,2),...
-%! clClip(:,1),clClip(:,2));
+%! subplot(3,2,3);
+%! hold('on');
+%! for i=1:size(detU.poly,1)
+%! pS = detU.poly(i,1);
+%! pE = detU.poly(i,2);
+%! if detU.poly(i,3)~=0
+%! fill(pU(pS:pE,1),pU(pS:pE,2),'r');
+%! else
+%! hax = fill(pU(pS:pE,1),pU(pS:pE,2),'b');
+%! legend(hax,'Holes');
+%! end
+%! end
+%! hold('off');
%! axis('equal');
%! xlim(clXLim);
%! ylim(clYLim);
%! title('OctCLIP union');
-%! legend('Union','Subject polygon','Clipper polygon','location','southeast');
%! %plot window for A-B
-%! subplot(2,2,3);
-%! plot(clXA,clYA,'r.-','markersize',10,'linewidth',3,clSub(:,1),clSub(:,2),...
-%! clClip(:,1),clClip(:,2));
+%! subplot(3,2,4);
+%! hold('on');
+%! for i=1:size(detA.poly,1)
+%! pS = detA.poly(i,1);
+%! pE = detA.poly(i,2);
+%! fill(pA(pS:pE,1),pA(pS:pE,2),'r');
+%! end
+%! hold('off');
%! axis('equal');
%! xlim(clXLim);
%! ylim(clYLim);
%! title('OctCLIP A-B');
-%! legend('A-B','Subject polygon','Clipper polygon','location','southeast');
%! %plot window for B-A
-%! subplot(2,2,4);
-%! plot(clXB,clYB,'r.-','markersize',10,'linewidth',3,clSub(:,1),clSub(:,2),...
-%! clClip(:,1),clClip(:,2));
+%! subplot(3,2,5);
+%! hold('on');
+%! for i=1:size(detB.poly,1)
+%! pS = detB.poly(i,1);
+%! pE = detB.poly(i,2);
+%! fill(pB(pS:pE,1),pB(pS:pE,2),'r');
+%! end
+%! hold('off');
%! axis('equal');
%! xlim(clXLim);
%! ylim(clYLim);
%! title('OctCLIP B-A');
-%! legend('B-A','Subject polygon','Clipper polygon','location','southeast');
+%! %plot window for XOR
+%! subplot(3,2,6);
+%! hold('on');
+%! for i=1:size(detX.poly,1)
+%! pS = detX.poly(i,1);
+%! pE = detX.poly(i,2);
+%! fill(pX(pS:pE,1),pX(pS:pE,2),'r');
+%! end
+%! hold('off');
+%! axis('equal');
+%! xlim(clXLim);
+%! ylim(clYLim);
+%! title('OctCLIP XOR');
%! %input message
%! disp('Press ENTER to continue ...');
%! pause();
-%! %kill and close the plot window
-%! clf();
-%! close();
+%!
+%! %subject polygon
+%! clSub = [1000.0 1000.0
+%! 2000.0 1000.0
+%! 2000.0 2800.0
+%! 800.0 2800.0
+%! 2400.0 1900.0
+%! 1000.0 1000.0];
+%! %clipper polygon
+%! clClip = [ 300.0 2500.0
+%! 2500.0 2600.0
+%! 1600.0 600.0
+%! 1300.0 3100.0
+%! 500.0 900.0
+%! 300.0 2500.0];
+%! %limits for the plots
+%! auxLim = [clSub;clClip];
+%! clXLim = [min(auxLim(:,1)) max(auxLim(:,1))];
+%! clYLim = [min(auxLim(:,2)) max(auxLim(:,2))];
+%! %compute intersection
+%! [pI,detI] = oc_polybool(clSub,clClip,'and');
+%! %compute union
+%! [pU,detU] = oc_polybool(clSub,clClip,'or',1);
+%! %compute A-B
+%! [pA,detA] = oc_polybool(clSub,clClip,'ab');
+%! %compute B-A
+%! [pB,detB] = oc_polybool(clSub,clClip,'ba');
+%! %compute XOR
+%! [pX,detX] = oc_polybool(clSub,clClip,'xor');
+%! %plotting
+%! figure(2);
+%! %plot window for original data
+%! subplot(3,2,1);
+%! plot(clSub(:,1),clSub(:,2),clClip(:,1),clClip(:,2));
+%! axis('equal');
+%! xlim(clXLim);
+%! ylim(clYLim);
+%! title('Original polygons');
+%! legend('Subject polygon','Clipper polygon','location','southeast');
+%! %plot window for intersection
+%! subplot(3,2,2);
+%! hold('on');
+%! for i=1:size(detI.poly,1)
+%! pS = detI.poly(i,1);
+%! pE = detI.poly(i,2);
+%! fill(pI(pS:pE,1),pI(pS:pE,2),'r');
+%! end
+%! hold('off');
+%! axis('equal');
+%! xlim(clXLim);
+%! ylim(clYLim);
+%! title('OctCLIP intersection');
+%! %plot window for union
+%! subplot(3,2,3);
+%! hold('on');
+%! for i=1:size(detU.poly,1)
+%! pS = detU.poly(i,1);
+%! pE = detU.poly(i,2);
+%! if detU.poly(i,3)~=0
+%! fill(pU(pS:pE,1),pU(pS:pE,2),'r');
+%! else
+%! hax = fill(pU(pS:pE,1),pU(pS:pE,2),'b');
+%! legend(hax,'Holes');
+%! end
+%! end
+%! hold('off');
+%! axis('equal');
+%! xlim(clXLim);
+%! ylim(clYLim);
+%! title('OctCLIP union');
+%! %plot window for A-B
+%! subplot(3,2,4);
+%! hold('on');
+%! for i=1:size(detA.poly,1)
+%! pS = detA.poly(i,1);
+%! pE = detA.poly(i,2);
+%! fill(pA(pS:pE,1),pA(pS:pE,2),'r');
+%! end
+%! hold('off');
+%! axis('equal');
+%! xlim(clXLim);
+%! ylim(clYLim);
+%! title('OctCLIP A-B');
+%! %plot window for B-A
+%! subplot(3,2,5);
+%! hold('on');
+%! for i=1:size(detB.poly,1)
+%! pS = detB.poly(i,1);
+%! pE = detB.poly(i,2);
+%! fill(pB(pS:pE,1),pB(pS:pE,2),'r');
+%! end
+%! hold('off');
+%! axis('equal');
+%! xlim(clXLim);
+%! ylim(clYLim);
+%! title('OctCLIP B-A');
+%! %plot window for XOR
+%! subplot(3,2,6);
+%! hold('on');
+%! for i=1:size(detX.poly,1)
+%! pS = detX.poly(i,1);
+%! pE = detX.poly(i,2);
+%! fill(pX(pS:pE,1),pX(pS:pE,2),'r');
+%! end
+%! hold('off');
+%! axis('equal');
+%! xlim(clXLim);
+%! ylim(clYLim);
+%! title('OctCLIP XOR');
diff --git a/src/Makefile b/src/Makefile
index 454d544..e15c37a 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#Compiler
-MKOCTFILE=mkoctfile
+MKOCTFILE?=mkoctfile
#Common warning flags for C and C++
FLAGSCOMW=-Wall -Wextra -Wshadow -Wcast-qual -Wcast-align -Wwrite-strings
#Common optimization flags for C and C++
@@ -20,12 +20,18 @@ all: compile
compile:
$(MKOCTFILE) -c -I. calctopo.c -o calctopo.o
$(MKOCTFILE) -c -I. compilador.c -o compilador.o
+ $(MKOCTFILE) -c -I. dpeuckera.c -o dpeuckera.o
+ $(MKOCTFILE) -c -I. dpeuckere.c -o dpeuckere.o
+ $(MKOCTFILE) -c -I. dpeuckerp.c -o dpeuckerp.o
$(MKOCTFILE) -c -I. dpeucker.c -o dpeucker.o
$(MKOCTFILE) -c -I. errores.c -o errores.o
$(MKOCTFILE) -c -I. eucli.c -o eucli.o
$(MKOCTFILE) -c -I. fgeneral.c -o fgeneral.o
$(MKOCTFILE) -c -I. geocnan.c -o geocnan.o
$(MKOCTFILE) -c -I. geocomp.c -o geocomp.o
+ $(MKOCTFILE) -c -I. -DCOLUMN_MAJOR_ORDER_MATVEC posmatvec.c -o posmatvec.o
+ $(MKOCTFILE) -c -I. -DCALCULO_PRODUCTO_MULT mate.c -o mate.o
+ $(MKOCTFILE) -c -I. arco.c -o arco.o
$(MKOCTFILE) -c -I. greiner.c -o greiner.o
$(MKOCTFILE) -c -I. polig.c -o polig.o
$(MKOCTFILE) -c -I. polil.c -o polil.o
@@ -33,6 +39,7 @@ compile:
$(MKOCTFILE) -c -I. recpolil.c -o recpolil.o
$(MKOCTFILE) -c -I. segmento.c -o segmento.o
$(MKOCTFILE) -c -I. ventorno.c -o ventorno.o
+ $(MKOCTFILE) -c -I. proyecaux.c -o proyecaux.o
$(MKOCTFILE) -s -I. _oc_polybool.cc *.o
.PHONY: clean
diff --git a/src/_oc_polybool.cc b/src/_oc_polybool.cc
index bcee558..058bdf8 100644
--- a/src/_oc_polybool.cc
+++ b/src/_oc_polybool.cc
@@ -1,5 +1,5 @@
/* -*- coding: utf-8 -*- */
-/* Copyright (C) 2011-2015 José Luis García Pallero, <jgpallero@gmail.com>
+/* Copyright (C) 2011-2020 José Luis García Pallero, <jgpallero@gmail.com>
*
* This file is part of OctCLIP.
*
@@ -21,8 +21,7 @@
/******************************************************************************/
#define HELPTEXT "\
-*- texinfo -*-\n\
-@deftypefn{Loadable Function}{[@var{X},@var{Y},@var{nPol},@var{nInt},\
-@var{nPert}] =}_oc_polybool(@var{sub},@var{clip},@var{op})\n\
+@deftypefn {}{[@var{p},@var{pp},@var{ni},@var{np}] =}_oc_polybool(@var{sub},@var{clip},@var{op},@var{hor})\n\
\n\
@cindex Performs boolean operations between two polygons.\n\
\n\
@@ -30,9 +29,11 @@ This function performs boolean operations between two polygons using the\n\
Greiner-Hormann algorithm (http://davis.wpi.edu/~matt/courses/clipping/).\n\
\n\
@var{sub} is a two column matrix containing the X and Y coordinates of the\n\
-vertices for the subject polygon.\n\n\
+vertices for the subject polygon (it must be unique, although\n\
+self-intersections are permitted).\n\n\
@var{clip} is a two column matrix containing the X and Y coordinates of the\n\
-vertices for the clipper polygon.\n\n\
+vertices for the clipper polygon(it must be unique, although\n\
+self-intersections are permitted).\n\n\
@var{op} is a text string containing the operation to perform between\n\
@var{sub} and @var{clip}. Possible values are:\n\
\n\
@@ -40,26 +41,43 @@ vertices for the clipper polygon.\n\n\
@item @var{'AND'}\n\
Intersection of @var{sub} and @var{clip}.\n\n\
@item @var{'OR'}\n\
-Union of @var{subt} and @var{clip}.\n\n\
+Union of @var{sub} and @var{clip}.\n\n\
@item @var{'AB'}\n\
Operation @var{sub} - @var{clip}.\n\n\
@item @var{'BA'}\n\
-Operation of @var{clip} - @var{sub}.\n\
+Operation of @var{clip} - @var{sub}.\n\n\
+@item @var{'XOR'}\n\
+Exclusive disjunction between @var{clip} and @var{sub}. This operation is\n\
+performed as the joining of 'AB' and 'BA' consecutively applied\n\
@end itemize\n\
\n\
+@var{hor} is an identifier for performing (value 1) or not (value 0) the\n\
+searching for holes in the result of the operation OR. When OR is applied\n\
+with non convex entities some of the resulting polygons can be actually\n\
+holes. Activating this argument the possible holes are identified. If the\n\
+operation is other than OR the value of this argument is irrelevant\n\
+\n\
For the matrices @var{sub} and @var{clip}, the first point is not needed to\n\
be repeated at the end (but is permitted). Pairs of (NaN,NaN) coordinates in\n\
@var{sub} and/or @var{clip} are omitted, so they are treated as if each one\n\
-stored a single polygon.\n\
+stored a single polygon, i.e., this function does not admit boolean\n\
+operations between multiple polygons of between polygons with holes, although\n\
+polygons containing self-intersections are permitted\n\
+\n\
+The output arguments are:\n\
\n\
-@var{X} is a column vector containing the X coordinates of the vertices of\n\
-the resultant polygon(s).\n\n\
-@var{Y} is a column vector containing the Y coordinates of the vertices of\n\
-the resultant polygon(s).\n\n\
-@var{nPol} is the number of output polygons.\n\n\
-@var{nInt} is the number of intersections between @var{sub} and @var{clip}.\n\n\
-@var{nPert} is the number of perturbed points of the @var{clip} polygon in\n\
-any particular case (points in the oborder of the other polygon) occurs see\n\
+@var{p} is a two column matrix containing the X and Y coordinates of the\n\
+vertices of the resultant polygon(s). If the result consist of multiple\n\
+polygons they are separated by rows os (NaN,NaN) values.\n\n\
+@var{pp} is a three-column matrix with a number of rows equal to the number\n\
+of polygons stored in the matrix @var{p}. The first column stores the row of\n\
+@var{p} where the corresponding polygon starts, the second column the row of\n\
+@var{p} where the polygon end, and the third colum is a mark identifying if\n\
+the polygon is a hole (value 0) or not (value 1). The values of the third\n\
+column are relevant only in the case of the OR operation\n\n\
+@var{ni} is the number of intersections between @var{sub} and @var{clip}.\n\n\
+@var{np} is the number of perturbed points of the @var{clip} polygon if any\n\
+particular case (points in the border of the other polygon) occurs see\n\
http://davis.wpi.edu/~matt/courses/clipping/ for details.\n\
\n\
This function do not check if the dimensions of @var{sub} and @var{clip} are\n\
@@ -88,7 +106,7 @@ DEFUN_DLD(_oc_polybool,args,,HELPTEXT)
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
//checking input arguments
- if(args.length()!=3)
+ if(args.length()!=4)
{
//error text
sprintf(&errorText[strlen(errorText)],
@@ -107,6 +125,7 @@ DEFUN_DLD(_oc_polybool,args,,HELPTEXT)
ColumnVector xClip=args(1).matrix_value().column(0);
ColumnVector yClip=args(1).matrix_value().column(1);
std::string opchar=args(2).string_value();
+ int sfh=args(3).int_value();
//computation vectors
double* xA=NULL;
double* yA=NULL;
@@ -122,7 +141,7 @@ DEFUN_DLD(_oc_polybool,args,,HELPTEXT)
//number of polygons, intersections and perturbations
size_t nPol=0,nInter=0,nPert=0;
//number of elements for the output vectors
- size_t nElem=0;
+ size_t nElem=0,posStart=0,posEnd=0,pos=0;
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
//pointers to data
@@ -131,8 +150,8 @@ DEFUN_DLD(_oc_polybool,args,,HELPTEXT)
xB = xClip.fortran_vec();
yB = yClip.fortran_vec();
//create double linked lists for subject and clipper polygons
- polA = CreaPoliClip(xA,yA,static_cast<size_t>(xSubj.length()),1,1);
- polB = CreaPoliClip(xB,yB,static_cast<size_t>(xClip.length()),1,1);
+ polA = CreaPoliClip(xA,yA,static_cast<size_t>(xSubj.numel()),1,1);
+ polB = CreaPoliClip(xB,yB,static_cast<size_t>(xClip.numel()),1,1);
//error checking
if((polB==NULL)||(polB==NULL))
{
@@ -165,6 +184,11 @@ DEFUN_DLD(_oc_polybool,args,,HELPTEXT)
{
op = GeocOpBoolBA;
}
+ else if((!strcmp(opchar.c_str(),"XOR"))||
+ (!strcmp(opchar.c_str(),"xor")))
+ {
+ op = GeocOpBoolXor;
+ }
else
{
//free peviously allocated memory
@@ -182,7 +206,7 @@ DEFUN_DLD(_oc_polybool,args,,HELPTEXT)
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
//clipping
- result = PoliBoolGreiner(polA,polB,op,GEOC_GREINER_FAC_EPS_PERTURB,
+ result = PoliBoolGreiner(polA,polB,op,GEOC_GREINER_FAC_EPS_PERTURB,sfh,
&nInter,&nPert);
//error checking
if(result==NULL)
@@ -201,32 +225,55 @@ DEFUN_DLD(_oc_polybool,args,,HELPTEXT)
////////////////////////////////////////////////////////////////////////
//number or output polygons
nPol = result->nPolig;
+ //output matrix
+ Matrix pp(nPol,3);
//dimensions for the output vectors
if(nPol)
{
+ //Number of elements
nElem = result->nElem;
+ posStart = 0;
+ posEnd = nElem-1;
+ if(EsGeocNan(result->x[0]))
+ {
+ nElem--;
+ posStart = 1;
+ }
+ if(EsGeocNan(result->x[posEnd]))
+ {
+ nElem--;
+ posEnd = result->nElem-2;
+ }
+ //output polygons data
+ for(i=0;i<nPol;i++)
+ {
+ //positions start in 1
+ pp(i,0) = result->posIni[i]+1-posStart;
+ pp(i,1) = pp(i,0)+result->nVert[i]-1;
+ pp(i,2) = result->atr[i];
+ }
}
else
{
nElem = 0;
}
- //output vectors
- ColumnVector xResult(nElem);
- ColumnVector yResult(nElem);
+ //output matrix
+ Matrix p(nElem,2);
//copy output data
- for(i=0;i<nElem;i++)
+ pos = 0;
+ for(i=posStart;i<=posEnd;i++)
{
- xResult(i) = result->x[i];
- yResult(i) = result->y[i];
+ p(pos,0) = result->x[i];
+ p(pos,1) = result->y[i];
+ pos++;
}
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
//output parameters list
- outputList(0) = xResult;
- outputList(1) = yResult;
- outputList(2) = nPol;
- outputList(3) = nInter;
- outputList(4) = nPert;
+ outputList(0) = p;
+ outputList(1) = pp;
+ outputList(2) = nInter;
+ outputList(3) = nPert;
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
//free memory
diff --git a/src/arco.c b/src/arco.c
new file mode 100644
index 0000000..e8a7fa6
--- /dev/null
+++ b/src/arco.c
@@ -0,0 +1,910 @@
+/* -*- coding: utf-8 -*- */
+/**
+\ingroup geom
+@{
+\file arco.c
+\brief Definición de funciones para la realización de cálculos con arcos de
+ circunferencia.
+\author José Luis García Pallero, jgpallero@gmail.com
+\date 08 de agosto de 2013
+\copyright
+Copyright (c) 2013, José Luis García Pallero. All rights reserved.
+\par
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+\par
+- Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+- Neither the name of the copyright holders nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+\par
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/******************************************************************************/
+/******************************************************************************/
+#include"libgeoc/arco.h"
+/******************************************************************************/
+/******************************************************************************/
+int ArcosCircMaxDisjuntos(const double tol,
+ const double lonMin1,
+ const double lonMax1,
+ const double lonMin2,
+ const double lonMax2)
+{
+ //comprobamos los casos de trabajo
+ if(((lonMax1-lonMin1)>(GEOC_CONST_PI-tol))||
+ ((lonMax2-lonMin2)>(GEOC_CONST_PI-tol)))
+ {
+ //indicamos que no son disjuntos, aunque en puridad no lo podemos decir,
+ //pero estos casos son difíciles de determinar porque el arco cruza el
+ //meridiano origen o su antimeridiano
+ return 0;
+ }
+ else
+ {
+ //consideramos únicamente solapamientos en longitud
+ return (!((lonMin1<(lonMax2+tol))&&(lonMax1>(lonMin2-tol))));
+ }
+}
+/******************************************************************************/
+/******************************************************************************/
+double AcimutArcoCircMaxEsf(const double tol,
+ const double latA,
+ const double lonA,
+ const double latB,
+ const double lonB,
+ double mRot[][3])
+{
+ //variables auxiliares
+ double sLat=0.0,cLat=0.0,sLon=0.0,cLon=0.0;
+ double x=0.0,y=0.0,z=0.0,yR=0.0,zR=0.0;
+ //variable de salida
+ double aci=0.0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //calculamos las razones trigonométricas de las coordenadas del vértice A
+ sLat = sin(latA);
+ cLat = cos(latA);
+ sLon = sin(lonA);
+ cLon = cos(lonA);
+ //construimos la matriz de rotación para llevar el punto A a (lat=0,lon=0)
+ //primero se rota en torno a Z el valor de la longitud, y luego en torno a Y
+ //el valor -latitud
+ //tal y como aquí se aplican, las rotaciones giran el sistema de coordenadas
+ //en lugar del radio vector del punto de trabajo
+ // | cos(lon) sin(lon) 0|
+ //Rz = |-sin(lon) cos(lon) 0|
+ // | 0 0 1|
+ //
+ // |cos(-lat) 0 -sin(-lat)| | cos(lat) 0 sin(lat)|
+ //Ry = | 0 1 0| = | 0 1 1|
+ // |sin(-lat) 0 cos(-lat)| |-sin(lat) 0 cos(lat)|
+ //
+ //la matriz de rotación es, entonces R = Ry*Rz, donde este orden de
+ //multiplicación de las matrices indica que primero se rota en torno a Z y
+ //luego en torno a Y
+ mRot[0][0] = cLat*cLon;
+ mRot[0][1] = cLat*sLon;
+ mRot[0][2] = sLat;
+ mRot[1][0] = -sLon;
+ mRot[1][1] = cLon;
+ mRot[1][2] = 0.0;
+ mRot[2][0] = -sLat*cLon;
+ mRot[2][1] = -sLat*sLon;
+ mRot[2][2] = cLat;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //comprobamos si los puntos son coincidentes
+ //aunque esta comprobación se podría haber hecho al principio, se hace aquí
+ //para poder construir previamente la matriz de rotación que lleve al punto
+ //A a (lat=0,lon=0)
+ if(GEOC_ES_CERO(latA-latB,tol)&&GEOC_ES_CERO(lonA-lonB,tol))
+ {
+ //imponemos un acimut igual a 0.0
+ aci = 0.0;
+ //salimos de la función
+ return aci;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //transformamos las coordenadas del extremo B a cartesianas
+ cLat = cos(latB);
+ x = cLat*cos(lonB);
+ y = cLat*sin(lonB);
+ z = sin(latB);
+ //transformamos al nuevo sistema las coordenadas Y y Z de B
+ AplicaMatrizRotacionCoorCart(1,x,y,z,mRot,NULL,&yR,&zR);
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //esta variable es como si fuera una especie de longitud de B en un sistema
+ //en el cual el eje de rotación fuese el X del nuevo sistema
+ //si es >= 0.0, es ya directamente el acimut buscado
+ aci = atan2(yR,zR);
+ //metemos la variable auxiliar en el dominio [0,2*pi), si ha lugar
+ if(aci<0.0)
+ {
+ aci += 2.0*GEOC_CONST_PI;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return aci;
+}
+/******************************************************************************/
+/******************************************************************************/
+void RotaArco00Ecuador(const double tol,
+ const double latA,
+ const double lonA,
+ const double latB,
+ const double lonB,
+ double mRot[][3],
+ double* lonBR)
+{
+ //coordenadas cartesianas
+ double x=0.0,y=0.0,z=0.0,xR=0.0,yR=0.0;
+ //matriz de rotación auxiliar
+ double mRotAux[3][3];
+ //acimut del arco AB
+ double aci=0.0;
+ //variables auxiliares
+ double alfa=0.0,cLat=0.0,sAlfa=0.0,cAlfa=0.0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //roto el sistema para llevar el punto A al punto (lat=0,lon=0)
+ aci = AcimutArcoCircMaxEsf(tol,latA,lonA,latB,lonB,mRotAux);
+ //el ángulo a rotar sobre el eje X será 90-aci
+ alfa = GEOC_CONST_PI/2.0-aci;
+ //calculo la matriz de rotación
+ //tal y como aquí se aplica, las rotación gira el sistema de coordenadas en
+ //lugar del radio vector del punto de trabajo
+ // |1 0 0|
+ //Rx = |0 cos(alfa) sin(alfa)|
+ // |0 -sin(alfa) con(alfa)|
+ //la matriz de rotación es, entonces R = Rx*mRotAux, donde este orden de
+ //multiplicación de las matrices indica que primero se rota en torno a los
+ //ejes que indique mRorAux y luego en torno a X
+ sAlfa = sin(alfa);
+ cAlfa = cos(alfa);
+ mRot[0][0] = mRotAux[0][0];
+ mRot[0][1] = mRotAux[0][1];
+ mRot[0][2] = mRotAux[0][2];
+ mRot[1][0] = cAlfa*mRotAux[1][0]+sAlfa*mRotAux[2][0];
+ mRot[1][1] = cAlfa*mRotAux[1][1]+sAlfa*mRotAux[2][1];
+ mRot[1][2] = sAlfa*mRotAux[2][2]; //+cAlfa*mRotAux[1][2], mRotAux[1][2]==0.0
+ mRot[2][0] = -sAlfa*mRotAux[1][0]+cAlfa*mRotAux[2][0];
+ mRot[2][1] = -sAlfa*mRotAux[1][1]+cAlfa*mRotAux[2][1];
+ mRot[2][2] = cAlfa*mRotAux[2][2]; //-sAlfa*mRotAux[1][2], mRotAux[1][2]==0.0
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //comprobamos si hay que calcular la longitud de B en el nuevo sistema
+ if(lonBR!=NULL)
+ {
+ //transformamos las coordenadas del extremo B a cartesianas
+ cLat = cos(latB);
+ x = cLat*cos(lonB);
+ y = cLat*sin(lonB);
+ z = sin(latB);
+ //calculamos las coordenadas X e Y de B en el nuevo sistema
+ AplicaMatrizRotacionCoorCart(1,x,y,z,mRot,&xR,&yR,NULL);
+ //calculamos la longitud de B en el nuevo sistema
+ *lonBR = atan2(yR,xR);
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return;
+}
+/******************************************************************************/
+/******************************************************************************/
+void AplicaMatrizRotacionCoorCart(const int sentido,
+ const double x,
+ const double y,
+ const double z,
+ double mRot[][3],
+ double* xR,
+ double* yR,
+ double* zR)
+{
+ //comprobamos el sentido de la rotación
+ if(sentido>=0)
+ {
+ //transformamos las coordenadas que se hayan pedido
+ if(xR!=NULL)
+ {
+ *xR = mRot[0][0]*x+mRot[0][1]*y+mRot[0][2]*z;
+ }
+ if(yR!=NULL)
+ {
+ *yR = mRot[1][0]*x+mRot[1][1]*y+mRot[1][2]*z;
+ }
+ if(zR!=NULL)
+ {
+ *zR = mRot[2][0]*x+mRot[2][1]*y+mRot[2][2]*z;
+ }
+ }
+ else
+ {
+ //transformamos las coordenadas que se hayan pedido
+ if(xR!=NULL)
+ {
+ *xR = mRot[0][0]*x+mRot[1][0]*y+mRot[2][0]*z;
+ }
+ if(yR!=NULL)
+ {
+ *yR = mRot[0][1]*x+mRot[1][1]*y+mRot[2][1]*z;
+ }
+ if(zR!=NULL)
+ {
+ *zR = mRot[0][2]*x+mRot[1][2]*y+mRot[2][2]*z;
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return;
+}
+/******************************************************************************/
+/******************************************************************************/
+void AplicaMatrizRotacionCoorGeod(const int sentido,
+ const double lat,
+ const double lon,
+ double mRot[][3],
+ double* latR,
+ double* lonR)
+{
+ //variables auxiliares
+ double x=0.0,y=0.0,z=0.0,xR=0.0,yR=0.0,zR=0.0,cLat=0.0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //comprobamos si hay que hacer cálculos
+ if((latR!=NULL)||(lonR!=NULL))
+ {
+ //razones trigonométricas auxiliares
+ cLat = cos(lat);
+ //trasformamos las coordenadas de entrada a cartesianas
+ x = cLat*cos(lon);
+ y = cLat*sin(lon);
+ z = sin(lat);
+ //aplicamos la rotación
+ AplicaMatrizRotacionCoorCart(sentido,x,y,z,mRot,&xR,&yR,&zR);
+ //convertimos de nuevo a geodésicas, si ha lugar
+ if(latR!=NULL)
+ {
+ *latR = asin(zR);
+ }
+ if(lonR!=NULL)
+ {
+ *lonR = atan2(yR,xR);
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return;
+}
+/******************************************************************************/
+/******************************************************************************/
+int IntersecCircMaxEsfAux(const double tol,
+ const double xC,
+ const double yC,
+ const double zC,
+ const double xD,
+ const double yD,
+ const double zD,
+ double* xP,
+ double* yP,
+ double* zP)
+{
+ //vectores normales
+ double NABx=0.0,NABy=0.0,NABz=0.0,NCDx=0.0,NCDy=0.0,NCDz=0.0;
+ double dx=0.0,dy=0.0,dz=0.0;
+ //variable auxiliar
+ double t=0.0;
+ //variable de salida
+ int cod=GEOC_ARC_NO_INTERSEC;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //vector normal al plano del ecuador AOB
+ NABx = 0.0;
+ NABy = 0.0;
+ NABz = 1.0;
+ //vector normal al plano COD
+ ProductoVectorial(xC,yC,zC,xD,yD,zD,&NCDx,&NCDy,&NCDz);
+ //vector director de la línea intersección de los dos planos
+ ProductoVectorial(NABx,NABy,NABz,NCDx,NCDy,NCDz,&dx,&dy,&dz);
+ //sólo seguimos si no hay casos especiales
+ if((!GEOC_ES_CERO(dx,tol))||
+ (!GEOC_ES_CERO(dy,tol))||
+ (!GEOC_ES_CERO(dz,tol)))
+ {
+ //hay intersección
+ cod = GEOC_ARC_INTERSEC;
+ //comprobamos si hay que devolver coordenadas
+ if((xP!=NULL)&&(yP!=NULL)&&(zP!=NULL))
+ {
+ //calculamos el inverso del módulo del vector (dx,dy,dz)
+ t = 1.0/sqrt(dx*dx+dy*dy+dz*dz);
+ //coordenadas del punto de intersección en la esfera de radio unidad
+ *xP = dx*t;
+ *yP = dy*t;
+ *zP = dz*t;
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return cod;
+}
+/******************************************************************************/
+/******************************************************************************/
+int IntersecArcCirMaxEsferaVertComunAux(const double tol,
+ const double lonB,
+ const double latC,
+ const double lonC,
+ const double latD,
+ const double lonD,
+ double* latP,
+ double* lonP)
+{
+ //identificadores de igualdad entre puntos
+ int AiC=0,AiD=0,BiC=0,BiD=0;
+ //variables auxiliares
+ double latA=0.0,lonA=0.0,latB=0.0;
+ double lonAAux=0.0,lonCAux=0.0,lonDAux=0.0;
+ //variable de salida
+ int cod=GEOC_ARC_NO_INTERSEC;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //por defecto, las coordenadas de salida son 0.0
+ if((latP!=NULL)&&(lonP!=NULL))
+ {
+ *latP = 0.0;
+ *lonP = 0.0;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //chequeamos la posible igualdad entre los vértices de los arcos
+ AiC = (GEOC_ES_CERO(latA-latC,tol))&&(GEOC_ES_CERO(lonA-lonC,tol));
+ AiD = (GEOC_ES_CERO(latA-latD,tol))&&(GEOC_ES_CERO(lonA-lonD,tol));
+ BiC = (GEOC_ES_CERO(latB-latC,tol))&&(GEOC_ES_CERO(lonB-lonC,tol));
+ BiD = (GEOC_ES_CERO(latB-latD,tol))&&(GEOC_ES_CERO(lonB-lonD,tol));
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //comprobamos los posibles casos en que los arcos tengan algún extremo común
+ if((AiC&&BiD)||(AiD&&BiC))
+ {
+ //los vértices coinciden, dos a dos: los arcos son el mismo
+ cod = GEOC_ARC_INTERSEC_MISMO_ARC;
+ //comprobamos si hay que asignar coordenadas de salida
+ if((latP!=NULL)&&(lonP!=NULL))
+ {
+ //el punto de corte es el vértice A
+ *latP = latA;
+ *lonP = lonA;
+ }
+ }
+ else if(AiC)
+ {
+ //compruebo si D está en el ecuador
+ if(GEOC_ES_CERO(latD,tol))
+ {
+ //comprobamos el tipo de colinelidad
+ if((lonB*lonD)<=0.0)
+ {
+ //si el producto de las longitudes es negativo quiere decir que
+ //los extremos B y D están cada uno a un lado del meridiano
+ //origen, luego los arcos se tocan en un punto y son colineales
+ cod = GEOC_ARC_INTERSEC_EXTREMOS_COLIN;
+ }
+ else
+ {
+ //los arcos se tocan en un punto y se solapan parcialmente
+ cod = GEOC_ARC_INTERSEC_COLIN;
+ }
+ }
+ else
+ {
+ //los arcos se tocan en un punto, pero no son colineales
+ cod = GEOC_ARC_INTERSEC_EXTREMOS_NO_COLIN;
+ }
+ //comprobamos si hay que asignar coordenadas de salida
+ if((latP!=NULL)&&(lonP!=NULL))
+ {
+ //el punto de corte es el vértice A
+ *latP = latA;
+ *lonP = lonA;
+ }
+ }
+ else if(AiD)
+ {
+ //compruebo si C está en el ecuador
+ if(GEOC_ES_CERO(latC,tol))
+ {
+ //comprobamos el tipo de colinelidad
+ if((lonB*lonC)<=0.0)
+ {
+ //si el producto de las longitudes es negativo quiere decir que
+ //los extremos B y C están cada uno a un lado del meridiano
+ //origen, luego los arcos se tocan en un punto y son colineales
+ cod = GEOC_ARC_INTERSEC_EXTREMOS_COLIN;
+ }
+ else
+ {
+ //los arcos se tocan en un punto y se solapan parcialmente
+ cod = GEOC_ARC_INTERSEC_COLIN;
+ }
+ }
+ else
+ {
+ //los arcos se tocan en un punto, pero no son colineales
+ cod = GEOC_ARC_INTERSEC_EXTREMOS_NO_COLIN;
+ }
+ //comprobamos si hay que asignar coordenadas de salida
+ if((latP!=NULL)&&(lonP!=NULL))
+ {
+ //el punto de corte es el vértice A
+ *latP = latA;
+ *lonP = lonA;
+ }
+ }
+ else if(BiC)
+ {
+ //compruebo si D está en el ecuador
+ if(GEOC_ES_CERO(latD,tol))
+ {
+ //ponemos el origen de longitudes en B
+ lonAAux = -lonB;
+ lonDAux = lonD-lonB;
+ //comprobamos el tipo de colinelidad
+ if((lonAAux*lonDAux)<=0.0)
+ {
+ //si el producto de las longitudes es negativo quiere decir que
+ //los extremos A y D están cada uno a un lado de B, luego los
+ //arcos se tocan en un punto y son colineales
+ cod = GEOC_ARC_INTERSEC_EXTREMOS_COLIN;
+ }
+ else
+ {
+ //los arcos se tocan en un punto y se solapan parcialmente
+ cod = GEOC_ARC_INTERSEC_COLIN;
+ }
+ }
+ else
+ {
+ //los arcos se tocan en un punto, pero no son colineales
+ cod = GEOC_ARC_INTERSEC_EXTREMOS_NO_COLIN;
+ }
+ //comprobamos si hay que asignar coordenadas de salida
+ if((latP!=NULL)&&(lonP!=NULL))
+ {
+ //el punto de corte es el vértice B
+ *latP = latB;
+ *lonP = lonB;
+ }
+ }
+ else if(BiD)
+ {
+ //compruebo si C está en el ecuador
+ if(GEOC_ES_CERO(latC,tol))
+ {
+ //ponemos el origen de longitudes en B
+ lonAAux = -lonB;
+ lonCAux = lonC-lonB;
+ //comprobamos el tipo de colinelidad
+ if((lonAAux*lonCAux)<=0.0)
+ {
+ //si el producto de las longitudes es negativo quiere decir que
+ //los extremos A y C están cada uno a un lado de B, luego los
+ //arcos se tocan en un punto y son colineales
+ cod = GEOC_ARC_INTERSEC_EXTREMOS_COLIN;
+ }
+ else
+ {
+ //los arcos se tocan en un punto y se solapan parcialmente
+ cod = GEOC_ARC_INTERSEC_COLIN;
+ }
+ }
+ else
+ {
+ //los arcos se tocan en un punto, pero no son colineales
+ cod = GEOC_ARC_INTERSEC_EXTREMOS_NO_COLIN;
+ }
+ //comprobamos si hay que asignar coordenadas de salida
+ if((latP!=NULL)&&(lonP!=NULL))
+ {
+ //el punto de corte es el vértice A
+ *latP = latB;
+ *lonP = lonB;
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return cod;
+}
+/******************************************************************************/
+/******************************************************************************/
+int IntersecArcCirMaxEsferaVertApoyadoAux(const double tol,
+ const double lonB,
+ const double latC,
+ const double lonC,
+ const double latD,
+ const double lonD,
+ double* latP,
+ double* lonP)
+{
+ //coordenadas de trabajo
+ double xC=0.0,yC=0.0,zC=0.0,xD=0.0,yD=0.0,zD=0.0,xP=0.0,yP=0.0,zP=0.0;
+ double latA=0.0,lonA=0.0,latB=0.0,lonP1=0.0,lonP2=0.0;
+ //variables auxiliares
+ double cLat=0.0;
+ //variable de salida
+ int cod=GEOC_ARC_NO_INTERSEC;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //por defecto, las coordenadas de salida son 0.0
+ if((latP!=NULL)&&(lonP!=NULL))
+ {
+ *latP = 0.0;
+ *lonP = 0.0;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //comprobamos si el arco CD está sobre el ecuador
+ if(GEOC_ES_CERO(latC,tol)&&GEOC_ES_CERO(latD,tol))
+ {
+ //comprobamos qué punto está en qué segmento
+ //consideramos también el caso de que los segmentos sólo se toquen en un
+ //extremo
+ if(((lonA>(lonC-tol))&&(lonA<(lonD+tol)))||
+ ((lonA<(lonC+tol))&&(lonA>(lonD-tol))))
+ {
+ //el punto A está entre C y D, los arcos se solapan
+ cod = GEOC_ARC_INTERSEC_COLIN;
+ //comprobamos si hay que asignar coordenadas de salida
+ if((latP!=NULL)&&(lonP!=NULL))
+ {
+ //el punto de corte es el vértice A
+ *latP = latA;
+ *lonP = lonA;
+ }
+ //salimos de la función
+ return cod;
+ }
+ else if(((lonB>(lonC-tol))&&(lonB<(lonD+tol)))||
+ ((lonB<(lonC+tol))&&(lonB>(lonD-tol))))
+ {
+ //el punto B está entre C y D, los arcos se solapan
+ cod = GEOC_ARC_INTERSEC_COLIN;
+ //comprobamos si hay que asignar coordenadas de salida
+ if((latP!=NULL)&&(lonP!=NULL))
+ {
+ //el punto de corte es el vértice B
+ *latP = latB;
+ *lonP = lonB;
+ }
+ //salimos de la función
+ return cod;
+ }
+ else
+ {
+ //salimos de la función
+ return cod;
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //coordenadas cartesianas tridimensionales geocéntricas de C
+ cLat = cos(latC);
+ xC = cLat*cos(lonC);
+ yC = cLat*sin(lonC);
+ zC = sin(latC);
+ //coordenadas cartesianas tridimensionales geocéntricas de D
+ cLat = cos(latD);
+ xD = cLat*cos(lonD);
+ yD = cLat*sin(lonD);
+ zD = sin(latD);
+ //calculamos la intersección de dos círculos máximos
+ //aquí ya no cabe caso singular, ya que si los dos arcos estuviesen en el
+ //ecuador habría sido detectado en el chequeo del principio de la función
+ IntersecCircMaxEsfAux(tol,xC,yC,zC,xD,yD,zD,&xP,&yP,&zP);
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //calculamos los posibles puntos de intersección
+ lonP1 = atan2(yP,xP);
+ lonP2 = lonP1+GEOC_CONST_PI;
+ lonP2 = (lonP2>GEOC_CONST_PI) ? lonP2-2.0*GEOC_CONST_PI : lonP2;
+ //vamos comprobando si algún punto de corte coincide con A, B, C o D
+ if(GEOC_ES_CERO(lonP1,tol)||GEOC_ES_CERO(lonP2,tol))
+ {
+ //los arcos no son colineales
+ cod = GEOC_ARC_INTERSEC_EXTREMO_NO_COLIN;
+ //comprobamos si hay que asignar coordenadas de salida
+ if((latP!=NULL)&&(lonP!=NULL))
+ {
+ //el punto de corte es el vértice A
+ *latP = latA;
+ *lonP = lonA;
+ }
+ }
+ else if(GEOC_ES_CERO(lonP1-lonB,tol)||GEOC_ES_CERO(lonP2-lonB,tol))
+ {
+ //los arcos no son colineales
+ cod = GEOC_ARC_INTERSEC_EXTREMO_NO_COLIN;
+ //comprobamos si hay que asignar coordenadas de salida
+ if((latP!=NULL)&&(lonP!=NULL))
+ {
+ //el punto de corte es el vértice B
+ *latP = latB;
+ *lonP = lonB;
+ }
+ }
+ else if((GEOC_ES_CERO(latC,tol))&&
+ (GEOC_ES_CERO(lonP1-lonC,tol)||GEOC_ES_CERO(lonP2-lonC,tol)))
+ {
+ //los arcos no son colineales
+ cod = GEOC_ARC_INTERSEC_EXTREMO_NO_COLIN;
+ //comprobamos si hay que asignar coordenadas de salida
+ if((latP!=NULL)&&(lonP!=NULL))
+ {
+ //el punto de corte es el vértice C
+ *latP = 0.0;
+ *lonP = lonC;
+ }
+ }
+ else if((GEOC_ES_CERO(latD,tol))&&
+ (GEOC_ES_CERO(lonP1-lonD,tol)||GEOC_ES_CERO(lonP2-lonD,tol)))
+ {
+ //los arcos no son colineales
+ cod = GEOC_ARC_INTERSEC_EXTREMO_NO_COLIN;
+ //comprobamos si hay que asignar coordenadas de salida
+ if((latP!=NULL)&&(lonP!=NULL))
+ {
+ //el punto de corte es el vértice D
+ *latP = 0.0;
+ *lonP = lonD;
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return cod;
+}
+/******************************************************************************/
+/******************************************************************************/
+int IntersecArcCircMaxEsferaAux(const double tol,
+ const double lonB,
+ const double latC,
+ const double lonC,
+ const double latD,
+ const double lonD,
+ const double xGC,
+ const double yGC,
+ const double zGC,
+ const double xGD,
+ const double yGD,
+ const double zGD,
+ double* latP,
+ double* lonP)
+{
+ //coordenadas de trabajo
+ double xC=0.0,yC=0.0,zC=0.0,xD=0.0,yD=0.0,zD=0.0;
+ double xP=0.0,yP=0.0,zP=0.0,lonP1=0.0,lonP2=0.0,lonPI=0.0;
+ //variables auxiliares
+ double cLat=0.0;
+ //variable de salida
+ int cod=GEOC_ARC_NO_INTERSEC;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //por defecto, las coordenadas de salida son 0.0
+ if((latP!=NULL)&&(lonP!=NULL))
+ {
+ *latP = 0.0;
+ *lonP = 0.0;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //comprobamos si CD cruza o no el ecuador
+ if(((latC>tol)&&(latD>tol))||((latC<-tol)&&(latD<-tol)))
+ {
+ //salimos de la función
+ return cod;
+ }
+ else
+ {
+ //casos en que los arcos puedan tener algún extremo común
+ cod = IntersecArcCirMaxEsferaVertComunAux(tol,lonB,latC,lonC,latD,lonD,
+ latP,lonP);
+ //si se ha encontrado intersección, salimos de la función
+ if(cod!=GEOC_ARC_NO_INTERSEC)
+ {
+ //salimos de la función
+ return cod;
+ }
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ //comprobamos si un extremo de un arco se apoya en el otro
+ cod = IntersecArcCirMaxEsferaVertApoyadoAux(tol,lonB,latC,lonC,
+ latD,lonD,latP,lonP);
+ //si se ha encontrado intersección, salimos de la función
+ if(cod!=GEOC_ARC_NO_INTERSEC)
+ {
+ //salimos de la función
+ return cod;
+ }
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ //comprobamos si no se han pasado coordenadas cartesianas para C
+ if(EsGeocNan(xC)&&EsGeocNan(yC)&&EsGeocNan(zC))
+ {
+ //coordenadas cartesianas tridimensionales geocéntricas de C
+ cLat = cos(latC);
+ xC = cLat*cos(lonC);
+ yC = cLat*sin(lonC);
+ zC = sin(latC);
+ }
+ else
+ {
+ //copiamos las coordenadas pasadas
+ xC = xGC;
+ yC = yGC;
+ zC = zGC;
+ }
+ //comprobamos si no se han pasado coordenadas cartesianas para D
+ if(EsGeocNan(xD)&&EsGeocNan(yD)&&EsGeocNan(zD))
+ {
+ //coordenadas cartesianas tridimensionales geocéntricas de D
+ cLat = cos(latD);
+ xD = cLat*cos(lonD);
+ yD = cLat*sin(lonD);
+ zD = sin(latD);
+ }
+ else
+ {
+ //copiamos las coordenadas pasadas
+ xD = xGD;
+ yD = yGD;
+ zD = zGD;
+ }
+ //calculamos la intersección de dos círculos máximos
+ //aquí ya no cabe caso singular, ya que si los dos arcos estuviesen en
+ //el ecuador habría sido detectado por la llamadas a
+ //IntersecArcCirMaxEsferaVertComunAux() o
+ //IntersecArcCirMaxEsferaVertApoyadoAux()
+ IntersecCircMaxEsfAux(tol,xC,yC,zC,xD,yD,zD,&xP,&yP,&zP);
+ //calculamos los posibles puntos de intersección
+ lonP1 = atan2(yP,xP);
+ lonP2 = lonP1+GEOC_CONST_PI;
+ lonP2 = (lonP2>GEOC_CONST_PI) ? lonP2-2.0*GEOC_CONST_PI : lonP2;
+ //compruebo si alguna de esas longitudes está en el segmento AB
+ if(((lonP1>-tol)&&(lonP1<lonB+tol))||((lonP1<tol)&&(lonP1>lonB-tol)))
+ {
+ //asigno el código de salida
+ cod = GEOC_ARC_INTERSEC;
+ //longitud de la intersección
+ lonPI = lonP1;
+ }
+ else if(((lonP2>-tol)&&(lonP2<lonB+tol))||
+ ((lonP2<tol)&&(lonP2>lonB-tol)))
+ {
+ //asigno el código de salida
+ cod = GEOC_ARC_INTERSEC;
+ //longitud de la intersección
+ lonPI = lonP2;
+ }
+ //compruebo si, habiendo corte, hay coordenadas de salida
+ if((cod!=GEOC_ARC_NO_INTERSEC)&&(latP!=NULL)&&(lonP!=NULL))
+ {
+ //asigno las coordenadas a las variables de salida
+ *latP = 0.0;
+ *lonP = lonPI;
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return cod;
+}
+/******************************************************************************/
+/******************************************************************************/
+int IntersecArcCircMaxEsfera(const double latA,
+ const double lonA,
+ const double latB,
+ const double lonB,
+ const double latC,
+ const double lonC,
+ const double latD,
+ const double lonD,
+ double* latP,
+ double* lonP)
+{
+ //tolerancia angular
+ double tol=fabs(GEOC_ARC_RES_ANG);
+ //coordenadas de trabajo
+ double xC=0.0,yC=0.0,zC=0.0,xD=0.0,yD=0.0,zD=0.0;
+ double xCR=0.0,yCR=0.0,zCR=0.0,xDR=0.0,yDR=0.0,zDR=0.0;
+ double lonBR=0.0,latCR=0.0,lonCR=0.0,latDR=0.0,lonDR=0.0;
+ double latPR=0.0,lonPR=0.0;
+ //matriz de rotación
+ double mRot[3][3];
+ //variable auxiliar
+ double cLat=0.0;
+ //variable de salida
+ int cod=GEOC_ARC_NO_INTERSEC;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //por defecto, si no hay intersección, las coordenadas de salida son 0.0
+ if((latP!=NULL)&&(lonP!=NULL))
+ {
+ *latP = 0.0;
+ *lonP = 0.0;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //si los rectángulos son disjuntos, los segmentos no se tocan
+ if(ArcosCircMaxDisjuntos(tol,
+ GEOC_MIN(lonA,lonB),GEOC_MAX(lonA,lonB),
+ GEOC_MIN(lonC,lonD),GEOC_MAX(lonC,lonD)))
+ {
+ //salimos de la función
+ return cod;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //calculamos la matriz de rotación para llevar AB al ecuador
+ RotaArco00Ecuador(tol,latA,lonA,latB,lonB,mRot,&lonBR);
+ //calculamos las coordenadas cartesianas de los puntos C y D
+ cLat = cos(latC);
+ xC = cLat*cos(lonC);
+ yC = cLat*sin(lonC);
+ zC = sin(latC);
+ cLat = cos(latD);
+ xD = cLat*cos(lonD);
+ yD = cLat*sin(lonD);
+ zD = sin(latD);
+ //rotamos los puntos C y D
+ AplicaMatrizRotacionCoorCart(1,xC,yC,zC,mRot,&xCR,&yCR,&zCR);
+ AplicaMatrizRotacionCoorCart(1,xD,yD,zD,mRot,&xDR,&yDR,&zDR);
+ //calculamos las coordenadas geodésicas rotadas
+ latCR = asin(zCR);
+ lonCR = atan2(yCR,xCR);
+ latDR = asin(zDR);
+ lonDR = atan2(yDR,xDR);
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //calculamos la intersección
+ cod = IntersecArcCircMaxEsferaAux(tol,lonBR,latCR,lonCR,latDR,lonDR,xCR,yCR,
+ zCR,xDR,yDR,zDR,&latPR,&lonPR);
+ //transformamos el resultado al sistema original, si ha lugar
+ if((cod!=GEOC_ARC_NO_INTERSEC)&&(latP!=NULL)&&(lonP!=NULL))
+ {
+ AplicaMatrizRotacionCoorGeod(-1,latPR,lonPR,mRot,latP,lonP);
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return cod;
+}
+/******************************************************************************/
+/******************************************************************************/
+/** @} */
+/******************************************************************************/
+/******************************************************************************/
+/* kate: encoding utf-8; end-of-line unix; syntax c; indent-mode cstyle; */
+/* kate: replace-tabs on; space-indent on; tab-indents off; indent-width 4; */
+/* kate: line-numbers on; folding-markers on; remove-trailing-space on; */
+/* kate: backspace-indents on; show-tabs on; */
+/* kate: word-wrap-column 80; word-wrap-marker-color #D2D2D2; word-wrap off; */
diff --git a/src/compilador.c b/src/compilador.c
index aa35e74..aa35e74 100755..100644
--- a/src/compilador.c
+++ b/src/compilador.c
diff --git a/src/dpeucker.c b/src/dpeucker.c
index f63f53d..1d06156 100644
--- a/src/dpeucker.c
+++ b/src/dpeucker.c
@@ -3,16 +3,17 @@
\ingroup geom
@{
\file dpeucker.c
-\brief Definición de funciones para el aligerado de polilíneas basadas en el
+\brief Definición de funciones para el aligerado de polilíneas, basadas en el
algoritmo de Douglas-Peucker.
\author José Luis García Pallero, jgpallero@gmail.com
-\date 04 de julio de 2011
-\section Licencia Licencia
-Copyright (c) 2011, José Luis García Pallero. All rights reserved.
-
+\note Este fichero contiene funciones paralelizadas con OpenMP.
+\date 17 de agosto de 2013
+\copyright
+Copyright (c) 2013-2014, José Luis García Pallero. All rights reserved.
+\par
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
-
+\par
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this
@@ -21,7 +22,7 @@ are permitted provided that the following conditions are met:
- Neither the name of the copyright holders nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
-
+\par
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -44,213 +45,64 @@ size_t* AligeraPolilinea(const double* x,
const size_t incX,
const size_t incY,
const double tol,
+ const int paralelizaTol,
const enum GEOC_DPEUCKER_ROBUSTO robusto,
- const size_t nPtosRobusto,
- const size_t nSegRobusto,
+ const size_t nSegRobOrig,
+ const size_t nSegRobAuto,
+ const int esf,
size_t* nPtosSal)
{
- //índice para recorrer bucles
- size_t p=0;
- //índice de los puntos de trabajo
- size_t i=0,j=0,k=0;
- //coordenadas de trabajo
- double xIni=0.0,yIni=0.0,xFin=0.0,yFin=0.0,xTrab=0.0,yTrab=0.0;
- //altura del triángulo de trabajo
- double h=0.0;
- //variable indicadora de punto a mantener
- int usado=0;
- //número de elementos de trabajo internos del vector de salida
- size_t nElem=0;
+ //identificador de caso especial
+ int hayCasoEspecial=0;
+ //valor absoluto de la tolerancia
+ double atol=fabs(tol);
//vector de salida
size_t* sal=NULL;
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
- //iniciamos la variable de salida de número de puntos a 0
- *nPtosSal = 0;
- //comprobamos casos especiales de nPtos
- if(nPtos==0)
+ //comprobamos casos especiales
+ sal = CasosEspecialesAligeraPolilinea(x,y,nPtos,incX,incY,atol,nPtosSal,
+ &hayCasoEspecial);
+ //comprobamos si ha habido algún caso especial
+ if(hayCasoEspecial)
{
- //salimos de la función con NULL
- return NULL;
- }
- else if(nPtos<=2)
- {
- //asignamos el número de puntos usados
- *nPtosSal = nPtos;
- //asignamos memoria para el vector de salida
- sal = (size_t*)malloc((*nPtosSal)*sizeof(size_t));
- //comprobamos los posibles errores
- if(sal==NULL)
+ //comprobamos si ha ocurrido algún error de asignación de memoria
+ if(nPtos&&(sal==NULL))
{
//mensaje de error
GEOC_ERROR("Error de asignación de memoria");
//salimos de la función
return NULL;
}
- //asignamos valores al vector de salida
- for(i=0;i<(*nPtosSal);i++)
+ else
{
- //asignamos el índice de trabajo
- sal[i] = i;
+ //salimos de la función
+ return sal;
}
- //salimos de la función
- return sal;
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
- //inicializamos el indicador interno de tamaño del vector
- nElem = GEOC_DPEUCKER_BUFFER_PTOS;
- //asignamos memoria para el vector de salida
- sal = (size_t*)malloc(nElem*sizeof(size_t));
+ //comprobamos si trabajamos con el algoritmo original o con el robusto
+ if(robusto==GeocDPeuckerOriginal)
+ {
+ //versión original del algoritmo
+ sal = DouglasPeuckerOriginal(x,y,nPtos,incX,incY,atol,esf,nPtosSal);
+ }
+ else
+ {
+ //utilizamos la variación robusta del algoritmo
+ sal = DouglasPeuckerRobusto(x,y,nPtos,incX,incY,atol,paralelizaTol,
+ robusto,nSegRobOrig,nSegRobAuto,esf,
+ nPtosSal);
+ }
//comprobamos los posibles errores
- if(sal==NULL)
+ if(nPtos&&(sal==NULL))
{
//mensaje de error
GEOC_ERROR("Error de asignación de memoria");
//salimos de la función
return NULL;
}
- //indicamos que el primer punto siempre se usa
- *nPtosSal = 1;
- sal[0] = 0;
- //puntos de trabajo para iniciar los cálculos
- i = 0;
- j = 1;
- k = 2;
- ////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////
- //entramos en un bucle infinito
- while(1)
- {
- //comprobamos si hay que salir del bucle
- if(k>(nPtos-1))
- {
- //salimos del bucle
- break;
- }
- //coordenadas de la base del triángulo
- xIni = x[i*incX];
- yIni = y[i*incY];
- xFin = x[k*incX];
- yFin = y[k*incY];
- //inicializamos a 0 la variable de punto usado
- usado = 0;
- //recorremos los puntos a testear
- for(p=j;p<k;p++)
- {
- //coordenadas del vértice del triángulo
- xTrab = x[p*incX];
- yTrab = y[p*incY];
- //calculamos la altura del triángulo
- h = AlturaTriangulo(xTrab,yTrab,xIni,yIni,xFin,yFin);
- //comprobamos si la altura supera a la tolerancia
- if(h>tol)
- {
- //indicamos que el punto ha sido usado
- usado = 1;
- //comprobamos si se utiliza el algoritmo robusto
- if(robusto!=GeocDPeuckerRobNo)
- {
- //comprobamos si hay que aplicar el algoritmo de
- //intersección con puntos originales
- if((robusto==GeocDPeuckerRobSi)||
- (robusto==GeocDPeuckerRobOrig))
- {
- //aplicamos el algoritmo
- AligPolilRobIntersecOrig(x,y,nPtos,incX,incY,
- nPtosRobusto,i,&p);
- }
- //comprobamos si hay que aplicar el algoritmo de auto
- //intersección
- if((robusto==GeocDPeuckerRobSi)||
- (robusto==GeocDPeuckerRobAuto))
- {
- //indicamos un número de puntos para el vector de salida
- //una unidad menor que el número realmente almacenado
- //para evitar el segmento inmediatamente anterior al que
- //vamos a crear
- AligPolilRobAutoIntersec(x,y,incX,incY,sal,
- (*nPtosSal)-1,nSegRobusto,i,
- &p);
- }
- }
- //añadimos al contador este nuevo punto
- (*nPtosSal)++;
- //comprobamos si hay que reasignar memoria
- if((*nPtosSal)>nElem)
- {
- //añadimos otro grupo de puntos
- nElem += GEOC_DPEUCKER_BUFFER_PTOS;
- //asignamos memoria para el vector de salida
- sal = (size_t*)realloc(sal,nElem*sizeof(size_t));
- //comprobamos los posibles errores
- if(sal==NULL)
- {
- //mensaje de error
- GEOC_ERROR("Error de asignación de memoria");
- //salimos de la función
- return NULL;
- }
- }
- //añadimos el nuevo punto usado
- sal[(*nPtosSal)-1] = p;
- //actualizamos los índices de los puntos de trabajo
- i = p;
- j = i+1;
- k = j+1;
- //salimos del bucle
- break;
- }
- }
- //comprobamos si no se ha utilizado ninguno de los vértices candidatos
- if(!usado)
- {
- //pasamos al siguiente punto como extremo del segmento
- k++;
- }
- }
- ////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////
- //comprobamos si el último punto se ha añadido
- if(sal[(*nPtosSal)-1]!=(nPtos-1))
- {
- //añadimos al contador el último punto
- (*nPtosSal)++;
- //comprobamos si hay que reasignar memoria
- if((*nPtosSal)>nElem)
- {
- //añadimos otro grupo de puntos
- nElem += GEOC_DPEUCKER_BUFFER_PTOS;
- //asignamos memoria para el vector de salida
- sal = (size_t*)realloc(sal,nElem*sizeof(size_t));
- //comprobamos los posibles errores
- if(sal==NULL)
- {
- //mensaje de error
- GEOC_ERROR("Error de asignación de memoria");
- //salimos de la función
- return NULL;
- }
- }
- //asignamos el último punto
- sal[(*nPtosSal)-1] = nPtos-1;
- }
- ////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////
- //comprobamos si el vector de salida tiene demasiada memoria asignada
- if(nElem>(*nPtosSal))
- {
- //ajustamos el tamaño del vector de salida
- sal = (size_t*)realloc(sal,(*nPtosSal)*sizeof(size_t));
- //comprobamos los posibles errores
- if(sal==NULL)
- {
- //mensaje de error
- GEOC_ERROR("Error de asignación de memoria");
- //salimos de la función
- return NULL;
- }
- }
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
//salimos de la función
@@ -258,207 +110,187 @@ size_t* AligeraPolilinea(const double* x,
}
/******************************************************************************/
/******************************************************************************/
-void AligPolilRobIntersecOrig(const double* x,
- const double* y,
- const size_t nPtos,
- const size_t incX,
- const size_t incY,
- const size_t ptosAUsar,
- const size_t posIni,
- size_t* posFin)
+size_t* DouglasPeuckerOriginal(const double* x,
+ const double* y,
+ const size_t nPtos,
+ const size_t incX,
+ const size_t incY,
+ const double tol,
+ const int esf,
+ size_t* nPtosSal)
{
- //índices para recorrer bucles
- size_t i=0,j=0;
- //coordenadas de trabajo
- double xA=0.0,yA=0.0,xB=0.0,yB=0.0,xC=0.0,yC=0.0,xD=0.0,yD=0.0;
- //punto de parada para comprobar la intersección de segmentos
- size_t parada=0;
- //identificador de intersección
- int inter=0;
+ //índice para recorrer bucles
+ size_t i=0;
+ //valor absoluto de la tolerancia
+ double atol=fabs(tol);
//variables auxiliares
- size_t aux=0;
- double xAux=0.0,yAux=0.0;
+ int aux=0;
+ size_t pos=0;
+ //vector de identificadores de elementos usados
+ char* usados=NULL;
+ //vector de salida
+ size_t* sal=NULL;
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
- //contemplamos una posible salida rápida
- if((*posFin)<=(posIni+1))
+ //iniciamos la variable de salida de número de puntos a 0
+ *nPtosSal = 0;
+ //asigno memoria para los puntos usados y la inicializo a ceros (calloc)
+ usados = (char*)calloc(nPtos,sizeof(char));
+ //comprobamos los posibles errores
+ if(usados==NULL)
{
+ //mensaje de error
+ GEOC_ERROR("Error de asignación de memoria");
//salimos de la función
- return;
+ return NULL;
}
+ //indico el primer punto y el último como usados
+ usados[0] = 1;
+ usados[nPtos-1] = 1;
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
- //calculamos el número de puntos que quedan hasta el final de los vectores
- //de coordenadas desde la posición de fin de segmento (contándola)
- aux = nPtos-(*posFin);
- //calculamos el punto de parada para la intersección de segmentos
- if((aux>ptosAUsar)&&(ptosAUsar!=0))
+ //comprobamos si trabajamos sobre la esfera o sobre el plano
+ if(esf)
{
- //paramos en un pnto tal que usemos ptosAUsar puntos
- parada = *posFin+ptosAUsar-1;
+ //aplico el algoritmo original sobre la esfera
+ DouglasPeuckerOriginalEsfera(x,y,nPtos,incX,incY,atol,0,nPtos-1,usados);
}
else
{
- //paramos en el penúltimo punto
- parada = nPtos-2;
+ //aplico el algoritmo original sobre el plano
+ DouglasPeuckerOriginalPlano(x,y,nPtos,incX,incY,atol,0,nPtos-1,usados);
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
- //las coordenadas del punto inicial del segmento base no cambian nunca
- xA = x[posIni*incX];
- yA = y[posIni*incY];
- //recorremos los puntos candidatos hasta el anterior al punto base
- for(i=(*posFin);i>posIni;i--)
+ //cuento los puntos usados
+ for(i=0;i<nPtos;i++)
+ {
+ //copio el identificador de uso en una variable de tipo entero, ya
+ //que si no el compilador gcc 4.7.0 da warning si asigno el valor de
+ //tipo char a la variable size_t
+ //da warning de posible error de conversión por cambio de signo
+ //aunque se haga la conversión explícita
+ aux = (int)usados[i];
+ //voy contando
+ (*nPtosSal) += (size_t)aux;
+ }
+ //asigno memoria para el vector de salida
+ sal = (size_t*)malloc((*nPtosSal)*sizeof(size_t));
+ //comprobamos los posibles errores
+ if(sal==NULL)
{
- //comprobamos si estamos ante el punto posterior al inicial
- if(i==(posIni+1))
+ //libero la memoria utilizada
+ free(usados);
+ //mensaje de error
+ GEOC_ERROR("Error de asignación de memoria");
+ //salimos de la función
+ return NULL;
+ }
+ //inicio la variable de posición
+ pos = 0;
+ //recorro el vector de elementos usados
+ for(i=0;i<nPtos;i++)
+ {
+ //compruebo si el elemento se ha usado
+ if(usados[i])
{
- //terminamos, porque este punto es el siguiente al punto base en el
- //listado original
- *posFin = i;
- //salimos del bucle
- break;
+ //asigno la posición
+ sal[pos] = i;
+ //aumento el contador de posiciones en el vector de salida
+ pos++;
}
- else
+ }
+ //compruebo si sólo se han usado dos puntos que son el mismo
+ if((*nPtosSal==2)&&(x[0]==x[(nPtos-1)*incX])&&(y[0]==y[(nPtos-1)*incY]))
+ {
+ //actualizamos el número de puntos de salida
+ *nPtosSal = 1;
+ //reasigno memoria
+ sal = (size_t*)realloc(sal,(*nPtosSal)*sizeof(size_t));
+ //comprobamos los posibles errores
+ if(sal==NULL)
{
- //coordenadas de los puntos inicial y final del segmento base
- xB = x[i*incX];
- yB = y[i*incY];
- //recorremos los puntos posteriores hasta el de parada
- for(j=i;j<=parada;j++)
- {
- //coordenadas de los puntos inicial y final del siguiente
- //segmento
- xC = x[j*incX];
- yC = y[j*incY];
- xD = x[(j+1)*incX];
- yD = y[(j+1)*incY];
- //calculamos la intersección entre los segmentos
- inter = IntersecSegmentos2D(xA,yA,xB,yB,xC,yC,xD,yD,&xAux,
- &yAux);
- //comprobamos si hay intersección entre los segmentos
- if(inter!=GEOC_SEG_NO_INTERSEC)
- {
- //salimos del bucle
- break;
- }
- }
- //comprobamos si no ha habido ninguna intersección
- if(inter==GEOC_SEG_NO_INTERSEC)
- {
- //indicamos el índice del vértice final
- *posFin = i;
- //salimos del bucle
- break;
- }
+ //libero la memoria utilizada
+ free(usados);
+ //mensaje de error
+ GEOC_ERROR("Error de asignación de memoria");
+ //salimos de la función
+ return NULL;
}
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
+ //libero la memoria utilizada
+ free(usados);
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
//salimos de la función
- return;
+ return sal;
}
/******************************************************************************/
/******************************************************************************/
-void AligPolilRobAutoIntersec(const double* x,
+size_t* DouglasPeuckerRobusto(const double* x,
const double* y,
+ const size_t nPtos,
const size_t incX,
const size_t incY,
- const size_t* posAlig,
- const size_t nPosAlig,
- const size_t segAUsar,
- const size_t posIni,
- size_t* posFin)
+ const double tol,
+ const int paralelizaTol,
+ const enum GEOC_DPEUCKER_ROBUSTO robusto,
+ const size_t nSegRobOrig,
+ const size_t nSegRobAuto,
+ const int esf,
+ size_t* nPtosSal)
{
- //índices para recorrer bucles
- size_t i=0,j=0;
- //variables de posición
- size_t k=0,l=0,pos=0;
- //coordenadas de trabajo
- double xA=0.0,yA=0.0,xB=0.0,yB=0.0,xC=0.0,yC=0.0,xD=0.0,yD=0.0;
- //número de segmentos calculados hasta ahora, excepto el último
- size_t nSeg=0;
- //identificador de intersección
- int inter=0;
- //variables auxiliares
- double xAux=0.0,yAux=0.0;
+ //valor absoluto de la tolerancia
+ double atol=fabs(tol);
+ //identificador de caso especial
+ int hayCasoEspecial=0;
+ //vector de salida
+ size_t* sal=NULL;
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
- //contemplamos una posible salida rápida
- if(((*posFin)<=(posIni+1))||(nPosAlig<2))
+ //comprobamos casos especiales
+ sal = CasosEspecialesAligeraPolilinea(x,y,nPtos,incX,incY,atol,nPtosSal,
+ &hayCasoEspecial);
+ //comprobamos si ha habido algún caso especial
+ if(hayCasoEspecial)
{
- //salimos de la función
- return;
+ //comprobamos si ha ocurrido algún error de asignación de memoria
+ if(nPtos&&(sal==NULL))
+ {
+ //mensaje de error
+ GEOC_ERROR("Error de asignación de memoria");
+ //salimos de la función
+ return NULL;
+ }
+ else
+ {
+ //salimos de la función
+ return sal;
+ }
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
- //calculamos el número de segmentos calculados hasta ahora, excepto el
- //anterior al de trabajo
- nSeg = nPosAlig-1;
- //comprobamos si se usan todos los segmentos o sólo parte
- if(segAUsar!=0)
+ //comprobamos si trabajamos sobre la esfera o sobre el plano
+ if(esf)
{
- //asignamos el número de segmentos a utilizar
- nSeg = (nSeg>segAUsar) ? segAUsar : nSeg;
+ //aplico el algoritmo robusto sobre la esfera
+ sal = DouglasPeuckerRobustoEsfera(x,y,nPtos,incX,incY,atol,
+ paralelizaTol,robusto,nSegRobOrig,
+ nSegRobAuto,nPtosSal);
}
- //las coordenadas del punto inicial del segmento base no cambian nunca
- xA = x[posIni*incX];
- yA = y[posIni*incY];
- ////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////
- //recorremos los puntos candidatos hasta el anterior al punto base
- for(i=(*posFin);i>posIni;i--)
+ else
{
- //comprobamos si estamos ante el punto posterior al inicial
- if(i==(posIni+1))
- {
- //terminamos, porque este punto es el siguiente al punto inicial
- *posFin = i;
- //salimos del bucle
- break;
- }
- else
- {
- //coordenadas del punto final del segmento base
- xB = x[i*incX];
- yB = y[i*incY];
- //recorremos el número de segmentos de trabajo
- for(j=0;j<nSeg;j++)
- {
- //posición del punto inicial del siguiente segmento anterior
- pos = nPosAlig-1-j;
- //índices inicial y final del siguiente segmento anterior
- k = posAlig[pos];
- l = posAlig[pos-1];
- //puntos inicial y final del siguiente segmento
- xC = x[k*incX];
- yC = y[k*incY];
- xD = x[l*incX];
- yD = y[l*incY];
- //calculamos la intersección entre los segmentos
- inter = IntersecSegmentos2D(xA,yA,xB,yB,xC,yC,xD,yD,&xAux,
- &yAux);
- //comprobamos si hay intersección entre los segmentos
- if(inter!=GEOC_SEG_NO_INTERSEC)
- {
- //salimos del bucle
- break;
- }
- }
- //comprobamos si no ha habido ninguna intersección
- if(inter==GEOC_SEG_NO_INTERSEC)
- {
- //indicamos el índice del vértice final
- *posFin = i;
- //salimos del bucle
- break;
- }
- }
+ //aplico el algoritmo robusto sobre el plano
+ sal = DouglasPeuckerRobustoPlano(x,y,nPtos,incX,incY,tol,paralelizaTol,
+ robusto,nSegRobOrig,nSegRobAuto,
+ nPtosSal);
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
//salimos de la función
- return;
+ return sal;
}
/******************************************************************************/
/******************************************************************************/
diff --git a/src/dpeuckera.c b/src/dpeuckera.c
new file mode 100644
index 0000000..1a98e73
--- /dev/null
+++ b/src/dpeuckera.c
@@ -0,0 +1,204 @@
+/* -*- coding: utf-8 -*- */
+/**
+\ingroup geom
+@{
+\file dpeuckera.c
+\brief Declaración de funciones auxiliares para el uso de la familia de
+ algoritmos de Douglas-Peucker.
+\author José Luis García Pallero, jgpallero@gmail.com
+\date 01 de abril de 2014
+\copyright
+Copyright (c) 2014, José Luis García Pallero. All rights reserved.
+\par
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+\par
+- Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+- Neither the name of the copyright holders nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+\par
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/******************************************************************************/
+/******************************************************************************/
+#include"libgeoc/dpeuckera.h"
+/******************************************************************************/
+/******************************************************************************/
+size_t* CasosEspecialesAligeraPolilinea(const double* x,
+ const double* y,
+ const size_t nPtos,
+ const size_t incX,
+ const size_t incY,
+ const double tol,
+ size_t* nPtosSal,
+ int* hayCasoEspecial)
+{
+ //índice para recorrer bucles
+ size_t i=0;
+ //valor absoluto de la tolerancia
+ double atol=fabs(tol);
+ //vector de salida
+ size_t* salida=NULL;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //en principio, el número de puntos de salida es el mismo que el de entrada
+ *nPtosSal = nPtos;
+ //inicializamos la variable indicadora de caso especial a 0
+ *hayCasoEspecial = 0;
+ //vamos comprobando casos especiales
+ if(nPtos==0)
+ {
+ //indicamos que estamos anteun caso especial
+ *hayCasoEspecial = 1;
+ //actualizamos la variable de número de puntos de salida
+ *nPtosSal = 0;
+ //salimos de la función
+ return NULL;
+ }
+ else if(nPtos==1)
+ {
+ //indicamos que estamos anteun caso especial
+ *hayCasoEspecial = 1;
+ //asignamos memoria para el vector de salida
+ salida = (size_t*)malloc(sizeof(size_t));
+ //comprobamos si ha ocurrido algún error
+ if(salida==NULL)
+ {
+ //mensaje de error
+ GEOC_ERROR("Error de asignación de memoria");
+ //salimos de la función
+ return NULL;
+ }
+ //la entrada sólo es un punto
+ *nPtosSal = 1;
+ salida[0] = 0;
+ }
+ else if(nPtos==2)
+ {
+ //indicamos que estamos ante un caso especial
+ *hayCasoEspecial = 1;
+ //en principio, los dos puntos son válidos
+ *nPtosSal = 2;
+ //comprobamos si los puntos son o no el mismo
+ if((x[0]==x[incX])&&(y[0]==y[incY]))
+ {
+ //sólo vale el primer punto
+ *nPtosSal = 1;
+ }
+ //asignamos memoria para el vector de salida
+ salida = (size_t*)malloc((*nPtosSal)*sizeof(size_t));
+ //comprobamos si ha ocurrido algún error
+ if(salida==NULL)
+ {
+ //mensaje de error
+ GEOC_ERROR("Error de asignación de memoria");
+ //salimos de la función
+ return NULL;
+ }
+ //copiamos los puntos válidos
+ for(i=0;i<(*nPtosSal);i++)
+ {
+ salida[i] = i;
+ }
+ }
+ else if((nPtos==3)&&(x[0]==x[2*incX])&&(y[0]==y[2*incY]))
+ {
+ //indicamos que estamos ante un caso especial
+ *hayCasoEspecial = 1;
+ //en principio, hay dos puntos válidos
+ *nPtosSal = 2;
+ //comprobamos también si el segundo punto es el mismo que el primero
+ if((x[0]==x[incX])&&(y[0]==y[incY]))
+ {
+ //sólo vale el primer punto
+ *nPtosSal = 1;
+ }
+ //asignamos memoria para el vector de salida
+ salida = (size_t*)malloc((*nPtosSal)*sizeof(size_t));
+ //comprobamos si ha ocurrido algún error
+ if(salida==NULL)
+ {
+ //mensaje de error
+ GEOC_ERROR("Error de asignación de memoria");
+ //salimos de la función
+ return NULL;
+ }
+ //copiamos los puntos válidos
+ for(i=0;i<(*nPtosSal);i++)
+ {
+ salida[i] = i;
+ }
+ }
+ else if(atol==0.0)
+ {
+ //indicamos que estamos anteun caso especial
+ *hayCasoEspecial = 1;
+ //asignamos memoria para el vector de salida
+ salida = (size_t*)malloc(nPtos*sizeof(size_t));
+ //comprobamos si ha ocurrido algún error
+ if(salida==NULL)
+ {
+ //mensaje de error
+ GEOC_ERROR("Error de asignación de memoria");
+ //salimos de la función
+ return NULL;
+ }
+ //inicializamos el número de puntos de salida y la posición del primero
+ *nPtosSal = 1;
+ salida[0] = 0;
+ //recorremos el resto de puntos
+ for(i=1;i<nPtos;i++)
+ {
+ //comprobamos si el punto de trabajo es distinto al anterior
+ if((x[i*incX]!=x[(i-1)*incX])&&(y[i*incY]!=y[(i-1)*incY]))
+ {
+ //asignamos la posición del punto de trabajo
+ salida[*nPtosSal] = i;
+ //actualizamos el número de puntos de salida
+ (*nPtosSal)++;
+ }
+ }
+ //comprobamos si se ha quitado algún punto
+ if(nPtos!=(*nPtosSal))
+ {
+ //reasignamos memoria para el vector de salida
+ salida = (size_t*)realloc(salida,(*nPtosSal)*sizeof(size_t));
+ //comprobamos si ha ocurrido algún error
+ if(salida==NULL)
+ {
+ //mensaje de error
+ GEOC_ERROR("Error de asignación de memoria");
+ //salimos de la función
+ return NULL;
+ }
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return salida;
+}
+/******************************************************************************/
+/******************************************************************************/
+/** @} */
+/******************************************************************************/
+/******************************************************************************/
+/* kate: encoding utf-8; end-of-line unix; syntax c; indent-mode cstyle; */
+/* kate: replace-tabs on; space-indent on; tab-indents off; indent-width 4; */
+/* kate: line-numbers on; folding-markers on; remove-trailing-space on; */
+/* kate: backspace-indents on; show-tabs on; */
+/* kate: word-wrap-column 80; word-wrap-marker-color #D2D2D2; word-wrap off; */
diff --git a/src/dpeuckere.c b/src/dpeuckere.c
new file mode 100644
index 0000000..5436759
--- /dev/null
+++ b/src/dpeuckere.c
@@ -0,0 +1,1495 @@
+/* -*- coding: utf-8 -*- */
+/**
+\ingroup geom
+@{
+\file dpeuckere.c
+\brief Definición de funciones auxiliares para el aligerado de polilíneas sobre
+ la superficie de la esfera, basadas en el algoritmo de Douglas-Peucker.
+\author José Luis García Pallero, jgpallero@gmail.com
+\note Este fichero contiene funciones paralelizadas con OpenMP.
+\date 15 de agosto de 2013
+\copyright
+Copyright (c) 2013-2020, José Luis García Pallero. All rights reserved.
+\par
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+\par
+- Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+- Neither the name of the copyright holders nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+\par
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/******************************************************************************/
+/******************************************************************************/
+#include"libgeoc/dpeuckere.h"
+/******************************************************************************/
+/******************************************************************************/
+int GeocParOmpDpeuckere(char version[])
+{
+ //comprobamos si hay paralelización
+#if defined(_OPENMP)
+ //comprobamos si hay que extraer versión
+ if(version!=NULL)
+ {
+ //calculamos la versión
+ VersionOpenMP(_OPENMP,version);
+ }
+ //salimos de la función
+ return 1;
+#else
+ if(version!=NULL)
+ {
+ //utilizamos la variable version para que no dé warming al compilar
+ strcpy(version,"");
+ }
+ //salimos de la función
+ return 0;
+#endif
+}
+/******************************************************************************/
+/******************************************************************************/
+void DouglasPeuckerOriginalEsfera(const double* x,
+ const double* y,
+ const size_t nPtos,
+ const size_t incX,
+ const size_t incY,
+ const double tol,
+ const size_t posIni,
+ const size_t posFin,
+ char* usados)
+{
+ //índice para recorrer bucles
+ size_t i=0;
+ //seno de la distancia angular de los puntos al segmento base
+ double dist=0.0;
+ //valor absoluto del seno de la tolerancia, excepto en el caso en que ésta
+ //sea mayor que pi/2, que hacemos 1-cos(tol) para que quede un valor mayor
+ //que 1
+ double stol=(tol<=(2.0*GEOC_CONST_PI)) ? fabs(sin(tol)) : 1.0-cos(tol);
+ //posición de la distancia máxima
+ size_t pos=0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //comprobamos casos especiales
+ if((nPtos<=2)||(stol==0.0))
+ {
+ //se usan todos los puntos
+ for(i=0;i<nPtos;i++)
+ {
+ usados[i] = 1;
+ }
+ //salimos de la función
+ return;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //sólo continuamos si los puntos extremos no están seguidos
+ if(posIni!=(posFin-1))
+ {
+ //calculamos la distancia máxima de los puntos de trabajo al arco
+ //formado por los extremos
+ dist = DouglasPeuckerSenDistMaxEsfera(y,x,incY,incX,posIni,posFin,&pos);
+ //comprobamos si esa distancia está fuera de tolerancia
+ if(dist>stol)
+ {
+ //indicamos que el punto se usa
+ usados[pos] = 1;
+ //paralelización con OpenMP
+#if defined(_OPENMP)
+#pragma omp parallel sections default(none) \
+ shared(incY,y,incX,x,nPtos,tol,posIni,posFin,pos,usados)
+#endif
+{
+#if defined(_OPENMP)
+#pragma omp section
+#endif
+ //aplicamos el algoritmo a la parte anterior al punto de trabajo
+ DouglasPeuckerOriginalEsfera(x,y,nPtos,incX,incY,tol,posIni,pos,
+ usados);
+#if defined(_OPENMP)
+#pragma omp section
+#endif
+ //aplicamos el algoritmo a la parte posterior al punto de trabajo
+ DouglasPeuckerOriginalEsfera(x,y,nPtos,incX,incY,tol,pos,posFin,
+ usados);
+} // --> fin del #pragma omp parallel sections
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return;
+}
+/******************************************************************************/
+/******************************************************************************/
+size_t* DouglasPeuckerRobustoEsfera(const double* x,
+ const double* y,
+ const size_t nPtos,
+ const size_t incX,
+ const size_t incY,
+ const double tol,
+ const int paralelizaTol,
+ const enum GEOC_DPEUCKER_ROBUSTO robusto,
+ const size_t nSegRobOrig,
+ const size_t nSegRobAuto,
+ size_t* nPtosSal)
+{
+ //índices para recorrer bucles
+ size_t i=0,j=0;
+ //valor absoluto de la tolerancia
+ double atol=fabs(tol);
+ //tolerancia angular
+ double tolAng=fabs(GEOC_ARC_RES_ANG);
+ //coordenadas de trabajo
+ double lonFinR=0.0;
+ //matriz de rotación
+ double mRot[3][3];
+ //variable indicadora de punto en tolerancia
+ int entol=0;
+ //identificador de caso especial
+ int hayCasoEspecial=0;
+ //identificadores de utilización de algoritmos semi robustos
+ int robOrig=0,robAuto=0;
+ //número de elementos de trabajo internos del vector de salida
+ size_t nElem=0;
+ //identificador de paralelización
+ int paraleliza=0;
+ //vectores para almacenar coordenadas cartesianas geocéntricas
+ double* xG=NULL;
+ double* yG=NULL;
+ double* zG=NULL;
+ //variable auxiliar
+ double cLat=0.0,latVert=0.0,lonVert=0.0;
+ //vector de salida
+ size_t* sal=NULL;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //comprobamos casos especiales
+ sal = CasosEspecialesAligeraPolilinea(x,y,nPtos,incX,incY,atol,nPtosSal,
+ &hayCasoEspecial);
+ //comprobamos si ha habido algún caso especial
+ if(hayCasoEspecial)
+ {
+ //comprobamos si ha ocurrido algún error de asignación de memoria
+ if(nPtos&&(sal==NULL))
+ {
+ //mensaje de error
+ GEOC_ERROR("Error de asignación de memoria");
+ //salimos de la función
+ return NULL;
+ }
+ else
+ {
+ //salimos de la función
+ return sal;
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //asignamos memoria para las coordenadas cartesianas geocéntricas
+ xG = (double*)malloc(nPtos*sizeof(double));
+ yG = (double*)malloc(nPtos*sizeof(double));
+ zG = (double*)malloc(nPtos*sizeof(double));
+ //comprobamos los posibles errores
+ if((xG==NULL)||(yG==NULL)||(zG==NULL))
+ {
+ //liberamos la posible memoeia asignada
+ free(xG);
+ free(yG);
+ free(zG);
+ //mensaje de error
+ GEOC_ERROR("Error de asignación de memoria");
+ //salimos de la función
+ return NULL;
+ }
+ //paralelización con OpenMP
+#if defined(_OPENMP)
+#pragma omp parallel for default(none) \
+ shared(nPtos,incY,y,incX,x,xG,yG,zG) \
+ private(i,latVert,lonVert,cLat)
+#endif
+ //recorremos los puntos de trabajo
+ for(i=0;i<nPtos;i++)
+ {
+ //extraemos las coordenadas geodésicas
+ latVert = y[i*incY];
+ lonVert = x[i*incX];
+ //calculamos el coseno de la latitud
+ cLat = cos(latVert);
+ //calculamos las coordenadas cartesianas, considerando radio unidad
+ xG[i] = cLat*cos(lonVert);
+ yG[i] = cLat*sin(lonVert);
+ zG[i] = sin(latVert);
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //comprobamos si se utiliza algoritmo de intersección con línea original
+ if((robusto==GeocDPeuckerRobSi)||(robusto==GeocDPeuckerRobOrig))
+ {
+ robOrig = 1;
+ }
+ //comprobamos si se utiliza algoritmo de intersección con línea generada
+ if((robusto==GeocDPeuckerRobSi)||(robusto==GeocDPeuckerRobAuto))
+ {
+ robAuto = 1;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+#if defined(_OPENMP)
+ //comprobamos si hay más de un procesador
+ if(omp_get_num_procs()>1)
+ {
+ //indicamos que hay paralelización
+ paraleliza = 1;
+ }
+#endif
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //inicializamos el indicador interno de tamaño del vector
+ nElem = GEOC_DPEUCKER_BUFFER_PTOS;
+ //asignamos memoria para el vector de salida
+ sal = (size_t*)malloc(nElem*sizeof(size_t));
+ //comprobamos los posibles errores
+ if(sal==NULL)
+ {
+ //liberamos la posible memoria asignada
+ free(xG);
+ free(yG);
+ free(zG);
+ //mensaje de error
+ GEOC_ERROR("Error de asignación de memoria");
+ //salimos de la función
+ return NULL;
+ }
+ //indicamos que el primer punto siempre se usa
+ *nPtosSal = 1;
+ sal[0] = 0;
+ //puntos de trabajo para iniciar los cálculos
+ i = 0;
+ j = 2;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //entramos en un bucle mientras no hayamos llegado hasta el último punto
+ while(j<nPtos)
+ {
+ //hacemos el cambio de sistema para qua la base AB quede en el ecuador,
+ //con A en el punto (lat=0,lon=0)
+ RotaArco00Ecuador(tolAng,y[i*incY],x[i*incX],y[j*incY],x[j*incX],mRot,
+ &lonFinR);
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ //comprobamos si los puntos intermedios están en tolerancia
+ //sólo paralelizamos si el número de puntos intermedios es mayor que uno
+ if(paraleliza&&paralelizaTol&&((j-i-1)>1))
+ {
+ //aplicamos el algoritmo en paralelo
+ entol = DouglasPeuckerPuntosEnTolEsferaOMP(x,y,incX,incY,xG,yG,zG,
+ atol,i,j,i+1,j-1,lonFinR,
+ mRot);
+ }
+ else
+ {
+ //aplicamos el algoritmo en serie
+ entol = DouglasPeuckerPuntosEnTolEsferaSerie(x,y,incX,incY,xG,yG,zG,
+ atol,i,j,i+1,j-1,
+ lonFinR,mRot);
+ }
+ //comprobamos si todos los puntos están en tolerancia
+ if(entol)
+ {
+ //pasamos al siguiente punto como extremo del segmento
+ j++;
+ }
+ else
+ {
+ //el punto final será el anterior al actual, ya que con el actual
+ //hay al menos un vértice fuera de tolerancia y con el anterior se
+ //comprobó en el paso previo del bucle que no había ningún vértice
+ //fuera
+ j--;
+ //aplicación del algoritmo de intersección con puntos originales
+ if(robOrig)
+ {
+ //aplicamos el algoritmo
+ DouglasPeuckerRobIntersecOrigEsfera(x,y,nPtos,incX,incY,xG,yG,
+ zG,nSegRobOrig,i,&j);
+ }
+ //aplicación del algoritmo de auto intersección
+ if(robAuto)
+ {
+ //aplicamos el algoritmo
+ DouglasPeuckerRobAutoIntersecEsfera(x,y,incX,incY,xG,yG,zG,i,&j,
+ sal,*nPtosSal,nSegRobAuto);
+ }
+ //añadimos al contador el nuevo punto
+ (*nPtosSal)++;
+ //comprobamos si hay que reasignar memoria
+ if((*nPtosSal)>nElem)
+ {
+ //añadimos otro grupo de puntos
+ nElem += GEOC_DPEUCKER_BUFFER_PTOS;
+ //asignamos memoria para el vector de salida
+ sal = (size_t*)realloc(sal,nElem*sizeof(size_t));
+ //comprobamos los posibles errores
+ if(sal==NULL)
+ {
+ //liberamos la posible memoria asignada
+ free(xG);
+ free(yG);
+ free(zG);
+ //mensaje de error
+ GEOC_ERROR("Error de asignación de memoria");
+ //salimos de la función
+ return NULL;
+ }
+ }
+ //añadimos el punto al vector de salida
+ sal[(*nPtosSal)-1] = j;
+ //actualizamos los índices de los puntos de trabajo
+ i = j;
+ j = i+2;
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //comprobamos si hay que añadir el último punto
+ if((sal[(*nPtosSal)-1]!=(nPtos-1))&&
+ ((x[sal[(*nPtosSal)-1]*incX]!=x[(nPtos-1)*incX])||
+ (y[sal[(*nPtosSal)-1]*incY]!=y[(nPtos-1)*incY])))
+ {
+ //añadimos al contador el último punto
+ (*nPtosSal)++;
+ //comprobamos si hay que reasignar memoria
+ if((*nPtosSal)>nElem)
+ {
+ //añadimos otro grupo de puntos
+ nElem += GEOC_DPEUCKER_BUFFER_PTOS;
+ //asignamos memoria para el vector de salida
+ sal = (size_t*)realloc(sal,nElem*sizeof(size_t));
+ //comprobamos los posibles errores
+ if(sal==NULL)
+ {
+ //liberamos la posible memoria asignada
+ free(xG);
+ free(yG);
+ free(zG);
+ //mensaje de error
+ GEOC_ERROR("Error de asignación de memoria");
+ //salimos de la función
+ return NULL;
+ }
+ }
+ //asignamos el último punto
+ sal[(*nPtosSal)-1] = nPtos-1;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //comprobamos si el vector de salida tiene demasiada memoria asignada
+ if(nElem>(*nPtosSal))
+ {
+ //ajustamos el tamaño del vector de salida
+ sal = (size_t*)realloc(sal,(*nPtosSal)*sizeof(size_t));
+ //comprobamos los posibles errores
+ if(sal==NULL)
+ {
+ //liberamos la posible memoria asignada
+ free(xG);
+ free(yG);
+ free(zG);
+ //mensaje de error
+ GEOC_ERROR("Error de asignación de memoria");
+ //salimos de la función
+ return NULL;
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //liberamos la posible memoria asignada
+ free(xG);
+ free(yG);
+ free(zG);
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return sal;
+}
+/******************************************************************************/
+/******************************************************************************/
+int DouglasPeuckerPuntosEnTolEsferaOMP(const double* x,
+ const double* y,
+ const size_t incX,
+ const size_t incY,
+ const double* xG,
+ const double* yG,
+ const double* zG,
+ const double tol,
+ const size_t posBaseIni,
+ const size_t posBaseFin,
+ const size_t posPtoIni,
+ const size_t posPtoFin,
+ const double lonFinR,
+ double mRot[][3])
+{
+ //índice para recorrer bucles
+ size_t i=0;
+ //valor absoluto de la tolerancia
+ double atol=fabs(tol);
+ //identificador de punto fuera de tolerancia
+ int ftol=0;
+ //coordenadas de los vértices de trabajo
+ double xTrab=0.0,yTrab=0.0,xGTrab=0.0,yGTrab=0.0,zGTrab=0.0;
+ //distancia calculada
+ double dist=0.0;
+ //identificador de existencia de coordenadas cartesianas geocéntricas
+ int ccart=0;
+ //variable de salida
+ int entol=1;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //comprobamos salida rápida
+ if((posBaseIni+1)>=posBaseFin)
+ {
+ //salimos de la función
+ return entol;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //valor absoluto del seno de la tolerancia, excepto en el caso en que ésta
+ //sea mayor que pi/2, que hacemos 1-cos(tol) para que quede un valor > 1
+ atol = (atol<=(2.0*GEOC_CONST_PI)) ? sin(atol) : 1.0-cos(atol);
+ //comprobamos si se han pasado coordenadas cartesianas geocénticas
+ if((xG!=NULL)&&(yG!=NULL)&&(zG!=NULL))
+ {
+ //indicamos que sí existen
+ ccart = 1;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //paralelización con OpenMP
+#if defined(_OPENMP)
+#pragma omp parallel for default(none) \
+ shared(posPtoIni,posPtoFin,incX,x,incY,y,ccart,xG,yG,zG,mRot,lonFinR,atol) \
+ private(i,xTrab,yTrab,xGTrab,yGTrab,zGTrab,dist) \
+ reduction(+:ftol)
+#endif
+ //recorremos los puntos de trabajo
+ for(i=posPtoIni;i<=posPtoFin;i++)
+ {
+ //sólo calculo si no se ha encontrado ningún punto fuera de tolerancia
+ //en este hilo
+ if(!ftol)
+ {
+ //extraemos las coordenadas del vértice de trabajo
+ xTrab = x[i*incX];
+ yTrab = y[i*incY];
+ //comprobamos si hay coordenadas cartesianas
+ if(ccart)
+ {
+ //extraigo las coordenadas cartesianas del vértice de trabajo
+ xGTrab = xG[i];
+ yGTrab = yG[i];
+ zGTrab = zG[i];
+ }
+ else
+ {
+ //como no hay coordenadas cartesianas, asigno NaN
+ xGTrab = GeocNan();
+ yGTrab = xGTrab;
+ zGTrab = xGTrab;
+ }
+ //calculamos la distancia sobre la esfera de radio unidad
+ dist = DouglasPeuckerSenDistMaxEsferaAux(yTrab,xTrab,xGTrab,yGTrab,
+ zGTrab,lonFinR,mRot);
+ //comprobamos si está fuera de tolerancia
+ if(dist>atol)
+ {
+ //aumentamos el indicador de fuera de tolerancia
+ ftol++;
+ }
+ }
+ } // --> fin del #pragma omp parallel for
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //comprobamos si hay algún punto fuera de tolerancia
+ if(ftol)
+ {
+ //indicamos que hay algún punto que no está en tolerancia
+ entol = 0;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return entol;
+}
+/******************************************************************************/
+/******************************************************************************/
+int DouglasPeuckerPuntosEnTolEsferaSerie(const double* x,
+ const double* y,
+ const size_t incX,
+ const size_t incY,
+ const double* xG,
+ const double* yG,
+ const double* zG,
+ const double tol,
+ const size_t posBaseIni,
+ const size_t posBaseFin,
+ const size_t posPtoIni,
+ const size_t posPtoFin,
+ const double lonFinR,
+ double mRot[][3])
+{
+ //índice para recorrer bucles
+ size_t i=0;
+ //valor absoluto de la tolerancia
+ double atol=fabs(tol);
+ //coordenadas de los vértices
+ double xTrab=0.0,yTrab=0.0;
+ double xGTrab=GeocNan(),yGTrab=GeocNan(),zGTrab=GeocNan();
+ //distancia calculada
+ double dist=0.0;
+ //identificador de existencia de coordenadas cartesianas geocéntricas
+ int ccart=0;
+ //variable de salida
+ int entol=1;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //comprobamos salida rápida
+ if((posBaseIni+1)>=posBaseFin)
+ {
+ //salimos de la función
+ return entol;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //valor absoluto del seno de la tolerancia, excepto en el caso en que ésta
+ //sea mayor que pi/2, que hacemos 1-cos(tol) para que quede un valor > 1
+ atol = (atol<=(2.0*GEOC_CONST_PI)) ? sin(atol) : 1.0-cos(atol);
+ //comprobamos si se han pasado coordenadas cartesianas geocénticas
+ if((xG!=NULL)&&(yG!=NULL)&&(zG!=NULL))
+ {
+ //indicamos que sí existen
+ ccart = 1;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //recorremos los puntos a chequear
+ for(i=posPtoIni;i<=posPtoFin;i++)
+ {
+ //extraemos las coordenadas del vértice de trabajo
+ xTrab = x[i*incX];
+ yTrab = y[i*incY];
+ //extraemos las coordenadas cartesianas del vértice de trabajo
+ if(ccart)
+ {
+ xGTrab = xG[i];
+ yGTrab = yG[i];
+ zGTrab = zG[i];
+ }
+ //calculamos la distancia sobre la esfera de radio unidad
+ dist = DouglasPeuckerSenDistMaxEsferaAux(yTrab,xTrab,xGTrab,yGTrab,
+ zGTrab,lonFinR,mRot);
+ //comprobamos si está fuera de tolerancia
+ if(dist>atol)
+ {
+ //indicamos que estamos fuera de tolerancia
+ entol = 0;
+ //salimos del bucle
+ break;
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return entol;
+}
+/******************************************************************************/
+/******************************************************************************/
+void DouglasPeuckerRobIntersecOrigEsfera(const double* x,
+ const double* y,
+ const size_t nPtos,
+ const size_t incX,
+ const size_t incY,
+ const double* xG,
+ const double* yG,
+ const double* zG,
+ const size_t segAUsar,
+ const size_t posIni,
+ size_t* posFin)
+{
+ //índice para recorrer bucles
+ size_t i=0;
+ //coordenadas del arco base
+ double xA=0.0,yA=0.0,xB=0.0,yB=0.0;
+ //posición de parada para comprobar la intersección de arcos
+ size_t posParada=0;
+ //identificación de paralelización
+ int paraleliza=0;
+ //variable identificadora de existencia de corte de segmentos
+ int corte=0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //si los puntos de inicio y fin son contiguos, hay salida rápida
+ if((posIni+1)>=(*posFin))
+ {
+ //salimos de la función
+ return;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+#if defined(_OPENMP)
+ //comprobamos si hay más de un procesador
+ if(omp_get_num_procs()>1)
+ {
+ //indicamos que hay paralelización
+ paraleliza = 1;
+ }
+#endif
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //posición de parada para el chequeo de segmentos/arcos
+ posParada = ((segAUsar==0)||(segAUsar>=(nPtos-(*posFin))))
+ ? nPtos-1
+ : (*posFin)+segAUsar;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //coordenadas del punto inicial del segmento/arco base (no cambian)
+ xA = x[posIni*incX];
+ yA = y[posIni*incY];
+ //construimos todos los segmentos/arcos base posibles
+ for(i=(*posFin);i>posIni;i--)
+ {
+ //comprobamos si estamos ante el punto posterior al inicial
+ if(i==(posIni+1))
+ {
+ //este punto es el siguiente al punto inicial del segmento/arco base
+ *posFin = i;
+ //salimos del bucle
+ break;
+ }
+ //coordenadas del punto final del segmento/arco base
+ xB = x[i*incX];
+ yB = y[i*incY];
+ //comprobamos si hay que paralelizar
+ if(paraleliza)
+ {
+ //calculamos en paralelo
+ corte = DouglasPeuckerRobIntersecOrigEsferaOMP(xA,yA,xB,yB,x,y,incX,
+ incY,xG,yG,zG,i,
+ posParada);
+ }
+ else
+ {
+ //calculamos en serie
+ corte = DouglasPeuckerRobIntersecOrigEsferaSerie(xA,yA,xB,yB,x,y,
+ incX,incY,xG,yG,zG,
+ i,posParada);
+ }
+ //comprobamos si no ha habido ninguna intersección
+ if(!corte)
+ {
+ //indicamos el índice del vértice final
+ *posFin = i;
+ //salimos del bucle de segmentos base
+ break;
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return;
+}
+/******************************************************************************/
+/******************************************************************************/
+int DouglasPeuckerRobIntersecOrigEsferaOMP(const double xA,
+ const double yA,
+ const double xB,
+ const double yB,
+ const double* x,
+ const double* y,
+ const size_t incX,
+ const size_t incY,
+ const double* xG,
+ const double* yG,
+ const double* zG,
+ const size_t posIni,
+ const size_t posFin)
+{
+ //índice para recorrer bucles
+ size_t i=0;
+ //tolerancia angular
+ double tol=fabs(GEOC_ARC_RES_ANG);
+ //coordenadas de los arcos de trabajo
+ double xC=0.0,yC=0.0,xD=0.0,yD=0.0;
+ double xBR=0.0,xCR=0.0,yCR=0.0,xDR=0.0,yDR=0.0;
+ double xGC=0.0,yGC=0.0,zGC=0.0,xGD=0.0,yGD=0.0,zGD=0.0;
+ double xGCR=0.0,yGCR=0.0,zGCR=0.0,xGDR=0.0,yGDR=0.0,zGDR=0.0;
+ //matriz de rotación
+ double mRot[3][3];
+ //identificador de haber pasado coordenadas cartesianas
+ int ccart=0;
+ //variable de salida
+ int corte=0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //llevamos AB al ecuador, con A en (lat=0,lon=0)
+ RotaArco00Ecuador(tol,yA,xA,yB,xB,mRot,&xBR);
+ //comprobamos si se han pasado coordenadas cartesianas
+ if((xG!=NULL)&&(yG!=NULL)&&(zG!=NULL))
+ {
+ //se han pasado
+ ccart = 1;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //paralelización con OpenMP
+#if defined(_OPENMP)
+#pragma omp parallel for default(none) \
+ shared(posIni,posFin,incX,x,incY,y,tol,xA,xB,ccart,xG,yG,zG,mRot,xBR) \
+ private(i,xGC,yGC,zGC,xGD,yGD,zGD,xGCR,yGCR,zGCR,xGDR,yGDR,zGDR, \
+ xC,yC,xD,yD,xCR,yCR,xDR,yDR) \
+ reduction(+:corte)
+#endif
+ //recorremos los puntos de trabajo
+ for(i=posIni;i<posFin;i++)
+ {
+ //sólo realizo cálculos si no se ha encontrado ningún corte en este hilo
+ if(!corte)
+ {
+ //puntos inicial y final del siguiente segmento/arco de trabajo
+ xC = x[i*incX];
+ yC = y[i*incY];
+ xD = x[(i+1)*incX];
+ yD = y[(i+1)*incY];
+ //sigo si los rectángulos que encierran a los segmentos se cortan
+ if(!ArcosCircMaxDisjuntos(tol,
+ GEOC_MIN(xA,xB),GEOC_MAX(xA,xB),
+ GEOC_MIN(xC,xD),GEOC_MAX(xC,xD)))
+ {
+ //comprobamos si hay coordenadas cartesianas
+ if(ccart)
+ {
+ //extraigo las coordenadas cartesianas
+ xGC = xG[i];
+ yGC = yG[i];
+ zGC = zG[i];
+ xGD = xG[i+1];
+ yGD = yG[i+1];
+ zGD = zG[i+1];
+ //aplico la rotación a las coordenadas cartesianas
+ AplicaMatrizRotacionCoorCart(1,xGC,yGC,zGC,mRot,&xGCR,&yGCR,
+ &zGCR);
+ AplicaMatrizRotacionCoorCart(1,xGD,yGD,zGD,mRot,&xGDR,&yGDR,
+ &zGDR);
+ //coordenadas geodésicas de los puntos rotados
+ yCR = asin(zGCR);
+ xCR = atan2(yGCR,xGCR);
+ yDR = asin(zGDR);
+ xDR = atan2(yGDR,xGDR);
+ }
+ else
+ {
+ //como no hay coordenadas cartesianas, asigno NaN
+ xGCR = GeocNan();
+ yGCR = xGCR;
+ zGCR = xGCR;
+ xGDR = xGCR;
+ yGDR = xGCR;
+ zGDR = xGCR;
+ //rotamos las coordenadas de C y D
+ AplicaMatrizRotacionCoorGeod(1,yC,xC,mRot,&yCR,&xCR);
+ AplicaMatrizRotacionCoorGeod(1,yD,xD,mRot,&yDR,&xDR);
+ }
+ //comprobamos si hay intersección
+ corte += DouglasPeuckerRobIntersecEsfera(xBR,xCR,yCR,xDR,yDR,
+ xGCR,yGCR,zGCR,xGDR,
+ yGDR,zGDR,posIni,i);
+ }
+ }
+ } // --> fin del #pragma omp parallel for
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return corte;
+}
+/******************************************************************************/
+/******************************************************************************/
+int DouglasPeuckerRobIntersecOrigEsferaSerie(const double xA,
+ const double yA,
+ const double xB,
+ const double yB,
+ const double* x,
+ const double* y,
+ const size_t incX,
+ const size_t incY,
+ const double* xG,
+ const double* yG,
+ const double* zG,
+ const size_t posIni,
+ const size_t posFin)
+{
+ //índice para recorrer bucles
+ size_t i=0;
+ //tolerancia angular
+ double tol=fabs(GEOC_ARC_RES_ANG);
+ //coordenadas de los segmentos de trabajo
+ double xC=0.0,yC=0.0,xD=0.0,yD=0.0;
+ double xBR=0.0,xCR=0.0,yCR=0.0,xDR=0.0,yDR=0.0;
+ double xGC=0.0,yGC=0.0,zGC=0.0,xGD=0.0,yGD=0.0,zGD=0.0;
+ double xGCR=GeocNan(),yGCR=GeocNan(),zGCR=GeocNan();
+ double xGDR=GeocNan(),yGDR=GeocNan(),zGDR=GeocNan();
+ //matriz de rotación
+ double mRot[3][3];
+ //identificador de haber pasado coordenadas cartesianas
+ int ccart=0;
+ //variable de salida
+ int corte=0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //llevamos AB al ecuador, con A en (lat=0,lon=0)
+ RotaArco00Ecuador(tol,yA,xA,yB,xB,mRot,&xBR);
+ //comprobamos si se han pasado coordenadas cartesianas
+ if((xG!=NULL)&&(yG!=NULL)&&(zG!=NULL))
+ {
+ //se han pasado
+ ccart = 1;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //recorremos los puntos de trabajo
+ for(i=posIni;i<posFin;i++)
+ {
+ //puntos inicial y final del siguiente segmento/arco de trabajo
+ xC = x[i*incX];
+ yC = y[i*incY];
+ xD = x[(i+1)*incX];
+ yD = y[(i+1)*incY];
+ //seguimos si los rectángulos que encierran a los segmentos se cortan
+ if(!ArcosCircMaxDisjuntos(tol,
+ GEOC_MIN(xA,xB),GEOC_MAX(xA,xB),
+ GEOC_MIN(xC,xD),GEOC_MAX(xC,xD)))
+ {
+ //comprobamos si hay coordenadas cartesianas
+ if(ccart)
+ {
+ //extraigo las coordenadas cartesianas
+ xGC = xG[i];
+ yGC = yG[i];
+ zGC = zG[i];
+ xGD = xG[i+1];
+ yGD = yG[i+1];
+ zGD = zG[i+1];
+ //aplico la rotación a las coordenadas cartesianas
+ AplicaMatrizRotacionCoorCart(1,xGC,yGC,zGC,mRot,&xGCR,&yGCR,
+ &zGCR);
+ AplicaMatrizRotacionCoorCart(1,xGD,yGD,zGD,mRot,&xGDR,&yGDR,
+ &zGDR);
+ //coordenadas geodésicas de los puntos rotados
+ yCR = asin(zGCR);
+ xCR = atan2(yGCR,xGCR);
+ yDR = asin(zGDR);
+ xDR = atan2(yGDR,xGDR);
+ }
+ else
+ {
+ //rotamos las coordenadas de C y D
+ AplicaMatrizRotacionCoorGeod(1,yC,xC,mRot,&yCR,&xCR);
+ AplicaMatrizRotacionCoorGeod(1,yD,xD,mRot,&yDR,&xDR);
+ }
+ //comprobamos si hay intersección
+ corte = DouglasPeuckerRobIntersecEsfera(xBR,xCR,yCR,xDR,yDR,xGCR,
+ yGCR,zGCR,xGDR,yGDR,zGDR,
+ posIni,i);
+ }
+ //si ha habido intersección de segmentos/arcos, salimos del bucle
+ if(corte)
+ {
+ //salimos del bucle
+ break;
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return corte;
+}
+/******************************************************************************/
+/******************************************************************************/
+void DouglasPeuckerRobAutoIntersecEsfera(const double* x,
+ const double* y,
+ const size_t incX,
+ const size_t incY,
+ const double* xG,
+ const double* yG,
+ const double* zG,
+ const size_t posIni,
+ size_t* posFin,
+ const size_t* posAlig,
+ const size_t nPosAlig,
+ const size_t segAUsar)
+{
+ //índice para recorrer bucles
+ size_t i=0;
+ //coordenadas del arco base
+ double xA=0.0,yA=0.0,xB=0.0,yB=0.0;
+ //posición de parada para comprobar la intersección de arcos
+ size_t posParada=0;
+ //identificación de paralelización
+ int paraleliza=0;
+ //variable identificadora de existencia de corte de segmentos
+ int corte=0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //si los puntos de inicio y fin son contiguos, hay salida rápida
+ if((posIni+1)>=(*posFin))
+ {
+ //salimos de la función
+ return;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+#if defined(_OPENMP)
+ //comprobamos si hay más de un procesador
+ if(omp_get_num_procs()>1)
+ {
+ //indicamos que hay paralelización
+ paraleliza = 1;
+ }
+#endif
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //posición de parada en el vector posAlig para el chequeo de segmentos/arcos
+ posParada = ((segAUsar==0)||(segAUsar>=(nPosAlig-1)))
+ ? 0
+ : nPosAlig-1-segAUsar;
+ //coordenadas del punto inicial del arco base (no cambian)
+ xA = x[posIni*incX];
+ yA = y[posIni*incY];
+ //construimos todos los arcos base posibles
+ for(i=(*posFin);i>posIni;i--)
+ {
+ //comprobamos si estamos ante el punto posterior al inicial
+ if(i==(posIni+1))
+ {
+ //este punto es el siguiente al punto inicial del segmento/arco base
+ *posFin = i;
+ //salimos del bucle
+ break;
+ }
+ //coordenadas del punto final del segmento/arco base
+ xB = x[i*incX];
+ yB = y[i*incY];
+ //comprobamos si hay que paralelizar
+ if(paraleliza)
+ {
+ //calculamos en paralelo
+ corte = DouglasPeuckerRobAutoIntersecEsferaOMP(xA,yA,xB,yB,x,y,incX,
+ incY,xG,yG,zG,
+ posAlig,nPosAlig,
+ nPosAlig-1,
+ posParada);
+ }
+ else
+ {
+ //calculamos en serie
+ corte = DouglasPeuckerRobAutoIntersecEsferaSerie(xA,yA,xB,yB,x,y,
+ incX,incY,xG,yG,zG,
+ posAlig,nPosAlig,
+ nPosAlig-1,
+ posParada);
+ }
+ //comprobamos si no ha habido ninguna intersección
+ if(!corte)
+ {
+ //indicamos el índice del vértice final
+ *posFin = i;
+ //salimos del bucle de segmentos base
+ break;
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return;
+}
+/******************************************************************************/
+/******************************************************************************/
+int DouglasPeuckerRobAutoIntersecEsferaOMP(const double xA,
+ const double yA,
+ const double xB,
+ const double yB,
+ const double* x,
+ const double* y,
+ const size_t incX,
+ const size_t incY,
+ const double* xG,
+ const double* yG,
+ const double* zG,
+ const size_t* posAlig,
+ const size_t nPosAlig,
+ const size_t posIni,
+ const size_t posFin)
+{
+ //índice para recorrer bucles
+ size_t i=0;
+ //tolerancia angular
+ double tol=fabs(GEOC_ARC_RES_ANG);
+ //coordenadas de los segmentos de trabajo
+ double xC=0.0,yC=0.0,xD=0.0,yD=0.0;
+ double xBR=0.0,xCR=0.0,yCR=0.0,xDR=0.0,yDR=0.0;
+ double xGC=0.0,yGC=0.0,zGC=0.0,xGD=0.0,yGD=0.0,zGD=0.0;
+ double xGCR=0.0,yGCR=0.0,zGCR=0.0,xGDR=0.0,yGDR=0.0,zGDR=0.0;
+ //matriz de rotación
+ double mRot[3][3];
+ //identificador de haber pasado coordenadas cartesianas
+ int ccart=0;
+ //variable de salida
+ int corte=0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //llevamos AB al ecuador, con A en (lat=0,lon=0)
+ RotaArco00Ecuador(tol,yA,xA,yB,xB,mRot,&xBR);
+ //comprobamos si se han pasado coordenadas cartesianas
+ if((xG!=NULL)&&(yG!=NULL)&&(zG!=NULL))
+ {
+ //se han pasado
+ ccart = 1;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //paralelización con OpenMP
+#if defined(_OPENMP)
+#pragma omp parallel for default(none) \
+ shared(posIni,posFin,incX,x,posAlig,incY,y,tol,xA,xB,ccart,xG,yG,zG,mRot,xBR, \
+ nPosAlig) \
+ private(i,xGC,yGC,zGC,xGD,yGD,zGD,xGCR,yGCR,zGCR,xGDR,yGDR,zGDR, \
+ xC,yC,xD,yD,xCR,yCR,xDR,yDR) \
+ reduction(+:corte)
+#endif
+ //recorremos los puntos de trabajo
+ for(i=posIni;i>posFin;i--)
+ {
+ //sólo realizo cálculos si no se ha encontrado ningún corte en este hilo
+ if(!corte)
+ {
+ //puntos inicial y final del siguiente segmento/arco de trabajo
+ xC = x[posAlig[i]*incX];
+ yC = y[posAlig[i]*incY];
+ xD = x[posAlig[i-1]*incX];
+ yD = y[posAlig[i-1]*incY];
+ //sigo si los rectángulos que encierran a los segmentos se cortan
+ if(!ArcosCircMaxDisjuntos(tol,
+ GEOC_MIN(xA,xB),GEOC_MAX(xA,xB),
+ GEOC_MIN(xC,xD),GEOC_MAX(xC,xD)))
+ {
+ //comprobamos si hay coordenadas cartesianas
+ if(ccart)
+ {
+ //extraigo las coordenadas cartesianas
+ xGC = xG[posAlig[i]];
+ yGC = yG[posAlig[i]];
+ zGC = zG[posAlig[i]];
+ xGD = xG[posAlig[i-1]];
+ yGD = yG[posAlig[i-1]];
+ zGD = zG[posAlig[i-1]];
+ //aplico la rotación a las coordenadas cartesianas
+ AplicaMatrizRotacionCoorCart(1,xGC,yGC,zGC,mRot,&xGCR,&yGCR,
+ &zGCR);
+ AplicaMatrizRotacionCoorCart(1,xGD,yGD,zGD,mRot,&xGDR,&yGDR,
+ &zGDR);
+ //coordenadas geodésicas de los puntos rotados
+ yCR = asin(zGCR);
+ xCR = atan2(yGCR,xGCR);
+ yDR = asin(zGDR);
+ xDR = atan2(yGDR,xGDR);
+ }
+ else
+ {
+ //como no hay coordenadas cartesianas, asigno NaN
+ xGCR = GeocNan();
+ yGCR = xGCR;
+ zGCR = xGCR;
+ xGDR = xGCR;
+ yGDR = xGCR;
+ zGDR = xGCR;
+ //rotamos las coordenadas de C y D
+ AplicaMatrizRotacionCoorGeod(1,yC,xC,mRot,&yCR,&xCR);
+ AplicaMatrizRotacionCoorGeod(1,yD,xD,mRot,&yDR,&xDR);
+ }
+ //comprobamos si hay intersección
+ corte += DouglasPeuckerRobIntersecEsfera(xBR,xCR,yCR,xDR,yDR,
+ xGCR,yGCR,zGCR,xGDR,
+ yGDR,zGDR,
+ posAlig[nPosAlig-1],
+ posAlig[i]);
+ }
+ }
+ } // --> fin del #pragma omp parallel for
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return corte;
+}
+/******************************************************************************/
+/******************************************************************************/
+int DouglasPeuckerRobAutoIntersecEsferaSerie(const double xA,
+ const double yA,
+ const double xB,
+ const double yB,
+ const double* x,
+ const double* y,
+ const size_t incX,
+ const size_t incY,
+ const double* xG,
+ const double* yG,
+ const double* zG,
+ const size_t* posAlig,
+ const size_t nPosAlig,
+ const size_t posIni,
+ const size_t posFin)
+{
+ //índice para recorrer bucles
+ size_t i=0;
+ //tolerancia angular
+ double tol=fabs(GEOC_ARC_RES_ANG);
+ //coordenadas de los segmentos de trabajo
+ double xC=0.0,yC=0.0,xD=0.0,yD=0.0;
+ double xBR=0.0,xCR=0.0,yCR=0.0,xDR=0.0,yDR=0.0;
+ double xGC=0.0,yGC=0.0,zGC=0.0,xGD=0.0,yGD=0.0,zGD=0.0;
+ double xGCR=GeocNan(),yGCR=GeocNan(),zGCR=GeocNan();
+ double xGDR=GeocNan(),yGDR=GeocNan(),zGDR=GeocNan();
+ //matriz de rotación
+ double mRot[3][3];
+ //identificador de haber pasado coordenadas cartesianas
+ int ccart=0;
+ //variable de salida
+ int corte=0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //llevamos AB al ecuador, con A en (lat=0,lon=0)
+ RotaArco00Ecuador(tol,yA,xA,yB,xB,mRot,&xBR);
+ //comprobamos si se han pasado coordenadas cartesianas
+ if((xG!=NULL)&&(yG!=NULL)&&(zG!=NULL))
+ {
+ //se han pasado
+ ccart = 1;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //recorremos los puntos de trabajo
+ for(i=posIni;i>posFin;i--)
+ {
+ //puntos inicial y final del siguiente segmento/arco de trabajo
+ xC = x[posAlig[i]*incX];
+ yC = y[posAlig[i]*incY];
+ xD = x[posAlig[i-1]*incX];
+ yD = y[posAlig[i-1]*incY];
+ //seguimos si los rectángulos que encierran a los segmentos se cortan
+ if(!ArcosCircMaxDisjuntos(tol,
+ GEOC_MIN(xA,xB),GEOC_MAX(xA,xB),
+ GEOC_MIN(xC,xD),GEOC_MAX(xC,xD)))
+ {
+ //comprobamos si hay coordenadas cartesianas
+ if(ccart)
+ {
+ //extraigo las coordenadas cartesianas
+ xGC = xG[posAlig[i]];
+ yGC = yG[posAlig[i]];
+ zGC = zG[posAlig[i]];
+ xGD = xG[posAlig[i-1]];
+ yGD = yG[posAlig[i-1]];
+ zGD = zG[posAlig[i-1]];
+ //aplico la rotación a las coordenadas cartesianas
+ AplicaMatrizRotacionCoorCart(1,xGC,yGC,zGC,mRot,&xGCR,&yGCR,
+ &zGCR);
+ AplicaMatrizRotacionCoorCart(1,xGD,yGD,zGD,mRot,&xGDR,&yGDR,
+ &zGDR);
+ //coordenadas geodésicas de los puntos rotados
+ yCR = asin(zGCR);
+ xCR = atan2(yGCR,xGCR);
+ yDR = asin(zGDR);
+ xDR = atan2(yGDR,xGDR);
+ }
+ else
+ {
+ //rotamos las coordenadas de C y D
+ AplicaMatrizRotacionCoorGeod(1,yC,xC,mRot,&yCR,&xCR);
+ AplicaMatrizRotacionCoorGeod(1,yD,xD,mRot,&yDR,&xDR);
+ }
+ //comprobamos si hay intersección
+ corte = DouglasPeuckerRobIntersecEsfera(xBR,xCR,yCR,xDR,yDR,xGCR,
+ yGCR,zGCR,xGDR,yGDR,zGDR,
+ posAlig[nPosAlig-1],
+ posAlig[i]);
+ }
+ //si ha habido intersección de segmentos/arcos, salimos del bucle
+ if(corte)
+ {
+ //salimos del bucle
+ break;
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return corte;
+}
+/******************************************************************************/
+/******************************************************************************/
+int DouglasPeuckerRobIntersecEsfera(const double xB,
+ const double xC,
+ const double yC,
+ const double xD,
+ const double yD,
+ const double xGC,
+ const double yGC,
+ const double zGC,
+ const double xGD,
+ const double yGD,
+ const double zGD,
+ const size_t posFinAB,
+ const size_t posIniCD)
+{
+ //tolerancia angular
+ double tol=fabs(GEOC_ARC_RES_ANG);
+ //variables auxiliares
+ double xAux=0.0,yAux=0.0;
+ //identificador de intersección
+ int inter=GEOC_DPEUCKER_NO_INTERSEC;
+ //variable de salida
+ int corte=0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //seguimos si los rectángulos que encierran a los arcos se cortan
+ if(!ArcosCircMaxDisjuntos(tol,
+ GEOC_MIN(0.0,xB),GEOC_MAX(0.0,xB),
+ GEOC_MIN(xC,xD),GEOC_MAX(xC,xD)))
+ {
+ //comprobamos la posible intersección de los arcos
+ inter = IntersecArcCircMaxEsferaAux(tol,xB,yC,xC,yD,xD,xGC,yGC,zGC,xGD,
+ yGD,zGD,&yAux,&xAux);
+ //compruebo si los dos arcos son contiguos
+ if(posFinAB==posIniCD)
+ {
+ //compruebo si es la sucesión de arco inicial+final
+ if((inter!=GEOC_ARC_INTERSEC_MISMO_ARC)&&
+ (inter!=GEOC_ARC_INTERSEC_COLIN))
+ {
+ //en este caso, no hay intersección
+ inter = GEOC_DPEUCKER_NO_INTERSEC;
+ }
+ }
+ //unificamos los identificadores de intersección
+ if(!((inter==GEOC_ARC_NO_INTERSEC)||(inter==GEOC_DPEUCKER_NO_INTERSEC)))
+ {
+ //hay intersección
+ corte = 1;
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return corte;
+}
+/******************************************************************************/
+/******************************************************************************/
+double DouglasPeuckerSenDistMaxEsfera(const double* lat,
+ const double* lon,
+ const size_t incLat,
+ const size_t incLon,
+ const size_t posIni,
+ const size_t posFin,
+ size_t* pos)
+{
+ //índice para recorrer bucles
+ size_t i=0;
+ //tolerancia angular
+ double tol=fabs(GEOC_ARC_RES_ANG);
+ //coordenadas del punto de trabajo
+ double latP=0.0,lonP=0.0;
+ //matriz de rotación
+ double mRot[3][3];
+ //longitud del extremo final de la base en el sistema rotado
+ double lonFinR=0.0;
+ //variable auxiliar
+ double distAux=0.0;
+ //variable de salida
+ double dist=-1.0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //comprobamos si los dos puntos están seguidos
+ if((posIni+1)==posFin)
+ {
+ //la posición que devolvemos es la del punto inicial
+ *pos = posIni;
+ //la distancia devuelta es -1.0
+ return dist;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //calculamos la matriz de rotación para llevar la base al ecuador
+ RotaArco00Ecuador(tol,
+ lat[posIni*incLat],lon[posIni*incLon],
+ lat[posFin*incLat],lon[posFin*incLon],mRot,&lonFinR);
+ //recorremos los puntos entre los extremos
+ for(i=posIni+1;i<posFin;i++)
+ {
+ //extraemos las coordenadas del punto de trabajo
+ latP = lat[i*incLat];
+ lonP = lon[i*incLon];
+ //calculamos la distancia desde el punto a la base
+ distAux = DouglasPeuckerSenDistMaxEsferaAux(latP,lonP,GeocNan(),
+ GeocNan(),GeocNan(),lonFinR,
+ mRot);
+ //comprobamos si la distancia calculada es mayor que la anterior
+ if(distAux>dist)
+ {
+ //actualizamos la distancia máxima
+ dist = distAux;
+ //guardamos la posición del punto
+ *pos = i;
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return dist;
+}
+/******************************************************************************/
+/******************************************************************************/
+double DouglasPeuckerSenDistMaxEsferaAux(const double latVert,
+ const double lonVert,
+ const double xVert,
+ const double yVert,
+ const double zVert,
+ const double lonBase2R,
+ double mRot[][3])
+{
+ //coordenadas cartesianas tridimensionales geocéntricas
+ double x=0.0,y=0.0,z=0.0,xR=0.0,yR=0.0,zR=0.0,xB2R=0.0,yB2R=0.0;
+ //longitud del vértice en el sistema rotado
+ double lonVR=0.0;
+ //variables auxiliares
+ double cLat=0.0,alfa=0.0,cAlfa=0.0;
+ //variable de salida
+ double dist=0.0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //comprobamos si se han pasado las coordenadas cartesianas del vértice
+ if((!EsGeocNan(xVert))&&(!EsGeocNan(yVert))&&(!EsGeocNan(zVert)))
+ {
+ //asignamos las coordenadas a las variables de trabajo
+ x = xVert;
+ y = yVert;
+ z = zVert;
+ }
+ else
+ {
+ //calculamos las coordenadas tridimensionales del vértice de trabajo
+ cLat = cos(latVert);
+ x = cLat*cos(lonVert);
+ y = cLat*sin(lonVert);
+ z = sin(latVert);
+ }
+ //aplicamos la rotación
+ AplicaMatrizRotacionCoorCart(1,x,y,z,mRot,&xR,&yR,&zR);
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //distinguimos todos los casos de trabajo
+ if((xR==0.0)&&(yR==0.0))
+ {
+ //el vértice queda en el polo
+ dist = 1.0;
+ }
+ else
+ {
+ //distinguimos casos especiales
+ if(((lonBase2R>0.0)&&(yR<0.0))||((lonBase2R<0.0)&&(yR>0.0)))
+ {
+ //vértice fuera de la base: izquierda de AB o derecha de BA
+ //coseno del ángulo en el espacio que forma el eje X con el vector
+ //OV, es decir, entre los vectores (1,0,0) y (xR,yR,zR)
+ cAlfa = xR/sqrt(xR*xR+yR*yR+zR*zR);
+ //ángulo
+ alfa = acos(cAlfa);
+ //comprobamos si el ángulo es mayor o menor de pi/2
+ if(alfa<=(2.0*GEOC_CONST_PI))
+ {
+ //la variable de salida es el seno del ángulo
+ dist = sin(alfa);
+ }
+ else
+ {
+ //la variable de salida es 1 menos el coseno del ángulo, para
+ //quede un valor mayor que 1
+ dist = 1.0-cos(alfa);
+ }
+ }
+ else
+ {
+ //longitud del vértice en el sistema rotado
+ lonVR = atan2(yR,xR);
+ //distinguimos casos especiales
+ if(((lonBase2R>0.0)&&(lonVR>lonBase2R))||
+ ((lonBase2R<0.0)&&(lonVR<lonBase2R)))
+ {
+ //vértice fuera de la base: derecha de AB o izquierda de BA
+ //coordenadas cartesianas del punto de la base que no es (0,0,0)
+ xB2R = cos(lonBase2R);
+ yB2R = sin(lonBase2R);
+ //coseno del ángulo en el espacio que forma el vector OBase2R
+ //con el vector OV, es decir, entre los vectores
+ //(xBase2R,yBase2R,0) y (xR,yR,zR)
+ cAlfa = (xB2R*xR+yB2R*yR)/sqrt(xR*xR+yR*yR+zR*zR);
+ //ángulo
+ alfa = acos(cAlfa);
+ //comprobamos si el ángulo es mayor o menor de pi/2
+ if(alfa<=(2.0*GEOC_CONST_PI))
+ {
+ //la variable de salida es el seno del ángulo
+ dist = sin(alfa);
+ }
+ else
+ {
+ //la variable de salida es 1 menos el coseno del ángulo,
+ //para quede un valor mayor que 1
+ dist = 1.0-cos(alfa);
+ }
+ }
+ else
+ {
+ //en el caso normal, la distancia es directamente el seno de la
+ //latitud del vértice, que es igual a la coordenada Z
+ dist = fabs(zR);
+ }
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return dist;
+}
+/******************************************************************************/
+/******************************************************************************/
+/** @} */
+/******************************************************************************/
+/******************************************************************************/
+/* kate: encoding utf-8; end-of-line unix; syntax c; indent-mode cstyle; */
+/* kate: replace-tabs on; space-indent on; tab-indents off; indent-width 4; */
+/* kate: line-numbers on; folding-markers on; remove-trailing-space on; */
+/* kate: backspace-indents on; show-tabs on; */
+/* kate: word-wrap-column 80; word-wrap-marker-color #D2D2D2; word-wrap off; */
diff --git a/src/dpeuckerp.c b/src/dpeuckerp.c
new file mode 100644
index 0000000..ef8af84
--- /dev/null
+++ b/src/dpeuckerp.c
@@ -0,0 +1,1114 @@
+/* -*- coding: utf-8 -*- */
+/**
+\ingroup geom
+@{
+\file dpeuckerp.c
+\brief Definición de funciones para el aligerado de polilíneas en el plano
+ basadas en el algoritmo de Douglas-Peucker.
+\author José Luis García Pallero, jgpallero@gmail.com
+\note Este fichero contiene funciones paralelizadas con OpenMP.
+\date 04 de julio de 2011
+\copyright
+Copyright (c) 2011-2020, José Luis García Pallero. All rights reserved.
+\par
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+\par
+- Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+- Neither the name of the copyright holders nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+\par
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/******************************************************************************/
+/******************************************************************************/
+#include"libgeoc/dpeuckerp.h"
+/******************************************************************************/
+/******************************************************************************/
+int GeocParOmpDpeuckerp(char version[])
+{
+ //comprobamos si hay paralelización
+#if defined(_OPENMP)
+ //comprobamos si hay que extraer versión
+ if(version!=NULL)
+ {
+ //calculamos la versión
+ VersionOpenMP(_OPENMP,version);
+ }
+ //salimos de la función
+ return 1;
+#else
+ if(version!=NULL)
+ {
+ //utilizamos la variable version para que no dé warming al compilar
+ strcpy(version,"");
+ }
+ //salimos de la función
+ return 0;
+#endif
+}
+/******************************************************************************/
+/******************************************************************************/
+void DouglasPeuckerOriginalPlano(const double* x,
+ const double* y,
+ const size_t nPtos,
+ const size_t incX,
+ const size_t incY,
+ const double tol,
+ const size_t posIni,
+ const size_t posFin,
+ char* usados)
+{
+ //índice para recorrer bucles
+ size_t i=0;
+ //distancia de los puntos al segmento base
+ double dist=0.0;
+ //valor absoluto de la tolerancia
+ double atol=fabs(tol);
+ //posición de la distancia máxima
+ size_t pos=0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //comprobamos casos especiales
+ if((nPtos<=2)||(atol==0.0))
+ {
+ //se usan todos los puntos
+ for(i=0;i<nPtos;i++)
+ {
+ usados[i] = 1;
+ }
+ //salimos de la función
+ return;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //sólo continuamos si los puntos extremos no están seguidos
+ if(posIni!=(posFin-1))
+ {
+ //calculamos la distancia máxima de los puntos de trabajo al segmento
+ //formado por los extremos
+ dist = DouglasPeuckerDistMaxPlano(x,y,incX,incY,posIni,posFin,&pos);
+ //comprobamos si esa distancia está fuera de tolerancia
+ if(dist>atol)
+ {
+ //indicamos que el punto se usa
+ usados[pos] = 1;
+ //paralelización con OpenMP
+#if defined(_OPENMP)
+#pragma omp parallel sections default(none) \
+ shared(nPtos,incX,x,incY,y,posIni,posFin,pos,tol,usados)
+#endif
+{
+#if defined(_OPENMP)
+#pragma omp section
+#endif
+ //aplicamos el algoritmo a la parte anterior al punto de trabajo
+ DouglasPeuckerOriginalPlano(x,y,nPtos,incX,incY,tol,posIni,pos,
+ usados);
+#if defined(_OPENMP)
+#pragma omp section
+#endif
+ //aplicamos el algoritmo a la parte posterior al punto de trabajo
+ DouglasPeuckerOriginalPlano(x,y,nPtos,incX,incY,tol,pos,posFin,
+ usados);
+} // --> fin del #pragma omp parallel sections
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return;
+}
+/******************************************************************************/
+/******************************************************************************/
+size_t* DouglasPeuckerRobustoPlano(const double* x,
+ const double* y,
+ const size_t nPtos,
+ const size_t incX,
+ const size_t incY,
+ const double tol,
+ const int paralelizaTol,
+ const enum GEOC_DPEUCKER_ROBUSTO robusto,
+ const size_t nSegRobOrig,
+ const size_t nSegRobAuto,
+ size_t* nPtosSal)
+{
+ //índices para recorrer bucles
+ size_t i=0,j=0;
+ //valor absoluto de la tolerancia
+ double atol=fabs(tol);
+ //variable indicadora de punto en tolerancia
+ int entol=0;
+ //identificador de caso especial
+ int hayCasoEspecial=0;
+ //identificadores de utilización de algoritmos semi robustos
+ int robOrig=0,robAuto=0;
+ //número de elementos de trabajo internos del vector de salida
+ size_t nElem=0;
+ //identificador de paralelización
+ int paraleliza=0;
+ //vector de salida
+ size_t* sal=NULL;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //comprobamos casos especiales
+ sal = CasosEspecialesAligeraPolilinea(x,y,nPtos,incX,incY,atol,nPtosSal,
+ &hayCasoEspecial);
+ //comprobamos si ha habido algún caso especial
+ if(hayCasoEspecial)
+ {
+ //comprobamos si ha ocurrido algún error de asignación de memoria
+ if(nPtos&&(sal==NULL))
+ {
+ //mensaje de error
+ GEOC_ERROR("Error de asignación de memoria");
+ //salimos de la función
+ return NULL;
+ }
+ else
+ {
+ //salimos de la función
+ return sal;
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //comprobamos si se utiliza algoritmo de intersección con línea original
+ if((robusto==GeocDPeuckerRobSi)||(robusto==GeocDPeuckerRobOrig))
+ {
+ robOrig = 1;
+ }
+ //comprobamos si se utiliza algoritmo de intersección con línea generada
+ if((robusto==GeocDPeuckerRobSi)||(robusto==GeocDPeuckerRobAuto))
+ {
+ robAuto = 1;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+#if defined(_OPENMP)
+ //comprobamos si hay más de un procesador
+ if(omp_get_num_procs()>1)
+ {
+ //indicamos que hay paralelización
+ paraleliza = 1;
+ }
+#endif
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //inicializamos el indicador interno de tamaño del vector
+ nElem = GEOC_DPEUCKER_BUFFER_PTOS;
+ //asignamos memoria para el vector de salida
+ sal = (size_t*)malloc(nElem*sizeof(size_t));
+ //comprobamos los posibles errores
+ if(sal==NULL)
+ {
+ //mensaje de error
+ GEOC_ERROR("Error de asignación de memoria");
+ //salimos de la función
+ return NULL;
+ }
+ //indicamos que el primer punto siempre se usa
+ *nPtosSal = 1;
+ sal[0] = 0;
+ //puntos de trabajo para iniciar los cálculos
+ i = 0;
+ j = 2;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //entramos en un bucle mientras no hayamos llegado hasta el último punto
+ while(j<nPtos)
+ {
+ //comprobamos si los puntos intermedios están en tolerancia
+ //sólo paralelizamos si el número de puntos intermedios es mayor que uno
+ if(paraleliza&&paralelizaTol&&((j-i-1)>1))
+ {
+ //aplicamos el algoritmo en paralelo
+ entol = DouglasPeuckerPuntosEnTolPlanoOMP(x,y,incX,incY,atol,i,j,
+ i+1,j-1);
+ }
+ else
+ {
+ //aplicamos el algoritmo en serie
+ entol = DouglasPeuckerPuntosEnTolPlanoSerie(x,y,incX,incY,atol,i,j,
+ i+1,j-1);
+ }
+ //comprobamos si todos los puntos están en tolerancia
+ if(entol)
+ {
+ //pasamos al siguiente punto como extremo del segmento
+ j++;
+ }
+ else
+ {
+ //el punto final será el anterior al actual, ya que con el actual
+ //hay al menos un vértice fuera de tolerancia y con el anterior se
+ //comprobó en el paso previo del bucle que no había ningún vértice
+ //fuera
+ j--;
+ //aplicación del algoritmo de intersección con puntos originales
+ if(robOrig)
+ {
+ //aplicamos el algoritmo
+ DouglasPeuckerRobIntersecOrigPlano(x,y,nPtos,incX,incY,
+ nSegRobOrig,i,&j);
+ }
+ //aplicación del algoritmo de auto intersección
+ if(robAuto)
+ {
+ //aplicamos el algoritmo
+ DouglasPeuckerRobAutoIntersecPlano(x,y,incX,incY,i,&j,sal,
+ *nPtosSal,nSegRobAuto);
+ }
+ //añadimos al contador el nuevo punto
+ (*nPtosSal)++;
+ //comprobamos si hay que reasignar memoria
+ if((*nPtosSal)>nElem)
+ {
+ //añadimos otro grupo de puntos
+ nElem += GEOC_DPEUCKER_BUFFER_PTOS;
+ //asignamos memoria para el vector de salida
+ sal = (size_t*)realloc(sal,nElem*sizeof(size_t));
+ //comprobamos los posibles errores
+ if(sal==NULL)
+ {
+ //mensaje de error
+ GEOC_ERROR("Error de asignación de memoria");
+ //salimos de la función
+ return NULL;
+ }
+ }
+ //añadimos el punto al vector de salida
+ sal[(*nPtosSal)-1] = j;
+ //actualizamos los índices de los puntos de trabajo
+ i = j;
+ j = i+2;
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //comprobamos si hay que añadir el último punto
+ if((sal[(*nPtosSal)-1]!=(nPtos-1))&&
+ ((x[sal[(*nPtosSal)-1]*incX]!=x[(nPtos-1)*incX])||
+ (y[sal[(*nPtosSal)-1]*incY]!=y[(nPtos-1)*incY])))
+ {
+ //añadimos al contador el último punto
+ (*nPtosSal)++;
+ //comprobamos si hay que reasignar memoria
+ if((*nPtosSal)>nElem)
+ {
+ //añadimos otro grupo de puntos
+ nElem += GEOC_DPEUCKER_BUFFER_PTOS;
+ //asignamos memoria para el vector de salida
+ sal = (size_t*)realloc(sal,nElem*sizeof(size_t));
+ //comprobamos los posibles errores
+ if(sal==NULL)
+ {
+ //mensaje de error
+ GEOC_ERROR("Error de asignación de memoria");
+ //salimos de la función
+ return NULL;
+ }
+ }
+ //asignamos el último punto
+ sal[(*nPtosSal)-1] = nPtos-1;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //comprobamos si el vector de salida tiene demasiada memoria asignada
+ if(nElem>(*nPtosSal))
+ {
+ //ajustamos el tamaño del vector de salida
+ sal = (size_t*)realloc(sal,(*nPtosSal)*sizeof(size_t));
+ //comprobamos los posibles errores
+ if(sal==NULL)
+ {
+ //mensaje de error
+ GEOC_ERROR("Error de asignación de memoria");
+ //salimos de la función
+ return NULL;
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return sal;
+}
+/******************************************************************************/
+/******************************************************************************/
+int DouglasPeuckerPuntosEnTolPlanoOMP(const double* x,
+ const double* y,
+ const size_t incX,
+ const size_t incY,
+ const double tol,
+ const size_t posBaseIni,
+ const size_t posBaseFin,
+ const size_t posPtoIni,
+ const size_t posPtoFin)
+{
+ //índice para recorrer bucles
+ size_t i=0;
+ //valor absoluto de la tolerancia
+ double atol=fabs(tol);
+ //identificador de punto fuera de tolerancia
+ int ftol=0;
+ //coordenadas de los vértices de trabajo
+ double xIni=0.0,yIni=0.0,xFin=0.0,yFin=0.0,xTrab=0.0,yTrab=0.0;
+ //longitud de la base y parámetros de rotación para el plano
+ double dx=0.0,sA=0.0,cA=0.0;
+ //distancia calculada
+ double dist=0.0;
+ //variable de salida
+ int entol=1;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //comprobamos salida rápida
+ if((posBaseIni+1)>=posBaseFin)
+ {
+ //salimos de la función
+ return entol;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //coordenadas del primer punto de la base
+ xIni = x[posBaseIni*incX];
+ yIni = y[posBaseIni*incY];
+ //coordenadas del segundo punto de la base, referidas al primero
+ xFin = x[posBaseFin*incX]-xIni;
+ yFin = y[posBaseFin*incY]-yIni;
+ //calculamos la longitud de la base y la rotación
+ DouglasPeuckerParamRotaBase(xFin,yFin,&sA,&cA,&dx);
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //paralelización con OpenMP
+#if defined(_OPENMP)
+#pragma omp parallel for default(none) \
+ shared(posPtoIni,posPtoFin,incX,x,incY,y,xIni,yIni,dx,sA,cA,atol) \
+ private(i,xTrab,yTrab,dist) \
+ reduction(+:ftol)
+#endif
+ //recorremos los puntos de trabajo
+ for(i=posPtoIni;i<=posPtoFin;i++)
+ {
+ //sólo calculo si no se ha encontrado ningún punto fuera de tolerancia
+ //en este hilo
+ if(!ftol)
+ {
+ //extraemos las coordenadas del vértice de trabajo y las referimos
+ //al punto inicial de la base
+ xTrab = x[i*incX]-xIni;
+ yTrab = y[i*incY]-yIni;
+ //calculamos la distancia del punto a la base
+ dist = DouglasPeuckerDistMaxPlanoAux(dx,sA,cA,xTrab,yTrab);
+ //comprobamos si está fuera de tolerancia
+ if(dist>atol)
+ {
+ //aumentamos el indicador de fuera de tolerancia
+ ftol++;
+ }
+ }
+ } // --> fin del #pragma omp parallel for
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //comprobamos si hay algún punto fuera de tolerancia
+ if(ftol)
+ {
+ //indicamos que hay algún punto que no está en tolerancia
+ entol = 0;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return entol;
+}
+/******************************************************************************/
+/******************************************************************************/
+int DouglasPeuckerPuntosEnTolPlanoSerie(const double* x,
+ const double* y,
+ const size_t incX,
+ const size_t incY,
+ const double tol,
+ const size_t posBaseIni,
+ const size_t posBaseFin,
+ const size_t posPtoIni,
+ const size_t posPtoFin)
+{
+ //índice para recorrer bucles
+ size_t i=0;
+ //valor absoluto de la tolerancia
+ double atol=fabs(tol);
+ //coordenadas de los vértices
+ double xIni=0.0,yIni=0.0,xFin=0.0,yFin=0.0,xTrab=0.0,yTrab=0.0;
+ //longitud de la base y parámetros de rotación para el plano
+ double dx=0.0,sA=0.0,cA=0.0;
+ //distancia calculada
+ double dist=0.0;
+ //variable de salida
+ int entol=1;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //comprobamos salida rápida
+ if((posBaseIni+1)>=posBaseFin)
+ {
+ //salimos de la función
+ return entol;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //coordenadas del primer punto de la base
+ xIni = x[posBaseIni*incX];
+ yIni = y[posBaseIni*incY];
+ //coordenadas del segundo punto de la base, referidas al primero
+ xFin = x[posBaseFin*incX]-xIni;
+ yFin = y[posBaseFin*incY]-yIni;
+ //calculamos la longitud de la base y la rotación
+ DouglasPeuckerParamRotaBase(xFin,yFin,&sA,&cA,&dx);
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //recorremos los puntos a chequear
+ for(i=posPtoIni;i<=posPtoFin;i++)
+ {
+ //extraemos las coordenadas del vértice de trabajo y las referimos al
+ //punto inicial de la base
+ xTrab = x[i*incX]-xIni;
+ yTrab = y[i*incY]-yIni;
+ //calculamos la distancia del punto a la base
+ dist = DouglasPeuckerDistMaxPlanoAux(dx,sA,cA,xTrab,yTrab);
+ //comprobamos si está fuera de tolerancia
+ if(dist>atol)
+ {
+ //indicamos que estamos fuera de tolerancia
+ entol = 0;
+ //salimos del bucle
+ break;
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return entol;
+}
+/******************************************************************************/
+/******************************************************************************/
+void DouglasPeuckerRobIntersecOrigPlano(const double* x,
+ const double* y,
+ const size_t nPtos,
+ const size_t incX,
+ const size_t incY,
+ const size_t segAUsar,
+ const size_t posIni,
+ size_t* posFin)
+{
+ //índice para recorrer bucles
+ size_t i=0;
+ //coordenadas del segmento base
+ double xA=0.0,yA=0.0,xB=0.0,yB=0.0;
+ //posición de parada para comprobar la intersección de segmentos/arcos
+ size_t posParada=0;
+ //identificación de paralelización
+ int paraleliza=0;
+ //variable identificadora de existencia de corte de segmentos
+ int corte=0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //si los puntos de inicio y fin son contiguos, hay salida rápida
+ if((posIni+1)>=(*posFin))
+ {
+ //salimos de la función
+ return;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+#if defined(_OPENMP)
+ //comprobamos si hay más de un procesador
+ if(omp_get_num_procs()>1)
+ {
+ //indicamos que hay paralelización
+ paraleliza = 1;
+ }
+#endif
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //posición de parada para el chequeo de segmentos/arcos
+ posParada = ((segAUsar==0)||(segAUsar>=(nPtos-(*posFin))))
+ ? nPtos-1
+ : (*posFin)+segAUsar;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //coordenadas del punto inicial del segmento/arco base (no cambian)
+ xA = x[posIni*incX];
+ yA = y[posIni*incY];
+ //construimos todos los segmentos/arcos base posibles
+ for(i=(*posFin);i>posIni;i--)
+ {
+ //comprobamos si estamos ante el punto posterior al inicial
+ if(i==(posIni+1))
+ {
+ //este punto es el siguiente al punto inicial del segmento/arco base
+ *posFin = i;
+ //salimos del bucle
+ break;
+ }
+ //coordenadas del punto final del segmento base
+ xB = x[i*incX];
+ yB = y[i*incY];
+ //comprobamos si hay que paralelizar
+ if(paraleliza)
+ {
+ //calculamos en paralelo
+ corte = DouglasPeuckerRobIntersecOrigPlanoOMP(xA,yA,xB,yB,x,y,incX,
+ incY,i,posParada);
+ }
+ else
+ {
+ //calculamos en serie
+ corte = DouglasPeuckerRobIntersecOrigPlanoSerie(xA,yA,xB,yB,x,y,
+ incX,incY,i,
+ posParada);
+ }
+ //comprobamos si no ha habido ninguna intersección
+ if(!corte)
+ {
+ //indicamos el índice del vértice final
+ *posFin = i;
+ //salimos del bucle de segmentos base
+ break;
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return;
+}
+/******************************************************************************/
+/******************************************************************************/
+int DouglasPeuckerRobIntersecOrigPlanoOMP(const double xA,
+ const double yA,
+ const double xB,
+ const double yB,
+ const double* x,
+ const double* y,
+ const size_t incX,
+ const size_t incY,
+ const size_t posIni,
+ const size_t posFin)
+{
+ //índice para recorrer bucles
+ size_t i=0;
+ //coordenadas de los segmentos de trabajo
+ double xC=0.0,yC=0.0,xD=0.0,yD=0.0;
+ //variable de salida
+ int corte=0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //paralelización con OpenMP
+#if defined(_OPENMP)
+#pragma omp parallel for default(none) \
+ shared(posIni,posFin,incX,x,incY,y,xA,xB,yA,yB) \
+ private(i,xC,yC,xD,yD) \
+ reduction(+:corte)
+#endif
+ //recorremos los puntos de trabajo
+ for(i=posIni;i<posFin;i++)
+ {
+ //sólo realizo cálculos si no se ha encontrado ningún corte en este hilo
+ if(!corte)
+ {
+ //puntos inicial y final del siguiente segmento/arco de trabajo
+ xC = x[i*incX];
+ yC = y[i*incY];
+ xD = x[(i+1)*incX];
+ yD = y[(i+1)*incY];
+ //sigo si los rectángulos que encierran a los segmentos se cortan
+ if(!GEOC_RECT_DISJUNTOS(GEOC_MIN(xA,xB),GEOC_MAX(xA,xB),
+ GEOC_MIN(yA,yB),GEOC_MAX(yA,yB),
+ GEOC_MIN(xC,xD),GEOC_MAX(xC,xD),
+ GEOC_MIN(yC,yD),GEOC_MAX(yC,yD)))
+ {
+ //comprobamos si hay intersección
+ corte += DouglasPeuckerRobIntersecPlano(xA,yA,xB,yB,xC,yC,xD,yD,
+ posIni,i);
+ }
+ }
+ } // --> fin del #pragma omp parallel for
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return corte;
+}
+/******************************************************************************/
+/******************************************************************************/
+int DouglasPeuckerRobIntersecOrigPlanoSerie(const double xA,
+ const double yA,
+ const double xB,
+ const double yB,
+ const double* x,
+ const double* y,
+ const size_t incX,
+ const size_t incY,
+ const size_t posIni,
+ const size_t posFin)
+{
+ //índice para recorrer bucles
+ size_t i=0;
+ //coordenadas de los segmentos de trabajo
+ double xC=0.0,yC=0.0,xD=0.0,yD=0.0;
+ //variable de salida
+ int corte=0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //recorremos los puntos de trabajo
+ for(i=posIni;i<posFin;i++)
+ {
+ //puntos inicial y final del siguiente segmento/arco de trabajo
+ xC = x[i*incX];
+ yC = y[i*incY];
+ xD = x[(i+1)*incX];
+ yD = y[(i+1)*incY];
+ //seguimos si los rectángulos que encierran a los segmentos se cortan
+ if(!GEOC_RECT_DISJUNTOS(GEOC_MIN(xA,xB),GEOC_MAX(xA,xB),
+ GEOC_MIN(yA,yB),GEOC_MAX(yA,yB),
+ GEOC_MIN(xC,xD),GEOC_MAX(xC,xD),
+ GEOC_MIN(yC,yD),GEOC_MAX(yC,yD)))
+ {
+ //comprobamos si hay intersección
+ corte = DouglasPeuckerRobIntersecPlano(xA,yA,xB,yB,xC,yC,xD,yD,
+ posIni,i);
+ }
+ //si ha habido intersección de segmentos/arcos, salimos del bucle
+ if(corte)
+ {
+ //salimos del bucle
+ break;
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return corte;
+}
+/******************************************************************************/
+/******************************************************************************/
+void DouglasPeuckerRobAutoIntersecPlano(const double* x,
+ const double* y,
+ const size_t incX,
+ const size_t incY,
+ const size_t posIni,
+ size_t* posFin,
+ const size_t* posAlig,
+ const size_t nPosAlig,
+ const size_t segAUsar)
+{
+ //índice para recorrer bucles
+ size_t i=0;
+ //coordenadas del segmento base
+ double xA=0.0,yA=0.0,xB=0.0,yB=0.0;
+ //posición de parada para comprobar la intersección de segmentos/arcos
+ size_t posParada=0;
+ //identificación de paralelización
+ int paraleliza=0;
+ //variable identificadora de existencia de corte de segmentos
+ int corte=0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //si los puntos de inicio y fin son contiguos, hay salida rápida
+ if((posIni+1)>=(*posFin))
+ {
+ //salimos de la función
+ return;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+#if defined(_OPENMP)
+ //comprobamos si hay más de un procesador
+ if(omp_get_num_procs()>1)
+ {
+ //indicamos que hay paralelización
+ paraleliza = 1;
+ }
+#endif
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //posición de parada en el vector posAlig para el chequeo de segmentos/arcos
+ posParada = ((segAUsar==0)||(segAUsar>=(nPosAlig-1)))
+ ? 0
+ : nPosAlig-1-segAUsar;
+ //coordenadas del punto inicial del segmento base (no cambian)
+ xA = x[posIni*incX];
+ yA = y[posIni*incY];
+ //construimos todos los segmentos base posibles
+ for(i=(*posFin);i>posIni;i--)
+ {
+ //comprobamos si estamos ante el punto posterior al inicial
+ if(i==(posIni+1))
+ {
+ //este punto es el siguiente al punto inicial del segmento base
+ *posFin = i;
+ //salimos del bucle
+ break;
+ }
+ //coordenadas del punto final del segmento base
+ xB = x[i*incX];
+ yB = y[i*incY];
+ //comprobamos si hay que paralelizar
+ if(paraleliza)
+ {
+ //calculamos en paralelo
+ corte = DouglasPeuckerRobAutoIntersecPlanoOMP(xA,yA,xB,yB,x,y,incX,
+ incY,posAlig,nPosAlig,
+ nPosAlig-1,posParada);
+ }
+ else
+ {
+ //calculamos en serie
+ corte = DouglasPeuckerRobAutoIntersecPlanoSerie(xA,yA,xB,yB,x,y,
+ incX,incY,posAlig,
+ nPosAlig,nPosAlig-1,
+ posParada);
+ }
+ //comprobamos si no ha habido ninguna intersección
+ if(!corte)
+ {
+ //indicamos el índice del vértice final
+ *posFin = i;
+ //salimos del bucle de segmentos base
+ break;
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return;
+}
+/******************************************************************************/
+/******************************************************************************/
+int DouglasPeuckerRobAutoIntersecPlanoOMP(const double xA,
+ const double yA,
+ const double xB,
+ const double yB,
+ const double* x,
+ const double* y,
+ const size_t incX,
+ const size_t incY,
+ const size_t* posAlig,
+ const size_t nPosAlig,
+ const size_t posIni,
+ const size_t posFin)
+{
+ //índice para recorrer bucles
+ size_t i=0;
+ //coordenadas de los segmentos de trabajo
+ double xC=0.0,yC=0.0,xD=0.0,yD=0.0;
+ //variable de salida
+ int corte=0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //paralelización con OpenMP
+#if defined(_OPENMP)
+#pragma omp parallel for default(none) \
+ shared(posIni,posFin,incX,x,posAlig,incY,y,xA,xB,yA,yB,nPosAlig) \
+ private(i,xC,yC,xD,yD) \
+ reduction(+:corte)
+#endif
+ //recorremos los puntos de trabajo
+ for(i=posIni;i>posFin;i--)
+ {
+ //sólo realizo cálculos si no se ha encontrado ningún corte en este hilo
+ if(!corte)
+ {
+ //puntos inicial y final del siguiente segmento/arco de trabajo
+ xC = x[posAlig[i]*incX];
+ yC = y[posAlig[i]*incY];
+ xD = x[posAlig[i-1]*incX];
+ yD = y[posAlig[i-1]*incY];
+ //seguimos si los rectángulos que encierran a los segmentos se cortan
+ if(!GEOC_RECT_DISJUNTOS(GEOC_MIN(xA,xB),GEOC_MAX(xA,xB),
+ GEOC_MIN(yA,yB),GEOC_MAX(yA,yB),
+ GEOC_MIN(xC,xD),GEOC_MAX(xC,xD),
+ GEOC_MIN(yC,yD),GEOC_MAX(yC,yD)))
+ {
+ //comprobamos si hay intersección
+ corte += DouglasPeuckerRobIntersecPlano(xB,yB,xA,yA,xC,yC,xD,yD,
+ posAlig[nPosAlig-1],
+ posAlig[i]);
+ }
+ }
+ } // --> fin del #pragma omp parallel for
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return corte;
+}
+/******************************************************************************/
+/******************************************************************************/
+int DouglasPeuckerRobAutoIntersecPlanoSerie(const double xA,
+ const double yA,
+ const double xB,
+ const double yB,
+ const double* x,
+ const double* y,
+ const size_t incX,
+ const size_t incY,
+ const size_t* posAlig,
+ const size_t nPosAlig,
+ const size_t posIni,
+ const size_t posFin)
+{
+ //índice para recorrer bucles
+ size_t i=0;
+ //coordenadas de los segmentos de trabajo
+ double xC=0.0,yC=0.0,xD=0.0,yD=0.0;
+ //variable de salida
+ int corte=0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //recorremos los puntos de trabajo
+ for(i=posIni;i>posFin;i--)
+ {
+ //puntos inicial y final del siguiente segmento/arco de trabajo
+ xC = x[posAlig[i]*incX];
+ yC = y[posAlig[i]*incY];
+ xD = x[posAlig[i-1]*incX];
+ yD = y[posAlig[i-1]*incY];
+ //seguimos si los rectángulos que encierran a los segmentos se cortan
+ if(!GEOC_RECT_DISJUNTOS(GEOC_MIN(xA,xB),GEOC_MAX(xA,xB),
+ GEOC_MIN(yA,yB),GEOC_MAX(yA,yB),
+ GEOC_MIN(xC,xD),GEOC_MAX(xC,xD),
+ GEOC_MIN(yC,yD),GEOC_MAX(yC,yD)))
+ {
+ //comprobamos si hay intersección
+ corte = DouglasPeuckerRobIntersecPlano(xB,yB,xA,yA,xC,yC,xD,yD,
+ posAlig[nPosAlig-1],
+ posAlig[i]);
+ }
+ //si ha habido intersección de segmentos/arcos, salimos del bucle
+ if(corte)
+ {
+ //salimos del bucle
+ break;
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return corte;
+}
+/******************************************************************************/
+/******************************************************************************/
+int DouglasPeuckerRobIntersecPlano(const double xA,
+ const double yA,
+ const double xB,
+ const double yB,
+ const double xC,
+ const double yC,
+ const double xD,
+ const double yD,
+ const size_t posFinAB,
+ const size_t posIniCD)
+{
+ //variables auxiliares
+ double xAux=0.0,yAux=0.0;
+ //identificador de intersección
+ int inter=GEOC_DPEUCKER_NO_INTERSEC;
+ //variable de salida
+ int corte=0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //seguimos si los rectángulos que encierran a los segmentos se cortan
+ if(!GEOC_RECT_DISJUNTOS(GEOC_MIN(xA,xB),GEOC_MAX(xA,xB),
+ GEOC_MIN(yA,yB),GEOC_MAX(yA,yB),
+ GEOC_MIN(xC,xD),GEOC_MAX(xC,xD),
+ GEOC_MIN(yC,yD),GEOC_MAX(yC,yD)))
+ {
+ //compruebo si los dos segmentos son contiguos
+ if(posFinAB==posIniCD)
+ {
+ //compruebo intersección con la función completa (lenta)
+ inter = IntersecSegmentos2D(xA,yA,xB,yB,xC,yC,xD,yD,
+ &xAux,&yAux);
+ //compruebo si es la sucesión de segmento inicial+final
+ if((inter!=GEOC_SEG_INTERSEC_MISMO_SEG)&&
+ (inter!=GEOC_SEG_INTERSEC_COLIN))
+ {
+ //en este caso, no hay intersección
+ inter = GEOC_DPEUCKER_NO_INTERSEC;
+ }
+ }
+ else
+ {
+ //compruebo intersección con la función simple (rápida)
+ inter = IntersecSegmentos2DSimple(xA,yA,xB,yB,xC,yC,xD,yD);
+ }
+ //unificamos los identificadores de intersección
+ if(!((inter==GEOC_SEG_NO_INTERSEC)||(inter==GEOC_DPEUCKER_NO_INTERSEC)))
+ {
+ //hay intersección
+ corte = 1;
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return corte;
+}
+/******************************************************************************/
+/******************************************************************************/
+double DouglasPeuckerDistMaxPlano(const double* x,
+ const double* y,
+ const size_t incX,
+ const size_t incY,
+ const size_t posIni,
+ const size_t posFin,
+ size_t* pos)
+{
+ //índice para recorrer bucles
+ size_t i=0;
+ //coordenadas de los extremos del segmento base y del punto de trabajo
+ double xIni=0.0,yIni=0.0,xFin=0.0,yFin=0.0,xP=0.0,yP=0.0;
+ //razones trigonométricas del ángulo de giro del sistema de coordenadas
+ double sA=0.0,cA=0.0;
+ //longitudes auxiliares
+ double dx=0.0,lonAux=0.0;
+ //variable de salida
+ double lon=-1.0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //comprobamos si los dos puntos están seguidos
+ if((posIni+1)==posFin)
+ {
+ //la posición que devolvemos es la del punto inicial
+ *pos = posIni;
+ //la distancia devuelta es -1.0
+ return lon;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //coordenadas del primer punto de la base
+ xIni = x[posIni*incX];
+ yIni = y[posIni*incY];
+ //coordenadas del segundo punto de la base, referidas al primero
+ xFin = x[posFin*incX]-xIni;
+ yFin = y[posFin*incY]-yIni;
+ //calculamos la longitud de la base y la rotación
+ DouglasPeuckerParamRotaBase(xFin,yFin,&sA,&cA,&dx);
+ //recorremos los puntos entre los extremos
+ for(i=posIni+1;i<posFin;i++)
+ {
+ //coordenadas del punto de trabajo referidas al punto inicial de la base
+ xP = x[i*incX]-xIni;
+ yP = y[i*incY]-yIni;
+ //calculamos la distancia del punto de trabajo al segmento base
+ lonAux = DouglasPeuckerDistMaxPlanoAux(dx,sA,cA,xP,yP);
+ //comprobamos si la distancia calculada es mayor que la anterior
+ if(lonAux>lon)
+ {
+ //actualizamos la distancia máxima
+ lon = lonAux;
+ //guardamos la posición del punto
+ *pos = i;
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return lon;
+}
+/******************************************************************************/
+/******************************************************************************/
+void DouglasPeuckerParamRotaBase(const double xBase2RB1,
+ const double yBase2RB1,
+ double* sAlfa,
+ double* cAlfa,
+ double* lonBase)
+{
+ //álgulo de rotación
+ double alfa=0.0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //ángulo a rotar el sistema de coordenadas para llevar el eje X a coincidir
+ //con el segmento base
+ alfa = atan2(yBase2RB1,xBase2RB1);
+ //calculamos las razones trigonométricas del ángulo de rotación
+ *sAlfa = sin(alfa);
+ *cAlfa = cos(alfa);
+ //la longitud del segmento base será el valor absoluto de la coordenada X
+ //del extremo final del segmento base en el sistema de coordenadas rotado
+ *lonBase = fabs((*cAlfa)*xBase2RB1+(*sAlfa)*yBase2RB1);
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return;
+}
+/******************************************************************************/
+/******************************************************************************/
+double DouglasPeuckerDistMaxPlanoAux(const double lonBase,
+ const double sAlfa,
+ const double cAlfa,
+ const double xVertRB1,
+ const double yVertRB1)
+{
+ //coordenadas del vértice de trabajo en el sistema rotado
+ double xVert1=0.0,yVert1=0.0;
+ //variable de salida
+ double lon=0.0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //transformamos el vértice de trabajo al nuevo sistema de coordenadas
+ xVert1 = cAlfa*xVertRB1+sAlfa*yVertRB1;
+ yVert1 = -sAlfa*xVertRB1+cAlfa*yVertRB1;
+ //comprobamos la posición del punto con respecto al segmento base
+ if((xVert1>=0.0)&&(xVert1<=lonBase))
+ {
+ //el punto de trabajo está entre los extremos del segmento base
+ //su distancia hasta él es el valor absoluto de su coordenada Y en
+ //el sistema rotado
+ lon = fabs(yVert1);
+ }
+ else if(xVert1<0.0)
+ {
+ //el punto de trabajo está a la izquierda del punto inicial de la
+ //base, luego su distancia hasta el segmento será la distancia
+ //hasta dicho punto inicial
+ //Konrad Ebisch (2002), A correction to the Douglas-Peucker line
+ //generalization algorithm, Computers and Geosciences, vol. 28,
+ //págs. 995 a 997
+ lon = sqrt(xVert1*xVert1+yVert1*yVert1);
+ }
+ else
+ {
+ //el punto de trabajo está a la derecha del punto final de la base,
+ //luego su distancia hasta el segmento será la distancia hasta dicho
+ //punto final
+ //Konrad Ebisch (2002), A correction to the Douglas-Peucker line
+ //generalization algorithm, Computers and Geosciences, vol. 28,
+ //págs. 995 a 997
+ lon = sqrt((xVert1-lonBase)*(xVert1-lonBase)+yVert1*yVert1);
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return lon;
+}
+/******************************************************************************/
+/******************************************************************************/
+/** @} */
+/******************************************************************************/
+/******************************************************************************/
+/* kate: encoding utf-8; end-of-line unix; syntax c; indent-mode cstyle; */
+/* kate: replace-tabs on; space-indent on; tab-indents off; indent-width 4; */
+/* kate: line-numbers on; folding-markers on; remove-trailing-space on; */
+/* kate: backspace-indents on; show-tabs on; */
+/* kate: word-wrap-column 80; word-wrap-marker-color #D2D2D2; word-wrap off; */
diff --git a/src/errores.c b/src/errores.c
index 4b7788a..4b7788a 100755..100644
--- a/src/errores.c
+++ b/src/errores.c
diff --git a/src/eucli.c b/src/eucli.c
index fcd8cd7..fcd8cd7 100755..100644
--- a/src/eucli.c
+++ b/src/eucli.c
diff --git a/src/fgeneral.c b/src/fgeneral.c
index c048f42..1479d5f 100755..100644
--- a/src/fgeneral.c
+++ b/src/fgeneral.c
@@ -8,12 +8,12 @@
\note Este fichero contiene funciones paralelizadas con OpenMP.
\date 10 de octubre de 2009
\version 1.0
-\section Licencia Licencia
-Copyright (c) 2009-2011, José Luis García Pallero. All rights reserved.
-
+\copyright
+Copyright (c) 2009-2020, José Luis García Pallero. All rights reserved.
+\par
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
-
+\par
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this
@@ -22,7 +22,7 @@ are permitted provided that the following conditions are met:
- Neither the name of the copyright holders nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
-
+\par
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -267,7 +267,7 @@ double Minimo(const double* lista,
//en versiones anteriores no existe la posibilidad de usar reduction(min:)
#if defined(_OPENMP)&&(_OPENMP>=GEOC_OMP_F_3_1)
#pragma omp parallel for default(none) \
- shared(lista) \
+ shared(nDatos,incDatos,lista) \
private(i,pos) \
reduction(min:salida)
#endif
@@ -306,7 +306,7 @@ double Maximo(const double* lista,
//en versiones anteriores no existe la posibilidad de usar reduction(max:)
#if defined(_OPENMP)&&(_OPENMP>=GEOC_OMP_F_3_1)
#pragma omp parallel for default(none) \
- shared(lista) \
+ shared(nDatos,incDatos,lista) \
private(i,pos) \
reduction(max:salida)
#endif
@@ -345,7 +345,7 @@ double MinimoAbs(const double* lista,
//en versiones anteriores no existe la posibilidad de usar reduction(min:)
#if defined(_OPENMP)&&(_OPENMP>=GEOC_OMP_F_3_1)
#pragma omp parallel for default(none) \
- shared(lista) \
+ shared(nDatos,incDatos,lista) \
private(i,pos) \
reduction(min:salida)
#endif
@@ -384,7 +384,7 @@ double MaximoAbs(const double* lista,
//en versiones anteriores no existe la posibilidad de usar reduction(max:)
#if defined(_OPENMP)&&(_OPENMP>=GEOC_OMP_F_3_1)
#pragma omp parallel for default(none) \
- shared(lista) \
+ shared(nDatos,incDatos,lista) \
private(i,pos) \
reduction(max:salida)
#endif
@@ -416,14 +416,18 @@ size_t MinimoSizeT(const size_t* lista,
//variable de posición
size_t pos=0;
//variable de salida, inicializada como el máximo valor para un size_t
+#if defined(SIZE_MAX)
size_t salida=SIZE_MAX;
+#else
+ size_t salida=(size_t)ULONG_MAX;
+#endif
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
//paralelización con OpenMP, sólo si la versión es superior a la 3.0
//en versiones anteriores no existe la posibilidad de usar reduction(min:)
#if defined(_OPENMP)&&(_OPENMP>=GEOC_OMP_F_3_1)
#pragma omp parallel for default(none) \
- shared(lista) \
+ shared(nDatos,incDatos,lista) \
private(i,pos) \
reduction(min:salida)
#endif
@@ -462,7 +466,7 @@ size_t MaximoSizeT(const size_t* lista,
//en versiones anteriores no existe la posibilidad de usar reduction(max:)
#if defined(_OPENMP)&&(_OPENMP>=GEOC_OMP_F_3_1)
#pragma omp parallel for default(none) \
- shared(lista) \
+ shared(nDatos,incDatos,lista) \
private(i,pos) \
reduction(max:salida)
#endif
diff --git a/src/geocnan.c b/src/geocnan.c
index 2a2aca5..2a2aca5 100755..100644
--- a/src/geocnan.c
+++ b/src/geocnan.c
diff --git a/src/greiner.c b/src/greiner.c
index cbe682c..6075c3a 100755..100644
--- a/src/greiner.c
+++ b/src/greiner.c
@@ -8,12 +8,12 @@
(http://davis.wpi.edu/~matt/courses/clipping/).
\author José Luis García Pallero, jgpallero@gmail.com
\date 14 de mayo de 2011
-\section Licencia Licencia
-Copyright (c) 2011, José Luis García Pallero. All rights reserved.
-
+\copyright
+Copyright (c) 2011-2020, José Luis García Pallero. All rights reserved.
+\par
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
-
+\par
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this
@@ -22,7 +22,7 @@ are permitted provided that the following conditions are met:
- Neither the name of the copyright holders nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
-
+\par
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -830,7 +830,8 @@ int Paso1Greiner(vertPoliClip* poliBas,
//un extremo e intersecciones colineales donde se
//comparte más de un punto
if((intersec==GEOC_SEG_INTERSEC_EXTREMO_NO_COLIN)||
- (intersec==GEOC_SEG_INTERSEC_EXTREMO_COLIN))
+ (intersec==GEOC_SEG_INTERSEC_EXTREMOS_NO_COLIN)||
+ (intersec==GEOC_SEG_INTERSEC_EXTREMOS_COLIN))
{
if((xI==auxC->xP)&&(yI==auxC->yP))
{
@@ -1230,17 +1231,26 @@ polig* PoliBoolGreiner(vertPoliClip* poliBas,
vertPoliClip* poliRec,
const enum GEOC_OP_BOOL_POLIG op,
const double facPer,
+ const int compruebaHuecosUnion,
size_t* nIntersec,
size_t* nPerturb)
{
+ //índice para recorrer bucles
+ size_t i=0;
//factor de perturbación
double factor=0.0;
//variables de posición
int posBas=0,posRec=0;
//identificador de error
int idError=GEOC_ERR_NO_ERROR;
- //polígono auxiliar
+ //variables auxiliares
+ int enPol1=GEOC_PTO_FUERA_POLIG,enPol2=GEOC_PTO_FUERA_POLIG;
+ size_t posIni=0;
+ double xAux=0.0,yAux=0.0;
+ //polígonos auxiliares
polig* ba=NULL;
+ polig* aux1=NULL;
+ polig* aux2=NULL;
//polígono de salida
polig* resultado=NULL;
////////////////////////////////////////////////////////////////////////////
@@ -1453,6 +1463,76 @@ polig* PoliBoolGreiner(vertPoliClip* poliBas,
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
+ //inicializo los atributos a 1
+ for(i=0;i<resultado->nPolig;i++)
+ {
+ resultado->atr[i] = 1;
+ }
+ //compruebo si hemos trabajado con unión
+ if(compruebaHuecosUnion&&(op==GeocOpBoolUnion))
+ {
+ //convierto los polígonos de trabajo en estructuras polig
+ aux1 = CreaPoligPoliClip(poliBas,1);
+ aux2 = CreaPoligPoliClip(poliRec,1);
+ //comprobamos los posibles errores
+ if((aux1==NULL)||(aux2==NULL))
+ {
+ //liberamos la memoria asignada
+ LibMemPolig(resultado);
+ LibMemPolig(aux1);
+ LibMemPolig(aux2);
+ //mensaje de error
+ GEOC_ERROR("Error de asignación de memoria en la llamada a "
+ "'CreaPoligPoliClip' para la comprobación de huecos en "
+ "la operación OR");
+ //salimos de la función
+ return NULL;
+ }
+ //recorro todos los polígonos generados en la unión
+ for(i=0;i<resultado->nPolig;i++)
+ {
+ //posición de inicio del polígono
+ posIni = resultado->posIni[i];
+ //genero un punto dentro del polígono
+ GeneraPtoEnPoligono(&(resultado->x[posIni]),&(resultado->y[posIni]),
+ resultado->nVert[i],1,1,0.0,1,&xAux,&yAux);
+ //comprobamos las coordenadas de salida
+ if (EsGeocNan(xAux)||EsGeocNan(yAux))
+ {
+ //digo que es un hueco
+ resultado->atr[i] = 0;
+ }
+ else
+ {
+ //compruebo si el punto está dentro de alguno de los dos
+ //polígonos de trabajo
+ posIni = aux1->posIni[0];
+ enPol1 = PtoEnPoligonoVerticeBordeDouble(xAux,yAux,
+ &(aux1->x[posIni]),
+ &(aux1->y[posIni]),
+ aux1->nVert[0],1,1,
+ 0.0,1);
+ posIni = aux2->posIni[0];
+ enPol2 = PtoEnPoligonoVerticeBordeDouble(xAux,yAux,
+ &(aux2->x[posIni]),
+ &(aux2->y[posIni]),
+ aux2->nVert[0],1,1,
+ 0.0,1);
+ //si el polígono no pertenece a ninguno de los dos originales es
+ //un hueco
+ if((!enPol1)&&(!enPol2))
+ {
+ //lo marco como hueco
+ resultado->atr[i] = 0;
+ }
+ }
+ }
+ //liberamos la memoria asignada
+ LibMemPolig(aux1);
+ LibMemPolig(aux2);
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
//salimos de la función
return resultado;
}
@@ -1462,6 +1542,7 @@ polig* PoliBoolGreinerMult(const polig* poliBas,
const polig* poliRec,
const enum GEOC_OP_BOOL_POLIG op,
const double facPer,
+ const int compruebaHuecosUnion,
size_t* nIntersec,
size_t* nPerturb)
{
@@ -1527,10 +1608,10 @@ polig* PoliBoolGreinerMult(const polig* poliBas,
{
//comprobamos si los restángulos que encierran a los polígonos
//son disjuntos o no
- pr = RectDisjuntos(poliBas->xMin[i],poliBas->xMax[i],
- poliBas->yMin[i],poliBas->yMax[i],
- poliRec->xMin[j],poliRec->xMax[j],
- poliRec->yMin[j],poliRec->yMax[j]);
+ pr = GEOC_RECT_DISJUNTOS(poliBas->xMin[i],poliBas->xMax[i],
+ poliBas->yMin[i],poliBas->yMax[i],
+ poliRec->xMin[j],poliRec->xMax[j],
+ poliRec->yMin[j],poliRec->yMax[j]);
//comprobamos los casos particulares si los rectángulos son
//disjuntos
if(pr&&(op==GeocOpBoolInter))
@@ -1631,7 +1712,8 @@ polig* PoliBoolGreinerMult(const polig* poliBas,
return NULL;
}
//recortamos
- poligAux = PoliBoolGreiner(poligBas,poligRec,op,facPer,&nInt,&nPer);
+ poligAux = PoliBoolGreiner(poligBas,poligRec,op,facPer,
+ compruebaHuecosUnion,&nInt,&nPer);
//comprobamos los posibles errores
if(poligAux==NULL)
{
diff --git a/src/libgeoc/arco.h b/src/libgeoc/arco.h
new file mode 100644
index 0000000..a5a7b8c
--- /dev/null
+++ b/src/libgeoc/arco.h
@@ -0,0 +1,617 @@
+/* -*- coding: utf-8 -*- */
+/**
+\ingroup geom
+@{
+\file arco.h
+\brief Declaración de funciones para la realización de cálculos con arcos de
+ circunferencia.
+\author José Luis García Pallero, jgpallero@gmail.com
+\date 08 de agosto de 2013
+\copyright
+Copyright (c) 2013-2014, José Luis García Pallero. All rights reserved.
+\par
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+\par
+- Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+- Neither the name of the copyright holders nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+\par
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/******************************************************************************/
+/******************************************************************************/
+#ifndef _ARCO_H_
+#define _ARCO_H_
+/******************************************************************************/
+/******************************************************************************/
+#include<math.h>
+#include"libgeoc/constantes.h"
+#include"libgeoc/fgeneral.h"
+#include"libgeoc/geocnan.h"
+#include"libgeoc/mate.h"
+#include"libgeoc/ptopol.h"
+/******************************************************************************/
+/******************************************************************************/
+#ifdef __cplusplus
+extern "C" {
+#endif
+/******************************************************************************/
+/******************************************************************************/
+/**
+\def GEOC_ARC_RES_ANG
+\brief Resolución angular por debajo de la cual no se distinguirán dos valores
+ angulares en radianes.
+\note Esta constante ha de ser \b SIEMPRE positiva.
+\date 14 de agosto de 2013: Creación de la constante.
+*/
+#define GEOC_ARC_RES_ANG (1.0e-12)
+/******************************************************************************/
+/******************************************************************************/
+/**
+\def GEOC_ARC_NO_INTERSEC
+\brief Identificador de que dos arcos no se cortan.
+\date 08 de agosto de 2013: Creación de la constante.
+*/
+#define GEOC_ARC_NO_INTERSEC 0
+/******************************************************************************/
+/******************************************************************************/
+/**
+\def GEOC_ARC_INTERSEC
+\brief Identificador de que dos arcos se cortan en un punto, pero no son
+ colineales.
+\date 08 de agosto de 2013: Creación de la constante.
+*/
+#define GEOC_ARC_INTERSEC 1
+/******************************************************************************/
+/******************************************************************************/
+/**
+\def GEOC_ARC_INTERSEC_EXTREMO_NO_COLIN
+\brief Identificador de que dos arcos se cortan en un punto, el cual es un
+ extremo que está encima del otro arco, pero no son colineales.
+\date 08 de agosto de 2013: Creación de la constante.
+*/
+#define GEOC_ARC_INTERSEC_EXTREMO_NO_COLIN 2
+/******************************************************************************/
+/******************************************************************************/
+/**
+\def GEOC_ARC_INTERSEC_EXTREMOS_NO_COLIN
+\brief Identificador de que dos arcos tienen un extremo común, pero no son
+ colineales.
+\date 13 de agosto de 2013: Creación de la constante.
+*/
+#define GEOC_ARC_INTERSEC_EXTREMOS_NO_COLIN 3
+/******************************************************************************/
+/******************************************************************************/
+/**
+\def GEOC_ARC_INTERSEC_EXTREMOS_COLIN
+\brief Identificador de que dos arcos tienen un punto común y son colineales.
+\date 08 de agosto de 2013: Creación de la constante.
+*/
+#define GEOC_ARC_INTERSEC_EXTREMOS_COLIN 4
+/******************************************************************************/
+/******************************************************************************/
+/**
+\def GEOC_ARC_INTERSEC_MISMO_ARC
+\brief Identificador de que dos arcos tienen todos sus puntos extremos en común.
+\date 08 de agosto de 2013: Creación de la constante.
+*/
+#define GEOC_ARC_INTERSEC_MISMO_ARC 5
+/******************************************************************************/
+/******************************************************************************/
+/**
+\def GEOC_ARC_INTERSEC_COLIN
+\brief Identificador de que dos arcos tienen más de un punto en común, es decir,
+ se solapan, pero no son el mismo arco.
+\date 08 de agosto de 2013: Creación de la constante.
+*/
+#define GEOC_ARC_INTERSEC_COLIN 6
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Comprueba si dos rectángulos sobre la superficie de la esfera son
+ disjuntos, atendiendo únicamente a la coordenada longitud geodésica.
+\param[in] tol Tolerancia angular, en radianes. Indica el valor por debajo del
+ cual dos ángulos se consideran iguales. Este argumento ha de ser un
+ número \b POSITIVO (no se comprueba internamente).
+\param[in] lonMin1 Longitud mínima del rectángulo 1, en radianes.
+\param[in] lonMax1 Longitud máxima del rectángulo 1, en radianes.
+\param[in] lonMin2 Longitud mínima del rectángulo 2, en radianes.
+\param[in] lonMax2 Longitud máxima del rectángulo 2, en radianes.
+\return Dos posibilidades:
+ - 0: Los rectángulos no son disjuntos, es decir, tienen alguna parte
+ común (se cortan o se tocan) o uno está completamente contenido en
+ el otro.
+ - Distinto de 0: Los rectángulos son disjuntos.
+\note Esta función asume que \em lonMin1<lonyMax1 y \em lonMin2<lonMax2.
+\note Hay casos sobre la superficie de la esfera en los que el solapamiento de
+ rectángulos es muy difícil de determinar, como aquéllos en que algún
+ rectángulo tiene incrementos de longitud mayores que \f$\pi\f$ o los que
+ alguno de los lados tiene igual latitud. Por todo ello, esta función sólo
+ tiene en cuenta longitudes. Si hay solapamiento en longitud, se considera
+ que los rectángulos no son disjuntos.
+\date 09 de junio de 2012: Creación de la función.
+\date 23 de septiembre de 2013: Adición del argumento \em tol.
+\todo Esta función no está probada.
+*/
+int ArcosCircMaxDisjuntos(const double tol,
+ const double lonMin1,
+ const double lonMax1,
+ const double lonMin2,
+ const double lonMax2);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula el acimut de un arco de círculo máximo AB sobre la esfera.
+\param[in] tol Tolerancia angular, en radianes. Indica el valor por debajo del
+ cual dos ángulos se consideran iguales. Este argumento ha de ser un
+ número \b POSITIVO (no se comprueba internamente).
+\param[in] latA Latitud del punto A, en radianes.
+\param[in] lonA Longitud del punto A, en radianes.
+\param[in] latB Latitud del punto B, en radianes.
+\param[in] lonB Longitud del punto B, en radianes.
+\param[out] mRot Matriz de rotación aplicada al arco AB para llevar el punto A
+ al punto de coordenadas \f$(\varphi=0,\lambda=0)\f$. Este
+ argumento ha de ser una matriz de 3x3 almacenada en el formato de C.
+\return Acimut del arco AB, en radianes.
+\note El argumento \em mRot ha de ser pasado como una matriz en formato de C;
+ esto es, se accederá a sus elementos como <em>mRot[fil][com]</em>.
+\note El dominio de salida del acimut es \f$[0,2\pi[\f$.
+\date 13 de agosto de 2013: Creación de la función.
+\date 23 de septiembre de 2013: Adición del argumento \em tol.
+\todo Esta función no está probada.
+*/
+double AcimutArcoCircMaxEsf(const double tol,
+ const double latA,
+ const double lonA,
+ const double latB,
+ const double lonB,
+ double mRot[][3]);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula una matriz de rotación tal que, aplicada a un arco de círculo
+ máximo AB sobre la esfera, el punto A sea el punto de coordenadas
+ \f$(\varphi=0,\lambda=0)\f$ y el B esté contenido en el ecuador.
+\param[in] tol Tolerancia angular, en radianes. Indica el valor por debajo del
+ cual dos ángulos se consideran iguales. Este argumento ha de ser un
+ número \b POSITIVO (no se comprueba internamente).
+\param[in] latA Latitud del punto A, en radianes.
+\param[in] lonA Longitud del punto A, en radianes.
+\param[in] latB Latitud del punto B, en radianes.
+\param[in] lonB Longitud del punto B, en radianes.
+\param[out] mRot Matriz de rotación para aplicar a las coordenadas cartesianas
+ tridimensionales geocéntricas de los extremos de un segmento para
+ llevarlos al sistema descrito anteriormente. Este argumento ha de
+ ser una matriz de 3x3, almacenada en el formato de C.
+\param[out] lonBR Longitud del punto B en el sistema rotado, en el dominio
+ \f$]-\pi,\pi]\f$, en radianes. Este argumento sólo es tenido en
+ cuenta si se pasa un puntero distinto de \p NULL.
+\note El argumento \em mRot ha de ser pasado como una matriz en formato de C;
+ esto es, se accederá a sus elementos como <em>mRot[fil][com]</em>.
+\date 13 de agosto de 2013: Creación de la función.
+\date 23 de septiembre de 2013: Adición del argumento \em tol.
+\todo Esta función no está probada.
+*/
+void RotaArco00Ecuador(const double tol,
+ const double latA,
+ const double lonA,
+ const double latB,
+ const double lonB,
+ double mRot[][3],
+ double* lonBR);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Aplica una matriz de rotación a un punto en coordenadas cartesianas
+ tridimensionales geocéntricas.
+\param[in] sentido Identificador para realizar la rotación directa o la inversa.
+ Dos posibilidades:
+ - Mayor o igual que 0: Se realiza la transformación directa.
+ - Menor que 0: Re realiza la transformación inversa.
+\param[in] x Coordenada X del punto.
+\param[in] y Coordenada Y del punto.
+\param[in] z Coordenada Z del punto.
+\param[in] mRot Matriz de rotación de 3x3, almacenada en el formato de C.
+\param[out] xR Coordenada X rotada. Este argumento sólo es tenido en cuenta si
+ se pasa un puntero distinto de \p NULL.
+\param[out] yR Coordenada Y rotada. Este argumento sólo es tenido en cuenta si
+ se pasa un puntero distinto de \p NULL.
+\param[out] zR Coordenada Z rotada. Este argumento sólo es tenido en cuenta si
+ se pasa un puntero distinto de \p NULL.
+\note El argumento \em mRot ha de ser pasado como una matriz en formato de C;
+ esto es, se accederá a sus elementos como <em>mRot[fil][com]</em>.
+\date 13 de agosto de 2013: Creación de la función.
+\todo Esta función no está probada.
+*/
+void AplicaMatrizRotacionCoorCart(const int sentido,
+ const double x,
+ const double y,
+ const double z,
+ double mRot[][3],
+ double* xR,
+ double* yR,
+ double* zR);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Aplica una matriz de rotación a un punto en coordenadas geodésicas.
+\param[in] sentido Identificador para realizar la rotación directa o la inversa.
+ Dos posibilidades:
+ - Mayor o igual que 0: Se realiza la transformación directa.
+ - Menor que 0: Re realiza la transformación inversa.
+\param[in] lat Latitud del punto, en radianes.
+\param[in] lon Longitud del punto, en radianes.
+\param[in] mRot Matriz de rotación de 3x3, almacenada en el formato de C.
+\param[out] latR Latitud del punto en el sistema rotado, en radianes. Este
+ argumento sólo es tenido en cuenta si se pasa un puntero distinto de
+ \p NULL.
+\param[out] lonR Longitud del punto en el sistema rotado, en radianes. Este
+ argumento sólo es tenido en cuenta si se pasa un puntero distinto de
+ \p NULL.
+\note El argumento \em mRot ha de ser pasado como una matriz en formato de C;
+ esto es, se accederá a sus elementos como <em>mRot[fil][com]</em>.
+\note El dominio de la variable de salida \em lat1 es
+ \f$[-\frac{\pi}{2},\frac{\pi}{2}]\f$.
+\note El dominio de la variable de salida \em lon1 es \f$]-\pi,\pi]\f$.
+\date 13 de agosto de 2013: Creación de la función.
+\todo Esta función no está probada.
+*/
+void AplicaMatrizRotacionCoorGeod(const int sentido,
+ const double lat,
+ const double lon,
+ double mRot[][3],
+ double* latR,
+ double* lonR);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula los puntos de intersección de dos círculos máximos sobre la
+ superfice de la esfera, estando uno de ellos, que se omite, contenido en
+ el ecuador.
+\param[in] tol Tolerancia. Indica el valor por debajo del cual la componente de
+ un vector se considera igual a 0.0. Este argumento ha de ser un
+ número \b POSITIVO (no se comprueba internamente).
+\param[in] xC Coordenada X cartesiana geocéntrica del primer extremo del arco.
+\param[in] yC Coordenada Y cartesiana geocéntrica del primer extremo del arco.
+\param[in] zC Coordenada Z cartesiana geocéntrica del primer extremo del arco.
+\param[in] xD Coordenada X cartesiana geocéntrica del segundo extremo del arco.
+\param[in] yD Coordenada Y cartesiana geocéntrica del segundo extremo del arco.
+\param[in] zD Coordenada Z cartesiana geocéntrica del segundo extremo del arco.
+\param[out] xP Coordenada X cartesiana geocéntrica de uno de los puntos de
+ intersección, sobre la esfera de radio unidad. La coordenada del
+ otro punto será -\em xP.
+\param[out] yP Coordenada Y cartesiana geocéntrica de uno de los puntos de
+ intersección, sobre la esfera de radio unidad. La coordenada del
+ otro punto será -\em yP.
+\param[out] zP Coordenada Z cartesiana geocéntrica de uno de los puntos de
+ intersección, sobre la esfera de radio unidad. La coordenada del
+ otro punto será -\em zP.
+\return Dos posibilidades:
+ - #GEOC_ARC_INTERSEC: Hay intersección.
+ - #GEOC_ARC_NO_INTERSEC: No se ha podido calcular intersección, por lo
+ que \em xP, \em yP y \em zP no se utilizan internamente. Las razones
+ pueden ser:
+ - El arco CD es coindidente con el ecuador.
+ - Los vectores OC y OD forman un ángulo de \f$0\f$ o \f$\pi\f$, y no
+ se puede calcular su vector normal.
+\note Esta función no es robusta, es decir, puede dar resultados incorrectos
+ debido a errores de redondeo.
+\note Aunque los puntos C y D pertenezcan a una esfera de radio arbitrario, las
+ coordenadas de los puntos de intersección de los círculos máximos se dan
+ sobre la esfera de radio unidad.
+\note Para que se devuelvan las coordnadas del punto intersección, los
+ argumentos \em xP, \em yP y \em zP han de ser, \b TODOS, distintos de
+ \p NULL.
+\date 13 de agosto de 2013: Creación de la función.
+\date 22 de septirmbre de 2013: Adición del argumento \em tol.
+*/
+int IntersecCircMaxEsfAux(const double tol,
+ const double xC,
+ const double yC,
+ const double zC,
+ const double xD,
+ const double yD,
+ const double zD,
+ double* xP,
+ double* yP,
+ double* zP);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula la intersección de dos arcos de círculo máximo sobre la
+ superfice de la esfera que tienen, al menos, un extremo común. Uno de los
+ arcos, que se omite, está en el ecuador, con su extremo inicial en el
+ punto \f$(\varphi=0,\lambda=0)\f$.
+\param[in] tol Tolerancia, en radianes. Indica el valor por debajo del cual la
+ diferencia entre dos ángulos se considera igual a 0.0. Este argumento
+ ha de ser un número \b POSITIVO (no se comprueba internamente).
+\param[in] lonB Longitud, en radianes, del segundo extremo del arco AB, en el
+ dominio \f$]-\pi,\pi]\f$.
+\param[in] latC Latitud, en radianes, del primer extremo del arco CD.
+\param[in] lonC Longitud, en radianes, del primer extremo del arco CD, en el
+ dominio \f$]-\pi,\pi]\f$.
+\param[in] latD Latitud, en radianes, del segundo extremo del arco CD.
+\param[in] lonD Longitud, en radianes, del segundo extremo del arco CD, en el
+ dominio \f$]-\pi,\pi]\f$.
+\param[out] latP Latitud, en radianes, del punto de intersección. Siempre 0.0.
+\param[out] lonP Longitud, en radianes, del punto de intersección, en el
+ dominio \f$]-\pi,\pi]\f$.
+\return Cinco posibilidades:
+ - #GEOC_ARC_NO_INTERSEC: Los arcos no tienen ningún punto en común.
+ - #GEOC_ARC_INTERSEC_EXTREMOS_NO_COLIN: Los arcos tienen un extremo
+ común, pero no son colineales.
+ - #GEOC_ARC_INTERSEC_EXTREMOS_COLIN: Los arcos tienen un extremo común y
+ son colineales.
+ - #GEOC_ARC_INTERSEC_COLIN: Los arcos tienen más de un punto en común.
+ - #GEOC_ARC_INTERSEC_MISMO_ARC: Los dos arcos son idénticos.
+\note Para que se devuelvan las coordnadas del punto intersección, los
+ argumentos \em latP y \em lonP han de ser, \b TODOS, distintos de \p NULL.
+\note Si los arcos no se tocan, las variables devueltos en \em latP y \em lonP
+ almacenan 0.0.
+\note Los arcos implicados no pueden subtender un ángulo mayor o igual que
+ \f$\pi\f$. Esta condición no se comprueba internamente, por lo que \b NO
+ se informa de su posible inclumplimiento, y la función se ejecutará
+ normalmente.
+\note Esta función no es robusta, es decir, puede dar resultados incorrectos
+ debido a errores de redondeo.
+\note Si hay intersección, las coordenadas devueltas coinciden exactamente con
+ las del vértice implicado, A, B, C o D.
+\note Si los arcos se tocan en los dos extremos (son el mismo arco), las
+ coordenadas devueltas son siempre las del vértice A.
+\note Un buen valor para \em tol puede ser #GEOC_ARC_RES_ANG.
+\note Las longitudes de trabajo han de estar, obligatoriamente, en el dominio
+ \f$]-\pi,\pi]\f$.
+\date 22 de septiembre de 2013: Creación de la función.
+*/
+int IntersecArcCirMaxEsferaVertComunAux(const double tol,
+ const double lonB,
+ const double latC,
+ const double lonC,
+ const double latD,
+ const double lonD,
+ double* latP,
+ double* lonP);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula la intersección de dos arcos de círculo máximo sobre la
+ superfice de la esfera que tienen partes en común (se solapan
+ parcialmente o el vértice de uno está apoyado en el otro arco-pero no en
+ un vértice del segundo-). Uno de los arcos, que se omite, está en el
+ ecuador, con su extremo inicial en el punto \f$(\varphi=0,\lambda=0)\f$.
+\param[in] tol Tolerancia, en radianes. Indica el valor por debajo del cual la
+ diferencia entre dos ángulos se considera igual a 0.0. Este argumento
+ ha de ser un número \b POSITIVO (no se comprueba internamente).
+\param[in] lonB Longitud, en radianes, del segundo extremo del arco AB, en el
+ dominio \f$]-\pi,\pi]\f$.
+\param[in] latC Latitud, en radianes, del primer extremo del arco CD.
+\param[in] lonC Longitud, en radianes, del primer extremo del arco CD, en el
+ dominio \f$]-\pi,\pi]\f$.
+\param[in] latD Latitud, en radianes, del segundo extremo del arco CD.
+\param[in] lonD Longitud, en radianes, del segundo extremo del arco CD, en el
+ dominio \f$]-\pi,\pi]\f$.
+\param[out] latP Latitud, en radianes, del punto de intersección. Siempre 0.0.
+\param[out] lonP Longitud, en radianes, del punto de intersección, en el
+ dominio \f$]-\pi,\pi]\f$.
+\return Tres posibilidades:
+ - #GEOC_ARC_NO_INTERSEC: Los arcos no tienen ningún punto en común.
+ - #GEOC_ARC_INTERSEC_EXTREMO_NO_COLIN: El extremo de un arco toca al
+ otro arco en un punto (excluidos los extremos del segundo), pero los
+ arcos no son colineales.
+ - #GEOC_ARC_INTERSEC_COLIN: Los arcos tienen más de un punto en común.
+\note Esta función considera los casos de arcos colineales que sólo coincidan en
+ un vértice como #GEOC_ARC_INTERSEC_COLIN. Para tratar correctamente esos
+ casos especiales, se recomienda ejecutar antes la función
+ \ref IntersecArcCirMaxEsferaVertComunAux.
+\note Para que se devuelvan las coordnadas del punto intersección, los
+ argumentos \em latP y \em lonP han de ser, \b TODOS, distintos de \p NULL.
+\note Si los arcos no se tocan, las variables devueltos en \em latP y \em lonP
+ almacenan 0.0.
+\note Los arcos implicados no pueden subtender un ángulo mayor o igual que
+ \f$\pi\f$. Esta condición no se comprueba internamente, por lo que \b NO
+ se informa de su posible inclumplimiento, y la función se ejecutará
+ normalmente.
+\note Esta función no es robusta, es decir, puede dar resultados incorrectos
+ debido a errores de redondeo.
+\note Si hay intersección, las coordenadas devueltas coinciden exactamente con
+ las del vértice implicado, A, B, C o D.
+\note Un buen valor para \em tol puede ser #GEOC_ARC_RES_ANG.
+\note Las longitudes de trabajo han de estar, obligatoriamente, en el dominio
+ \f$]-\pi,\pi]\f$.
+\date 22 de septiembre de 2013: Creación de la función.
+*/
+int IntersecArcCirMaxEsferaVertApoyadoAux(const double tol,
+ const double lonB,
+ const double latC,
+ const double lonC,
+ const double latD,
+ const double lonD,
+ double* latP,
+ double* lonP);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula la intersección de dos arcos de círculo máximo sobre la
+ superfice de la esfera, uno de los cuales, que se omite, está en el
+ ecuador, con su extremo inicial en el punto \f$(\varphi=0,\lambda=0)\f$.
+\param[in] tol Tolerancia, en radianes. Indica el valor por debajo del cual la
+ diferencia entre dos ángulos se considera igual a 0.0. Este argumento
+ ha de ser un número \b POSITIVO (no se comprueba internamente).
+\param[in] lonB Longitud, en radianes, del segundo extremo del arco AB, en el
+ dominio \f$]-\pi,\pi]\f$.
+\param[in] latC Latitud, en radianes, del primer extremo del arco CD.
+\param[in] lonC Longitud, en radianes, del primer extremo del arco CD, en el
+ dominio \f$]-\pi,\pi]\f$.
+\param[in] latD Latitud, en radianes, del segundo extremo del arco CD.
+\param[in] lonD Longitud, en radianes, del segundo extremo del arco CD, en el
+ dominio \f$]-\pi,\pi]\f$.
+\param[in] xGC Coordenada X cartesiana geocéntrica para esfera de radio
+ unidad, en el sistema original, correspondiente al punto C. Este
+ argumento sólo se tiene en cuenta si es distinto del valor devuelto
+ por \ref GeocNan.
+\param[in] yGC Coordenada Y cartesiana geocéntrica para esfera de radio
+ unidad, en el sistema original, correspondiente al punto C. Este
+ argumento sólo se tiene en cuenta si es distinto del valor devuelto
+ por \ref GeocNan.
+\param[in] zGC Coordenada Z cartesiana geocéntrica para esfera de radio
+ unidad, en el sistema original, correspondiente al punto C. Este
+ argumento sólo se tiene en cuenta si es distinto del valor devuelto
+ por \ref GeocNan.
+\param[in] xGD Coordenada X cartesiana geocéntrica para esfera de radio
+ unidad, en el sistema original, correspondiente al punto C. Este
+ argumento sólo se tiene en cuenta si es distinto del valor devuelto
+ por \ref GeocNan.
+\param[in] yGD Coordenada Y cartesiana geocéntrica para esfera de radio
+ unidad, en el sistema original, correspondiente al punto C. Este
+ argumento sólo se tiene en cuenta si es distinto del valor devuelto
+ por \ref GeocNan.
+\param[in] zGD Coordenada Z cartesiana geocéntrica para esfera de radio
+ unidad, en el sistema original, correspondiente al punto C. Este
+ argumento sólo se tiene en cuenta si es distinto del valor devuelto
+ por \ref GeocNan.
+\param[out] latP Latitud, en radianes, del punto de intersección. Siempre 0.0.
+\param[out] lonP Longitud, en radianes, del punto de intersección, en el
+ dominio \f$]-\pi,\pi]\f$.
+\return Siete posibilidades:
+ - #GEOC_ARC_NO_INTERSEC: Los arcos no tienen ningún punto en común.
+ - #GEOC_ARC_INTERSEC: Los arcos se cortan en un punto.
+ - #GEOC_ARC_INTERSEC_EXTREMO_NO_COLIN: El extremo de un arco toca al
+ otro arco en un punto (excluidos los extremos del segungo), pero los
+ arcos no son colineales.
+ - #GEOC_ARC_INTERSEC_EXTREMOS_NO_COLIN: Los arcos tienen un extremo
+ común, pero no son colineales.
+ - #GEOC_ARC_INTERSEC_EXTREMOS_COLIN: Los arcos tienen un extremo común y
+ son colineales.
+ - #GEOC_ARC_INTERSEC_MISMO_ARC: Los dos arcos son idénticos.
+ - #GEOC_ARC_INTERSEC_COLIN: Los arcos tienen más de un punto en común.
+\note Para que se devuelvan las coordnadas del punto intersección, los
+ argumentos \em latP y \em lonP han de ser, \b TODOS, distintos de \p NULL.
+\note Si los arcos no se tocan, las variables devueltos en \em latP y \em lonP
+ almacenan 0.0.
+\note Los arcos implicados no pueden subtender un ángulo mayor o igual que
+ \f$\pi\f$. Esta condición no se comprueba internamente, por lo que \b NO
+ se informa de su posible inclumplimiento, y la función se ejecutará
+ normalmente.
+\note Esta función no es robusta, es decir, puede dar resultados incorrectos
+ debido a errores de redondeo.
+\note Un buen valor para \em tol puede ser #GEOC_ARC_RES_ANG.
+\note Las longitudes de trabajo han de estar, obligatoriamente, en el dominio
+ \f$]-\pi,\pi]\f$.
+\note Los argumentos \em xGC, \em yGC, \em zGC, \em xGD, \em yGD y \em zGD sólo
+ son tenidos en cuenta si se trabaja sobre la esfera y cada tríada es
+ distinta de \ref GeocNan, en cuyo caso las coordenadas cartesianas
+ tridimensionales geocéntricas, necesarias para los cálculos llevados a
+ cabo por la función, son calculadas internamente a partir de los
+ argumentos \em latC, \em lonC, \em latD y \em latD.
+\date 22 de septiembre de 2013: Creación de la función.
+\date 28 de marzo de 2014: Adición de los argumentos \em xGC, \em yGC, \em zGC,
+ \em xGD, \em yGD y \em zGD.
+*/
+int IntersecArcCircMaxEsferaAux(const double tol,
+ const double lonB,
+ const double latC,
+ const double lonC,
+ const double latD,
+ const double lonD,
+ const double xGC,
+ const double yGC,
+ const double zGC,
+ const double xGD,
+ const double yGD,
+ const double zGD,
+ double* latP,
+ double* lonP);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula la intersección de dos arcos de círculo máximo sobre la
+ superfice de la esfera.
+\param[in] latA Latitud, en radianes, del primer extremo del arco AB.
+\param[in] lonA Longitud, en radianes, del primer extremo del arco AB.
+\param[in] latB Latitud, en radianes, del segundo extremo del arco AB.
+\param[in] lonB Longitud, en radianes, del segundo extremo del arco AB.
+\param[in] latC Latitud, en radianes, del primer extremo del arco CD.
+\param[in] lonC Longitud, en radianes, del primer extremo del arco CD.
+\param[in] latD Latitud, en radianes, del segundo extremo del arco CD.
+\param[in] lonD Longitud, en radianes, del segundo extremo del arco CD.
+\param[out] latP Latitud, en radianes, del punto de intersección. El dominio de
+ la latitud utilizado es, independientemente del usado en las
+ variables de entrada, \f$[-\frac{\pi}{2},\frac{\pi}{2}]\f$.
+\param[out] lonP Longitud, en radianes, del punto de intersección. El dominio de
+ la longitud utilizado es, independientemente del usado en las
+ variables de entrada, \f$]-\pi,\pi]\f$.
+\return Siete posibilidades:
+ - #GEOC_ARC_NO_INTERSEC: Los arcos no tienen ningún punto en común.
+ - #GEOC_ARC_INTERSEC: Los arcos se cortan en un punto.
+ - #GEOC_ARC_INTERSEC_EXTREMO_NO_COLIN: El extremo de un arco toca al
+ otro arco en un punto (excluidos los extremos del segungo), pero los
+ arcos no son colineales.
+ - #GEOC_ARC_INTERSEC_EXTREMOS_NO_COLIN: Los arcos tienen un extremo
+ común, pero no son colineales.
+ - #GEOC_ARC_INTERSEC_EXTREMOS_COLIN: Los arcos tienen un extremo común y
+ son colineales.
+ - #GEOC_ARC_INTERSEC_MISMO_ARC: Los dos arcos son idénticos.
+ - #GEOC_ARC_INTERSEC_COLIN: Los arcos tienen más de un punto en común.
+\note Para que se devuelvan las coordnadas del punto intersección, los
+ argumentos \em latP y \em lonP han de ser, \b TODOS, distintos de \p NULL.
+\note Si los arcos no se tocan, las variables devueltos en \em latP y \em lonP
+ almacenan 0.0.
+\note Los arcos implicados no pueden subtender un ángulo mayor o igual que
+ \f$\pi\f$. Esta condición no se comprueba internamente, por lo que \b NO
+ se informa de su posible inclumplimiento, y la función se ejecutará
+ normalmente.
+\note Esta función no es robusta, es decir, puede dar resultados incorrectos
+ debido a errores de redondeo.
+\note Esta función considera dos puntos iguales a aquellos que estén en un
+ entorno de #GEOC_ARC_RES_ANG radianes.
+\note Si los arcos se tocan en los dos extremos (son el mismo arco), las
+ coordenadas devueltas son siempre las del vértice A.
+\note Si los arcos tienen más de un punto en común, pero no son el mismo arco,
+ las coordenadas de salida siempre son las de un punto extremo de un arco.
+ Este punto extremo se intentará que sea uno de los puntos iniciales de
+ algún arco, anque no se puede asegurar.
+\date 13 de agosto de 2013: Creación de la función.
+*/
+int IntersecArcCircMaxEsfera(const double latA,
+ const double lonA,
+ const double latB,
+ const double lonB,
+ const double latC,
+ const double lonC,
+ const double latD,
+ const double lonD,
+ double* latP,
+ double* lonP);
+/******************************************************************************/
+/******************************************************************************/
+#ifdef __cplusplus
+}
+#endif
+/******************************************************************************/
+/******************************************************************************/
+#endif
+/******************************************************************************/
+/******************************************************************************/
+/** @} */
+/******************************************************************************/
+/******************************************************************************/
+/* kate: encoding utf-8; end-of-line unix; syntax c; indent-mode cstyle; */
+/* kate: replace-tabs on; space-indent on; tab-indents off; indent-width 4; */
+/* kate: line-numbers on; folding-markers on; remove-trailing-space on; */
+/* kate: backspace-indents on; show-tabs on; */
+/* kate: word-wrap-column 80; word-wrap-marker-color #D2D2D2; word-wrap off; */
diff --git a/src/libgeoc/compilador.h b/src/libgeoc/compilador.h
index bdd9684..bdd9684 100755..100644
--- a/src/libgeoc/compilador.h
+++ b/src/libgeoc/compilador.h
diff --git a/src/libgeoc/constantes.h b/src/libgeoc/constantes.h
index 294f5a6..294f5a6 100755..100644
--- a/src/libgeoc/constantes.h
+++ b/src/libgeoc/constantes.h
diff --git a/src/libgeoc/dpeucker.h b/src/libgeoc/dpeucker.h
index b4fe38a..4d79318 100644
--- a/src/libgeoc/dpeucker.h
+++ b/src/libgeoc/dpeucker.h
@@ -3,16 +3,17 @@
\ingroup geom
@{
\file dpeucker.h
-\brief Declaración de funciones para el aligerado de polilíneas basadas en el
+\brief Declaración de funciones para el aligerado de polilíneas, basadas en el
algoritmo de Douglas-Peucker.
\author José Luis García Pallero, jgpallero@gmail.com
-\date 04 de julio de 2011
-\section Licencia Licencia
-Copyright (c) 2009-2010, José Luis García Pallero. All rights reserved.
-
+\note Este fichero contiene funciones paralelizadas con OpenMP.
+\date 17 de agosto de 2013
+\copyright
+Copyright (c) 2013-2014, José Luis García Pallero. All rights reserved.
+\par
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
-
+\par
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this
@@ -21,7 +22,7 @@ are permitted provided that the following conditions are met:
- Neither the name of the copyright holders nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
-
+\par
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -40,12 +41,10 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/******************************************************************************/
/******************************************************************************/
#include<stdlib.h>
-#include<math.h>
-#include"libgeoc/calctopo.h"
-#include"libgeoc/constantes.h"
-#include"libgeoc/eucli.h"
-#include"libgeoc/fgeneral.h"
-#include"libgeoc/segmento.h"
+#include"libgeoc/dpeuckera.h"
+#include"libgeoc/dpeuckere.h"
+#include"libgeoc/dpeuckerp.h"
+#include"libgeoc/errores.h"
/******************************************************************************/
/******************************************************************************/
#ifdef __cplusplus
@@ -54,82 +53,67 @@ extern "C" {
/******************************************************************************/
/******************************************************************************/
/**
-\def GEOC_DPEUCKER_BUFFER_PTOS
-\brief Número de puntos para ir asignando memoria en bloques para el vector de
- salida en la funcion \ref AligeraPolilinea.
-\date 06 de julio de 2011: Creación de la constante.
-*/
-#define GEOC_DPEUCKER_BUFFER_PTOS 100
-/******************************************************************************/
-/******************************************************************************/
-/** \enum GEOC_DPEUCKER_ROBUSTO
-\brief Aplicación o no del algoritmo robusto de aligerado de polilíneas.
-\date 10 de julio de 2011: Creación del tipo.
-*/
-enum GEOC_DPEUCKER_ROBUSTO
-{
- /** \brief \b *NO* se realiza aligerado robusto. */
- GeocDPeuckerRobNo=111,
- /** \brief \b *SÍ* se realiza aligerado robusto. */
- GeocDPeuckerRobSi=112,
- /** \brief Aligerado semi robusto con \ref AligPolilRobIntersecOrig. */
- GeocDPeuckerRobOrig=113,
- /** \brief Aligerado semi robusto con \ref AligPolilRobAutoIntersec. */
- GeocDPeuckerRobAuto=114
-};
-/******************************************************************************/
-/******************************************************************************/
-/**
-\brief Elimina vértices de una polilínea mediante un algoritmo inspirado en el
- de Douglas-Peucker.
-
- Este algoritmo, comenzando por el primer punto de la polilínea, va
- uniendo puntos en segmentos de tal forma que se eliminan todos aquellos
- puntos que queden a una distancia perpendicular menor o igual a \em tol
- del segmento de trabajo. Así aplicado, pueden ocurrir casos singulares en
- los que la polilínea aligerada tenga casos de auto intersección entre sus
- lados resultantes. Para evitar esto, se puede aplicar la versión robusta
- del algoritmo.
-\param[in] x Vector que contiene las coordenadas X de los vértices de la
- polilínea de trabajo.
-\param[in] y Vector que contiene las coordenadas Y de los vértices de la
- polilínea de trabajo.
+\brief Elimina vértices de una polilínea mediante una familia de algoritmos
+ basados en el de Douglas-Peucker.
+\param[in] x Vector que contiene las coordenadas X o las longitudes, en
+ radianes, de los vértices de la polilínea de trabajo.
+\param[in] y Vector que contiene las coordenadas Y o las latitudes, en radianes,
+ de los vértices de la polilínea de trabajo.
\param[in] nPtos Número de elementos de los vectores \em x e \em y.
\param[in] incX Posiciones de separación entre los elementos del vector \em x.
Este argumento siempre ha de ser un número positivo.
\param[in] incY Posiciones de separación entre los elementos del vector \em y.
Este argumento siempre ha de ser un número positivo.
-\param[in] tol Tolerancia para eliminar vértices, en las mismas unidades que las
- coordenadas de los vértices.
+\param[in] tol Tolerancia para eliminar vértices. Dos posibilidades:
+ - Si se trabaja en coordenadas planas, este argumento ha de estar en
+ las mismas unidades que las coordenadas de los vértices.
+ - Si se trabaja sobre la esfera, este argumento ha de ser una
+ longitud de arco de círculo máximo sobre la esfera de radio unidad.
+\param[in] paralelizaTol Identificador para evaluar o no en paralelo si los
+ puntos candidatos están en tolerancia. Dos posibilidades:
+ - 0: Se evalúa en serie (aunque la compilación se haya hecho en
+ paralelo) si los puntos están en tolerancia.
+ - Distinto de 0: Se evalúa en paralelo (sólo si se ha compilado en
+ paralelo) si los puntos están en tolerancia.
\param[in] robusto Identificador para realizar o no un aligerado robusto. Ha de
ser un elemento del tipo enumerado #GEOC_DPEUCKER_ROBUSTO. Varias
posibilidades:
- - #GeocDPeuckerRobNo: No se aplica el algoritmo robusto.
+ - #GeocDPeuckerOriginal: Utiliza el algoritmo de Douglas-Peucker
+ original, que no es robusto.
+ - #GeocDPeuckerRobNo: Utiliza la variación no recursiva del algoritmo
+ de Douglas-Peucker, que no es robusta.
- #GeocDPeuckerRobSi: Se aplica el algoritmo robusto completo, que
garantiza la no ocurrencia de auto intersecciones en la polilínea
resultante. Internamente, primero se aplica el tratamiento robusto
de la opción #GeocDPeuckerRobOrig y luego el de la opción
#GeocDPeuckerRobAuto.
- #GeocDPeuckerRobOrig: Se aplica un algoritmo semi robusto que
- consiste en garantizar que los segmentos de la polilínea aligerada
- que se van creando no intersectarán con ninguno de los segmentos
- que forman los vértices que quedan por procesar de la polilínea
- original. En casos muy especiales, este algoritmo puede seguir
- dando lugar a auto intersecciones.
+ consiste en garantizar que los segmentos/arcos de la polilínea
+ aligerada que se van creando no intersectarán con ninguno de los
+ segmentos/arcos que forman los vértices que quedan por procesar de
+ la polilínea original. En casos muy especiales, este algoritmo
+ puede seguir dando lugar a auto intersecciones.
- #GeocDPeuckerRobAuto: Se aplica un algoritmo semi robusto que
- consiste en garantizar que los segmentos de la polilínea aligerada
- que se van creando no intersectarán con ninguno de los segmentos de
- la polilínea aligerada creados con anterioridad. En casos muy
- especiales, este algoritmo puede seguir dando lugar a auto
- intersecciones.
-\param[in] nPtosRobusto Número de puntos de la polilínea original a utilizar en
- el caso de tratamiento robusto con las opciones #GeocDPeuckerRobSi o
- #GeocDPeuckerRobOrig. Si se pasa el valor 0, se utilizan todos los
- puntos hasta el final de la polilínea original.
-\param[in] nSegRobusto Número de segmentos de la polilínea aligerada a utilizar
+ consiste en garantizar que los segmentos/arcos de la polilínea
+ aligerada que se van creando no intersectarán con ninguno de los
+ segmentos/arcos de la polilínea aligerada creados con anterioridad.
+ En casos muy especiales, este algoritmo puede seguir dando lugar a
+ auto intersecciones.
+\param[in] nSegRobOrig Número de segmentos/arcos de la polilínea original a
+ utilizar en el caso de tratamiento robusto con las opciones
+ #GeocDPeuckerRobSi o #GeocDPeuckerRobOrig. Si se pasa el valor 0, se
+ utilizan todos los segmentos/arcos hasta el final de la polilínea
+ original.
+\param[in] nSegRobAuto Número de segmentos de la polilínea aligerada a utilizar
en el caso de tratamiento robusto con las opciones #GeocDPeuckerRobSi
o #GeocDPeuckerRobAuto. Si se pasa el valor 0, se utilizan todos los
segmentos hasta el inicio de la polilínea aligerada.
+\param[in] esf Identificador de trabajo sobre la superficie de la esfera. Dos
+ posibilidades:
+ - 0: No se trabaja sobre la superficie de la esfera, sino en el
+ plano.
+ - Distinto de 0: Se trabaja sobre la superficie de la esfera de radio
+ unidad.
\param[out] nPtosSal Número de puntos de la polilínea aligerada.
\return Vector de \em nPtosSal elementos que contiene los índices en los
vectores \em x e \em y de los vértices que formarán la polilínea
@@ -138,10 +122,23 @@ enum GEOC_DPEUCKER_ROBUSTO
\note Esta función no comprueba si el número de elementos de los vectores \em x
e \em y es congruente con el valor pasado en \em nPtos.
\note Esta función asume que \em nPtos es mayor que 0. En caso contrario,
- devuelve \p NULL.
-\date 07 de julio de 2011: Creación de la función.
-\date 10 de julio de 2011: Cambio del tipo del argumento \em robusto al tipo
- enumerado #GEOC_DPEUCKER_ROBUSTO.
+ devuelve \p NULL, por lo que un valor de retorno igual a \p NULL sólo es
+ indicativo de error cuando \em nPtos es mayor que 0.
+\note Esta función comprueba los casos especiales con
+ \ref CasosEspecialesAligeraPolilinea.
+\note El argumento \em paralelizaTol \b SÓLO afecta a la paralelización de la
+ comprobación de puntos en tolerancia. Los chequeos de intersección de
+ segmentos/arcos siempre se hacen en paralelo (si el código ha sido
+ compilado al efecto).
+\date 25 de mayo de 2012: Creación de la función.
+\date 08 de agosto de 2013: Comprobación de casos especiales.
+\date 17 de agosto de 2013: Unificación de las funciones de aligerado en el
+ plano y en la esfera.
+\date 20 de agosto de 2013: Sustitución de las antiguas variables de entrada
+ \em nPtosRobusto y \em nSegRobusto por \em nSegRobOrig y \em nSegRobAuto.
+\date 23 de agosto de 2013: Adición del argumento de entrada \em paralelizaTol.
+\date 21 de septiembre de 2013: Adición de la capacidad de trabajar sobre la
+ esfera con el algoritmo de Douglas-Peucker original.
\todo Esta función todavía no está probada.
*/
size_t* AligeraPolilinea(const double* x,
@@ -150,97 +147,172 @@ size_t* AligeraPolilinea(const double* x,
const size_t incX,
const size_t incY,
const double tol,
+ const int paralelizaTol,
const enum GEOC_DPEUCKER_ROBUSTO robusto,
- const size_t nPtosRobusto,
- const size_t nSegRobusto,
+ const size_t nSegRobOrig,
+ const size_t nSegRobAuto,
+ const int esf,
size_t* nPtosSal);
/******************************************************************************/
/******************************************************************************/
/**
-\brief Aproximación robusta al aligerado de líneas consistente en evitar que los
- segmentos creados intersecten con los de la polilínea original a partir
- del punto de trabajo actual.
-\param[in] x Vector que contiene las coordenadas X de los vértices de la
- polilínea de trabajo.
-\param[in] y Vector que contiene las coordenadas Y de los vértices de la
- polilínea de trabajo.
+\brief Elimina vértices de una polilínea mediante el algoritmo original de
+ Douglas-Peucker.
+\param[in] x Vector que contiene las coordenadas X o las longitudes, en
+ radianes, de los vértices de la polilínea de trabajo.
+\param[in] y Vector que contiene las coordenadas Y o las latitudes, en radianes,
+ de los vértices de la polilínea de trabajo.
\param[in] nPtos Número de elementos de los vectores \em x e \em y.
\param[in] incX Posiciones de separación entre los elementos del vector \em x.
Este argumento siempre ha de ser un número positivo.
\param[in] incY Posiciones de separación entre los elementos del vector \em y.
Este argumento siempre ha de ser un número positivo.
-\param[in] ptosAUsar Número de puntos a utilizar de la polilínea original. Si se
- pasa el valor 0 se utilizan todos los puntos que quedan desde el
- punto de trabajo hasta el final.
-\param[in] posIni Posición inicial del segmento a chequear.
-\param[in,out] posFin Posición final del segmento a chequear. Al término de la
- ejecución de la función almacena la posición del punto que hace
- que el segmento de la polilínea aligerada no intersecte con
- ninguno de los que quedan de la polilínea original.
+\param[in] tol Tolerancia para eliminar vértices. Dos posibilidades:
+ - Si se trabaja en coordenadas planas, este argumento ha de estar en
+ las mismas unidades que las coordenadas de los vértices.
+ - Si se trabaja sobre la esfera, este argumento ha de ser una
+ longitud de arco de círculo máximo sobre la esfera de radio unidad.
+\param[in] esf Identificador de trabajo sobre la superficie de la esfera. Dos
+ posibilidades:
+ - 0: No se trabaja sobre la superficie de la esfera, sino en el
+ plano.
+ - Distinto de 0: Se trabaja sobre la superficie de la esfera de radio
+ unidad.
+\param[out] nPtosSal Número de puntos de la polilínea aligerada.
+\return Vector de \em nPtosSal elementos que contiene los índices en los
+ vectores \em x e \em y de los vértices que formarán la polilínea
+ aligerada. Si ocurre algún error de asignación de memoria se devuelve el
+ valor \p NULL.
\note Esta función no comprueba si el número de elementos de los vectores \em x
e \em y es congruente con el valor pasado en \em nPtos.
-\note Esta función no comprueba si los índices pasados en los argumentos
- \em posIni y \em posFin son congruentes con el tamaño de los vectores
- pasado en \em nPtos.
-\note Esta función no comprueba internamente si la variable \em ptosAUsar es
- congruente con el valor pasado en \em nPtos.
-\date 07 de julio de 2011: Creación de la función.
+\note Esta función asume que \em nPtos es mayor que 0. En caso contrario,
+ devuelve \p NULL, por lo que un valor de retorno igual a \p NULL sólo es
+ indicativo de error cuando \em nPtos es mayor que 0.
+\note Esta función puede devolver resultados erróneos si algún segmento base es
+ mayor o igual que \f$\pi\f$.
+\date 21 de septiembre de 2013: Creación de la función.
\todo Esta función todavía no está probada.
*/
-void AligPolilRobIntersecOrig(const double* x,
- const double* y,
- const size_t nPtos,
- const size_t incX,
- const size_t incY,
- const size_t ptosAUsar,
- const size_t posIni,
- size_t* posFin);
+size_t* DouglasPeuckerOriginal(const double* x,
+ const double* y,
+ const size_t nPtos,
+ const size_t incX,
+ const size_t incY,
+ const double tol,
+ const int esf,
+ size_t* nPtosSal);
/******************************************************************************/
/******************************************************************************/
/**
-\brief Aproximación robusta al aligerado de líneas consistente en evitar que los
- segmentos creados intersecten con los anteriores de la polilínea
- aligerada.
-\param[in] x Vector que contiene las coordenadas X de los vértices de la
- polilínea de trabajo.
-\param[in] y Vector que contiene las coordenadas Y de los vértices de la
- polilínea de trabajo.
+\brief Elimina vértices de una polilínea mediante un algoritmo no recursivo,
+ inspirado en el de Douglas-Peucker.
+\brief Este algoritmo, comenzando por el primer punto de la polilínea, va
+ uniendo puntos en segmentos/arcos de tal forma que se eliminan todos
+ aquellos puntos que queden a una distancia menor o igual a \em tol del
+ segmento/arco de trabajo. Así aplicado, pueden ocurrir casos singulares
+ en los que la polilínea aligerada tenga casos de auto intersección entre
+ sus lados resultantes. Para evitar esto, se puede aplicar la versión
+ robusta del algoritmo.
+\param[in] x Vector que contiene las coordenadas X o las longitudes, en
+ radianes, de los vértices de la polilínea de trabajo.
+\param[in] y Vector que contiene las coordenadas Y o las latitudes, en radianes,
+ de los vértices de la polilínea de trabajo.
+\param[in] nPtos Número de elementos de los vectores \em x e \em y.
\param[in] incX Posiciones de separación entre los elementos del vector \em x.
Este argumento siempre ha de ser un número positivo.
\param[in] incY Posiciones de separación entre los elementos del vector \em y.
Este argumento siempre ha de ser un número positivo.
-\param[in] posAlig Vector de posiciones de \em x e \em y utilizadas en la
- polilínea aligerada.
-\param[in] nPosAlig Número de elementos de \em posAlig menos el último punto
- añadido. Esto se hace así para evitar chequear el segmento
- inmediatamente anterior, que siempre tiene un punto en común (su
- extremo final) con el de trabajo.
-\param[in] segAUsar Número de segmentos a utilizar de la polilínea aligerada. Si
- se pasa el valor 0 se utilizan todos los segmentos anteriores.
-\param[in] posIni Posición inicial del segmento a chequear.
-\param[in,out] posFin Posición final del segmento a chequear. Al término de la
- ejecución de la función almacena la posición del punto que hace
- que el segmento de la polilínea aligerada no intersecte con
- ninguno de los anteriormente calculados.
+\param[in] tol Tolerancia para eliminar vértices. Dos posibilidades:
+ - Si se trabaja en coordenadas planas, este argumento ha de estar en
+ las mismas unidades que las coordenadas de los vértices.
+ - Si se trabaja sobre la esfera, este argumento ha de ser una
+ longitud de arco de círculo máximo sobre la esfera de radio unidad.
+\param[in] paralelizaTol Identificador para evaluar o no en paralelo si los
+ puntos candidatos están en tolerancia. Dos posibilidades:
+ - 0: Se evalúa en serie (aunque la compilación se haya hecho en
+ paralelo) si los puntos están en tolerancia.
+ - Distinto de 0: Se evalúa en paralelo (sólo si se ha compilado en
+ paralelo) si los puntos están en tolerancia.
+\param[in] robusto Identificador para realizar o no un aligerado robusto. Ha de
+ ser un elemento del tipo enumerado #GEOC_DPEUCKER_ROBUSTO. Varias
+ posibilidades:
+ - #GeocDPeuckerOriginal: En este caso esta opción es equivalente a
+ pasar #GeocDPeuckerRobNo.
+ - #GeocDPeuckerRobNo: Utiliza la variación no recursiva del algoritmo
+ de Douglas-Peucker, que no es robusta.
+ - #GeocDPeuckerRobSi: Se aplica el algoritmo robusto completo, que
+ garantiza la no ocurrencia de auto intersecciones en la polilínea
+ resultante. Internamente, primero se aplica el tratamiento robusto
+ de la opción #GeocDPeuckerRobOrig y luego el de la opción
+ #GeocDPeuckerRobAuto.
+ - #GeocDPeuckerRobOrig: Se aplica un algoritmo semi robusto que
+ consiste en garantizar que los segmentos/arcos de la polilínea
+ aligerada que se van creando no intersectarán con ninguno de los
+ segmentos/arcos que forman los vértices que quedan por procesar de
+ la polilínea original. En casos muy especiales, este algoritmo
+ puede seguir dando lugar a auto intersecciones.
+ - #GeocDPeuckerRobAuto: Se aplica un algoritmo semi robusto que
+ consiste en garantizar que los segmentos/arcos de la polilínea
+ aligerada que se van creando no intersectarán con ninguno de los
+ segmentos/arcos de la polilínea aligerada creados con anterioridad.
+ En casos muy especiales, este algoritmo puede seguir dando lugar a
+ auto intersecciones.
+\param[in] nSegRobOrig Número de segmentos/arcos de la polilínea original a
+ utilizar en el caso de tratamiento robusto con las opciones
+ #GeocDPeuckerRobSi o #GeocDPeuckerRobOrig. Si se pasa el valor 0, se
+ utilizan todos los segmentos/arcos hasta el final de la polilínea
+ original.
+\param[in] nSegRobAuto Número de segmentos de la polilínea aligerada a utilizar
+ en el caso de tratamiento robusto con las opciones #GeocDPeuckerRobSi
+ o #GeocDPeuckerRobAuto. Si se pasa el valor 0, se utilizan todos los
+ segmentos hasta el inicio de la polilínea aligerada.
+\param[in] esf Identificador de trabajo sobre la superficie de la esfera. Dos
+ posibilidades:
+ - 0: No se trabaja sobre la superficie de la esfera, sino en el
+ plano.
+ - Distinto de 0: Se trabaja sobre la superficie de la esfera de radio
+ unidad.
+\param[out] nPtosSal Número de puntos de la polilínea aligerada.
+\return Vector de \em nPtosSal elementos que contiene los índices en los
+ vectores \em x e \em y de los vértices que formarán la polilínea
+ aligerada. Si ocurre algún error de asignación de memoria se devuelve el
+ valor \p NULL.
\note Esta función no comprueba si el número de elementos de los vectores \em x
e \em y es congruente con el valor pasado en \em nPtos.
-\note Esta función no comprueba si los índices pasados en los argumentos
- \em posIni y \em posFin son congruentes con el tamaño de los vectores
- pasado en \em nPtos.
-\note Esta función trabaja internamente con el valor absoluto del argumento
- \em tamRect.
-\date 05 de julio de 2011: Creación de la función.
+\note Esta función asume que \em nPtos es mayor que 0. En caso contrario,
+ devuelve \p NULL, por lo que un valor de retorno igual a \p NULL sólo es
+ indicativo de error cuando \em nPtos es mayor que 0.
+\note Esta función comprueba los casos especiales con
+ \ref CasosEspecialesAligeraPolilinea.
+\note El argumento \em paralelizaTol \b SÓLO afecta a la paralelización de la
+ comprobación de puntos en tolerancia. Los chequeos de intersección de
+ segmentos/arcos siempre se hacen en paralelo (si el código ha sido
+ compilado al efecto).
+\date 07 de julio de 2011: Creación de la función.
+\date 10 de julio de 2011: Cambio del tipo del argumento \em robusto al tipo
+ enumerado #GEOC_DPEUCKER_ROBUSTO.
+\date 14 de mayo de 2012: Corregido bug que hacía que no se escogiese bien el
+ vértice a añadir a la polilínea aligerada.
+\date 25 de mayo de 2012: Cambio de nombre de la función.
+\date 17 de agosto de 2013: Comprobación de casos especiales y unificación de
+ las funciones de aligerado en el plano y en la esfera.
+\date 20 de agosto de 2013: Sustitución de las antiguas variables de entrada
+ \em nPtosRobusto y \em nSegRobusto por \em nSegRobOrig y \em nSegRobAuto.
+\date 23 de agosto de 2013: Adición del argumento de entrada \em paralelizaTol.
\todo Esta función todavía no está probada.
*/
-void AligPolilRobAutoIntersec(const double* x,
+size_t* DouglasPeuckerRobusto(const double* x,
const double* y,
+ const size_t nPtos,
const size_t incX,
const size_t incY,
- const size_t* posAlig,
- const size_t nPosAlig,
- const size_t segAUsar,
- const size_t posIni,
- size_t* posFin);
+ const double tol,
+ const int paralelizaTol,
+ const enum GEOC_DPEUCKER_ROBUSTO robusto,
+ const size_t nSegRobOrig,
+ const size_t nSegRobAuto,
+ const int esf,
+ size_t* nPtosSal);
/******************************************************************************/
/******************************************************************************/
#ifdef __cplusplus
diff --git a/src/libgeoc/dpeuckera.h b/src/libgeoc/dpeuckera.h
new file mode 100644
index 0000000..7750e80
--- /dev/null
+++ b/src/libgeoc/dpeuckera.h
@@ -0,0 +1,210 @@
+/* -*- coding: utf-8 -*- */
+/**
+\ingroup geom
+@{
+\file dpeuckera.h
+\brief Declaración de elementos y funciones auxiliares para el uso de la familia
+ de algoritmos de Douglas-Peucker.
+\author José Luis García Pallero, jgpallero@gmail.com
+\date 18 de agosto de 2013
+\copyright
+Copyright (c) 2013-2014, José Luis García Pallero. All rights reserved.
+\par
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+\par
+- Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+- Neither the name of the copyright holders nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+\par
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/******************************************************************************/
+/******************************************************************************/
+#ifndef _DPEUCKERA_H_
+#define _DPEUCKERA_H_
+/******************************************************************************/
+/******************************************************************************/
+#include<math.h>
+#include"libgeoc/arco.h"
+#include"libgeoc/errores.h"
+#include"libgeoc/ptopol.h"
+/******************************************************************************/
+/******************************************************************************/
+#ifdef __cplusplus
+extern "C" {
+#endif
+/******************************************************************************/
+/******************************************************************************/
+/**
+\def GEOC_DPEUCKER_BUFFER_PTOS
+\brief Número de puntos para ir asignando memoria en bloques para el vector de
+ salida de las funciones de aligerado de polilíneas.
+\date 17 de agosto de 2013: Creación de la constante.
+*/
+#define GEOC_DPEUCKER_BUFFER_PTOS 1000
+/******************************************************************************/
+/******************************************************************************/
+/**
+\def GEOC_DPEUCKER_NO_INTERSEC
+\brief Identificador de que dos segmentos o arcos no se cortan.
+\date 18 de agosto de 2013: Creación de la constante.
+*/
+#define GEOC_DPEUCKER_NO_INTERSEC 0
+/******************************************************************************/
+/******************************************************************************/
+/**
+\def GEOC_DP_RECT_DISJ
+\brief Comprueba si dos rectángulos son disjuntos.
+\param[in] esf Identificador de trabajo sobre la superficie de la esfera. Dos
+ posibilidades:
+ - 0: No se trabaja sobre la superficie de la esfere, sino en el
+ plano.
+ - Distinto de 0: Se trabaja sobre la superficie de la esfera de radio
+ unidad.
+\param[in] tol Tolerancia angular, en radianes. Indica el valor por debajo del
+ cual dos ángulos se consideran iguales. Este argumento ha de ser un
+ número \b POSITIVO (no se comprueba internamente).
+\param[in] xMin1 Coordenada X o longitud, en radianes, mínima del rectángulo 1.
+\param[in] xMax1 Coordenada X o longitud, en radianes, máxima del rectángulo 1.
+\param[in] yMin1 Coordenada Y o latitud, en radianes, mínima del rectángulo 1.
+\param[in] yMax1 Coordenada Y o latitud, en radianes, máxima del rectángulo 1.
+\param[in] xMin2 Coordenada X o longitud, en radianes, mínima del rectángulo 2.
+\param[in] xMax2 Coordenada X o longitud, en radianes, máxima del rectángulo 2.
+\param[in] yMin2 Coordenada Y o latitud, en radianes, mínima del rectángulo 2.
+\param[in] yMax2 Coordenada Y o latitud, en radianes, máxima del rectángulo 2.
+\return Dos posibilidades:
+ - 0: Los rectángulos no son disjuntos, es decir, tienen alguna parte
+ común (se cortan o se tocan) o uno está completamente contenido en
+ el otro.
+ - Distinto de 0: Los rectángulos son disjuntos.
+\note Esta función asume que \em xMin1<xMax1, \em yMin1<yMax1, \em xMin2<xMax2 e
+ \em yMin2<yMax2.
+\note Si se trabaja sobre la esfera, esta macro utiliza internamente la función
+ \ref ArcosCircMaxDisjuntos, mientras que si estamos en el plano se usa la
+ macro \ref GEOC_RECT_DISJUNTOS.
+\date 18 de agosto de 2013: Creación de la macro.
+\date 23 de septiembre de 2013: Adición del argumento \em tol.
+\todo Esta macro no está probada.
+*/
+#define GEOC_DP_RECT_DISJ(esf,tol, \
+ xMin1,xMax1,yMin1,yMax1,xMin2,xMax2,yMin2,yMax2) \
+((esf) \
+? (ArcosCircMaxDisjuntos(tol,xMin1,xMax1,xMin2,xMax2)) \
+: (GEOC_RECT_DISJUNTOS(xMin1,xMax1,yMin1,yMax1,xMin2,xMax2,yMin2,yMax2)))
+/******************************************************************************/
+/******************************************************************************/
+/** \enum GEOC_DPEUCKER_ROBUSTO
+\brief Aplicación o no del algoritmo robusto de aligerado de polilíneas.
+\date 10 de julio de 2011: Creación del tipo.
+\date 24 de mayo de 2011: Adición del la opción \em GeocDPeuckerOriginal.
+*/
+enum GEOC_DPEUCKER_ROBUSTO
+{
+ /** \brief Se usa el algoritmo original de Douglas-Peucker (no robusto). */
+ GeocDPeuckerOriginal=111,
+ /** \brief \b *NO* se realiza aligerado robusto (con mi algoritmo). */
+ GeocDPeuckerRobNo=112,
+ /** \brief \b *SÍ* se realiza aligerado robusto. */
+ GeocDPeuckerRobSi=113,
+ /** \brief Aligerado semi robusto con
+ \ref DouglasPeuckerRobIntersecOrigPlano y
+ \ref DouglasPeuckerRobIntersecOrigEsfera. */
+ GeocDPeuckerRobOrig=114,
+ /** \brief Aligerado semi robusto con
+ \ref DouglasPeuckerRobAutoIntersecPlano y
+ \ref DouglasPeuckerRobAutoIntersecEsfera. */
+ GeocDPeuckerRobAuto=115
+};
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Comprueba algunos casos especiales antes del aligerado de vértices de una
+ polilínea.
+\param[in] x Vector que contiene las coordenadas X o las longitudes de los
+ vértices de la polilínea de trabajo.
+\param[in] y Vector que contiene las coordenadas Y o las latitudes de los
+ vértices de la polilínea de trabajo.
+\param[in] nPtos Número de elementos de los vectores \em x e \em y.
+\param[in] incX Posiciones de separación entre los elementos del vector \em x.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] incY Posiciones de separación entre los elementos del vector \em y.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] tol Tolerancia para eliminar vértices. Este argumento sólo se tiene
+ internamente en cuenta si vale 0.0.
+\param[out] nPtosSal Número de puntos de la polilínea aligerada, si se ha
+ encontrado algún caso especial.
+\param[out] hayCasoEspecial Identificador de caso especial. Dos posibilidades:
+ - 0: No se ha encontrado ningún caso especial.
+ - Distinto de 0: Sí se ha encontrado algún caso especial.
+\return Vector de \em nPtosSal elementos que contiene los índices en los
+ vectores \em x e \em y de los vértices que formarán la polilínea
+ aligerada, en el caso de que se haya encontrado algún caso especial. Si
+ ocurre algún error de asignación de memoria se devuelve el valor
+ \p NULL. Este argumento sólo tiene sentido si se ha devuelto un valor de
+ \em hayCasoEspecial distinto de 0.
+\note Esta función no comprueba si el número de elementos de los vectores \em x
+ e \em y es congruente con el valor pasado en \em nPtos.
+\note Esta función asume que \em nPtos es mayor que 0. En caso contrario,
+ devuelve \p NULL, por lo que un valor de retorno igual a \p NULL sólo es
+ indicativo de error cuando \em nPtos es mayor que 0.
+\note Esta función comprueba los siguientes casos especiales:
+ - Si sólo hay un punto de entrada: En este caso, \em nPtosSal vale 1 y el
+ vector de salida contiene la posición de ese único punto.
+ - Si hay dos puntos de entrada, y estos son el mismo: En este caso,
+ \em nPtosSal vale 1 y el vector de salida contiene la posición
+ únicamente del primero de ellos.
+ - Si hay dos puntos de entrada, y estos son distintos: En este caso,
+ \em nPtosSal vale 2 y el vector de salida contiene la posición de los
+ dos puntos, aunque la distancia entre ellos sea menor que \em tol.
+ - Si hay tres puntos de entrada, y el primero es el mismo que el tercero:
+ En este caso, \em nPtosSal vale 2 y el vector de salida contiene la
+ posición de los dos primeros.
+ - En el caso en que el segundo punto también sea igual al primero,
+ \em nPtosSal vale 1 y el vector de salida contiene la posición
+ únicamente del primero.
+ - Si \em tol vale 0.0: En este caso, se eliminan los posibles puntos
+ repetidos en los vectores de coordenadas de entrada.
+\date 08 de agosto de 2013: Creación de la función.
+\todo Esta función todavía no está probada.
+*/
+size_t* CasosEspecialesAligeraPolilinea(const double* x,
+ const double* y,
+ const size_t nPtos,
+ const size_t incX,
+ const size_t incY,
+ const double tol,
+ size_t* nPtosSal,
+ int* hayCasoEspecial);
+/******************************************************************************/
+/******************************************************************************/
+#ifdef __cplusplus
+}
+#endif
+/******************************************************************************/
+/******************************************************************************/
+#endif
+/******************************************************************************/
+/******************************************************************************/
+/** @} */
+/******************************************************************************/
+/******************************************************************************/
+/* kate: encoding utf-8; end-of-line unix; syntax c; indent-mode cstyle; */
+/* kate: replace-tabs on; space-indent on; tab-indents off; indent-width 4; */
+/* kate: line-numbers on; folding-markers on; remove-trailing-space on; */
+/* kate: backspace-indents on; show-tabs on; */
+/* kate: word-wrap-column 80; word-wrap-marker-color #D2D2D2; word-wrap off; */
diff --git a/src/libgeoc/dpeuckere.h b/src/libgeoc/dpeuckere.h
new file mode 100644
index 0000000..46ead43
--- /dev/null
+++ b/src/libgeoc/dpeuckere.h
@@ -0,0 +1,1002 @@
+/* -*- coding: utf-8 -*- */
+/**
+\ingroup geom
+@{
+\file dpeuckere.h
+\brief Declaración de funciones auxiliares para el aligerado de polilíneas sobre
+ la superficie de la esfera, basadas en el algoritmo de Douglas-Peucker.
+\author José Luis García Pallero, jgpallero@gmail.com
+\note Este fichero contiene funciones paralelizadas con OpenMP.
+\date 15 de agosto de 2013
+\copyright
+Copyright (c) 2013-2014, José Luis García Pallero. All rights reserved.
+\par
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+\par
+- Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+- Neither the name of the copyright holders nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+\par
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/******************************************************************************/
+/******************************************************************************/
+#ifndef _DPEUCKERE_H_
+#define _DPEUCKERE_H_
+/******************************************************************************/
+/******************************************************************************/
+#if defined(_OPENMP)
+#include<omp.h>
+#endif
+#include<math.h>
+#include"libgeoc/constantes.h"
+#include"libgeoc/geocnan.h"
+#include"libgeoc/dpeuckera.h"
+#include"libgeoc/arco.h"
+#include"libgeoc/geocomp.h"
+/******************************************************************************/
+/******************************************************************************/
+#ifdef __cplusplus
+extern "C" {
+#endif
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Indica si hay alguna función compilada en paralelo con OpenMP en el
+ fichero \ref dpeuckerp.c.
+\return Dos posibles valores:
+ - 0: No hay ninguna función compilada en paralelo con OpenMP.
+ - Distinto de 0: Sí hay alguna función compilada en paralelo con OpenMP.
+\note Esta función asume que el argumento \em version tiene suficiente memoria
+ asignada (si es distinto de \p NULL).
+\date 17 de agosto de 2013: Creación de la función.
+\date 03 de abril de 2014: Particularización de la función sólo para la esfera.
+*/
+int GeocParOmpDpeuckere(char version[]);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Elimina vértices de una polilínea sobre la superficie de una esfera
+ mediante una modificación del algoritmo de Douglas-Peucker.
+\brief El algoritmo original, a partir del cual se ha hecho esta modificación,
+ está documentado en:
+
+\brief James E. Burt, 1989. Line Generalization on the Sphere. Geographical
+ Analysis 21 (1), 68-74.
+
+ También se utiliza una adaptación del criterio apuntado en:
+ Ebisch, K., October 2002. A correction to the Douglas–Peucker line
+ generalization algorithm. Computers and Geosciences 28 (8), 995–997.
+\param[in] x Vector que contiene las longitudes, en radianes, de los vértices de
+ la polilínea de trabajo.
+\param[in] y Vector que contiene las latitudes, en radianes, de los vértices de
+ la polilínea de trabajo.
+\param[in] nPtos Número de elementos de los vectores \em x e \em y.
+\param[in] incX Posiciones de separación entre los elementos del vector \em x.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] incY Posiciones de separación entre los elementos del vector \em y.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] tol Tolerancia para eliminar vértices: longitud de arco de círculo
+ máximo sobre la esfera de radio unidad.
+\param[in] posIni Posición en los vectores de coordenadas del punto inicial del
+ segmento base para añadir puntos a la línea simplificada.
+\param[in] posFin Posición en los vectores de coordenadas del punto final del
+ segmento base para añadir puntos a la línea simplificada.
+\param[out] usados Vector de \em nPtos elementos para indicar los puntos que
+ finalmente se usan en la polilínea simplificada. En la entrada,
+ todos sus elementos han de contener el valor 0, excepto las
+ posiciones \em 0 y \em nPtos-1, que han de contener el valor 1. En
+ la salida, las posiciones correspondientes a los puntos de la línea
+ inicial no utilizados almacenarán el valor \em 0, mientras que las
+ posiciones de los puntos utilizados almacenarán el valor \em 1.
+\note Esta función se puede ejecutar en paralelo con OpenMP.
+\note Esta función es recursiva.
+\note Esta función no comprueba si el número de elementos de los vectores \em x
+ e \em y es congruente con el valor pasado en \em nPtos.
+\note Esta función asume que los valores \em posIni y \em posFin son posiciones
+ válidas.
+\note Esta función asume que el vector \em usados contiene suficiente memoria
+ asignada.
+\date 21 de septiembre de 2013: Creación de la función.
+\todo Esta función todavía no está probada.
+*/
+void DouglasPeuckerOriginalEsfera(const double* x,
+ const double* y,
+ const size_t nPtos,
+ const size_t incX,
+ const size_t incY,
+ const double tol,
+ const size_t posIni,
+ const size_t posFin,
+ char* usados);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Elimina vértices de una polilínea sobre la superficie de la esfera
+ mediante un algoritmo no recursivo, inspirado en el de Douglas-Peucker.
+\brief Este algoritmo, comenzando por el primer punto de la polilínea, va
+ uniendo puntos en arcos de tal forma que se eliminan todos aquellos
+ puntos que queden a una distancia menor o igual a \em tol del arco de
+ trabajo. Así aplicado, pueden ocurrir casos singulares en los que la
+ polilínea aligerada tenga casos de auto intersección entre sus lados
+ resultantes. Para evitar esto, se puede aplicar la versión robusta del
+ algoritmo.
+\param[in] x Vector que contiene las longitudes, en radianes, de los vértices de
+ la polilínea de trabajo.
+\param[in] y Vector que contiene las latitudes, en radianes, de los vértices de
+ la polilínea de trabajo.
+\param[in] nPtos Número de elementos de los vectores \em x e \em y.
+\param[in] incX Posiciones de separación entre los elementos del vector \em x.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] incY Posiciones de separación entre los elementos del vector \em y.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] tol Tolerancia para eliminar vértices, como longitud de arco de
+ círculo máximo sobre la esfera de radio unidad.
+\param[in] paralelizaTol Identificador para evaluar o no en paralelo si los
+ puntos candidatos están en tolerancia. Dos posibilidades:
+ - 0: Se evalúa en serie (aunque la compilación se haya hecho en
+ paralelo) si los puntos están en tolerancia.
+ - Distinto de 0: Se evalúa en paralelo (sólo si se ha compilado en
+ paralelo) si los puntos están en tolerancia.
+\param[in] robusto Identificador para realizar o no un aligerado robusto. Ha de
+ ser un elemento del tipo enumerado #GEOC_DPEUCKER_ROBUSTO. Varias
+ posibilidades:
+ - #GeocDPeuckerOriginal: En este caso esta opción es equivalente a
+ pasar #GeocDPeuckerRobNo.
+ - #GeocDPeuckerRobNo: Utiliza la variación no recursiva del algoritmo
+ de Douglas-Peucker, que no es robusta.
+ - #GeocDPeuckerRobSi: Se aplica el algoritmo robusto completo, que
+ garantiza la no ocurrencia de auto intersecciones en la polilínea
+ resultante. Internamente, primero se aplica el tratamiento robusto
+ de la opción #GeocDPeuckerRobOrig y luego el de la opción
+ #GeocDPeuckerRobAuto.
+ - #GeocDPeuckerRobOrig: Se aplica un algoritmo semi robusto que
+ consiste en garantizar que los segmentos/arcos de la polilínea
+ aligerada que se van creando no intersectarán con ninguno de los
+ arcos que forman los vértices que quedan por procesar de la
+ polilínea original. En casos muy especiales, este algoritmo puede
+ seguir dando lugar a auto intersecciones.
+ - #GeocDPeuckerRobAuto: Se aplica un algoritmo semi robusto que
+ consiste en garantizar que los arcos de la polilínea aligerada que
+ se van creando no intersectarán con ninguno de los arcos de la
+ polilínea aligerada creados con anterioridad. En casos muy
+ especiales, este algoritmo puede seguir dando lugar a auto
+ intersecciones.
+\param[in] nSegRobOrig Número de arcos de la polilínea original a utilizar en el
+ caso de tratamiento robusto con las opciones #GeocDPeuckerRobSi o
+ #GeocDPeuckerRobOrig. Si se pasa el valor 0, se utilizan todos los
+ arcos hasta el final de la polilínea original.
+\param[in] nSegRobAuto Número de segmentos de la polilínea aligerada a utilizar
+ en el caso de tratamiento robusto con las opciones #GeocDPeuckerRobSi
+ o #GeocDPeuckerRobAuto. Si se pasa el valor 0, se utilizan todos los
+ arcos hasta el inicio de la polilínea aligerada.
+\param[out] nPtosSal Número de puntos de la polilínea aligerada.
+\return Vector de \em nPtosSal elementos que contiene los índices en los
+ vectores \em x e \em y de los vértices que formarán la polilínea
+ aligerada. Si ocurre algún error de asignación de memoria se devuelve el
+ valor \p NULL.
+\note Esta función no comprueba si el número de elementos de los vectores \em x
+ e \em y es congruente con el valor pasado en \em nPtos.
+\note Esta función asume que \em nPtos es mayor que 0. En caso contrario,
+ devuelve \p NULL, por lo que un valor de retorno igual a \p NULL sólo es
+ indicativo de error cuando \em nPtos es mayor que 0.
+\note Esta función comprueba los casos especiales con
+ \ref CasosEspecialesAligeraPolilinea.
+\note El argumento \em paralelizaTol \b SÓLO afecta a la paralelización de la
+ comprobación de puntos en tolerancia. Los chequeos de intersección de
+ segmentos/arcos siempre se hacen en paralelo (si el código ha sido
+ compilado al efecto).
+\date 07 de julio de 2011: Creación de la función.
+\date 10 de julio de 2011: Cambio del tipo del argumento \em robusto al tipo
+ enumerado #GEOC_DPEUCKER_ROBUSTO.
+\date 14 de mayo de 2012: Corregido bug que hacía que no se escogiese bien el
+ vértice a añadir a la polilínea aligerada.
+\date 25 de mayo de 2012: Cambio de nombre de la función.
+\date 17 de agosto de 2013: Comprobación de casos especiales y unificación de
+ las funciones de aligerado en el plano y en la esfera.
+\date 20 de agosto de 2013: Sustitución de las antiguas variables de entrada
+ \em nPtosRobusto y \em nSegRobusto por \em nSegRobOrig y \em nSegRobAuto.
+\date 23 de agosto de 2013: Adición del argumento de entrada \em paralelizaTol.
+\date 02 de abril de 2014: Particularización de la función sólo para la esfera.
+\todo Esta función todavía no está probada.
+*/
+size_t* DouglasPeuckerRobustoEsfera(const double* x,
+ const double* y,
+ const size_t nPtos,
+ const size_t incX,
+ const size_t incY,
+ const double tol,
+ const int paralelizaTol,
+ const enum GEOC_DPEUCKER_ROBUSTO robusto,
+ const size_t nSegRobOrig,
+ const size_t nSegRobAuto,
+ size_t* nPtosSal);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Comprueba, mediante una ejecución en paralelo, con OpenMP, si una serie
+ de puntos entre los extremos de un arco base están en tolerancia, según
+ el criterio de la familia de algoritmos de Douglas-Peucker.
+\param[in] x Vector que contiene las longitudes, en radianes, de los vértices de
+ la polilínea de trabajo.
+\param[in] y Vector que contiene las latitudes, en radianes, de los vértices de
+ la polilínea de trabajo.
+\param[in] incX Posiciones de separación entre los elementos del vector \em x.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] incY Posiciones de separación entre los elementos del vector \em y.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] xG Vector de las mismas dimensiones que \em x e \em y que contiene
+ las coordenadas X cartesianas geocéntricas con esfera de radio unidad
+ de los puntos de trabajo. Sus elementos han de estar situados de
+ forma contigua en memoria. Este argumento sólo se tiene en cuenta si
+ es distinto de \p NULL.
+\param[in] yG Vector de las mismas dimensiones que \em x e \em y que contiene
+ las coordenadas Y cartesianas geocéntricas con esfera de radio unidad
+ de los puntos de trabajo. Sus elementos han de estar situados de
+ forma contigua en memoria. Este argumento sólo se tiene en cuenta si
+ es distinto de \p NULL.
+\param[in] zG Vector de las mismas dimensiones que \em x e \em y que contiene
+ las coordenadas Z cartesianas geocéntricas con esfera de radio unidad
+ de los puntos de trabajo. Sus elementos han de estar situados de
+ forma contigua en memoria. Este argumento sólo se tiene en cuenta si
+ es distinto de \p NULL.
+\param[in] tol Tolerancia para eliminar vértices, como longitud de arco de
+ círculo máximo sobre la esfera de radio unidad.
+\param[in] posBaseIni Posición en los vectores \em x e \em y del punto inicial
+ del arco base.
+\param[in] posBaseFin Posición en los vectores \em x e \em y del punto final del
+ arco base.
+\param[in] posPtoIni Posición en los vectores \em x, \em y, \em xG, \em yG y
+ \em zG del punto inicial a partir del cual (incluido) se chequeará la
+ tolerancia.
+\param[in] posPtoFin Posición en los vectores \em x, \em y, \em xG, \em yG y
+ \em zG del punto inicial hasta el cual (incluido) se chequeará la
+ tolerancia.
+\param[in] lonFinR Longitud del punto final del arco base en el sistema rotado.
+\param[in] mRot Matriz de rotación aplicada a la base del triángulo para
+ llevarla al ecuador, con el punto inicial en
+ \f$(\varphi=0,\lambda=0)\f$. Este argumento ha de ser una matriz de
+ 3x3 almacenada en el formato de C.
+\return Identificador de que los puntos intermedios están o no en tolerancia.
+ Dos posibilidades:
+ - 0: Hay algún punto que se sale de tolerancia.
+ - Distinto de 0: Todos los puntos están en tolerancia.
+\note Esta función está paralelizada con OpenMP.
+\note Esta función no comprueba si las posiciones pasadas en \em posBaseIni,
+ \em posBaseFin, \em posPtoIni y \em posPtoFin son congruentes con el
+ número de elementos de los vectores \em x, \em y y, en su caso \em xG,
+ \em yG y \em zG.
+\note Esta función asume que
+ \em posBaseIni < \em posPtoIni <= \em posPtoFin < \em posBaseFin.
+\note Los argumentos \em xG, \em yG y \em zG sólo son tenidos en cuenta si los
+ tres son distintos de \p NULL.
+\date 18 de agosto de 2013: Creación de la función.
+\date 27 de marzo de 2014: Adición de los argumentos \em xG, \em yG y \em zG.
+\date 02 de abril de 2014: Particularización de la función sólo para la esfera.
+\todo Esta función todavía no está probada.
+*/
+int DouglasPeuckerPuntosEnTolEsferaOMP(const double* x,
+ const double* y,
+ const size_t incX,
+ const size_t incY,
+ const double* xG,
+ const double* yG,
+ const double* zG,
+ const double tol,
+ const size_t posBaseIni,
+ const size_t posBaseFin,
+ const size_t posPtoIni,
+ const size_t posPtoFin,
+ const double lonFinR,
+ double mRot[][3]);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Comprueba, mediante una ejecución en serie, si una serie de puntos entre
+ los extremos de un arco base están en tolerancia, según el criterio de la
+ familia de algoritmos de Douglas-Peucker.
+\param[in] x Vector que contiene las longitudes, en radianes, de los vértices de
+ la polilínea de trabajo.
+\param[in] y Vector que contiene las latitudes, en radianes, de los vértices de
+ la polilínea de trabajo.
+\param[in] incX Posiciones de separación entre los elementos del vector \em x.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] incY Posiciones de separación entre los elementos del vector \em y.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] xG Vector de las mismas dimensiones que \em x e \em y que contiene
+ las coordenadas X cartesianas geocéntricas con esfera de radio unidad
+ de los puntos de trabajo. Sus elementos han de estar situados de
+ forma contigua en memoria. Este argumento sólo se tiene en cuenta si
+ es distinto de \p NULL.
+\param[in] yG Vector de las mismas dimensiones que \em x e \em y que contiene
+ las coordenadas Y cartesianas geocéntricas con esfera de radio unidad
+ de los puntos de trabajo. Sus elementos han de estar situados de
+ forma contigua en memoria. Este argumento sólo se tiene en cuenta si
+ es distinto de \p NULL.
+\param[in] zG Vector de las mismas dimensiones que \em x e \em y que contiene
+ las coordenadas Z cartesianas geocéntricas con esfera de radio unidad
+ de los puntos de trabajo. Sus elementos han de estar situados de
+ forma contigua en memoria. Este argumento sólo se tiene en cuenta si
+ es distinto de \p NULL.
+\param[in] tol Tolerancia para eliminar vértices, como longitud de arco de
+ círculo máximo sobre la esfera de radio unidad.
+\param[in] posBaseIni Posición en los vectores \em x e \em y del punto inicial
+ del arco base.
+\param[in] posBaseFin Posición en los vectores \em x e \em y del punto final del
+ arco base.
+\param[in] posPtoIni Posición en los vectores \em x, \em y, \em xG, \em yG y
+ \em zG del punto inicial a partir del cual (incluido) se chequeará la
+ tolerancia.
+\param[in] posPtoFin Posición en los vectores \em x, \em y, \em xG, \em yG y
+ \em zG del punto inicial hasta el cual (incluido) se chequeará la
+ tolerancia.
+\param[in] lonFinR Longitud del punto final del arco base en el sistema rotado.
+\param[in] mRot Matriz de rotación aplicada a la base del triángulo para
+ llevarla al ecuador, con el punto inicial en
+ \f$(\varphi=0,\lambda=0)\f$. Este argumento ha de ser una matriz de
+ 3x3 almacenada en el formato de C.
+\return Identificador de que los puntos intermedios están o no en tolerancia.
+ Dos posibilidades:
+ - 0: Hay algún punto que se sale de tolerancia.
+ - Distinto de 0: Todos los puntos están en tolerancia.
+\note Esta función no comprueba si las posiciones pasadas en \em posBaseIni,
+ \em posBaseFin, \em posPtoIni y \em posPtoFin son congruentes con el
+ número de elementos de los vectores \em x, \em y y, en su caso \em xG,
+ \em yG y \em zG.
+\note Esta función asume que
+ \em posBaseIni < \em posPtoIni <= \em posPtoFin < \em posBaseFin.
+\note Los argumentos \em xG, \em yG y \em zG sólo son tenidos en cuenta si los
+ tres son distintos de \p NULL y se trabaja sobre la esfera.
+\date 18 de agosto de 2013: Creación de la función.
+\date 27 de marzo de 2014: Adición de los argumentos \em xG, \em yG y \em zG.
+\date 02 de abril de 2014: Particularización de la función sólo para la esfera.
+\todo Esta función todavía no está probada.
+*/
+int DouglasPeuckerPuntosEnTolEsferaSerie(const double* x,
+ const double* y,
+ const size_t incX,
+ const size_t incY,
+ const double* xG,
+ const double* yG,
+ const double* zG,
+ const double tol,
+ const size_t posBaseIni,
+ const size_t posBaseFin,
+ const size_t posPtoIni,
+ const size_t posPtoFin,
+ const double lonFinR,
+ double mRot[][3]);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Aproximación robusta al aligerado de líneas consistente en evitar que los
+ arcos creados intersecten con los de la polilínea original a partir del
+ punto de trabajo actual.
+\param[in] x Vector que contiene las longitudes, en radianes, de los vértices de
+ la polilínea de trabajo.
+\param[in] y Vector que contiene las latitudes, en radianes, de los vértices de
+ la polilínea de trabajo.
+\param[in] nPtos Número de elementos de los vectores \em x e \em y.
+\param[in] incX Posiciones de separación entre los elementos del vector \em x.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] incY Posiciones de separación entre los elementos del vector \em y.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] xG Vector de las mismas dimensiones que \em x e \em y que contiene
+ las coordenadas X cartesianas geocéntricas con esfera de radio unidad
+ de los puntos de trabajo. Sus elementos han de estar situados de
+ forma contigua en memoria. Este argumento sólo se tiene en cuenta si
+ es distinto de \p NULL.
+\param[in] yG Vector de las mismas dimensiones que \em x e \em y que contiene
+ las coordenadas Y cartesianas geocéntricas con esfera de radio unidad
+ de los puntos de trabajo. Sus elementos han de estar situados de
+ forma contigua en memoria. Este argumento sólo se tiene en cuenta si
+ es distinto de \p NULL.
+\param[in] zG Vector de las mismas dimensiones que \em x e \em y que contiene
+ las coordenadas Z cartesianas geocéntricas con esfera de radio unidad
+ de los puntos de trabajo. Sus elementos han de estar situados de
+ forma contigua en memoria. Este argumento sólo se tiene en cuenta si
+ es distinto de \p NULL.
+\param[in] segAUsar Número de arcos a utilizar de la polilínea original. Si se
+ pasa el valor 0 se utilizan todos los arcos que quedan desde el punto
+ de trabajo hasta el final.
+\param[in] posIni Posición inicial del arco a chequear.
+\param[in,out] posFin Posición final del arco a chequear. Al término de la
+ ejecución de la función almacena la posición del punto que hace
+ que el arco de la polilínea aligerada no intersecte con ninguno
+ de los que quedan de la polilínea original.
+\note Esta función no comprueba si el número de elementos de los vectores \em x,
+ \em y, \em xG, \em yG y \em zG, es congruente con el valor pasado en
+ \em nPtos.
+\note Esta función no comprueba si los índices pasados en los argumentos
+ \em posIni y \em posFin son congruentes con el tamaño de los vectores
+ pasado en \em nPtos.
+\note Los argumentos \em xG, \em yG y \em zG sólo son tenidos en cuenta si los
+ tres son distintos de \p NULL.
+\date 07 de julio de 2011: Creación de la función.
+\date 25 de mayo de 2012: Cambio de nombre de la función.
+\date 18 de agosto de 2013: Unificación para el uso sobre el plano y sobre la
+ esfera.
+\date 20 de agosto de 2013: Reorganización interna de la ejecución en serie y en
+ paralelo de la función.
+\date 27 de marzo de 2014: Adición de los argumentos \em xG, \em yG y \em zG.
+\date 02 de abril de 2014: Particularización de la función sólo para la esfera.
+\todo Esta función todavía no está probada.
+*/
+void DouglasPeuckerRobIntersecOrigEsfera(const double* x,
+ const double* y,
+ const size_t nPtos,
+ const size_t incX,
+ const size_t incY,
+ const double* xG,
+ const double* yG,
+ const double* zG,
+ const size_t segAUsar,
+ const size_t posIni,
+ size_t* posFin);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Comprueba, mediante una ejecución en paralelo con OpenMP, si una serie de
+ arcos se cortan con un arco base AB, a partir de éste en adelante.
+\param[in] xA Longitud, en radianes, del punto A.
+\param[in] yA Latitud, en radianes, del punto A.
+\param[in] xB Longitud, en radianes, del punto B.
+\param[in] yB Latitud, en radianes, del punto B.
+\param[in] x Vector que contiene las longitudes, en radianes, de los vértices de
+ la polilínea de trabajo.
+\param[in] y Vector que contiene las latitudes, en radianes, de los vértices de
+ la polilínea de trabajo.
+\param[in] incX Posiciones de separación entre los elementos del vector \em x.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] incY Posiciones de separación entre los elementos del vector \em y.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] xG Vector de las mismas dimensiones que \em x e \em y que contiene
+ las coordenadas X cartesianas geocéntricas con esfera de radio unidad
+ de los puntos de trabajo. Sus elementos han de estar situados de
+ forma contigua en memoria. Este argumento sólo se tiene en cuenta si
+ es distinto de \p NULL.
+\param[in] yG Vector de las mismas dimensiones que \em x e \em y que contiene
+ las coordenadas Y cartesianas geocéntricas con esfera de radio unidad
+ de los puntos de trabajo. Sus elementos han de estar situados de
+ forma contigua en memoria. Este argumento sólo se tiene en cuenta si
+ es distinto de \p NULL.
+\param[in] zG Vector de las mismas dimensiones que \em x e \em y que contiene
+ las coordenadas Z cartesianas geocéntricas con esfera de radio unidad
+ de los puntos de trabajo. Sus elementos han de estar situados de
+ forma contigua en memoria. Este argumento sólo se tiene en cuenta si
+ es distinto de \p NULL.
+\param[in] posIni Posición en los vectores \em x, \em y, \em xG, \em yG y \em zG
+ del punto inicial a partir del cual (incluido) se comenzarán a
+ chequear arcos.
+\param[in] posFin Posición en los vectores \em x, \em y, \em xG, \em yG y \em zG
+ del punto final hasta el cual (incluido) se chequearán arcos.
+\return Dos posibilidades:
+ - 0: No hay ninguna intersección entre AB y los arcos desde \em posIni
+ hasta \em posFin.
+ - Distinto de 0: Hay al menos una intersección entre AB y los arcos
+ desde \em posIni hasta \em posFin.
+\note Esta función está paralelizada con OpenMP.
+\note Esta función no comprueba si los argumentos \em posIni y \em posFin son
+ congruentes con las dimensiones de los vectores \em x \em y, \em xG,
+ \em yG y \em zG.
+\note Esta función asume que \em posIni<\em posFin.
+\note Los argumentos \em xG, \em yG y \em zG sólo son tenidos en cuenta si los
+ tres son distintos de \p NULL.
+\note Esta función utiliza internamente la función
+ \ref DouglasPeuckerRobIntersecEsfera, que no es robusta. En consecuencia,
+ los resultados de esta función tampoco lo son.
+\date 20 de agosto de 2013: Creación de la función.
+\date 27 de marzo de 2014: Adición de los argumentos \em xG, \em yG y \em zG.
+\date 02 de abril de 2014: Particularización de la función sólo para la esfera.
+\todo Esta función todavía no está probada.
+*/
+int DouglasPeuckerRobIntersecOrigEsferaOMP(const double xA,
+ const double yA,
+ const double xB,
+ const double yB,
+ const double* x,
+ const double* y,
+ const size_t incX,
+ const size_t incY,
+ const double* xG,
+ const double* yG,
+ const double* zG,
+ const size_t posIni,
+ const size_t posFin);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Comprueba, mediante una ejecución en serie, si una serie de arcos se
+ cortan con un arco base AB, a partir de éste en adelante.
+\param[in] xA Longitud, en radianes, del punto A.
+\param[in] yA Latitud, en radianes, del punto A.
+\param[in] xB Longitud, en radianes, del punto B.
+\param[in] yB Latitud, en radianes, del punto B.
+\param[in] x Vector que contiene las longitudes, en radianes, de los vértices de
+ la polilínea de trabajo.
+\param[in] y Vector que contiene las latitudes, en radianes, de los vértices de
+ la polilínea de trabajo.
+\param[in] incX Posiciones de separación entre los elementos del vector \em x.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] incY Posiciones de separación entre los elementos del vector \em y.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] xG Vector de las mismas dimensiones que \em x e \em y que contiene
+ las coordenadas X cartesianas geocéntricas con esfera de radio unidad
+ de los puntos de trabajo. Sus elementos han de estar situados de
+ forma contigua en memoria. Este argumento sólo se tiene en cuenta si
+ es distinto de \p NULL.
+\param[in] yG Vector de las mismas dimensiones que \em x e \em y que contiene
+ las coordenadas Y cartesianas geocéntricas con esfera de radio unidad
+ de los puntos de trabajo. Sus elementos han de estar situados de
+ forma contigua en memoria. Este argumento sólo se tiene en cuenta si
+ es distinto de \p NULL.
+\param[in] zG Vector de las mismas dimensiones que \em x e \em y que contiene
+ las coordenadas Z cartesianas geocéntricas con esfera de radio unidad
+ de los puntos de trabajo. Sus elementos han de estar situados de
+ forma contigua en memoria. Este argumento sólo se tiene en cuenta si
+ es distinto de \p NULL.
+\param[in] posIni Posición en los vectores \em x, \em y, \em xG, \em yG y \em zG
+ del punto inicial a partir del cual (incluido) se comenzarán a
+ chequear arcos.
+\param[in] posFin Posición en los vectores \em x, \em y, \em xG, \em yG y \em zG
+ del punto final hasta el cual (incluido) se chequearán arcos.
+\return Dos posibilidades:
+ - 0: No hay ninguna intersección entre AB y los arcos desde \em posIni
+ hasta \em posFin.
+ - Distinto de 0: Hay al menos una intersección entre AB y los arcos
+ desde \em posIni hasta \em posFin.
+\note Esta función no comprueba si los argumentos \em posIni y \em posFin son
+ congruentes con las dimensiones de los vectores \em x \em y, \em xG,
+ \em yG y \em zG.
+\note Esta función asume que \em posIni<\em posFin.
+\note Los argumentos \em xG, \em yG y \em zG sólo son tenidos en cuenta si los
+ tres son distintos de \p NULL.
+\note Esta función utiliza internamente la función
+ \ref DouglasPeuckerRobIntersecEsfera, que no es robusta. En consecuencia,
+ los resultados de esta función tampoco lo son.
+\date 20 de agosto de 2013: Creación de la función.
+\date 27 de marzo de 2014: Adición de los argumentos \em xG, \em yG y \em zG.
+\date 02 de abril de 2014: Particularización de la función sólo para la esfera.
+\todo Esta función todavía no está probada.
+*/
+int DouglasPeuckerRobIntersecOrigEsferaSerie(const double xA,
+ const double yA,
+ const double xB,
+ const double yB,
+ const double* x,
+ const double* y,
+ const size_t incX,
+ const size_t incY,
+ const double* xG,
+ const double* yG,
+ const double* zG,
+ const size_t posIni,
+ const size_t posFin);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Aproximación robusta al aligerado de líneas consistente en evitar que los
+ arcos creados intersecten con los anteriores de la polilínea aligerada.
+\param[in] x Vector que contiene las longitudes, en radianes, de los vértices de
+ la polilínea de trabajo.
+\param[in] y Vector que contiene las latitudes, en radianes, de los vértices de
+ la polilínea de trabajo.
+\param[in] incX Posiciones de separación entre los elementos del vector \em x.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] incY Posiciones de separación entre los elementos del vector \em y.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] xG Vector de las mismas dimensiones que \em x e \em y que contiene
+ las coordenadas X cartesianas geocéntricas con esfera de radio unidad
+ de los puntos de trabajo. Sus elementos han de estar situados de
+ forma contigua en memoria. Este argumento sólo se tiene en cuenta si
+ es distinto de \p NULL.
+\param[in] yG Vector de las mismas dimensiones que \em x e \em y que contiene
+ las coordenadas Y cartesianas geocéntricas con esfera de radio unidad
+ de los puntos de trabajo. Sus elementos han de estar situados de
+ forma contigua en memoria. Este argumento sólo se tiene en cuenta si
+ es distinto de \p NULL.
+\param[in] zG Vector de las mismas dimensiones que \em x e \em y que contiene
+ las coordenadas Z cartesianas geocéntricas con esfera de radio unidad
+ de los puntos de trabajo. Sus elementos han de estar situados de
+ forma contigua en memoria. Este argumento sólo se tiene en cuenta si
+ es distinto de \p NULL.
+\param[in] posIni Posición (en los vectores \em x e \em y) inicial del arco a
+ chequear.
+\param[in,out] posFin Posición (en los vectores \em x e \em y) final del arco a
+ chequear. Al término de la ejecución de la función almacena la
+ posición del punto que hace que el arco de la polilínea aligerada
+ no intersecte con ninguno de los anteriormente calculados.
+\param[in] posAlig Vector de posiciones de \em x e \em y utilizadas en la
+ polilínea aligerada.
+\param[in] nPosAlig Número de elementos de \em posAlig.
+\param[in] segAUsar Número de arcos a utilizar de la polilínea aligerada. Si se
+ pasa el valor 0 se utilizan todos los arcos anteriores.
+\note Esta función no comprueba si el número de elementos de los vectores \em x,
+ \em y, \em xG, \em yG y \em zG, es congruente con el valor pasado en
+ \em nPtos.
+\note Esta función no comprueba si los índices pasados en los argumentos
+ \em posIni y \em posFin son congruentes con el tamaño de los vectores
+ pasado en \em nPtos.
+\note Esta función no comprueba si los índices almacenados en \em posAlig son
+ congruentes con el tamaño de los vectores \em x e \em y.
+\note Esta función no comprueba si el valor pasado en \em nPosAlig es congruente
+ con el tamaño del vector \em posAlig.
+\note Los argumentos \em xG, \em yG y \em zG sólo son tenidos en cuenta si los
+ tres son distintos de \p NULL.
+\date 05 de julio de 2011: Creación de la función.
+\date 14 de mayo de 2012: Modificación del argumento \em nPosAlig para que
+ contenga el tamaño real del vector \em posAlig.
+\date 25 de mayo de 2012: Cambio de nombre de la función.
+\date 18 de agosto de 2013: Unificación para el uso sobre el plano y sobre la
+ esfera.
+\date 20 de agosto de 2013: Reorganización interna de la ejecución en serie y en
+ paralelo de la función.
+\date 27 de marzo de 2014: Adición de los argumentos \em xG, \em yG y \em zG.
+\date 02 de abril de 2014: Particularización de la función sólo para la esfera.
+\todo Esta función todavía no está probada.
+*/
+void DouglasPeuckerRobAutoIntersecEsfera(const double* x,
+ const double* y,
+ const size_t incX,
+ const size_t incY,
+ const double* xG,
+ const double* yG,
+ const double* zG,
+ const size_t posIni,
+ size_t* posFin,
+ const size_t* posAlig,
+ const size_t nPosAlig,
+ const size_t segAUsar);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Comprueba, mediante una ejecución en paralelo con OpenMP, si una serie de
+ arcos de la polilínea ya aligerada se cortan con un arco base AB, a
+ partir de éste hacia atrás.
+\param[in] xA Longitud, en radianes, del punto A.
+\param[in] yA Latitud, en radianes, del punto A.
+\param[in] xB Longitud, en radianes, del punto B.
+\param[in] yB Latitud, en radianes, del punto B.
+\param[in] x Vector que contiene las longitudes, en radianes, de los vértices de
+ la polilínea de trabajo.
+\param[in] y Vector que contiene las latitudes, en radianes, de los vértices de
+ la polilínea de trabajo.
+\param[in] incX Posiciones de separación entre los elementos del vector \em x.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] incY Posiciones de separación entre los elementos del vector \em y.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] xG Vector de las mismas dimensiones que \em x e \em y que contiene
+ las coordenadas X cartesianas geocéntricas con esfera de radio unidad
+ de los puntos de trabajo. Sus elementos han de estar situados de
+ forma contigua en memoria. Este argumento sólo se tiene en cuenta si
+ es distinto de \p NULL.
+\param[in] yG Vector de las mismas dimensiones que \em x e \em y que contiene
+ las coordenadas Y cartesianas geocéntricas con esfera de radio unidad
+ de los puntos de trabajo. Sus elementos han de estar situados de
+ forma contigua en memoria. Este argumento sólo se tiene en cuenta si
+ es distinto de \p NULL.
+\param[in] zG Vector de las mismas dimensiones que \em x e \em y que contiene
+ las coordenadas Z cartesianas geocéntricas con esfera de radio unidad
+ de los puntos de trabajo. Sus elementos han de estar situados de
+ forma contigua en memoria. Este argumento sólo se tiene en cuenta si
+ es distinto de \p NULL.
+\param[in] posAlig Vector de posiciones de \em x e \em y utilizadas en la
+ polilínea aligerada.
+\param[in] nPosAlig Número de elementos de \em posAlig.
+\param[in] posIni Posición en el vector \em posAlig del punto inicial a partir
+ del cual (incluido) se comenzarán a chequear arcos.
+\param[in] posFin Posición en el vector \em posAlig del punto final hasta el
+ cual (incluido) se chequearán arcos.
+\return Dos posibilidades:
+ - 0: No hay ninguna intersección entre AB y los arcos.
+ - Distinto de 0: Hay al menos una intersección entre AB y los arcos.
+\note Esta función está paralelizada con OpenMP.
+\note Esta función no comprueba si los índices almacenados en \em posAlig son
+ congruentes con las dimensiones de los vectores \em x \em y, \em xG,
+ \em yG y \em zG.
+\note Esta función no comprueba si los valores pasados en \em posIni, \em posFin
+ y \em nPosAlig son congruentes con el tamaño del vector \em posAlig.
+\note Esta función asume que \em posIni>\em posFin (ya que vamos hacia atrás).
+\note Los argumentos \em xG, \em yG y \em zG sólo son tenidos en cuenta si los
+ tres son distintos de \p NULL.
+\note Esta función utiliza internamente la función
+ \ref DouglasPeuckerRobIntersecEsfera, que no es robusta. En consecuencia,
+ los resultados de esta función tampoco lo son.
+\date 20 de agosto de 2013: Creación de la función.
+\date 02 de abril de 2014: Particularización de la función sólo para la esfera.
+\todo Esta función todavía no está probada.
+*/
+int DouglasPeuckerRobAutoIntersecEsferaOMP(const double xA,
+ const double yA,
+ const double xB,
+ const double yB,
+ const double* x,
+ const double* y,
+ const size_t incX,
+ const size_t incY,
+ const double* xG,
+ const double* yG,
+ const double* zG,
+ const size_t* posAlig,
+ const size_t nPosAlig,
+ const size_t posIni,
+ const size_t posFin);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Comprueba, mediante una ejecución en serie, si una serie de arcos de la
+ polilínea ya aligerada se cortan con un arco base AB, a partir de éste
+ hacia atrás.
+\param[in] xA Longitud, en radianes, del punto A.
+\param[in] yA Latitud, en radianes, del punto A.
+\param[in] xB Longitud, en radianes, del punto B.
+\param[in] yB Latitud, en radianes, del punto B.
+\param[in] x Vector que contiene las longitudes, en radianes, de los vértices de
+ la polilínea de trabajo.
+\param[in] y Vector que contiene las latitudes, en radianes, de los vértices de
+ la polilínea de trabajo.
+\param[in] incX Posiciones de separación entre los elementos del vector \em x.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] incY Posiciones de separación entre los elementos del vector \em y.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] xG Vector de las mismas dimensiones que \em x e \em y que contiene
+ las coordenadas X cartesianas geocéntricas con esfera de radio unidad
+ de los puntos de trabajo. Sus elementos han de estar situados de
+ forma contigua en memoria. Este argumento sólo se tiene en cuenta si
+ es distinto de \p NULL.
+\param[in] yG Vector de las mismas dimensiones que \em x e \em y que contiene
+ las coordenadas Y cartesianas geocéntricas con esfera de radio unidad
+ de los puntos de trabajo. Sus elementos han de estar situados de
+ forma contigua en memoria. Este argumento sólo se tiene en cuenta si
+ es distinto de \p NULL.
+\param[in] zG Vector de las mismas dimensiones que \em x e \em y que contiene
+ las coordenadas Z cartesianas geocéntricas con esfera de radio unidad
+ de los puntos de trabajo. Sus elementos han de estar situados de
+ forma contigua en memoria. Este argumento sólo se tiene en cuenta si
+ es distinto de \p NULL.
+\param[in] posAlig Vector de posiciones de \em x e \em y utilizadas en la
+ polilínea aligerada.
+\param[in] nPosAlig Número de elementos de \em posAlig.
+\param[in] posIni Posición en el vector \em posAlig del punto inicial a partir
+ del cual (incluido) se comenzarán a chequear arcos.
+\param[in] posFin Posición en el vector \em posAlig del punto final hasta el
+ cual (incluido) se chequearán arcos.
+\return Dos posibilidades:
+ - 0: No hay ninguna intersección entre AB y los arcos.
+ - Distinto de 0: Hay al menos una intersección entre AB y los arcos.
+\note Esta función no comprueba si los índices almacenados en \em posAlig son
+ congruentes con las dimensiones de los vectores \em x \em y, \em xG,
+ \em yG y \em zG.
+\note Esta función no comprueba si los valores pasados en \em posIni, \em posFin
+ y \em nPosAlig son congruentes con el tamaño del vector \em posAlig.
+\note Esta función asume que \em posIni>\em posFin (ya que vamos hacia atrás).
+\note Los argumentos \em xG, \em yG y \em zG sólo son tenidos en cuenta si los
+ tres son distintos de \p NULL.
+\note Esta función utiliza internamente la función
+ \ref DouglasPeuckerRobIntersecEsfera, que no es robusta. En consecuencia,
+ los resultados de esta función tampoco lo son.
+\date 20 de agosto de 2013: Creación de la función.
+\date 02 de abril de 2014: Particularización de la función sólo para la esfera.
+\todo Esta función todavía no está probada.
+*/
+int DouglasPeuckerRobAutoIntersecEsferaSerie(const double xA,
+ const double yA,
+ const double xB,
+ const double yB,
+ const double* x,
+ const double* y,
+ const size_t incX,
+ const size_t incY,
+ const double* xG,
+ const double* yG,
+ const double* zG,
+ const size_t* posAlig,
+ const size_t nPosAlig,
+ const size_t posIni,
+ const size_t posFin);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula la intersección de dos arcos AB y CD en la esfera. Se asume que
+ el arco AB está contenido en el ecuador, con el punto A de coordenadas
+ \f$(\varphi=0,\lambda=0)\f$.
+\param[in] xB Longitud, en radianes, del punto B.
+\param[in] xC Longitud, en radianes, del punto C.
+\param[in] yC Latitud, en radianes, del punto C.
+\param[in] xD Longitud, en radianes, del punto D.
+\param[in] yD Latitud, en radianes, del punto D.
+\param[in] xGC Coordenada X cartesiana geocéntrica para esfera de radio
+ unidad, en el sistema original, correspondiente al punto C. Este
+ argumento sólo se tiene en cuenta si es distinto del valor devuelto
+ por \ref GeocNan.
+\param[in] yGC Coordenada Y cartesiana geocéntrica para esfera de radio
+ unidad, en el sistema original, correspondiente al punto C. Este
+ argumento sólo se tiene en cuenta si es distinto del valor devuelto
+ por \ref GeocNan.
+\param[in] zGC Coordenada Z cartesiana geocéntrica para esfera de radio
+ unidad, en el sistema original, correspondiente al punto C. Este
+ argumento sólo se tiene en cuenta si es distinto del valor devuelto
+ por \ref GeocNan.
+\param[in] xGD Coordenada X cartesiana geocéntrica para esfera de radio
+ unidad, en el sistema original, correspondiente al punto C. Este
+ argumento sólo se tiene en cuenta si es distinto del valor devuelto
+ por \ref GeocNan.
+\param[in] yGD Coordenada Y cartesiana geocéntrica para esfera de radio
+ unidad, en el sistema original, correspondiente al punto C. Este
+ argumento sólo se tiene en cuenta si es distinto del valor devuelto
+ por \ref GeocNan.
+\param[in] zGD Coordenada Z cartesiana geocéntrica para esfera de radio
+ unidad, en el sistema original, correspondiente al punto C. Este
+ argumento sólo se tiene en cuenta si es distinto del valor devuelto
+ por \ref GeocNan.
+\param[in] posFinAB Posición del punto final del arco AB en los vectores
+ originales de coordenadas.
+\param[in] posIniCD Posición del punto inicial del arco CD en los vectores
+ originales de coordenadas.
+\return Dos posibilidades:
+ - 0: No hay intersección entre AB y CD.
+ - Distinto de 0: Sí hay intersección entre AB y CD.
+\note El dominio de las longitudes pasadas ha de ser \f$]-\pi,\pi]\f$.
+\note Los argumentos \em xGC, \em yGC, \em zGC, \em xGD, \em yGD y \em zGD sólo
+ son tenidos en cuenta si cada tríada es distinta de \ref GeocNan, en cuyo
+ caso las coordenadas cartesianas tridimensionales geocéntricas, necesarias
+ para los cálculos llevados a cabo por la función, son calculadas
+ internamente a partir de los argumentos \em xC, \em yC, \em xD e \em yD.
+\note Esta función utiliza internamente las funciones
+ \ref IntersecArcCircMaxEsferaAux, que no es robusta. En consecuencia, los
+ resultados de esta función tampoco lo son.
+\date 20 de agosto de 2013: Creación de la función.
+\date 28 de marzo de 2014: Adición de los argumentos \em xGC, \em yGC, \em zGC,
+ \em xGD, \em yGD y \em zGD.
+\date 02 de abril de 2014: Particularización de la función sólo para la esfera.
+\todo Esta función todavía no está probada.
+*/
+int DouglasPeuckerRobIntersecEsfera(const double xB,
+ const double xC,
+ const double yC,
+ const double xD,
+ const double yD,
+ const double xGC,
+ const double yGC,
+ const double zGC,
+ const double xGD,
+ const double yGD,
+ const double zGD,
+ const size_t posFinAB,
+ const size_t posIniCD);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula el seno en valor absoluto de la distancia sobre un círculo máximo
+ del punto más alejado de un conjunto de puntos candidatos a un arco de
+ círculo máximo para su uso en el aligerado de polilíneas mediante el
+ algoritmo de Douglas-Peucker.
+\brief Esta función trabaja en un sistema de referencia esférico tal que la base
+ del triángulo está situada en el ecuador, con su punto inicial el de
+ coordenadas \f$(\varphi=0,\lambda=0)\f$.
+\param[in] lat Vector que contiene las latitudes, en radianes, de los vértices
+ de la polilínea de trabajo.
+\param[in] lon Vector que contiene las longitudes, en radianes, de los vértices
+ de la polilínea de trabajo.
+\param[in] incLat Posiciones de separación entre los elementos del vector
+ \em lat. Este argumento siempre ha de ser un número positivo.
+\param[in] incLon Posiciones de separación entre los elementos del vector
+ \em lon. Este argumento siempre ha de ser un número positivo.
+\param[in] posIni Posición en los vectores de coordenadas del punto inicial del
+ segmento base.
+\param[in] posFin Posición en los vectores de coordenadas del punto final del
+ segmento base.
+\param[out] pos Posición en los vectores de coordenadas del punto situado entre
+ \em posIni y \em posFin más alejado de la línea base. Si \em posFin
+ es el punto inmediatamente posterior a \em posIni, esta variable
+ devuelve \em posIni.
+\return Seno en valor absoluto de la distancia angular sobre un círculo máximo
+ del punto más alejado a la línea base. Si \em posFin es el punto
+ inmediatamente posterior a \em posIni, se devuelve el valor -1.0.
+\note Esta función no comprueba si el número de elementos de los vectores
+ \em lat y \em lon es congruente con los valores pasados en \em posIni y
+ \em posFin.
+\note En el caso de que el arco \f$\alpha\f$ de trabajo sea mayor que
+ \f$\frac{\pi}{2}\f$, esta función devuelve el valor \f$1+\cos(\alpha)\f$,
+ en lugar del seno.
+\note Esta función puede devolver resultados erróneos si algún segmento base es
+ mayor o igual que \f$\pi\f$.
+\date 21 de septiembre de 2013: Creación de la función.
+\date 26 de marzo de 2014: La función ahora devuelve el valor absoluto del seno
+ de la distancia angular.
+\todo Esta función todavía no está probada.
+*/
+double DouglasPeuckerSenDistMaxEsfera(const double* lat,
+ const double* lon,
+ const size_t incLat,
+ const size_t incLon,
+ const size_t posIni,
+ const size_t posFin,
+ size_t* pos);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula el seno en valor absoluto de la distancia sobre un círculo máximo
+ de un punto a un arco para su uso en el aligerado de polilíneas mediante
+ mi modificación del algoritmo de Douglas-Peucker.
+\brief Esta función trabaja en un sistema de referencia esférico tal que la base
+ del triángulo está situada en el ecuador, con su punto inicial el de
+ coordenadas \f$(\varphi=0,\lambda=0)\f$.
+\param[in] latVert Latitud del punto de trabajo, en el sistema original, en
+ radianes.
+\param[in] lonVert Longitud del punto de trabajo, en el sistema original, en
+ radianes.
+\param[in] xVert Coordenada X cartesiana geocéntrica para esfera de radio
+ unidad, en el sistema original, correspondiente al punto de trabajo.
+ Este argumento sólo se tiene en cuenta si es distinto del valor
+ devuelto por \ref GeocNan.
+\param[in] yVert Coordenada Y cartesiana geocéntrica para esfera de radio
+ unidad, en el sistema original, correspondiente al punto de trabajo.
+ Este argumento sólo se tiene en cuenta si es distinto del valor
+ devuelto por \ref GeocNan.
+\param[in] zVert Coordenada Z cartesiana geocéntrica para esfera de radio
+ unidad, en el sistema original, correspondiente al punto de trabajo.
+ Este argumento sólo se tiene en cuenta si es distinto del valor
+ devuelto por \ref GeocNan.
+\param[in] lonBase2R Longiud del punto final de la base del triángulo, en el
+ sistema rotado, en radianes.
+\param[out] mRot Matriz de rotación aplicada a la base del triángulo para
+ llevarla al sistema descrito. Este argumento ha de ser una matriz de
+ 3x3 almacenada en el formato de C.
+\return Seno en valor absoluto de la distancia angular sobre un círculo máximo
+ del punto al arco base.
+\note En el caso de que el arco \f$\alpha\f$ de trabajo sea mayor que
+ \f$\frac{\pi}{2}\f$, esta función devuelve el valor \f$1+\cos(\alpha)\f$,
+ en lugar del seno.
+\note Ninguno de los lados ni ángulos del triángulo puede ser mayor de
+ \f$\pi\f$, hecho que no se comprueba internamente.
+\note Los argumentos \em xVert, \em yVert y \em zVert sólo son tenidos en cuenta
+ si los tres son distintos de \ref GeocNan, en cuyo caso las coordenadas
+ cartesianas tridimensionales geocéntricas, necesarias para los cálculos
+ llevados a cabo por la función, son calculadas internamente a partir de
+ los argumentos \em latVert y \em lonVert.
+\date 15 de agosto de 2013: Creación de la función.
+\date 26 de marzo de 2014: La función ahora devuelve el valor absoluto del seno
+ de la distancia angular.
+\todo Esta función todavía no está probada.
+*/
+double DouglasPeuckerSenDistMaxEsferaAux(const double latVert,
+ const double lonVert,
+ const double xVert,
+ const double yVert,
+ const double zVert,
+ const double lonBase2R,
+ double mRot[][3]);
+/******************************************************************************/
+/******************************************************************************/
+#ifdef __cplusplus
+}
+#endif
+/******************************************************************************/
+/******************************************************************************/
+#endif
+/******************************************************************************/
+/******************************************************************************/
+/** @} */
+/******************************************************************************/
+/******************************************************************************/
+/* kate: encoding utf-8; end-of-line unix; syntax c; indent-mode cstyle; */
+/* kate: replace-tabs on; space-indent on; tab-indents off; indent-width 4; */
+/* kate: line-numbers on; folding-markers on; remove-trailing-space on; */
+/* kate: backspace-indents on; show-tabs on; */
+/* kate: word-wrap-column 80; word-wrap-marker-color #D2D2D2; word-wrap off; */
diff --git a/src/libgeoc/dpeuckerp.h b/src/libgeoc/dpeuckerp.h
new file mode 100644
index 0000000..d43e31e
--- /dev/null
+++ b/src/libgeoc/dpeuckerp.h
@@ -0,0 +1,774 @@
+/* -*- coding: utf-8 -*- */
+/**
+\ingroup geom
+@{
+\file dpeuckerp.h
+\brief Declaración de funciones para el aligerado de polilíneas en el plano
+ basadas en el algoritmo de Douglas-Peucker.
+\author José Luis García Pallero, jgpallero@gmail.com
+\note Este fichero contiene funciones paralelizadas con OpenMP.
+\date 04 de julio de 2011
+\copyright
+Copyright (c) 2011-2014, José Luis García Pallero. All rights reserved.
+\par
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+\par
+- Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+- Neither the name of the copyright holders nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+\par
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/******************************************************************************/
+/******************************************************************************/
+#ifndef _DPEUCKERP_H_
+#define _DPEUCKERP_H_
+/******************************************************************************/
+/******************************************************************************/
+#if defined(_OPENMP)
+#include<omp.h>
+#endif
+#include<stdlib.h>
+#include<math.h>
+#include"libgeoc/dpeuckera.h"
+#include"libgeoc/segmento.h"
+#include"libgeoc/geocomp.h"
+/******************************************************************************/
+/******************************************************************************/
+#ifdef __cplusplus
+extern "C" {
+#endif
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Indica si hay alguna función compilada en paralelo con OpenMP en el
+ fichero \ref dpeuckerp.c.
+\return Dos posibles valores:
+ - 0: No hay ninguna función compilada en paralelo con OpenMP.
+ - Distinto de 0: Sí hay alguna función compilada en paralelo con OpenMP.
+\note Esta función asume que el argumento \em version tiene suficiente memoria
+ asignada (si es distinto de \p NULL).
+\date 17 de agosto de 2013: Creación de la función.
+\date 03 de abril de 2014: Particularización de la función sólo para el plano.
+*/
+int GeocParOmpDpeuckerp(char version[]);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Elimina vértices de una polilínea en el plano mediante el algoritmo de
+ Douglas-Peucker.
+\brief El algoritmo original está documentado en:
+
+\brief Douglas, D. H., Peucker, T. K., 1973. Algorithms for the reduction of the
+ number of points required to represent a digitized line or its
+ caricature. The Canadian Cartographer 10 (2), 112–122.
+
+ También se utiliza el criterio apuntado en:
+ Ebisch, K., October 2002. A correction to the Douglas–Peucker line
+ generalization algorithm. Computers and Geosciences 28 (8), 995–997.
+\param[in] x Vector que contiene las coordenadas X de los vértices de la
+ polilínea de trabajo.
+\param[in] y Vector que contiene las coordenadas Y de los vértices de la
+ polilínea de trabajo.
+\param[in] nPtos Número de elementos de los vectores \em x e \em y.
+\param[in] incX Posiciones de separación entre los elementos del vector \em x.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] incY Posiciones de separación entre los elementos del vector \em y.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] tol Tolerancia para eliminar vértices, en las mismas unidades que las
+ coordenadas de los vértices.
+\param[in] posIni Posición en los vectores de coordenadas del punto inicial del
+ segmento base para añadir puntos a la línea simplificada.
+\param[in] posFin Posición en los vectores de coordenadas del punto final del
+ segmento base para añadir puntos a la línea simplificada.
+\param[out] usados Vector de \em nPtos elementos para indicar los puntos que
+ finalmente se usan en la polilínea simplificada. En la entrada,
+ todos sus elementos han de contener el valor 0, excepto las
+ posiciones \em 0 y \em nPtos-1, que han de contener el valor 1. En
+ la salida, las posiciones correspondientes a los puntos de la línea
+ inicial no utilizados almacenarán el valor \em 0, mientras que las
+ posiciones de los puntos utilizados almacenarán el valor \em 1.
+\note Esta función se puede ejecutar en paralelo con OpenMP.
+\note Esta función es recursiva.
+\note Esta función no comprueba si el número de elementos de los vectores \em x
+ e \em y es congruente con el valor pasado en \em nPtos.
+\note Esta función asume que los valores \em posIni y \em posFin son posiciones
+ válidas.
+\note Esta función asume que el vector \em usados contiene suficiente memoria
+ asignada.
+\date 25 de mayo de 2012: Creación de la función.
+\todo Esta función todavía no está probada.
+*/
+void DouglasPeuckerOriginalPlano(const double* x,
+ const double* y,
+ const size_t nPtos,
+ const size_t incX,
+ const size_t incY,
+ const double tol,
+ const size_t posIni,
+ const size_t posFin,
+ char* usados);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Elimina vértices de una polilínea en el plano mediante un algoritmo no
+ recursivo, inspirado en el de Douglas-Peucker.
+\brief Este algoritmo, comenzando por el primer punto de la polilínea, va
+ uniendo puntos en segmentos de tal forma que se eliminan todos aquellos
+ puntos que queden a una distancia menor o igual a \em tol del segmento
+ de trabajo. Así aplicado, pueden ocurrir casos singulares en los que la
+ polilínea aligerada tenga casos de auto intersección entre sus lados
+ resultantes. Para evitar esto, se puede aplicar la versión robusta del
+ algoritmo.
+\param[in] x Vector que contiene las coordenadas X de los vértices de la
+ polilínea de trabajo.
+\param[in] y Vector que contiene las coordenadas Y de los vértices de la
+ polilínea de trabajo.
+\param[in] nPtos Número de elementos de los vectores \em x e \em y.
+\param[in] incX Posiciones de separación entre los elementos del vector \em x.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] incY Posiciones de separación entre los elementos del vector \em y.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] tol Tolerancia para eliminar vértices, en las mismas unidades que las
+ coordenadas de éstos.
+\param[in] paralelizaTol Identificador para evaluar o no en paralelo si los
+ puntos candidatos están en tolerancia. Dos posibilidades:
+ - 0: Se evalúa en serie (aunque la compilación se haya hecho en
+ paralelo) si los puntos están en tolerancia.
+ - Distinto de 0: Se evalúa en paralelo (sólo si se ha compilado en
+ paralelo) si los puntos están en tolerancia.
+\param[in] robusto Identificador para realizar o no un aligerado robusto. Ha de
+ ser un elemento del tipo enumerado #GEOC_DPEUCKER_ROBUSTO. Varias
+ posibilidades:
+ - #GeocDPeuckerOriginal: En este caso esta opción es equivalente a
+ pasar #GeocDPeuckerRobNo.
+ - #GeocDPeuckerRobNo: Utiliza la variación no recursiva del algoritmo
+ de Douglas-Peucker, que no es robusta.
+ - #GeocDPeuckerRobSi: Se aplica el algoritmo robusto completo, que
+ garantiza la no ocurrencia de auto intersecciones en la polilínea
+ resultante. Internamente, primero se aplica el tratamiento robusto
+ de la opción #GeocDPeuckerRobOrig y luego el de la opción
+ #GeocDPeuckerRobAuto.
+ - #GeocDPeuckerRobOrig: Se aplica un algoritmo semi robusto que
+ consiste en garantizar que los segmentos de la polilínea aligerada
+ que se van creando no intersectarán con ninguno de los segmentos
+ que forman los vértices que quedan por procesar de la polilínea
+ original. En casos muy especiales, este algoritmo puede seguir
+ dando lugar a auto intersecciones.
+ - #GeocDPeuckerRobAuto: Se aplica un algoritmo semi robusto que
+ consiste en garantizar que los segmentos de la polilínea aligerada
+ que se van creando no intersectarán con ninguno de los segmentos
+ de la polilínea aligerada creados con anterioridad. En casos muy
+ especiales, este algoritmo puede seguir dando lugar a auto
+ intersecciones.
+\param[in] nSegRobOrig Número de segmentos de la polilínea original a utilizar
+ en el caso de tratamiento robusto con las opciones #GeocDPeuckerRobSi
+ o #GeocDPeuckerRobOrig. Si se pasa el valor 0, se utilizan todos los
+ segmentos hasta el final de la polilínea original.
+\param[in] nSegRobAuto Número de segmentos de la polilínea aligerada a utilizar
+ en el caso de tratamiento robusto con las opciones #GeocDPeuckerRobSi
+ o #GeocDPeuckerRobAuto. Si se pasa el valor 0, se utilizan todos los
+ segmentos hasta el inicio de la polilínea aligerada.
+\param[out] nPtosSal Número de puntos de la polilínea aligerada.
+\return Vector de \em nPtosSal elementos que contiene los índices en los
+ vectores \em x e \em y de los vértices que formarán la polilínea
+ aligerada. Si ocurre algún error de asignación de memoria se devuelve el
+ valor \p NULL.
+\note Esta función no comprueba si el número de elementos de los vectores \em x
+ e \em y es congruente con el valor pasado en \em nPtos.
+\note Esta función asume que \em nPtos es mayor que 0. En caso contrario,
+ devuelve \p NULL, por lo que un valor de retorno igual a \p NULL sólo es
+ indicativo de error cuando \em nPtos es mayor que 0.
+\note Esta función comprueba los casos especiales con
+ \ref CasosEspecialesAligeraPolilinea.
+\note El argumento \em paralelizaTol \b SÓLO afecta a la paralelización de la
+ comprobación de puntos en tolerancia. Los chequeos de intersección de
+ segmentos/arcos siempre se hacen en paralelo (si el código ha sido
+ compilado al efecto).
+\date 07 de julio de 2011: Creación de la función.
+\date 10 de julio de 2011: Cambio del tipo del argumento \em robusto al tipo
+ enumerado #GEOC_DPEUCKER_ROBUSTO.
+\date 14 de mayo de 2012: Corregido bug que hacía que no se escogiese bien el
+ vértice a añadir a la polilínea aligerada.
+\date 25 de mayo de 2012: Cambio de nombre de la función.
+\date 17 de agosto de 2013: Comprobación de casos especiales y unificación de
+ las funciones de aligerado en el plano y en la esfera.
+\date 20 de agosto de 2013: Sustitución de las antiguas variables de entrada
+ \em nPtosRobusto y \em nSegRobusto por \em nSegRobOrig y \em nSegRobAuto.
+\date 23 de agosto de 2013: Adición del argumento de entrada \em paralelizaTol.
+\date 01 de abril de 2014: Particularización de la función sólo para el plano.
+\todo Esta función todavía no está probada.
+*/
+size_t* DouglasPeuckerRobustoPlano(const double* x,
+ const double* y,
+ const size_t nPtos,
+ const size_t incX,
+ const size_t incY,
+ const double tol,
+ const int paralelizaTol,
+ const enum GEOC_DPEUCKER_ROBUSTO robusto,
+ const size_t nSegRobOrig,
+ const size_t nSegRobAuto,
+ size_t* nPtosSal);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Comprueba, mediante una ejecución en paralelo, con OpenMP, si una serie
+ de puntos entre los extremos de un segmento base están en tolerancia,
+ según el criterio de la familia de algoritmos de Douglas-Peucker.
+\param[in] x Vector que contiene las coordenadas X de los vértices de la
+ polilínea de trabajo.
+\param[in] y Vector que contiene las coordenadas Y de los vértices de la
+ polilínea de trabajo.
+\param[in] incX Posiciones de separación entre los elementos del vector \em x.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] incY Posiciones de separación entre los elementos del vector \em y.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] tol Tolerancia para eliminar vértices, en las mismas unidades que las
+ coordenadas de éstos.
+\param[in] posBaseIni Posición en los vectores \em x e \em y del punto inicial
+ del segmento base.
+\param[in] posBaseFin Posición en los vectores \em x e \em y del punto final del
+ segmento base.
+\param[in] posPtoIni Posición en los vectores \em x e \em y del punto inicial a
+ partir del cual (incluido) se chequeará la tolerancia.
+\param[in] posPtoFin Posición en los vectores \em x e \em y del punto inicial
+ hasta el cual (incluido) se chequeará la tolerancia.
+\return Identificador de que los puntos intermedios están o no en tolerancia.
+ Dos posibilidades:
+ - 0: Hay algún punto que se sale de tolerancia.
+ - Distinto de 0: Todos los puntos están en tolerancia.
+\note Esta función está paralelizada con OpenMP.
+\note Esta función no comprueba si las posiciones pasadas en \em posBaseIni,
+ \em posBaseFin, \em posPtoIni y \em posPtoFin son congruentes con el
+ número de elementos de los vectores \em x e \em y.
+\note Esta función asume que
+ \em posBaseIni < \em posPtoIni <= \em posPtoFin < \em posBaseFin.
+\date 18 de agosto de 2013: Creación de la función.
+\date 27 de marzo de 2014: Adición de los argumentos \em xG, \em yG y \em zG.
+\date 01 de abril de 2014: Particularización de la función sólo para el plano.
+\todo Esta función todavía no está probada.
+*/
+int DouglasPeuckerPuntosEnTolPlanoOMP(const double* x,
+ const double* y,
+ const size_t incX,
+ const size_t incY,
+ const double tol,
+ const size_t posBaseIni,
+ const size_t posBaseFin,
+ const size_t posPtoIni,
+ const size_t posPtoFin);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Comprueba, mediante una ejecución en serie, si una serie de puntos entre
+ los extremos de un segmento base están en tolerancia, según el criterio
+ de la familia de algoritmos de Douglas-Peucker.
+\param[in] x Vector que contiene las coordenadas X de los vértices de la
+ polilínea de trabajo.
+\param[in] y Vector que contiene las coordenadas Y de los vértices de la
+ polilínea de trabajo.
+\param[in] incX Posiciones de separación entre los elementos del vector \em x.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] incY Posiciones de separación entre los elementos del vector \em y.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] tol Tolerancia para eliminar vértices, en las mismas unidades que las
+ coordenadas de éstos.
+\param[in] posBaseIni Posición en los vectores \em x e \em y del punto inicial
+ del segmento/arco base.
+\param[in] posBaseFin Posición en los vectores \em x e \em y del punto final del
+ segmento/arco base.
+\param[in] posPtoIni Posición en los vectores \em x e \em y del punto inicial a
+ partir del cual (incluido) se chequeará la tolerancia.
+\param[in] posPtoFin Posición en los vectores \em x e \em y del punto inicial
+ hasta el cual (incluido) se chequeará la tolerancia.
+\return Identificador de que los puntos intermedios están o no en tolerancia.
+ Dos posibilidades:
+ - 0: Hay algún punto que se sale de tolerancia.
+ - Distinto de 0: Todos los puntos están en tolerancia.
+\note Esta función no comprueba si las posiciones pasadas en \em posBaseIni,
+ \em posBaseFin, \em posPtoIni y \em posPtoFin son congruentes con el
+ número de elementos de los vectores \em x e \em y.
+\note Esta función asume que
+ \em posBaseIni < \em posPtoIni <= \em posPtoFin < \em posBaseFin.
+\date 18 de agosto de 2013: Creación de la función.
+\date 27 de marzo de 2014: Adición de los argumentos \em xG, \em yG y \em zG.
+\date 01 de abril de 2014: Particularización de la función sólo para el plano.
+\todo Esta función todavía no está probada.
+*/
+int DouglasPeuckerPuntosEnTolPlanoSerie(const double* x,
+ const double* y,
+ const size_t incX,
+ const size_t incY,
+ const double tol,
+ const size_t posBaseIni,
+ const size_t posBaseFin,
+ const size_t posPtoIni,
+ const size_t posPtoFin);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Aproximación robusta al aligerado de líneas consistente en evitar que los
+ segmentos creados intersecten con los de la polilínea original a partir
+ del punto de trabajo actual.
+\param[in] x Vector que contiene las coordenadas X de los vértices de la
+ polilínea de trabajo.
+\param[in] y Vector que contiene las coordenadas Y de los vértices de la
+ polilínea de trabajo.
+\param[in] nPtos Número de elementos de los vectores \em x e \em y.
+\param[in] incX Posiciones de separación entre los elementos del vector \em x.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] incY Posiciones de separación entre los elementos del vector \em y.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] segAUsar Número de segmentos a utilizar de la polilínea original. Si
+ se pasa el valor 0 se utilizan todos los segmentos que quedan desde
+ el punto de trabajo hasta el final.
+\param[in] posIni Posición inicial del segmento a chequear.
+\param[in,out] posFin Posición final del segmento a chequear. Al término de la
+ ejecución de la función almacena la posición del punto que hace
+ que el segmento de la polilínea aligerada no intersecte con
+ ninguno de los que quedan de la polilínea original.
+\note Esta función no comprueba si el número de elementos de los vectores \em x
+ e \em y es congruente con el valor pasado en \em nPtos.
+\note Esta función no comprueba si los índices pasados en los argumentos
+ \em posIni y \em posFin son congruentes con el tamaño de los vectores
+ pasado en \em nPtos.
+\date 07 de julio de 2011: Creación de la función.
+\date 25 de mayo de 2012: Cambio de nombre de la función.
+\date 18 de agosto de 2013: Unificación para el uso sobre el plano y sobre la
+ esfera.
+\date 20 de agosto de 2013: Reorganización interna de la ejecución en serie y en
+ paralelo de la función.
+\date 27 de marzo de 2014: Adición de los argumentos \em xG, \em yG y \em zG.
+\date 01 de abril de 2014: Particularización de la función sólo para el plano.
+\todo Esta función todavía no está probada.
+*/
+void DouglasPeuckerRobIntersecOrigPlano(const double* x,
+ const double* y,
+ const size_t nPtos,
+ const size_t incX,
+ const size_t incY,
+ const size_t segAUsar,
+ const size_t posIni,
+ size_t* posFin);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Comprueba, mediante una ejecución en paralelo con OpenMP, si una serie de
+ segmentos se cortan con un segmento/arco base AB, a partir de éste en
+ adelante.
+\param[in] xA Coordenada X del punto A.
+\param[in] yA Coordenada Y del punto A.
+\param[in] xB Coordenada X del punto B.
+\param[in] yB Coordenada Y del punto B.
+\param[in] x Vector que contiene las coordenadas X de los vértices de la
+ polilínea de trabajo.
+\param[in] y Vector que contiene las coordenadas Y de los vértices de la
+ polilínea de trabajo.
+\param[in] incX Posiciones de separación entre los elementos del vector \em x.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] incY Posiciones de separación entre los elementos del vector \em y.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] posIni Posición en los vectores \em x e \em y del punto inicial a
+ partir del cual (incluido) se comenzarán a chequear segmentos.
+\param[in] posFin Posición en los vectores \em x e \em y del punto final hasta
+ el cual (incluido) se chequearán segmentos.
+\return Dos posibilidades:
+ - 0: No hay ninguna intersección entre AB y los segmentos desde
+ \em posIni hasta \em posFin.
+ - Distinto de 0: Hay al menos una intersección entre AB y los segmentos
+ desde \em posIni hasta \em posFin.
+\note Esta función está paralelizada con OpenMP.
+\note Esta función no comprueba si los argumentos \em posIni y \em posFin son
+ congruentes con las dimensiones de los vectores \em x e \em y.
+\note Esta función asume que \em posIni<\em posFin.
+\note Esta función utiliza internamente la función
+ \ref DouglasPeuckerRobIntersecPlano, que no es robusta. En consecuencia,
+ los resultados de esta función tampoco lo son.
+\date 20 de agosto de 2013: Creación de la función.
+\date 27 de marzo de 2014: Adición de los argumentos \em xG, \em yG y \em zG.
+\date 01 de abril de 2014: Particularización de la función sólo para el plano.
+\todo Esta función todavía no está probada.
+*/
+int DouglasPeuckerRobIntersecOrigPlanoOMP(const double xA,
+ const double yA,
+ const double xB,
+ const double yB,
+ const double* x,
+ const double* y,
+ const size_t incX,
+ const size_t incY,
+ const size_t posIni,
+ const size_t posFin);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Comprueba, mediante una ejecución en serie, si una serie de segmentos
+ se cortan con un segmento base AB, a partir de éste en adelante.
+\param[in] xA Coordenada X del punto A.
+\param[in] yA Coordenada Y del punto A.
+\param[in] xB Coordenada X del punto B.
+\param[in] yB Coordenada Y del punto B.
+\param[in] x Vector que contiene las coordenadas X de los vértices de la
+ polilínea de trabajo.
+\param[in] y Vector que contiene las coordenadas Y de los vértices de la
+ polilínea de trabajo.
+\param[in] incX Posiciones de separación entre los elementos del vector \em x.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] incY Posiciones de separación entre los elementos del vector \em y.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] posIni Posición en los vectores \em x e \em y del punto inicial a
+ partir del cual (incluido) se comenzarán a chequear segmentos.
+\param[in] posFin Posición en los vectores \em x e \em y del punto final hasta
+ el cual (incluido) se chequearán segmentos.
+\return Dos posibilidades:
+ - 0: No hay ninguna intersección entre AB y los segmentos desde
+ \em posIni hasta \em posFin.
+ - Distinto de 0: Hay al menos una intersección entre AB y los segmentos
+ desde \em posIni hasta \em posFin.
+\note Esta función no comprueba si los argumentos \em posIni y \em posFin son
+ congruentes con las dimensiones de los vectores \em x e \em y.
+\note Esta función asume que \em posIni<\em posFin.
+\note Esta función utiliza internamente la función
+ \ref DouglasPeuckerRobIntersecPlano, que no es robusta. En consecuencia,
+ los resultados de esta función tampoco lo son.
+\date 20 de agosto de 2013: Creación de la función.
+\date 27 de marzo de 2014: Adición de los argumentos \em xG, \em yG y \em zG.
+\date 01 de abril de 2014: Particularización de la función sólo para el plano.
+\todo Esta función todavía no está probada.
+*/
+int DouglasPeuckerRobIntersecOrigPlanoSerie(const double xA,
+ const double yA,
+ const double xB,
+ const double yB,
+ const double* x,
+ const double* y,
+ const size_t incX,
+ const size_t incY,
+ const size_t posIni,
+ const size_t posFin);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Aproximación robusta al aligerado de líneas consistente en evitar que los
+ segmentos creados intersecten con los anteriores de la polilínea
+ aligerada.
+\param[in] x Vector que contiene las coordenadas X de los vértices de la
+ polilínea de trabajo.
+\param[in] y Vector que contiene las coordenadas Y de los vértices de la
+ polilínea de trabajo.
+\param[in] incX Posiciones de separación entre los elementos del vector \em x.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] incY Posiciones de separación entre los elementos del vector \em y.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] posIni Posición (en los vectores \em x e \em y) inicial del
+ segmento a chequear.
+\param[in,out] posFin Posición (en los vectores \em x e \em y) final del
+ segmento a chequear. Al término de la ejecución de la función
+ almacena la posición del punto que hace que el segmento de la
+ polilínea aligerada no intersecte con ninguno de los
+ anteriormente calculados.
+\param[in] posAlig Vector de posiciones de \em x e \em y utilizadas en la
+ polilínea aligerada.
+\param[in] nPosAlig Número de elementos de \em posAlig.
+\param[in] segAUsar Número de segmentos a utilizar de la polilínea aligerada. Si
+ se pasa el valor 0 se utilizan todos los segmentos anteriores.
+\note Esta función no comprueba si el número de elementos de los vectores \em x
+ e \em y.
+\note Esta función no comprueba si los índices pasados en los argumentos
+ \em posIni y \em posFin son congruentes con el tamaño de los vectores
+ pasado en \em nPtos.
+\note Esta función no comprueba si los índices almacenados en \em posAlig son
+ congruentes con el tamaño de los vectores \em x e \em y.
+\note Esta función no comprueba si el valor pasado en \em nPosAlig es congruente
+ con el tamaño del vector \em posAlig.
+\date 05 de julio de 2011: Creación de la función.
+\date 14 de mayo de 2012: Modificación del argumento \em nPosAlig para que
+ contenga el tamaño real del vector \em posAlig.
+\date 25 de mayo de 2012: Cambio de nombre de la función.
+\date 18 de agosto de 2013: Unificación para el uso sobre el plano y sobre la
+ esfera.
+\date 20 de agosto de 2013: Reorganización interna de la ejecución en serie y en
+ paralelo de la función.
+\date 27 de marzo de 2014: Adición de los argumentos \em xG, \em yG y \em zG.
+\date 01 de abril de 2014: Particularización de la función sólo para el plano.
+\todo Esta función todavía no está probada.
+*/
+void DouglasPeuckerRobAutoIntersecPlano(const double* x,
+ const double* y,
+ const size_t incX,
+ const size_t incY,
+ const size_t posIni,
+ size_t* posFin,
+ const size_t* posAlig,
+ const size_t nPosAlig,
+ const size_t segAUsar);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Comprueba, mediante una ejecución en paralelo con OpenMP, si una serie de
+ segmentos de la polilínea ya aligerada se cortan con un segmento base AB,
+ a partir de éste hacia atrás.
+\param[in] xA Coordenada X del punto A.
+\param[in] yA Coordenada Y del punto A.
+\param[in] xB Coordenada X del punto B.
+\param[in] yB Coordenada Y del punto B.
+\param[in] x Vector que contiene las coordenadas X de los vértices de la
+ polilínea de trabajo.
+\param[in] y Vector que contiene las coordenadas Y de los vértices de la
+ polilínea de trabajo.
+\param[in] incX Posiciones de separación entre los elementos del vector \em x.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] incY Posiciones de separación entre los elementos del vector \em y.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] posAlig Vector de posiciones de \em x e \em y utilizadas en la
+ polilínea aligerada.
+\param[in] nPosAlig Número de elementos de \em posAlig.
+\param[in] posIni Posición en el vector \em posAlig del punto inicial a partir
+ del cual (incluido) se comenzarán a chequear segmentos.
+\param[in] posFin Posición en el vector \em posAlig del punto final hasta el
+ cual (incluido) se chequearán segmentos.
+\return Dos posibilidades:
+ - 0: No hay ninguna intersección entre AB y los segmentos.
+ - Distinto de 0: Hay al menos una intersección entre AB y los segmentos.
+\note Esta función está paralelizada con OpenMP.
+\note Esta función no comprueba si los índices almacenados en \em posAlig son
+ congruentes con el tamaño de los vectores \em x e \em y.
+\note Esta función no comprueba si los valores pasados en \em posIni, \em posFin
+ y \em nPosAlig son congruentes con el tamaño del vector \em posAlig.
+\note Esta función asume que \em posIni>\em posFin (ya que vamos hacia atrás).
+\date 20 de agosto de 2013: Creación de la función.
+\date 01 de abril de 2014: Particularización de la función sólo para el plano.
+\todo Esta función todavía no está probada.
+*/
+int DouglasPeuckerRobAutoIntersecPlanoOMP(const double xA,
+ const double yA,
+ const double xB,
+ const double yB,
+ const double* x,
+ const double* y,
+ const size_t incX,
+ const size_t incY,
+ const size_t* posAlig,
+ const size_t nPosAlig,
+ const size_t posIni,
+ const size_t posFin);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Comprueba, mediante una ejecución en serie, si una serie de segmentos de
+ la polilínea ya aligerada se cortan con un segmento base AB, a partir de
+ éste hacia atrás.
+\param[in] xA Coordenada X del punto A.
+\param[in] yA Coordenada Y del punto A.
+\param[in] xB Coordenada X del punto B.
+\param[in] yB Coordenada Y del punto B.
+\param[in] x Vector que contiene las coordenadas X de los vértices de la
+ polilínea de trabajo.
+\param[in] y Vector que contiene las coordenadas Y de los vértices de la
+ polilínea de trabajo.
+\param[in] incX Posiciones de separación entre los elementos del vector \em x.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] incY Posiciones de separación entre los elementos del vector \em y.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] posAlig Vector de posiciones de \em x e \em y utilizadas en la
+ polilínea aligerada.
+\param[in] nPosAlig Número de elementos de \em posAlig.
+\param[in] posIni Posición en el vector \em posAlig del punto inicial a partir
+ del cual (incluido) se comenzarán a chequear segmentos.
+\param[in] posFin Posición en el vector \em posAlig del punto final hasta el
+ cual (incluido) se chequearán segmentos.
+\return Dos posibilidades:
+ - 0: No hay ninguna intersección entre AB y los segmentos.
+ - Distinto de 0: Hay al menos una intersección entre AB y los segmentos.
+\note Esta función no comprueba si los índices almacenados en \em posAlig son
+ congruentes con el tamaño de los vectores \em x e \em y.
+\note Esta función no comprueba si los valores pasados en \em posIni, \em posFin
+ y \em nPosAlig son congruentes con el tamaño del vector \em posAlig.
+\note Esta función asume que \em posIni>\em posFin (ya que vamos hacia atrás).
+\date 20 de agosto de 2013: Creación de la función.
+\date 01 de abril de 2014: Particularización de la función sólo para el plano.
+\todo Esta función todavía no está probada.
+*/
+int DouglasPeuckerRobAutoIntersecPlanoSerie(const double xA,
+ const double yA,
+ const double xB,
+ const double yB,
+ const double* x,
+ const double* y,
+ const size_t incX,
+ const size_t incY,
+ const size_t* posAlig,
+ const size_t nPosAlig,
+ const size_t posIni,
+ const size_t posFin);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula la intersección de dos segmentos AB y CD en el plano.
+\param[in] xA Coordenada X del punto A.
+\param[in] yA Coordenada Y del punto A.
+\param[in] xB Coordenada X del punto B.
+\param[in] yB Coordenada Y del punto B.
+\param[in] xC Coordenada X del punto C.
+\param[in] yC Coordenada Y del punto C.
+\param[in] xD Coordenada X del punto D.
+\param[in] yD Coordenada Y del punto D.
+\param[in] posFinAB Posición del punto final del segmento AB en los vectores
+ originales de coordenadas.
+\param[in] posIniCD Posición del punto inicial del segmento CD en los vectores
+ originales de coordenadas.
+\return Dos posibilidades:
+ - 0: No hay intersección entre AB y CD.
+ - Distinto de 0: Sí hay intersección entre AB y CD.
+\note Esta función utiliza internamente las funciones \ref IntersecSegmentos2D o
+ \ref IntersecSegmentos2DSimple, que no son robustas. En consecuencia, los
+ resultados de esta función tampoco lo son.
+\date 20 de agosto de 2013: Creación de la función.
+\date 28 de marzo de 2014: Adición de los argumentos \em xGC, \em yGC, \em zGC,
+ \em xGD, \em yGD y \em zGD.
+\date 01 de abril de 2014: Particularización de la función sólo para el plano.
+\todo Esta función todavía no está probada.
+*/
+int DouglasPeuckerRobIntersecPlano(const double xA,
+ const double yA,
+ const double xB,
+ const double yB,
+ const double xC,
+ const double yC,
+ const double xD,
+ const double yD,
+ const size_t posFinAB,
+ const size_t posIniCD);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula la distancia a un segmento del punto más alejado de un conjunto
+ de puntos candidatos para su uso en el aligerado de polilíneas mediante
+ el algoritmo de Douglas-Peucker.
+\brief Esta función implementa el criterio apuntado en:
+
+\brief Ebisch, K., October 2002. A correction to the Douglas–Peucker line
+ generalization algorithm. Computers and Geosciences 28 (8), 995–997.
+\param[in] x Vector que contiene las coordenadas X de los vértices de la
+ polilínea de trabajo.
+\param[in] y Vector que contiene las coordenadas Y de los vértices de la
+ polilínea de trabajo.
+\param[in] incX Posiciones de separación entre los elementos del vector \em x.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] incY Posiciones de separación entre los elementos del vector \em y.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] posIni Posición en los vectores de coordenadas del punto inicial del
+ segmento base.
+\param[in] posFin Posición en los vectores de coordenadas del punto final del
+ segmento base.
+\param[out] pos Posición en los vectores de coordenadas del punto más alejado de
+ la línea base. Si \em posFin es el punto inmediatamente posterior a
+ \em posIni, esta variable devuelve \em posIni.
+\return Distancia del punto más alejado a la línea base. Si \em posFin es el
+ punto inmediatamente posterior a \em posIni, se devuelve el valor -1.0.
+\note Esta función no comprueba si el número de elementos de los vectores \em x
+ e \em y es congruente con los valores pasados en \em posIni y \em posFin.
+\date 25 de mayo de 2012: Creación de la función.
+\date 16 de marzo de 2014: Reestructuración de la función para el cálculo de la
+ distancia de una forma más eficiente por medio de la transformación del
+ sistema de coordenadas original.
+\todo Esta función todavía no está probada.
+*/
+double DouglasPeuckerDistMaxPlano(const double* x,
+ const double* y,
+ const size_t incX,
+ const size_t incY,
+ const size_t posIni,
+ const size_t posFin,
+ size_t* pos);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula los parámetros de rotación para girar el sistema de coordenadas
+ con origen en el punto inicial de la base y llevar el eje X a coincidir
+ con ella, para su uso en el aligerado de polilíneas mediante el algoritmo
+ de Douglas-Peucker.
+\param[in] xBase2RB1 Coordenada X del punto final de la base en el sistema de
+ coordenadas original, reducida al punto inicial.
+\param[in] yBase2RB1 Coordenada Y del punto final de la base en el sistema de
+ coordenadas original, reducida al punto inicial.
+\param[out] sAlfa Seno del ángulo de rotación para llevar el eje X del sistema
+ de coordenadas (con origen en el punto inicial de la base) a
+ coincidir con el segmento base.
+\param[out] cAlfa Coseno del ángulo de rotación para llevar el eje X del sistema
+ de coordenadas (con origen en el punto inicial de la base) a
+ coincidir con el segmento base.
+\param[out] lonBase Longitud de la base.
+\date 16 de marzo de 2014: Creación de la función.
+\todo Esta función todavía no está probada.
+*/
+void DouglasPeuckerParamRotaBase(const double xBase2RB1,
+ const double yBase2RB1,
+ double* sAlfa,
+ double* cAlfa,
+ double* lonBase);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula la distancia de un punto a un segmento AB para su uso en el
+ aligerado de polilíneas mediante el algoritmo de Douglas-Peucker.
+\brief Esta función implementa el criterio apuntado en:
+
+\brief Ebisch, K., October 2002. A correction to the Douglas–Peucker line
+ generalization algorithm. Computers and Geosciences 28 (8), 995–997.
+\param[in] lonBase Longitud de la base.
+\param[in] sAlfa Seno del ángulo de rotación para llevar el eje X del sistema de
+ coordenadas (con origen en el punto inicial de la base) a coincidir
+ con el segmento base.
+\param[in] cAlfa Coseno del ángulo de rotación para llevar el eje X del sistema
+ de coordenadas (con origen en el punto inicial de la base) a
+ coincidir con el segmento base.
+\param[in] xVertRB1 Coordenada X del punto de trabajo en el sistema de
+ coordenadas original, reducida al punto inicial de la base.
+\param[in] yVertRB1 Coordenada Y del punto de trabajo en el sistema de
+ coordenadas original, reducida al punto inicial de la base.
+\return Distancia del punto a la línea base.
+\note Los argumentos \em lonBase, \em sAlfa y \em cAlfa son los parámetros
+ calculados por la función \ref DouglasPeuckerParamRotaBase.
+\date 16 de marzo de 2014: Creación de la función.
+\todo Esta función todavía no está probada.
+*/
+double DouglasPeuckerDistMaxPlanoAux(const double lonBase,
+ const double sAlfa,
+ const double cAlfa,
+ const double xVertRB1,
+ const double yVertRB1);
+/******************************************************************************/
+/******************************************************************************/
+#ifdef __cplusplus
+}
+#endif
+/******************************************************************************/
+/******************************************************************************/
+#endif
+/******************************************************************************/
+/******************************************************************************/
+/** @} */
+/******************************************************************************/
+/******************************************************************************/
+/* kate: encoding utf-8; end-of-line unix; syntax c; indent-mode cstyle; */
+/* kate: replace-tabs on; space-indent on; tab-indents off; indent-width 4; */
+/* kate: line-numbers on; folding-markers on; remove-trailing-space on; */
+/* kate: backspace-indents on; show-tabs on; */
+/* kate: word-wrap-column 80; word-wrap-marker-color #D2D2D2; word-wrap off; */
diff --git a/src/libgeoc/errores.h b/src/libgeoc/errores.h
index 3b91f08..3b91f08 100755..100644
--- a/src/libgeoc/errores.h
+++ b/src/libgeoc/errores.h
diff --git a/src/libgeoc/eucli.h b/src/libgeoc/eucli.h
index 1ee7d7c..1ee7d7c 100755..100644
--- a/src/libgeoc/eucli.h
+++ b/src/libgeoc/eucli.h
diff --git a/src/libgeoc/fgeneral.h b/src/libgeoc/fgeneral.h
index 2dc3832..8634583 100755..100644
--- a/src/libgeoc/fgeneral.h
+++ b/src/libgeoc/fgeneral.h
@@ -8,12 +8,12 @@
\note Este fichero contiene funciones paralelizadas con OpenMP.
\date 25 de septiembre de 2009
\version 1.0
-\section Licencia Licencia
-Copyright (c) 2009-2011, José Luis García Pallero. All rights reserved.
-
+\copyright
+Copyright (c) 2009-2018, José Luis García Pallero. All rights reserved.
+\par
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
-
+\par
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this
@@ -22,7 +22,7 @@ are permitted provided that the following conditions are met:
- Neither the name of the copyright holders nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
-
+\par
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -42,6 +42,7 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/******************************************************************************/
#include<stdlib.h>
#include<stdint.h>
+#include<limits.h>
#include<float.h>
#include<math.h>
#include"libgeoc/constantes.h"
@@ -55,6 +56,63 @@ extern "C" {
/******************************************************************************/
/******************************************************************************/
/**
+\def GEOC_UNIX
+\brief Comprueba si estamos en un entorno UNIX o compatible.
+\return Dos posibilidades:
+ - 1: Estamos en un entorno UNIX o compatible.
+ - 0: No estamos en un entorno UNIX o compatible.
+\note Esta variable sólo se puede usar en sentencias condicionales del
+ preprocesador.
+\date 03 de enero de 2013: Creación de la constante.
+\note Esta macro todavía no está probada.
+*/
+#define GEOC_UNIX 0
+#if (!defined(_WIN32)&&(defined(__unix__)||defined(__unix)||defined(unix)|| \
+ (defined(__APPLE__)&&defined(__MACH__))))
+ #undef GEOC_UNIX
+ #define GEOC_UNIX 1
+#endif
+/******************************************************************************/
+/******************************************************************************/
+/**
+\def GEOC_SUNOS
+\brief Comprueba si estamos en un entorno de sistema operativo de Oracle
+ (antigua Sun).
+\return Dos posibilidades:
+ - 1: Estamos en un entorno de Oracle.
+ - 0: No estamos en un entorno de Oracle.
+\note Esta variable sólo se puede usar en sentencias condicionales del
+ preprocesador.
+\date 18 de enero de 2013: Creación de la constante.
+\note Esta macro todavía no está probada.
+*/
+#define GEOC_SUNOS 0
+#if (defined(__sun__)||defined(__sun)||defined(__SunOS))
+ #undef GEOC_SUNOS
+ #define GEOC_SUNOS 1
+#endif
+/******************************************************************************/
+/******************************************************************************/
+/**
+\def GEOC_WINDOWS
+\brief Comprueba si estamos en un entorno Microsoft Windows de 32 ó 64 bits.
+\return Dos posibilidades:
+ - 1: Estamos en un entorno MS Windows.
+ - 0: No estamos en un entorno MS Windows.
+\note Esta variable sólo se puede usar en sentencias condicionales del
+ preprocesador.
+\date 07 de enero de 2013: Creación de la constante.
+\note Esta macro todavía no está probada.
+*/
+#define GEOC_WINDOWS 0
+#if (defined(__WIN32__)||defined(__WIN32)||defined(_WIN32)||defined(WIN32)|| \
+ defined(__WIN64__)||defined(__WIN64)||defined(_WIN64)||defined(WIN64))
+ #undef GEOC_WINDOWS
+ #define GEOC_WINDOWS 1
+#endif
+/******************************************************************************/
+/******************************************************************************/
+/**
\def GEOC_SIGNO
\brief Macro para determinar el signo de un escalar.
\param[in] a Un número.
@@ -89,7 +147,7 @@ extern "C" {
/******************************************************************************/
/******************************************************************************/
/**
-\def GEOC_PARI
+\def GEOC_ES_PAR
\brief Macro para comprobar si un número de tipo entero es par.
\param[in] a Un número.
\return Dos posibilidades:
@@ -100,8 +158,9 @@ extern "C" {
tipo entero: \p char, \p short, \p int, \p long o \p long \p long (con los
identificadores \p signed o \p undigned).
\date 15 de marzo de 2011: Creación de la macro.
+\date 11 de septiembre de 2012: Renombrado de la macro.
*/
-#define GEOC_PARI(a) ((a)%2 ? 0 : 1)
+#define GEOC_ES_PAR(a) ((a)%2 ? 0 : 1)
/******************************************************************************/
/******************************************************************************/
/**
@@ -132,6 +191,27 @@ extern "C" {
/******************************************************************************/
/******************************************************************************/
/**
+\def GEOC_COMPARA_VERSIONES
+\brief Compara dos números de versión.
+\param[in] vMay1 Número de versión mayor de la versión 1 a comparar.
+\param[in] vMen1 Número de versión menor de la versión 1 a comparar.
+\param[in] vMic1 Número de versión micro de la versión 1 a comparar.
+\param[in] vMay2 Número de versión mayor de la versión 2 a comparar.
+\param[in] vMen2 Número de versión menor de la versión 2 a comparar.
+\param[in] vMic2 Número de versión micro de la versión 2 a comparar.
+\return Dos posibilidades:
+ - 1: Si la versión 1 es mayor (posterior) o igual que la versión 2.
+ - 0: Si la versión 1 es menor (anterior) que la versión 2.
+\date 05 de agosto de 2012: Creación de la constante.
+\note Esta macro todavía no está probada.
+*/
+#define GEOC_COMPARA_VERSIONES(vMay1,vMen1,vMic1,vMay2,vMen2,vMic2) \
+(((vMay1)>(vMay2))|| \
+ (((vMay1)==(vMay2))&&((vMen1)>(vMen2)))|| \
+ (((vMay1)==(vMay2))&&((vMen1)==(vMen2))&&((vMic1)>=(vMic2))))
+/******************************************************************************/
+/******************************************************************************/
+/**
\brief Indica si hay alguna función compilada en paralelo con OpenMP en el
fichero \ref fgeneral.c.
\param[out] version Cadena identificadora de la versión de OpenMP utilizada.
@@ -508,14 +588,19 @@ void LibMemMatrizC(double** matriz);
/******************************************************************************/
/**
\brief Calcula las posiciones de comienzo de elementos repetidos en un vector.
-
- - Para un vector de datos [1,2,2,3,4,4] se devuelve el vector de
- posiciones [0,1,3,4].
- - Para un vector de datos [1,2,2,3,4] se devuelve el vector de posiciones
- [0,1,3,4].
- - Para un vector de datos [1,1,1,1,1] se devuelve el vector de posiciones
- [0].
- - Para un vector de datos [1] se devuelve el vector de posiciones [0].
+\brief <ul>
+ <li>Para un vector de datos [1,2,2,3,4,4] se devuelve el vector de
+ posiciones [0,1,3,4].
+ </li>
+ <li>Para un vector de datos [1,2,2,3,4] se devuelve el vector de
+ posiciones [0,1,3,4].
+ </li>
+ <li>Para un vector de datos [1,1,1,1,1] se devuelve el vector de
+ posiciones [0].
+ </li>
+ <li>Para un vector de datos [1] se devuelve el vector de posiciones [0].
+ </li>
+ </ul>
\param[in] datos Vector de datos.
\param[in] nDatos Número de elementos de \em datos. No puede ser 0.
\param[in] incDatos Posiciones de separación entre los elementos del vector
@@ -546,19 +631,24 @@ size_t* PosRepeEnVector(const double* datos,
/**
\brief Calcula el número de elementos repetidos en un vector a partir de la
salida de la función \ref PosRepeEnVector.
-
- - Para un vector de datos [1,2,2,3,4,4], donde la función
- \ref PosRepeEnVector devuelve el vector de posiciones [0,1,3,4], esta
- función devuelve el vector [1,2,1,2].
- - Para un vector de datos [1,2,2,3,4], donde la función
- \ref PosRepeEnVector devuelve el vector de posiciones [0,1,3,4], esta
- función devuelve el vector [1,2,1,1].
- - Para un vector de datos [1,1,1,1,1], donde la función
- \ref PosRepeEnVector devuelve el vector de posiciones [0], esta función
- devuelve el vector [5].
- - Para un vector de datos [1], donde la función
- \ref PosRepeEnVector devuelve el vector de posiciones [0], esta función
- devuelve el vector [1].
+\brief <ul>
+ <li>Para un vector de datos [1,2,2,3,4,4], donde la función
+ \ref PosRepeEnVector devuelve el vector de posiciones [0,1,3,4], esta
+ función devuelve el vector [1,2,1,2].
+ </li>
+ <li>Para un vector de datos [1,2,2,3,4], donde la función
+ \ref PosRepeEnVector devuelve el vector de posiciones [0,1,3,4], esta
+ función devuelve el vector [1,2,1,1].
+ </li>
+ <li>Para un vector de datos [1,1,1,1,1], donde la función
+ \ref PosRepeEnVector devuelve el vector de posiciones [0], esta
+ función devuelve el vector [5].
+ </li>
+ <li>Para un vector de datos [1], donde la función
+ \ref PosRepeEnVector devuelve el vector de posiciones [0], esta
+ función devuelve el vector [1].
+ </li>
+ </ul>
\param[in] pos Vector de posiciones devuelto por la función
\ref PosRepeEnVector.
\param[in] nPos Número de elementos de \em pos. No puede ser 0.
diff --git a/src/libgeoc/general.h b/src/libgeoc/general.h
index c7d5f0f..c7d5f0f 100755..100644
--- a/src/libgeoc/general.h
+++ b/src/libgeoc/general.h
diff --git a/src/libgeoc/geocnan.h b/src/libgeoc/geocnan.h
index c55c1ef..c55c1ef 100755..100644
--- a/src/libgeoc/geocnan.h
+++ b/src/libgeoc/geocnan.h
diff --git a/src/libgeoc/geom.h b/src/libgeoc/geom.h
index 134cb7b..134cb7b 100755..100644
--- a/src/libgeoc/geom.h
+++ b/src/libgeoc/geom.h
diff --git a/src/libgeoc/greiner.h b/src/libgeoc/greiner.h
index 37fe416..2a36011 100755..100644
--- a/src/libgeoc/greiner.h
+++ b/src/libgeoc/greiner.h
@@ -8,12 +8,12 @@
(http://davis.wpi.edu/~matt/courses/clipping/).
\author José Luis García Pallero, jgpallero@gmail.com
\date 14 de mayo de 2011
-\section Licencia Licencia
-Copyright (c) 2011, José Luis García Pallero. All rights reserved.
-
+\copyright
+Copyright (c) 2011-2020, José Luis García Pallero. All rights reserved.
+\par
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
-
+\par
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this
@@ -22,7 +22,7 @@ are permitted provided that the following conditions are met:
- Neither the name of the copyright holders nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
-
+\par
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -59,10 +59,8 @@ extern "C" {
/******************************************************************************/
/**
\def GEOC_GREINER_FAC_EPS_PERTURB
-\brief Factor de escala para el cálculo de la cantidad mínima de perturbación
- para un valor. Esta variable se usa en la función \ref CantPerturbMin.
-
- A base de hacer pruebas he visto que es desaconsejable un valor por
+\brief Factor de escala para el cálculo de la cantidad mínima de perturbación.
+\brief A base de hacer pruebas he visto que es desaconsejable un valor por
debajo de 10.0.
\date 22 de mayo de 2011: Creación de la constante.
*/
@@ -211,13 +209,11 @@ vertPoliClip* CreaVertPoliClip(const double x,
siempre se repite al final. Si en los vectores \em x e \em y el último
elemento no es igual que el primero, igualmente se crea en la lista de
salida.
-\note Si en los vectores de coordenadas \em x e \em y hay valores #GEOC_NAN,
- éstos no se tienen en cuenta a la hora de la creación de la estructura de
- salida.
-\note Que los vectores de coordenadas \em x e \em y admitan vértices con
- coordenadas (#GEOC_NAN,#GEOC_NAN) no quiere decir que éstos sean
- separadores de múltiples polígonos. \em x e \em y \b *SÓLO* deben
- almacenar un único polígono.
+\note Si en los vectores de coordenadas \em x e \em y hay valores #GEOC_NAN
+ éstos \b*NO* serán considerados como separadores de múltiples polígonos,
+ por lo que en la estructura de salida se asumirá que se almacena un
+ polígono único cuyos vértices son los pasados sin tener en cuenta los
+ pares (#GEOC_NAN,#GEOC_NAN).
\date 18 de mayo de 2011: Creación de la función.
\date 24 de mayo de 2011: Adición del soporte de coordenadas
(#GEOC_NAN,#GEOC_NAN) en los vectores de entrada.
@@ -274,8 +270,7 @@ vertPoliClip* ReiniciaPoliClip(vertPoliClip* poli);
\brief Reinicia los vértices de un polígono almacenado como una lista doblemente
enlazada de elementos \ref _vertPoliClip para poder volver a calcular
otra operación booleana sin tener que recalcular las intersecciones.
-
- Esta función devuelve todos los campos _vertPoliClip::visitado a 0 y los
+\brief Esta función devuelve todos los campos _vertPoliClip::visitado a 0 y los
campos _vertPoliClip::entrada a 0.
\param[in] poli Puntero al primer elemento del polígono.
\return Puntero al primer elemento del polígono original. Si se devuelve
@@ -651,10 +646,25 @@ polig* Paso3Greiner(vertPoliClip* poliBas,
coordenadas de algunos vértices. Este valor es usado internamente por
la función \ref Paso1Greiner (ver su documentación). Un buen valor
para este argumento es #GEOC_GREINER_FAC_EPS_PERTURB.
+\param[in] compruebaHuecosUnion Identificador para comprobar si alguno de los
+ polígonos generados en la operación #GeocOpBoolUnion es es realidad
+ un elemento que no pertenece a ninguno de los polígonos originales,
+ caso que puede darse en algunas situaciones con polígonos de trabajo
+ no convexos. Esta opción sólo es tenida en cuenta si \em op vale
+ #GeocOpBoolUnion Dos posibles valores:
+ - 0: No se comprueba.
+ - Distinto de 0: Sí se comprueba.
\param[out] nIntersec Número de intersecciones calculadas.
\param[out] nPerturb Número de puntos perturbados en el proceso.
\return Estructura \ref polig con los polígonos resultado de la operación. Si se
- devuelve \p NULL ha ocurrido un error de asignación de memoria.
+ devuelve \p NULL ha ocurrido un error de asignación de memoria. Cada
+ elemento del campo polig::atr puede tener dos posibles valores:
+ - 0: El polígono correspondiente es un agujero, luego no es un resultado
+ válido para la operación solicitada en \em op. Este valor sólo
+ puede darse si \em op vale #GeocOpBoolUnion y si se ha pasado un
+ valor de \em compruebaHuecosOr distinto de 0.
+ - 1: El polígono correspondiente es válido para la operación solicitada
+ en \em op.
\note Esta función no comprueba si las variables \em poliBas y \em poliRec son
polígonos correctamente almacenados.
\note Esta función no comprueba internamente si \em op pertenece al tipo
@@ -671,17 +681,23 @@ polig* Paso3Greiner(vertPoliClip* poliBas,
resultados de #GeocOpBoolAB y #GeocOpBoolBA. En ningún momento se realiza
la operación booleana #GeocOpBoolUnion entre los resultados de
#GeocOpBoolAB y #GeocOpBoolBA.
+\note Esta función asume que tanto \em poliBas como \em poliRec almacenan cada
+ una un polígono único.
+\note Los polígonos pueden tener autointersecciones.
\date 22 de mayo de 2011: Creación de la función.
\date 29 de mayo de 2011: Cambio de la variable de salida por la estructura
\ref polig.
\date 30 de mayo de 2011: Adición de la capacidad de calcular la operación unión
exclusiva \p xor.
+\date 11 de mayo de 2011: Adición del atributo polig::atr y del argumento de
+ entrada \em compruebaHuecosUnion.
\todo Esta función no está probada.
*/
polig* PoliBoolGreiner(vertPoliClip* poliBas,
vertPoliClip* poliRec,
const enum GEOC_OP_BOOL_POLIG op,
const double facPer,
+ const int compruebaHuecosUnion,
size_t* nIntersec,
size_t* nPerturb);
/******************************************************************************/
@@ -707,6 +723,14 @@ polig* PoliBoolGreiner(vertPoliClip* poliBas,
coordenadas de algunos vértices. Este valor es usado internamente por
la función \ref Paso1Greiner (ver su documentación). Un buen valor
para este argumento es #GEOC_GREINER_FAC_EPS_PERTURB.
+\param[in] compruebaHuecosUnion Identificador para comprobar si alguno de los
+ polígonos generados en la operación #GeocOpBoolUnion es es realidad
+ un elemento que no pertenece a ninguno de los polígonos originales,
+ caso que puede darse en algunas situaciones con polígonos de trabajo
+ no convexos. Esta opción sólo es tenida en cuenta si \em op vale
+ #GeocOpBoolUnion Dos posibles valores:
+ - 0: No se comprueba.
+ - Distinto de 0: Sí se comprueba.
\param[out] nIntersec Número total de intersecciones calculadas entre todas los
polígonos.
\param[out] nPerturb Número total de puntos perturbados en el proceso.
@@ -733,13 +757,17 @@ polig* PoliBoolGreiner(vertPoliClip* poliBas,
resultados de #GeocOpBoolAB y #GeocOpBoolBA. En ningún momento se realiza
la operación booleana #GeocOpBoolUnion entre los resultados de
#GeocOpBoolAB y #GeocOpBoolBA.
+\note Los polígonos pueden tener autointersecciones.
\date 07 de junio de 2011: Creación de la función.
+\date 11 de mayo de 2011: Adición del atributo polig::atr y del argumento de
+ entrada \em compruebaHuecosUnion.
\todo Esta función no está probada.
*/
polig* PoliBoolGreinerMult(const polig* poliBas,
const polig* poliRec,
const enum GEOC_OP_BOOL_POLIG op,
const double facPer,
+ const int compruebaHuecosUnion,
size_t* nIntersec,
size_t* nPerturb);
/******************************************************************************/
diff --git a/src/libgeoc/mate.h b/src/libgeoc/mate.h
new file mode 100644
index 0000000..b546574
--- /dev/null
+++ b/src/libgeoc/mate.h
@@ -0,0 +1,482 @@
+/* -*- coding: utf-8 -*- */
+/**
+\defgroup mate Módulo MATEMATICAS
+\ingroup anespec gshhs legendre
+\brief En este módulo se reúnen las funciones necesarias para la realización de
+ cálculos matemáticos generales.
+@{
+\file mate.h
+\brief Declaración de funciones para la realización de cálculos matemáticos
+ generales.
+
+En el momento de la compilación de las funciones que dan el factorial de un
+número y el producto de una serie de números ha de seleccionarse el tipo de
+cálculo a utilizar (para números mayores que #GEOC_MATE_CONST_DBL_NMAXFAC y
+#GEOC_MATE_CONST_LDBL_NMAXFAC). Para realizar el cálculo es necesario definir la
+variable \em CALCULO_PRODUCTO_MULT si se quiere utilizar el producto o
+\em CALCULO_PRODUCTO_LOG si se quieren utilizar logaritmos. En \p gcc, las
+variables para el preprocesador se pasan como \em -DXXX, donde \em XXX es la
+variable a introducir.
+\author José Luis García Pallero, jgpallero@gmail.com
+\date 17 de mayo de 2010
+\copyright
+Copyright (c) 2009-2014, José Luis García Pallero. All rights reserved.
+\par
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+\par
+- Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+- Neither the name of the copyright holders nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+\par
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/******************************************************************************/
+/******************************************************************************/
+#ifndef _MATE_H_
+#define _MATE_H_
+/******************************************************************************/
+/******************************************************************************/
+#include<stdlib.h>
+#include<math.h>
+#include"libgeoc/constantes.h"
+#include"libgeoc/posmatvec.h"
+/******************************************************************************/
+/******************************************************************************/
+#ifdef __cplusplus
+extern "C" {
+#endif
+/******************************************************************************/
+/******************************************************************************/
+/**
+\def GEOC_PROD_MULT
+\brief Identificador de cálculo de productos de series de números correlativos
+ por multiplicación directa.
+\date 30 de diciembre de 2010: Creación de la constante.
+*/
+#define GEOC_PROD_MULT 0
+/******************************************************************************/
+/******************************************************************************/
+/**
+\def GEOC_PROD_LOG
+\brief Identificador de cálculo de productos de series de números correlativos
+ por logaritmos.
+\date 30 de diciembre de 2010: Creación de la constante.
+*/
+#define GEOC_PROD_LOG 1
+/******************************************************************************/
+/******************************************************************************/
+/**
+\def GEOC_MATE_CONST_DBL_NMAXFAC
+\brief Número más alto para el que se almacena su factorial de manera explícita
+ para tipo de dato \p double.
+\date 03 de octubre de 2010: Creación de la constante.
+*/
+#define GEOC_MATE_CONST_DBL_NMAXFAC (170)
+/******************************************************************************/
+/******************************************************************************/
+/**
+\def GEOC_MATE_CONST_LDBL_NMAXFAC
+\brief Número más alto para el que se almacena su factorial de manera explícita
+ para tipo de dato \p long \p double.
+\date 03 de octubre de 2010: Creación de la constante.
+*/
+#define GEOC_MATE_CONST_LDBL_NMAXFAC (200)
+/******************************************************************************/
+/******************************************************************************/
+/** \struct __mateFactExpl
+\brief Estructura contenedora de valores explícitos de algunos factoriales.
+\brief Esta estructura se basa en la que se puede encontrar en el fichero
+ \p gamma.c, de la biblioteca GSL.
+\date 03 de octubre de 2010: Creación de la estructura.
+*/
+typedef struct
+{
+ /** \brief Número. */
+ size_t numero;
+ /** \brief Factorial del número almacenado en __mateFacExpl::numero. */
+ long double valor;
+}__mateFactExpl;
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Indica el tipo de cálculo del producto de una serie de números
+ correlativos.
+\return Dos posibles valores:
+ - #GEOC_PROD_MULT: Cálculo por multiplicación directa.
+ - #GEOC_PROD_LOG: Cálculo mediante logaritmos.
+\date 30 de diciembre de 2010: Creación de la función.
+*/
+int GeocTipoCalcProd(void);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula la media de una serie de valores de tipo \p double.
+\param[in] datos Dirección de comienzo del vector que almacena los datos.
+\param[in] nDatos Número de datos que contiene el vector.
+\param[in] inc Posiciones de separación entre los elementos del vector de datos.
+ Si es un número negativo, el vector se recorre desde el final hasta
+ el principio.
+\return Valor medio de la serie de datos.
+\note Esta función asume que \em nDatos>0.
+\date 19 de noviembre de 2009: Creación de la función.
+*/
+double Media(const double* datos,
+ const size_t nDatos,
+ const int inc);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula la varianza de una serie de valores de tipo \p double.
+\brief Esta función calcula la varianza mediante la fórmula
+ \f$
+ \sigma^2_x=\frac{\sum_{i=1}^{N}(x_i-\bar{x})^2}{N-1},
+ \f$
+ donde \f$N\f$ es el número de elementos de trabajo y \f$\bar{x}\f$ es la
+ media.
+\param[in] datos Dirección de comienzo del vector que almacena los datos.
+\param[in] nDatos Número de datos que contiene el vector.
+\param[in] inc Posiciones de separación entre los elementos del vector de datos.
+ Si es un número negativo, el vector se recorre desde el final hasta
+ el principio.
+\param[in] media Valor medio de la serie de datos.
+\note Esta función asume que \em nDatos>1.
+\return Varianza de la serie de datos.
+\date 09 de marzo de 2011: Creación de la función.
+*/
+double Varianza(const double* datos,
+ const size_t nDatos,
+ const int inc,
+ const double media);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula la media ponderada de una serie de valores de tipo \p double.
+\param[in] datos Dirección de comienzo del vector que almacena los datos.
+\param[in] nDatos Número de datos que contienen los vectores \em datos y
+ \em pesos.
+\param[in] incDatos Posiciones de separación entre los elementos del vector
+ \em datos. Si es un número negativo, el vector se recorre desde el
+ final hasta el principio.
+\param[in] pesos Dirección de comienzo del vector que almacena los pesos.
+\param[in] incPesos Posiciones de separación entre los elementos del vector
+ \em pesos. Si es un número negativo, el vector se recorre desde el
+ final hasta el principio.
+\return Valor medio de la serie de datos.
+\note Esta función asume que \em nDatos>0.
+\date 23 de abril de 2010: Creación de la función.
+\todo Esta función no está probada.
+*/
+double MediaPonderada(const double* datos,
+ const size_t nDatos,
+ const int incDatos,
+ const double* pesos,
+ const int incPesos);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula la mediana de una serie de valores de tipo \p double.
+\param[in] datos Dirección de comienzo del vector que almacena los datos, que ha
+ de estar ordenado (en orden ascendente o descendente, da igual).
+\param[in] nDatos Número de datos que contiene el vector.
+\param[in] inc Posiciones de separación entre los elementos del vector de datos.
+ Si es un número negativo, el vector se recorre desde el final hasta
+ el principio.
+\date 19 de noviembre de 2009: Creación de la función.
+*/
+double Mediana(const double* datos,
+ const size_t nDatos,
+ const int inc);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula el producto de una serie de números mediante multiplicaciones.
+\param[in] inicio Número inicial de la serie.
+\param[in] fin Número final de la serie.
+\return Producto acumulado de los números de la serie, calculado mediante
+ multiplicaciones.
+\date 03 de octubre de 2010: Creación de la función.
+*/
+double ProductoMult(size_t inicio,
+ size_t fin);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula el producto de una serie de números mediante multiplicaciones.
+\param[in] inicio Número inicial de la serie.
+\param[in] fin Número final de la serie.
+\return Producto acumulado de los números de la serie, calculado mediante
+ multiplicaciones.
+\note Los cálculos intermedios y el resultado se almacenan en datos de tipo
+ \p long \p double, para prevenir desbordamientos (el tipo de dato
+ \p double -8 bytes- sólo es capaz de almacenar los rangos -1.79769e308 a
+ -2.22507e-308 y 2.22507e-308 a 1.79769e308).
+\date 03 de octubre de 2010: Creación de la función.
+*/
+long double ProductoMultLD(size_t inicio,
+ size_t fin);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula el producto de una serie de números mediante logaritmos.
+\param[in] inicio Número inicial de la serie.
+\param[in] fin Número final de la serie.
+\return Producto acumulado de los números de la serie, calculado mediante
+ logaritmos.
+\date 03 de octubre de 2010: Creación de la función.
+*/
+double ProductoLog(size_t inicio,
+ size_t fin);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula el producto de una serie de números mediante logaritmos.
+\param[in] inicio Número inicial de la serie.
+\param[in] fin Número final de la serie.
+\return Producto acumulado de los números de la serie, calculado mediante
+ logaritmos.
+\note Los cálculos intermedios y el resultado se almacenan en datos de tipo
+ \p long \p double, para prevenir desbordamientos (el tipo de dato
+ \p double -8 bytes- sólo es capaz de almacenar los rangos -1.79769e308 a
+ -2.22507e-308 y 2.22507e-308 a 1.79769e308).
+\date 03 de octubre de 2010: Creación de la función.
+*/
+long double ProductoLogLD(size_t inicio,
+ size_t fin);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula el producto de una serie de números.
+\param[in] inicio Número inicial de la serie.
+\param[in] fin Número final de la serie.
+\return Producto acumulado de los números de la serie.
+\date 03 de octubre de 2010: Creación de la función.
+*/
+double Producto(size_t inicio,
+ size_t fin);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula el producto de una serie de números.
+\param[in] inicio Número inicial de la serie.
+\param[in] fin Número final de la serie.
+\return Producto acumulado de los números de la serie.
+\note Los cálculos intermedios y el resultado se almacenan en datos de tipo
+ \p long \p double, para prevenir desbordamientos (el tipo de dato
+ \p double -8 bytes- sólo es capaz de almacenar los rangos -1.79769e308 a
+ -2.22507e-308 y 2.22507e-308 a 1.79769e308).
+\date 03 de octubre de 2010: Creación de la función.
+*/
+long double ProductoLD(size_t inicio,
+ size_t fin);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula el factorial de un número mediante productos.
+\param[in] numero Número.
+\return Factorial del número pasado.
+\date 03 de octubre de 2010: Creación de la función.
+*/
+double FactorialMult(size_t numero);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula el factorial de un número mediante productos.
+\param[in] numero Número.
+\return Factorial del número pasado.
+\note Los cálculos intermedios y el resultado se almacenan en datos de tipo
+ \p long \p double, para prevenir desbordamientos (el tipo de dato
+ \p double -8 bytes- sólo es capaz de almacenar los rangos -1.79769e308 a
+ -2.22507e-308 y 2.22507e-308 a 1.79769e308).
+\date 03 de octubre de 2010: Creación de la función.
+*/
+long double FactorialMultLD(size_t numero);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula el factorial de un número como el antilogaritmo de la suma de
+ logaritmos.
+\param[in] numero Número.
+\return Factorial del número pasado.
+\date 03 de octubre de 2010: Creación de la función.
+*/
+double FactorialLog(size_t numero);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula el factorial de un número como el antilogaritmo de la suma de
+ logaritmos.
+\param[in] numero Número.
+\return Factorial del número pasado.
+\note Los cálculos intermedios y el resultado se almacenan en datos de tipo
+ \p long \p double, para prevenir desbordamientos (el tipo de dato
+ \p double -8 bytes- sólo es capaz de almacenar los rangos -1.79769e308 a
+ -2.22507e-308 y 2.22507e-308 a 1.79769e308).
+\date 03 de octubre de 2010: Creación de la función.
+*/
+long double FactorialLogLD(size_t numero);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula el factorial de un número.
+\param[in] numero Número.
+\return Factorial del número pasado.
+\note Si el número es menor o igual que #GEOC_MATE_CONST_DBL_NMAXFAC, el
+ factorial se toma de un array donde están almacenados de manera explícita
+ los resultados. Si es mayor que #GEOC_MATE_CONST_DBL_NMAXFAC, el factorial
+ se calcula.
+\date 02 de marzo de 2009: Creación de la función.
+\date 03 de octubre de 2010: Reprogramación de la función como llamada a las
+ funciones \ref FactorialMult o \ref FactorialLog y cambio del tipo de dato
+ devuelto de \p size_t a \p double.
+*/
+double Factorial(size_t numero);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula el factorial de un número.
+\param[in] numero Número.
+\return Factorial del número pasado.
+\note Si el número es menor o igual que #GEOC_MATE_CONST_LDBL_NMAXFAC, el
+ factorial se toma de un array donde están almacenados de manera explícita
+ los resultados. Si es mayor que #GEOC_MATE_CONST_LDBL_NMAXFAC, el
+ factorial se calcula.
+\note Los cálculos intermedios y el resultado se almacenan en datos de tipo
+ \p long \p double, para prevenir desbordamientos (el tipo de dato
+ \p double -8 bytes- sólo es capaz de almacenar los rangos -1.79769e308 a
+ -2.22507e-308 y 2.22507e-308 a 1.79769e308).
+\date 03 de octubre de 2010: Creación de la función.
+*/
+long double FactorialLD(size_t numero);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula el producto vectorial de dos vectores.
+\param[in] x1 Coordenada X del primer vector.
+\param[in] y1 Coordenada Y del primer vector.
+\param[in] z1 Coordenada Z del primer vector.
+\param[in] x2 Coordenada X del segundo vector.
+\param[in] y2 Coordenada Y del segundo vector.
+\param[in] z2 Coordenada Z del segundo vector.
+\param[out] x Coordenada X del vector producto vectorial de 1 y 2.
+\param[out] y Coordenada Y del vector producto vectorial de 1 y 2.
+\param[out] z Coordenada Z del vector producto vectorial de 1 y 2.
+\date 08 de agosto de 2013: Creación de la función.
+\todo Esta función no está probada.
+*/
+void ProductoVectorial(const double x1,
+ const double y1,
+ const double z1,
+ const double x2,
+ const double y2,
+ const double z2,
+ double* x,
+ double* y,
+ double* z);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula los senos y cosenos de una serie de ángulos equiespaciados.
+\brief Esta función utiliza en el cálculo las expresiones (ecuacies número 5.4.6
+ y 5.4.7, pág. 219) que se puede encontrar en:
+
+ William H. Press, Saul A. Teukolsky, William T. Vetterling y Brian P.
+ Flannery, 2007, Numerical recipes. The Art of Scientific Computing, 3a
+ edición. Cambridge University Press, ISBN: 978-0-521-88068-8.
+\param[in] anguloIni Ángulo inicial de la serie, en radianes.
+\param[in] incAngulo Incremento entre los valores algulares de la serie, en
+ radianes.
+\param[in] numValores Número de valores angulares de la serie, incluido
+ \em anguloIni.
+\param[out] seno Vector para almacenar el seno de los valores angulares de la
+ serie.
+\param[in] incSeno Posiciones de separación entre los elementos del vector de
+ salida \em seno. Este argumento siempre ha de ser un número positivo.
+\param[out] coseno Vector para almacenar el coseno de los valores angulares de
+ la serie.
+\param[in] incCoseno Posiciones de separación entre los elementos del vector de
+ salida \em coseno. Este argumento siempre ha de ser un número
+ positivo.
+\note Esta función no comprueba internamente si los vectores pasados contienen
+ suficiente memoria.
+\note Según pruebas realizadas, para una serie de 1000000 de elementos con
+ incremento angular de 50 grados, las diferencias con respecto a los senos
+ y cosenos calculados con las funciones de math.h están en el entorno de
+ 1e-10. Para incrementos de 1 grado, en el entorno de 1e-12.
+\date 27 de diciembre de 2014: Creación de la función.
+\todo Esta función no está probada.
+*/
+void SinCosRecurrencia(const double anguloIni,
+ const double incAngulo,
+ const size_t numValores,
+ double* seno,
+ const size_t incSeno,
+ double* coseno,
+ const size_t incCoseno);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Construye un \em spline cúbico natural para una serie de puntos e
+ interpola el valor de la función para una posición dada.
+\param[in] x Puntero a la dirección de memoria donde comienza el vector que
+ almacena las coordenadas X de los puntos dato.
+\param[in] y Puntero a la dirección de memoria donde comienza el vector que
+ almacena los valores de la función a interpolar, correspondientes a
+ cada posición del vector pasado en el argumento \em x.
+\param[in] nDatos Tamaño de los vectores \em x e \em y.
+\param[in,out] xInterp Puntero a la dirección de memoria donde comienza el
+ vector que almacena las coordenadas X de los puntos a interpolar.
+ Al término de la ejecución de la función, este argumento almacena
+ las coordenadas Y interpoladas.
+\param[in] nInterp Tamaño del vector \em xInterp.
+\note El código de esta función es una modificación de la versión que se puede
+ encontrar en:
+ http://koders.com/cpp/fid16BE3A5D46A7AC7BF84EECB1ADBF99B913A8F610.aspx
+\note El código original está acogido a la GNU Lesser General Public License
+ Version 2.1
+\note Esta función no controla internamente si los vectores \em x e \em y son
+ del tamaño especificado en \em nDatos.
+\note Esta función no controla internamente si el vector \em xInterp es del
+ tamaño especificado en \em nInterp.
+\note Esta función no controla internamente si las coordenadas X de los puntos a
+ interpolar están dentro o fuera de los límites de los puntos dato.
+\date 02 de marzo de 2009: Creación de la función.
+\todo Esta función todavía no está programada.
+*/
+void SplineCubicoNatural(double* x,
+ double* y,
+ size_t nDatos,
+ double* xInterp,
+ size_t nInterp);
+/******************************************************************************/
+/******************************************************************************/
+#ifdef __cplusplus
+}
+#endif
+/******************************************************************************/
+/******************************************************************************/
+#endif
+/******************************************************************************/
+/******************************************************************************/
+/** @} */
+/******************************************************************************/
+/******************************************************************************/
+/* kate: encoding utf-8; end-of-line unix; syntax c; indent-mode cstyle; */
+/* kate: replace-tabs on; space-indent on; tab-indents off; indent-width 4; */
+/* kate: line-numbers on; folding-markers on; remove-trailing-space on; */
+/* kate: backspace-indents on; show-tabs on; */
+/* kate: word-wrap-column 80; word-wrap-marker-color #D2D2D2; word-wrap off; */
diff --git a/src/libgeoc/polig.h b/src/libgeoc/polig.h
index 0588800..50f8812 100755..100644
--- a/src/libgeoc/polig.h
+++ b/src/libgeoc/polig.h
@@ -8,12 +8,12 @@
\author José Luis García Pallero, jgpallero@gmail.com
\note Este fichero contiene funciones paralelizadas con OpenMP.
\date 20 de abril de 2011
-\section Licencia Licencia
-Copyright (c) 2011, José Luis García Pallero. All rights reserved.
-
+\copyright
+Copyright (c) 2011-2020, José Luis García Pallero. All rights reserved.
+\par
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
-
+\par
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this
@@ -22,7 +22,7 @@ are permitted provided that the following conditions are met:
- Neither the name of the copyright holders nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
-
+\par
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -43,11 +43,15 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
+#include"libgeoc/arco.h"
+#include"libgeoc/constantes.h"
#include"libgeoc/dpeucker.h"
+#include"libgeoc/dpeuckera.h"
#include"libgeoc/errores.h"
#include"libgeoc/fgeneral.h"
#include"libgeoc/geocnan.h"
#include"libgeoc/geocomp.h"
+#include"libgeoc/proyecaux.h"
/******************************************************************************/
/******************************************************************************/
#ifdef __cplusplus
@@ -62,6 +66,7 @@ extern "C" {
\date 26 de mayo de 2011: Reorganización total de la estructura.
\date 28 de mayo de 2011: Adición de los campos polig::hayArea, polig::area,
polig::hayLim, polig::xMin, polig::xMax, polig::yMin e polig::yMax.
+\date 10 de mayo de 2020: Adición del campo polig::atr.
*/
typedef struct
{
@@ -156,6 +161,13 @@ typedef struct
contrario al de las agujas del reloj.
*/
double* area;
+ /**
+ \brief Vector de polig::nPolig elementos, que almacena un atributo
+ cualquiera elegido por el usuario referido a cada polígono. Este
+ campo sólo sirve para posibles manejos del usuario en el empleo de
+ la estructura. Los elementos se inicializan con el valor 0.
+ */
+ int* atr;
}polig;
/******************************************************************************/
/******************************************************************************/
@@ -190,8 +202,7 @@ polig* IniciaPoligVacio(void);
/**
\brief Función auxiliar para la rutina de creación de una estructura \ref polig
a partir de dos vectores que contienen las coordenadas de los vértices.
-
- Esta función calcula el número máximo de elementos que almacenarán los
+\brief Esta función calcula el número máximo de elementos que almacenarán los
vectores de coordenadas de una estructura \ref polig y el número de
polígonos almacenados en los vectores de trabajo.
\param[in] nElem Número de elementos de los vectores de coordenadas originales.
@@ -231,8 +242,7 @@ int AuxCreaPolig1(const size_t nElem,
/**
\brief Función auxiliar para la rutina de creación de una estructura \ref polig
a partir de dos vectores que contienen las coordenadas de los vértices.
-
- Esta función copia una serie de datos de dos vectores en otros dos.
+\brief Esta función copia una serie de datos de dos vectores en otros dos.
\param[in] x Vector que contiene las coordenadas X de los vértices a copiar.
\param[in] y Vector que contiene las coordenadas Y de los vértices a copiar.
\param[in] nElem Número de elementos de los vectores \em x e \em y.
@@ -269,8 +279,7 @@ void AuxCreaPolig2(const double* x,
/**
\brief Función auxiliar para las rutinas de creación de estructuras \ref polig
a partir de dos vectores que contienen las coordenadas de los vértices.
-
- Esta función crea los polígonos en el formato de almacenamiento de
+\brief Esta función crea los polígonos en el formato de almacenamiento de
\ref polig a partir de los vectores de entrada.
\param[in] x Vector que contiene las coordenadas X de los vértices de trabajo.
\param[in] y Vector que contiene las coordenadas Y de los vértices de trabajo.
@@ -350,7 +359,8 @@ void AuxCreaPolig3(const double* x,
\em incY.
\note Si los vectores \em x e \em y almacenan varios polígonos, éstos se separan
mediante valores #GEOC_NAN. Poner #GEOC_NAN en la primera posición y/o la
- última es opcional.
+ última es opcional, pero sea cual sea la elección ha de ser la misma para
+ los dos vectores.
\note Los posibles valores #GEOC_NAN han de estar en las mismas posiciones en
\em x e \em y.
\note Para los polígonos, es opcional repetir las coordenadas del primer vértice
@@ -624,20 +634,49 @@ void LimitesPoligonosPolig(const double* x,
\param[in,out] poli Estructura \ref polig, que almacena una serie de polígonos.
Al término de la ejecución de la función, se han añadido las
superficies de los polígonos almacenados.
+\param[in] facCoor Factor a aplicar a las coordenadas antes del cálculo de las
+ superficies. Si los cálculos se van a hacer sobre el elipsoide, este
+ argumento debe llevar las coordenadas a radianes, si no lo están.
+\param[in] geo Identificador de que el polígono está sobre la superficie del
+ elipsoide. Dos posibilidades:
+ - 0: El polígono está en el plano euclideo.
+ - Distinto de 0: El polígono está sobre la superficie del elipsoide.
+\param[in] a Semieje mayor del elipsoide. Este argumento sólo es tenido en
+ cuenta si se ha indicado trabajo sobre el elipsoide mediante el
+ argumento \em geo.
+\param[in] f Aplanamiento del elipsoide. Este argumento sólo es tenido en
+ cuenta si se ha indicado trabajo sobre el elipsoide mediante el
+ argumento \em geo.
\return Variable de error. Dos posibilidades:
- #GEOC_ERR_NO_ERROR: Todo ha ido bien.
- #GEOC_ERR_ASIG_MEMORIA: Ha ocurrido un error de asignación de memoria.
\note Esta función asume que la estructura de entrada \ref polig tiene memoria
asignada.
+\note El área calculada sólo es correcta si el polígono es simple, esto es, si
+ sus lados no se cortan entre ellos mismos (ver la documentación de
+ polig::area).
+\note Se asume que \em facCoor>0.0, condición que no se controla internamente.
\note En caso de error de asignación de memoria, la memoria de la estructura de
entrada no se libera.
+\note El cálculo del área sobre el elipsoide se realiza proyectando los puntos
+ mediante una proyección cilíndrica equivalente de Lambert.
\date 29 de mayo de 2011: Creación de la función.
\date 01 de agosto de 2011: Corregido error que hacía que se calculasen mal las
superficies debido a un incorrecto uso del argumento \em restaPosIni de la
función \ref AreaPoligonosSimplesPolig.
+\date 16 de agosto de 2013: Adición de la capacidad de cálculo de áreas para
+ polígonos sobre la superficie del elipsoide.
+\date 17 de agosto de 2013: Modificación de la función para que el área se
+ calcule siempre, aunque la estructura ya la contenga. Se dota de esta
+ capacidad por si se llama repetidas veces a la función con valores
+ distintos de \em facCoor.
\note Esta función todavía no está probada.
*/
-int CalcAreaPolig(polig* poli);
+int CalcAreaPolig(polig* poli,
+ const double facCoor,
+ const int geo,
+ const double a,
+ const double f);
/******************************************************************************/
/******************************************************************************/
/**
@@ -893,61 +932,110 @@ void MuevePolig(polig* poli,
Al término de la ejecución de la función, almacena el resultado
de la aplicación a cada polígono del algoritmo de aligerado de
vértices implementado en la función \ref AligeraPolilinea.
-\param[in] tol Tolerancia para eliminar vértices, en las mismas unidades que las
- coordenadas de los vértices. Ver la ayuda de la función
- \ref AligeraPolilinea.
+\param[in] esf Identificador de que el polígono está sobre la superficie de la
+ esfera. Dos posibilidades:
+ - 0: El polígono está en el plano euclideo.
+ - Distinto de 0: El polígono está sobre la esfera.
+\param[in] facCoor Factor de escala a aplicar a las coordenadas del polígono
+ para realizar el aligerado. Si se trabaja sobre la esfera, este
+ argumento ha de llevar las coordenadas de los puntos de trabajo a
+ radianes. Las coordenadas devueltas al término de la ejecución de
+ está función no se verán afectadas por este factor.
+\param[in] tol Tolerancia para eliminar vértices. Si se trabaja sobre la
+ superficie de la esfera, este valor ha de estar en radianes, es
+ decir, será una distancia sobre la superficie de la esfera de radio
+ unidad. Ver la ayuda de la función \ref AligeraPolilinea.
+\param[in] paralelizaTol Identificador para evaluar o no en paralelo si los
+ puntos candidatos están en tolerancia. Dos posibilidades:
+ - 0: Se evalúa en serie (aunque la compilación se haya hecho en
+ paralelo) si los puntos están en tolerancia.
+ - Distinto de 0: Se evalúa en paralelo (sólo si se ha compilado en
+ paralelo) si los puntos están en tolerancia.
\param[in] robusto Identificador para realizar o no un aligerado robusto. Ha de
ser un elemento del tipo enumerado #GEOC_DPEUCKER_ROBUSTO. Varias
posibilidades:
- - #GeocDPeuckerRobNo: No se aplica el algoritmo robusto.
+ - #GeocDPeuckerOriginal: Utiliza el algoritmo de Douglas-Peucker
+ original, que no es robusto.
+ - #GeocDPeuckerRobNo: Utiliza la variación no recursiva del algoritmo
+ de Douglas-Peucker, que no es robusta.
- #GeocDPeuckerRobSi: Se aplica el algoritmo robusto completo, que
- garantiza la no ocurrencia de auto intersecciones en el polígono
+ garantiza la no ocurrencia de auto intersecciones en la polilínea
resultante. Internamente, primero se aplica el tratamiento robusto
de la opción #GeocDPeuckerRobOrig y luego el de la opción
#GeocDPeuckerRobAuto.
- #GeocDPeuckerRobOrig: Se aplica un algoritmo semi robusto que
- consiste en garantizar que los segmentos del polígono aligerado que
- se van creando no intersectarán con ninguno de los segmentos que
- forman los vértices que quedan por procesar del polígono original.
- En casos muy especiales, este algoritmo puede seguir dando lugar a
- auto intersecciones.
+ consiste en garantizar que los segmentos de la polilínea aligerada
+ que se van creando no intersectarán con ninguno de los segmentos
+ que forman los vértices que quedan por procesar de la polilínea
+ original. En casos muy especiales, este algoritmo puede seguir
+ dando lugar a auto intersecciones.
- #GeocDPeuckerRobAuto: Se aplica un algoritmo semi robusto que
- consiste en garantizar que los segmentos del polígono aligerado que
- se van creando no intersectarán con ninguno de los segmentos del
- polígono aligerado creados con anterioridad. En casos muy
+ consiste en garantizar que los segmentos de la polilínea aligerada
+ que se van creando no intersectarán con ninguno de los segmentos de
+ la polilínea aligerada creados con anterioridad. En casos muy
especiales, este algoritmo puede seguir dando lugar a auto
intersecciones.
-\param[in] nPtosRobusto Número de puntos del polígono original a utilizar en el
- caso de tratamiento robusto con las opciones #GeocDPeuckerRobSi o
- #GeocDPeuckerRobOrig. Si se pasa el valor 0, se utilizan todos los
- puntos hasta el final del polígono original.
-\param[in] nSegRobusto Número de segmentos del polígono aligerado a utilizar en
- el caso de tratamiento robusto con las opciones #GeocDPeuckerRobSi o
- #GeocDPeuckerRobAuto. Si se pasa el valor 0, se utilizan todos los
- segmentos hasta el inicio del polígono aligerado.
+\param[in] nSegRobOrig Número de segmentos/arcos de la polilínea original a
+ utilizar en el caso de tratamiento robusto con las opciones
+ #GeocDPeuckerRobSi o #GeocDPeuckerRobOrig. Si se pasa el valor 0, se
+ utilizan todos los segmentos/arcos hasta el final de la polilínea
+ original.
+\param[in] nSegRobAuto Número de segmentos de la polilínea aligerada a utilizar
+ en el caso de tratamiento robusto con las opciones #GeocDPeuckerRobSi
+ o #GeocDPeuckerRobAuto. Si se pasa el valor 0, se utilizan todos los
+ segmentos hasta el inicio de la polilínea aligerada.
+\param[in] a Semieje mayor del elipsoide. Este argumento sólo es tenido en
+ cuenta si se ha indicado trabajo sobre el elipsoide mediante el
+ argumento \em geo.
+\param[in] f Aplanamiento del elipsoide. Este argumento sólo es tenido en
+ cuenta si se ha indicado trabajo sobre el elipsoide mediante el
+ argumento \em geo.
\return Variable de error. Dos posibilidades:
- #GEOC_ERR_NO_ERROR: Todo ha ido bien.
- #GEOC_ERR_ASIG_MEMORIA: Ha ocurrido un error de asignación de memoria.
\note Esta función asume que \em poli está, como mínimo, inicializado.
\note Si \em poli tiene límites y/o áreas calculadas en la entrada, también los
tendrá en la salida.
-\note Un polígono aligerado sólo será válido si después de aplicarle la función
- \ref AligeraPolilinea mantiene un mínimo de 3 puntos no alineados por lo
- que, al término de la ejecución de esta función, el resultado puede ser
- una estructura \ref polig vacía.
+\note Si \em poli está sobre la superficie de la esfera, el campo polig::x
+ almacenará la longitud, mientras que polig::y almacenará la latitud. Del
+ mismo modo, los límites polig::xMin y polig::xMax almacenarán longitudes y
+ polig::yMin y polig::yMax, latitudes.
+\note Se asume que \em facCoor>0.0, condición que no se controla internamente.
+\note Un polígono aligerado sólo será válido si después de aplicarle la
+ función \ref AligeraPolilinea mantiene un mínimo de 3 puntos no alineados,
+ por lo que, al término de la ejecución de esta función, el resultado puede
+ ser una estructura \ref polig vacía.
+\note El argumento \em paralelizaTol \b SÓLO afecta a la paralelización de la
+ comprobación de puntos en tolerancia. Los chequeos de intersección de
+ segmentos/arcos siempre se hacen en paralelo (si el código ha sido
+ compilado al efecto).
\date 09 de julio de 2011: Creación de la función.
\date 10 de julio de 2011: Cambio del tipo del argumento \em robusto al tipo
enumerado #GEOC_DPEUCKER_ROBUSTO.
\date 31 de julio de 2011: Corregido error con índices a la hora de guardar los
resultados y comprobación de que los polígonos de salida no estén
compuestos por tres puntos alineados.
+\date 25 de mayo de 2012: Adición de la posibilidad de usar el algoritmo de
+ Douglas-Peucker original.
+\date 16 de agosto de 2013: Adición de la capacidad de trabajar con polígonos en
+ la superficie de la esfera.
+\date 20 de agosto de 2013: Sustitución de las antiguas variables de entrada
+ \em nPtosRobusto y \em nSegRobusto por \em nSegRobOrig y \em nSegRobAuto.
+\date 23 de agosto de 2013: Adición del argumento de entrada \em paralelizaTol.
+\date 21 de septiembre de 2013: Adición de la capacidad de trabajar sobre la
+ esfera con el algoritmo de Douglas-Peucker original.
\todo Esta función todavía no está probada.
*/
int AligeraPolig(polig* poli,
+ const int esf,
+ const double facCoor,
const double tol,
+ const int paralelizaTol,
const enum GEOC_DPEUCKER_ROBUSTO robusto,
- const size_t nPtosRobusto,
- const size_t nSegRobusto);
+ const size_t nSegRobOrig,
+ const size_t nSegRobAuto,
+ const double a,
+ const double f);
/******************************************************************************/
/******************************************************************************/
/**
@@ -960,16 +1048,23 @@ int AligeraPolig(polig* poli,
del polígono de trabajo. Dos posibles valores:
- 0: No se imprimen.
- Distinto de 0: Sí se imprimen.
-\param[in] formCoor Cadena de carácteres indicadora del formato para escribir
+\param[in] formCoor Cadena de caracteres indicadora del formato para escribir
las coordenadas de los límites. Este argumento sólo se usa
internamente si se ha indicado la impresión de límites.
\param[in] impArea Identificador para imprimir o no la superficie del polígono
de trabajo. Dos posibles valores:
- 0: No se imprime.
- Distinto de 0: Sí se imprime.
-\param[in] formArea Cadena de carácteres indicadora del formato para escribir el
+\param[in] formArea Cadena de caracteres indicadora del formato para escribir el
valor de la superficie. Este argumento sólo se usa internamente si se
ha indicado la impresión de la superficie del polígono.
+\param[in] impAtr Identificador para imprimir o no el atributo almacenado en
+ polig::atr. Dos posibles valores:
+ - 0: No se imprime.
+ - Distinto de 0: Sí se imprime.
+\param[in] formAtr Cadena de caracteres indicadora del formato para escribir el
+ valor del atributo. Este argumento sólo se usa internamente si se
+ ha indicado la impresión del atributo.
\param[in] factorX Factor para multiplicar las coordenadas X de los vértices
antes de imprimirlas.
\param[in] factorY Factor para multiplicar las coordenadas Y de los vértices
@@ -983,9 +1078,12 @@ int AligeraPolig(polig* poli,
\param[in] idFich Identificador de fichero abierto para escribir.
\note Esta función está paralelizada con OpenMP.
\note La cabecera completa tiene el siguiente formato:
- <tt>iniCab númVert área xMín xMáx yMín yMáx</tt>.
+ <tt>iniCab númVert área xMín xMáx yMín yMáx atributo</tt>.
\note Si la estructura no tiene información de límites y/o áreas y se indica que
se impriman, los valores se calculan internamente.
+\note El área imprimida sólo es correcta si el polígono es simple, esto es, si
+ sus lados no se cortan entre ellos mismos (ver la documentación de
+ polig::area).
\note Esta función asume que \em poli es una estructura \ref polig correctamente
almacenada.
\note Esta función no comprueba si la estructura pasada tiene memoria asignada.
@@ -994,6 +1092,7 @@ int AligeraPolig(polig* poli,
\note Esta función no comprueba internamente si el identificador pasado
corresponde a un fichero abierto para escribir.
\date 18 de junio de 2011: Creación de la función.
+\date 10 de mayo de 2020: Adición de los argumentos \em impAtr y \em formAtr.
\note Esta función todavía no está probada.
*/
void ImprimeCabeceraPoligFichero(const polig* poli,
@@ -1003,6 +1102,8 @@ void ImprimeCabeceraPoligFichero(const polig* poli,
const char formCoor[],
const int impArea,
const char formArea[],
+ const int impAtr,
+ const char formAtr[],
const double factorX,
const double factorY,
const int repitePrimerPunto,
@@ -1029,7 +1130,7 @@ void ImprimeCabeceraPoligFichero(const polig* poli,
polígonos (\p NaN) detrás del último polígono. Dos posibles valores:
- 0: No se imprime.
- Distinto de 0: Sí se imprime.
-\param[in] formCoor Cadena de carácteres indicadora del formato de cada
+\param[in] formCoor Cadena de caracteres indicadora del formato de cada
coordenada a imprimir.
\param[in] impCabecera Identificador para imprimir o no una cabecera con
información general por cada polígono. Dos posibles valores:
@@ -1044,14 +1145,24 @@ void ImprimeCabeceraPoligFichero(const polig* poli,
de los polígonos de trabajo. Dos posibles valores:
- 0: No se imprime.
- Distinto de 0: Sí se imprime.
-\param[in] formArea Cadena de carácteres indicadora del formato para escribir el
+\param[in] formArea Cadena de caracteres indicadora del formato para escribir el
valor de la superficie. Este argumento sólo se usa internamente si se
ha indicado la impresión de la superficie de los polígonos.
+\param[in] impAtr Identificador para imprimir o no el atributo almacenado en
+ polig::atr. Dos posibles valores:
+ - 0: No se imprime.
+ - Distinto de 0: Sí se imprime.
+\param[in] formAtr Cadena de caracteres indicadora del formato para escribir el
+ valor del atributo. Este argumento sólo se usa internamente si se
+ ha indicado la impresión del atributo.
\param[in] idFich Identificador de fichero abierto para escribir.
\note La cabecera completa tiene el siguiente formato:
- <tt>iniCab númVert área xMín xMáx yMín yMáx</tt>.
+ <tt>iniCab númVert área xMín xMáx yMín yMáx atributo</tt>.
\note Si la estructura no tiene información de límites y/o áreas y se indica que
se impriman, los valores se calculan internamente.
+\note El área imprimida sólo es correcta si el polígono es simple, esto es, si
+ sus lados no se cortan entre ellos mismos (ver la documentación de
+ polig::area).
\note Esta función asume que \em poli es una estructura \ref polig correctamente
almacenada.
\note Esta función no comprueba si la estructura pasada tiene memoria asignada.
@@ -1066,6 +1177,7 @@ void ImprimeCabeceraPoligFichero(const polig* poli,
\date 22 de septiembre de 2011: Corregido bug que hacía que, dependiendo del
compilador y/o los flags de optimización en la compilación, se imprimiesen
mal (con un signo menos delante) los valores Not-a-Number.
+\date 10 de mayo de 2020: Adición de los argumentos \em impAtr y \em formAtr.
\note Esta función todavía no está probada.
*/
void ImprimePoligFichero(const polig* poli,
@@ -1080,6 +1192,8 @@ void ImprimePoligFichero(const polig* poli,
const int impLim,
const int impArea,
const char formArea[],
+ const int impAtr,
+ const char formAtr[],
FILE* idFich);
/******************************************************************************/
/******************************************************************************/
diff --git a/src/libgeoc/polil.h b/src/libgeoc/polil.h
index 174ffae..8c9a73d 100755..100644
--- a/src/libgeoc/polil.h
+++ b/src/libgeoc/polil.h
@@ -8,12 +8,12 @@
\author José Luis García Pallero, jgpallero@gmail.com
\note Este fichero contiene funciones paralelizadas con OpenMP.
\date 03 de junio de 2011
-\section Licencia Licencia
-Copyright (c) 2011, José Luis García Pallero. All rights reserved.
-
+\copyright
+Copyright (c) 2011-2013, José Luis García Pallero. All rights reserved.
+\par
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
-
+\par
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this
@@ -22,7 +22,7 @@ are permitted provided that the following conditions are met:
- Neither the name of the copyright holders nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
-
+\par
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -43,6 +43,7 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include<stdio.h>
#include<stdlib.h>
#include"libgeoc/dpeucker.h"
+#include"libgeoc/dpeuckera.h"
#include"libgeoc/errores.h"
#include"libgeoc/fgeneral.h"
#include"libgeoc/geocnan.h"
@@ -162,8 +163,7 @@ polil* IniciaPolilVacia(void);
/**
\brief Función auxiliar para la rutina de creación de una estructura \ref polil
a partir de dos vectores que contienen las coordenadas de los vértices.
-
- Esta función calcula el número máximo de elementos que almacenarán los
+\brief Esta función calcula el número máximo de elementos que almacenarán los
vectores de coordenadas de una estructura \ref polil y el número de
polilíneas almacenadas en los vectores de trabajo.
\param[in] nElem Número de elementos de los vectores de coordenadas originales.
@@ -206,8 +206,7 @@ int AuxCreaPolil1(const size_t nElem,
/**
\brief Función auxiliar para la rutina de creación de una estructura \ref polil
a partir de dos vectores que contienen las coordenadas de los vértices.
-
- Esta función copia una serie de datos de dos vectores en otros dos.
+\brief Esta función copia una serie de datos de dos vectores en otros dos.
\param[in] x Vector que contiene las coordenadas X de los vértices a copiar.
\param[in] y Vector que contiene las coordenadas Y de los vértices a copiar.
\param[in] nElem Número de elementos de los vectores \em x e \em y.
@@ -237,8 +236,7 @@ void AuxCreaPolil2(const double* x,
/**
\brief Función auxiliar para las rutinas de creación de estructuras \ref polil
a partir de dos vectores que contienen las coordenadas de los vértices.
-
- Esta función crea las polilíneas en el formato de almacenamiento de
+\brief Esta función crea las polilíneas en el formato de almacenamiento de
\ref polil a partir de los vectores de entrada.
\param[in] x Vector que contiene las coordenadas X de los vértices de trabajo.
\param[in] y Vector que contiene las coordenadas Y de los vértices de trabajo.
@@ -619,13 +617,32 @@ void MuevePolil(polil* poli,
Al término de la ejecución de la función, almacena el resultado
de la aplicación a cada polilínea del algoritmo de aligerado de
vértices implementado en la función \ref AligeraPolilinea.
-\param[in] tol Tolerancia para eliminar vértices, en las mismas unidades que las
- coordenadas de los vértices. Ver la ayuda de la función
- \ref AligeraPolilinea.
+\param[in] esf Identificador de que la polilínea está sobre la superficie de la
+ esfera. Dos posibilidades:
+ - 0: La polilínea está en el plano euclideo.
+ - Distinto de 0: La polilínea está sobre la esfera.
+\param[in] facCoor Factor de escala a aplicar a las coordenadas de la polilínea
+ para realizar el aligerado. Si se trabaja sobre la esfera, este
+ argumento ha de llevar las coordenadas de los puntos de trabajo a
+ radianes. Las coordenadas devueltas al término de la ejecución de
+ está función no se verán afectadas por este factor.
+\param[in] tol Tolerancia para eliminar vértices. Si se trabaja sobre la
+ superficie de la esfera, este valor ha de estar en radianes, es
+ decir, será una distancia sobre la superficie de la esfera de radio
+ unidad. Ver la ayuda de la función \ref AligeraPolilinea.
+\param[in] paralelizaTol Identificador para evaluar o no en paralelo si los
+ puntos candidatos están en tolerancia. Dos posibilidades:
+ - 0: Se evalúa en serie (aunque la compilación se haya hecho en
+ paralelo) si los puntos están en tolerancia.
+ - Distinto de 0: Se evalúa en paralelo (sólo si se ha compilado en
+ paralelo) si los puntos están en tolerancia.
\param[in] robusto Identificador para realizar o no un aligerado robusto. Ha de
ser un elemento del tipo enumerado #GEOC_DPEUCKER_ROBUSTO. Varias
posibilidades:
- - #GeocDPeuckerRobNo: No se aplica el algoritmo robusto.
+ - #GeocDPeuckerOriginal: Utiliza el algoritmo de Douglas-Peucker
+ original, que no es robusto.
+ - #GeocDPeuckerRobNo: Utiliza la variación no recursiva del algoritmo
+ de Douglas-Peucker, que no es robusta.
- #GeocDPeuckerRobSi: Se aplica el algoritmo robusto completo, que
garantiza la no ocurrencia de auto intersecciones en la polilínea
resultante. Internamente, primero se aplica el tratamiento robusto
@@ -643,11 +660,12 @@ void MuevePolil(polil* poli,
la polilínea aligerada creados con anterioridad. En casos muy
especiales, este algoritmo puede seguir dando lugar a auto
intersecciones.
-\param[in] nPtosRobusto Número de puntos de la polilínea original a utilizar en
- el caso de tratamiento robusto con las opciones #GeocDPeuckerRobSi o
- #GeocDPeuckerRobOrig. Si se pasa el valor 0, se utilizan todos los
- puntos hasta el final de la polilínea original.
-\param[in] nSegRobusto Número de segmentos de la polilínea aligerada a utilizar
+\param[in] nSegRobOrig Número de segmentos/arcos de la polilínea original a
+ utilizar en el caso de tratamiento robusto con las opciones
+ #GeocDPeuckerRobSi o #GeocDPeuckerRobOrig. Si se pasa el valor 0, se
+ utilizan todos los segmentos/arcos hasta el final de la polilínea
+ original.
+\param[in] nSegRobAuto Número de segmentos de la polilínea aligerada a utilizar
en el caso de tratamiento robusto con las opciones #GeocDPeuckerRobSi
o #GeocDPeuckerRobAuto. Si se pasa el valor 0, se utilizan todos los
segmentos hasta el inicio de la polilínea aligerada.
@@ -657,25 +675,44 @@ void MuevePolil(polil* poli,
\note Esta función asume que \em poli está, como mínimo, inicializada.
\note Si \em poli tiene límites calculados en la entrada, también los tendrá en
la salida.
+\note Si \em poli está sobre la superficie de la esfera, el campo polil::x
+ almacenará la longitud, mientras que polil::y almacenará la latitud. Del
+ mismo modo, los límites polil::xMin y polil::xMax almacenarán longitudes y
+ polil::yMin y polil::yMax, latitudes.
+\note Se asume que \em facCoor>0.0, condición que no se controla internamente.
\note Una polilínea aligerada sólo será válida si después de aplicarle la
función \ref AligeraPolilinea mantiene un mínimo de 2 puntos que no sean
- el mismo (esto sólo puede ocurrir si se pasa un polígono -los vértices de
- inicio y final coinciden- y sólo quedan al final los extremos). Al término
- de la ejecución de esta función, el resultado puede ser una estructura
- \ref polil vacía.
+ el mismo. Al término de la ejecución de esta función, el resultado puede
+ ser una estructura \ref polil vacía.
+\note El argumento \em paralelizaTol \b SÓLO afecta a la paralelización de la
+ comprobación de puntos en tolerancia. Los chequeos de intersección de
+ segmentos/arcos siempre se hacen en paralelo (si el código ha sido
+ compilado al efecto).
\date 09 de julio de 2011: Creación de la función.
\date 10 de julio de 2011: Cambio del tipo del argumento \em robusto al tipo
enumerado #GEOC_DPEUCKER_ROBUSTO.
\date 31 de julio de 2011: Corregido error con índices a la hora de guardar los
resultados y modificación para no tomar como válidas las polilíneas que se
quedan en sólo dos vértices que sean el mismo.
+\date 25 de mayo de 2012: Adición de la posibilidad de usar el algoritmo de
+ Douglas-Peucker original.
+\date 16 de agosto de 2013: Adición de la capacidad de trabajar con polilíneas
+ en la superficie de la esfera.
+\date 20 de agosto de 2013: Sustitución de las antiguas variables de entrada
+ \em nPtosRobusto y \em nSegRobusto por \em nSegRobOrig y \em nSegRobAuto.
+\date 23 de agosto de 2013: Adición del argumento de entrada \em paralelizaTol.
+\date 21 de septiembre de 2013: Adición de la capacidad de trabajar sobre la
+ esfera con el algoritmo de Douglas-Peucker original.
\todo Esta función todavía no está probada.
*/
int AligeraPolil(polil* poli,
+ const int esf,
+ const double facCoor,
const double tol,
+ const int paralelizaTol,
const enum GEOC_DPEUCKER_ROBUSTO robusto,
- const size_t nPtosRobusto,
- const size_t nSegRobusto);
+ const size_t nSegRobOrig,
+ const size_t nSegRobAuto);
/******************************************************************************/
/******************************************************************************/
/**
@@ -688,7 +725,7 @@ int AligeraPolil(polil* poli,
de la polilínea de trabajo. Dos posibles valores:
- 0: No se imprimen.
- Distinto de 0: Sí se imprimen.
-\param[in] formCoor Cadena de carácteres indicadora del formato para escribir
+\param[in] formCoor Cadena de caracteres indicadora del formato para escribir
las coordenadas de los límites. Este argumento sólo se usa
internamente si se ha indicado la impresión de límites.
\param[in] factorX Factor para multiplicar las coordenadas X de los vértices
@@ -738,7 +775,7 @@ void ImprimeCabeceraPolilFichero(const polil* poli,
valores:
- 0: No se imprime.
- Distinto de 0: Sí se imprime.
-\param[in] formCoor Cadena de carácteres indicadora del formato de cada
+\param[in] formCoor Cadena de caracteres indicadora del formato de cada
coordenada a imprimir.
\param[in] impCabecera Identificador para imprimir o no una cabecera con
información general por cada polilínea. Dos posibles valores:
diff --git a/src/libgeoc/posmatvec.h b/src/libgeoc/posmatvec.h
new file mode 100644
index 0000000..126ffa8
--- /dev/null
+++ b/src/libgeoc/posmatvec.h
@@ -0,0 +1,512 @@
+/* -*- coding: utf-8 -*- */
+/**
+\ingroup algebra anespec geopot gshhs matriz mmcc snx
+@{
+\file posmatvec.h
+\brief Declaración de funciones para realizar cálculos de posiciones de
+ elementos en matrices almacenadas en formato vector.
+
+En el momento de la compilación de las funciones de cálculo de posición ha de
+seleccionarse el tipo de almacenamiento matricial. Para realizar la selección es
+necesario definir la variable \em ROW_MAJOR_ORDER_MATVEC si se quiere
+almacenamiento de tipo ROW MAJOR ORDER o \em COLUMN_MAJOR_ORDER_MATVEC si se
+quiere almacenamiento de tipo COLUMN MAJOR ORDER. En \p gcc, las variables para
+el preprocesador se pasan como \em -DXXX, donde \em XXX es la variable a
+introducir.
+
+Una matriz puede ser almacenada en formato vector de dos formas distintas: ROW
+MAJOR ORDER y COLUMN MAJOR ORDER. En la primera, la matriz es almacenada por
+filas, mientras que en la segunda lo es por columnas. Por ejemplo, la matriz
+\code
+m = [1 2 3 4
+ 5 6 7 8]
+\endcode
+será almacenada en ROW MAJOR ORDER como
+\code
+m = [1 2 3 4 5 6 7 8]
+\endcode
+y en COLUMN MAJOR ORDER como
+\code
+m = [1 5 2 6 3 7 4 8]
+\endcode
+\author José Luis García Pallero, jgpallero@gmail.com
+\date 14 de enero de 2009
+\section Licencia Licencia
+Copyright (c) 2009-2013, José Luis García Pallero. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+- Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+- Neither the name of the copyright holders nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/******************************************************************************/
+/******************************************************************************/
+#ifndef _POSMATVEC_H_
+#define _POSMATVEC_H_
+/******************************************************************************/
+/******************************************************************************/
+#include<stdlib.h>
+#include<string.h>
+/******************************************************************************/
+/******************************************************************************/
+#ifdef __cplusplus
+extern "C" {
+#endif
+/******************************************************************************/
+/******************************************************************************/
+/**
+\def GEOC_LON_CAD_COD_ALM
+\brief Longitud máxima de una cadena para almacenar el código identificador de
+ tipo de almacenamiento matricial.
+\date 25 de septiembre de 2009: Creación de la constante.
+*/
+#define GEOC_LON_CAD_COD_ALM 25
+/******************************************************************************/
+/******************************************************************************/
+/**
+\def GEOC_MATR_COD_ALM_RMO
+\brief Código identificador de almacenamiento como ROW MAJOR ORDER.
+\date 14 de enero de 2009: Creación de la constante.
+*/
+#define GEOC_MATR_COD_ALM_RMO "ROW-MAJOR-ORDER"
+/******************************************************************************/
+/******************************************************************************/
+/**
+\def GEOC_MATR_COD_ALM_CMO
+\brief Código identificador de almacenamiento como COLUMN MAJOR ORDER.
+\date 14 de enero de 2009: Creación de la constante.
+*/
+#define GEOC_MATR_COD_ALM_CMO "COLUMN-MAJOR-ORDER"
+/******************************************************************************/
+/******************************************************************************/
+/**
+\def GEOC_INICIO_VEC
+\brief Macro para seleccionar el índice correspondiente al primer elemento de un
+ vector dependiendo del valor de las posiciones de separación entre sus
+ elementos. El índice buscado será diferente de 0 cuando el valor de
+ posiciones de separación sea menor que 0.
+\param[in] n Número de elementos del vector. Ha de ser una variable de tipo
+ \p size_t.
+\param[in] inc Posiciones de separación entre los elementos del vector.
+\return Índice del primer elemento del vector.
+\note Esta macro ha sido copiada (sólo se le ha cambiado el nombre) del fichero
+ \em cblas.h del código fuente de la biblioteca \p gsl \p v.1.12, que se
+ distribuye bajo licencia GPL v.3 o posterior.
+\date 19 de noviembre de 2009: Creación de la macro.
+*/
+#define GEOC_INICIO_VEC(n,inc) ((inc) >= 0 ? 0 : ((n)-1)*(size_t)(-(inc)))
+/******************************************************************************/
+/******************************************************************************/
+/**
+\def GEOC_LMFC_RMO
+\brief Devuelve las columnas almacenadas en memoria de una matriz.
+\param[in] filMem Filas de la matriz almacenada en memoria.
+\param[in] colMem Columnas de la matriz almacenada en memoria.
+\return Número de columnas almacenadas en memoria.
+\date 25 de noviembre de 2009: Creación de la macro.
+*/
+//se añade 0*filMem para que el compilador no dé warning por variable no usada
+#define GEOC_LMFC_RMO(filMem,colMem) ((colMem)+0*(filMem))
+/******************************************************************************/
+/******************************************************************************/
+/**
+\def GEOC_LMFC_CMO
+\brief Devuelve las filas almacenadas en memoria de una matriz.
+\param[in] filMem Filas de la matriz almacenada en memoria.
+\param[in] colMem Columnas de la matriz almacenada en memoria.
+\return Número de filas almacenadas en memoria.
+\date 25 de noviembre de 2009: Creación de la macro.
+*/
+//se añade 0*colMem para que el compilador no dé warning por variable no usada
+#define GEOC_LMFC_CMO(filMem,colMem) ((filMem)+0*(colMem))
+/******************************************************************************/
+/******************************************************************************/
+/**
+\def GEOC_POSMATVEC_RMO
+\brief Calcula la posición de un elemento de una matriz almacenada en ROW MAJOR
+ ORDER en el vector que la contiene.
+\param[in] filMem Filas reales (almacenadas en memoria) de la matriz.
+\param[in] colMem Columnas reales (almacenadas en memoria) de la matriz.
+\param[in] fil Fila del elemento de trabajo.
+\param[in] col Columna del elemento de trabajo.
+\return Posición del elemento de trabajo en el vector que almacena la matriz.
+\note Esta macro no comprueba si la posición del elemento de trabajo concuerda
+ con las dimensiones de la matriz.
+\date 25 de noviembre de 2009: Creación de la macro.
+\date 13 de abril de 2010: Cambio de las dimensiones de la matriz por las
+ realmente almacenadas en memoria.
+*/
+//se añade 0*filMem para que el compilador no dé warning por variable no usada
+#define GEOC_POSMATVEC_RMO(filMem,colMem,fil,col) \
+((fil)*(colMem)+(col)+0*(filMem))
+/******************************************************************************/
+/******************************************************************************/
+/**
+\def GEOC_POSMATVEC_CMO
+\brief Calcula la posición de un elemento de una matriz almacenada en COLUMN
+ MAJOR ORDER en el vector que la contiene.
+\param[in] filMem Filas reales (almacenadas en memoria) de la matriz.
+\param[in] colMem Columnas reales (almacenadas en memoria) de la matriz.
+\param[in] fil Fila del elemento de trabajo.
+\param[in] col Columna del elemento de trabajo.
+\return Posición del elemento de trabajo en el vector que almacena la matriz.
+\note Esta macro no comprueba si la posición del elemento de trabajo concuerda
+ con las dimensiones de la matriz.
+\date 25 de noviembre de 2009: Creación de la macro.
+\date 13 de abril de 2010: Cambio de las dimensiones de la matriz por las
+ realmente almacenadas en memoria.
+*/
+//se añade 0*colMem para que el compilador no dé warning por variable no usada
+#define GEOC_POSMATVEC_CMO(filMem,colMem,fil,col) \
+((col)*(filMem)+(fil)+0*(colMem))
+/******************************************************************************/
+/******************************************************************************/
+/**
+\def GEOC_POSMATVEC_TRIEM_INF_RMO
+\brief Calcula la posición de un elemento de una matriz triangular inferior
+ empaquetada en ROW MAJOR ORDER en el vector en el que está almacenada.
+\param[in] dim Dimensiones de la matriz (filas==columnas).
+\param[in] fil Fila del elemento de trabajo.
+\param[in] col Columna del elemento de trabajo.
+\return Posición del elemento de trabajo en el vector que almacena la matriz.
+\note Esta macro no comprueba si la posición del elemento de trabajo concuerda
+ con las dimensiones de la matriz.
+\date 29 de enero de 2011: Creación de la macro.
+*/
+//se añade 0*dim para que el compilador no dé warning por variable no usada
+#define GEOC_POSMATVEC_TRIEM_INF_RMO(dim,fil,col) \
+((col)+(fil)*((fil)+1)/2+0*(dim))
+/******************************************************************************/
+/******************************************************************************/
+/**
+\def GEOC_POSMATVEC_TRIEM_SUP_RMO
+\brief Calcula la posición de un elemento de una matriz triangular superior
+ empaquetada en ROW MAJOR ORDER en el vector en el que está almacenada.
+\param[in] dim Dimensiones de la matriz (filas==columnas).
+\param[in] fil Fila del elemento de trabajo.
+\param[in] col Columna del elemento de trabajo.
+\return Posición del elemento de trabajo en el vector que almacena la matriz.
+\note Esta macro no comprueba si la posición del elemento de trabajo concuerda
+ con las dimensiones de la matriz.
+\date 29 de enero de 2011: Creación de la macro.
+*/
+#define GEOC_POSMATVEC_TRIEM_SUP_RMO(dim,fil,col) \
+((col)-(fil)+(fil)*(2*(dim)-(fil)+1)/2)
+/******************************************************************************/
+/******************************************************************************/
+/**
+\def GEOC_POSMATVEC_TRIEM_INF_CMO
+\brief Calcula la posición de un elemento de una matriz triangular inferior
+ empaquetada en COLUMN MAJOR ORDER en el vector en el que está almacenada.
+\param[in] dim Dimensiones de la matriz (filas==columnas).
+\param[in] fil Fila del elemento de trabajo.
+\param[in] col Columna del elemento de trabajo.
+\return Posición del elemento de trabajo en el vector que almacena la matriz.
+\note Esta macro no comprueba si la posición del elemento de trabajo concuerda
+ con las dimensiones de la matriz.
+\date 29 de enero de 2011: Creación de la macro.
+*/
+#define GEOC_POSMATVEC_TRIEM_INF_CMO(dim,fil,col) \
+((fil)-(col)+(col)*(2*(dim)-(col)+1)/2)
+/******************************************************************************/
+/******************************************************************************/
+/**
+\def GEOC_POSMATVEC_TRIEM_SUP_CMO
+\brief Calcula la posición de un elemento de una matriz triangular superior
+ empaquetada en COLUMN MAJOR ORDER en el vector en el que está almacenada.
+\param[in] dim Dimensiones de la matriz (filas==columnas).
+\param[in] fil Fila del elemento de trabajo.
+\param[in] col Columna del elemento de trabajo.
+\return Posición del elemento de trabajo en el vector que almacena la matriz.
+\note Esta macro no comprueba si la posición del elemento de trabajo concuerda
+ con las dimensiones de la matriz.
+\date 29 de enero de 2011: Creación de la macro.
+*/
+//se añade 0*dim para que el compilador no dé warning por variable no usada
+#define GEOC_POSMATVEC_TRIEM_SUP_CMO(dim,fil,col) \
+((fil)+(col)*((col)+1)/2+0*(dim))
+/******************************************************************************/
+/******************************************************************************/
+/** \enum GEOC_MATR_ID_TRI
+\brief Indicador de parte de triangular de matriz.
+\date 26 de julio de 2009: Creación del tipo.
+*/
+enum GEOC_MATR_ID_TRI
+{
+ /** \brief Indicador de parte triangular superior. */
+ GeocMatTriSup=121,
+ /** \brief Indicador de parte triangular inferior. */
+ GeocMatTriInf=122
+};
+/******************************************************************************/
+/******************************************************************************/
+/** \enum GEOC_MATR_ID_DIAG
+\brief Indicador del contenido de la diagonal de una matriz triangular.
+\date 26 de septiembre de 2009: Creación del tipo.
+*/
+enum GEOC_MATR_ID_DIAG
+{
+ /** \brief Indicador de diagonal con algún elemento distinto de 1. */
+ GeocMatDiagNoUnos=131,
+ /** \brief Indicador de diagonal cuyos elementos son 1. */
+ GeocMatDiagUnos=132
+};
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Comprueba si el tipo de almacenamiento utilizado es COLUMN-MAJOR-ORDER.
+\return Dos posibilidades:
+ - 0: El tipo de almacenamiento es ROW-MAJOR-ORDER.
+ - Distinto de 0: El tipo de almacenamiento es COLUMN-MAJOR-ORDER.
+\note El tipo de almacenamiento se selecciona en el momento de la compilación
+ mediante la definición de una de las siguientes variables:
+ \em ROW_MAJOR_ORDER_MATVEC (para un almacenamiento de tipo
+ ROW MAJOR ORDER) o \em COLUMN_MAJOR_ORDER_MATVEC (para un almacenamiento
+ de tipo COLUMN MAJOR ORDER). En \p gcc, las variables para el
+ preprocesador se pasan como \em -DXXX, donde \em XXX es la variable a
+ introducir.
+\date 29 de julio de 2013: Creación de la función.
+*/
+int EsAlmMatVecCMO(void);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Devuelve el código de almacenamiento utilizado.
+\param[out] tipo Cadena de texto identificadora del tipo de almacenamiento. Una
+ de las almacenadas en #GEOC_MATR_COD_ALM_RMO o
+ #GEOC_MATR_COD_ALM_CMO.
+\note El tipo de almacenamiento se selecciona en el momento de la compilación
+ mediante la definición de una de las siguientes variables:
+ \em ROW_MAJOR_ORDER_MATVEC (para un almacenamiento de tipo
+ ROW MAJOR ORDER) o \em COLUMN_MAJOR_ORDER_MATVEC (para un almacenamiento
+ de tipo COLUMN MAJOR ORDER). En \p gcc, las variables para el
+ preprocesador se pasan como \em -DXXX, donde \em XXX es la variable a
+ introducir.
+\date 14 de enero de 2009: Creación de la función.
+*/
+void TipoAlmMatVec(char tipo[]);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Devuelve la longitud de las filas o columnas almacenadas en memoria de
+ una matriz, según el tipo de almacenamiento utilizado.
+\param[in] filMem Filas de la matriz almacenada en memoria.
+\param[in] colMem Columnas de la matriz almacenada en memoria.
+\return Filas o columnas almacenadas en memoria. Si el tipo de almacenamiento es
+ \em ROW_MAJOR_ORDER_MATVEC se devuelve \em colMem, mientras que si es
+ \em COLUMN_MAJOR_ORDER_MATVEC se devuelve \em filMem.
+\note Esta función comprueba internamente el tipo de almacenamiento utilizado.
+\date 19 de noviembre de 2009: Creación de la función.
+\date 25 de noviembre de 2009: Cálculos internos mediante macros.
+\date 30 de enero de 2011: Añado el identificador \p const a los argumentos de
+ entrada.
+*/
+size_t Lmfc(const size_t filMem,
+ const size_t colMem);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Devuelve las posiciones entre cada elemento de una fila de una matriz
+ densa.
+\param[in] filMem Filas de la matriz realmente almacenadas en memoria.
+\return Posiciones entre cada elemento de las filas de la matriz.
+\note Esta función comprueba internamente el tipo de almacenamiento utilizado.
+\date 30 de enero de 2011: Creación de la función.
+*/
+size_t IncElemFil(const size_t filMem);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Devuelve las posiciones entre cada elemento de una columna de una matriz
+ densa.
+\param[in] colMem Columnas de la matriz realmente almacenadas en memoria.
+\return Posiciones entre cada elemento de las columnas de la matriz.
+\note Esta función comprueba internamente el tipo de almacenamiento utilizado.
+\date 30 de enero de 2011: Creación de la función.
+*/
+size_t IncElemCol(const size_t colMem);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula la posición de un elemento de una matriz en el vector en el que
+ está almacenada.
+\param[in] filMem Filas reales (almacenadas en memoria) de la matriz.
+\param[in] colMem Columnas reales (almacenadas en memoria) de la matriz.
+\param[in] fil Fila del elemento de trabajo.
+\param[in] col Columna del elemento de trabajo.
+\return Posición del elemento de trabajo en el vector que almacena la matriz.
+\note Esta función comprueba internamente el tipo de almacenamiento utilizado.
+\note Esta función no comprueba si la posición del elemento de trabajo concuerda
+ con las dimensiones de la matriz.
+\date 14 de enero de 2009: Creación de la función.
+\date 25 de noviembre de 2009: Cálculos internos mediante macros.
+\date 13 de abril de 2010: Cambio de las dimensiones de la matriz por las
+ realmente almacenadas en memoria.
+*/
+size_t PosMatVec(const size_t filMem,
+ const size_t colMem,
+ const size_t fil,
+ const size_t col);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula la posición en una matriz a partir de la posición en el vector en
+ que está almacenada.
+\param[in] filMem Filas reales (almacenadas en memoria) de la matriz.
+\param[in] colMem Columnas reales (almacenadas en memoria) de la matriz.
+\param[in] posVec Posición en el vector.
+\param[out] fil Columna del elemento de trabajo.
+\param[out] col Columna del elemento de trabajo.
+\note Esta función comprueba internamente el tipo de almacenamiento utilizado.
+\note Esta función no comprueba si la posición del elemento de trabajo concuerda
+ con las dimensiones de la matriz.
+\date 14 de enero de 2009: Creación de la función.
+\date 13 de abril de 2010: Cambio de las dimensiones de la matriz por las
+ realmente almacenadas en memoria.
+*/
+void PosVecMat(const size_t filMem,
+ const size_t colMem,
+ const size_t posVec,
+ size_t* fil,
+ size_t* col);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula la posición de un elemento de una matriz general banda en el
+ vector en el que está almacenada.
+\param[in] diagInf Número de subdiagonales de la matriz.
+\param[in] diagSup Número de superdiagonales de la matriz.
+\param[in] fil Fila del elemento de trabajo.
+\param[in] col Columna del elemento de trabajo.
+\return Posición del elemento de trabajo en el vector que almacena la matriz.
+\note Esta función comprueba internamente el tipo de almacenamiento utilizado.
+\note Esta función no comprueba si la posición del elemento de trabajo concuerda
+ con las dimensiones y la parte que contiene datos de la matriz.
+\date 21 de agosto de 2009: Creación de la función.
+*/
+size_t PosMatGenBanVec(const size_t diagInf,
+ const size_t diagSup,
+ const size_t fil,
+ const size_t col);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula la posición de un elemento de una matriz triangular empaquetada
+ en el vector en el que está almacenada.
+\param[in] dim Dimensiones de la matriz (filas==columnas).
+\param[in] supInf Identificador de matriz triangular superior o inferior. Ha de
+ ser un elemento perteneciente al tipo enumerado #GEOC_MATR_ID_TRI.
+\param[in] fil Fila del elemento de trabajo.
+\param[in] col Columna del elemento de trabajo.
+\return Posición del elemento de trabajo en el vector que almacena la matriz.
+\note Esta función comprueba internamente el tipo de almacenamiento utilizado.
+\note Esta función no comprueba si el argumento \em supInf es correcto.
+\note Esta función no comprueba si la posición del elemento de trabajo concuerda
+ con las dimensiones y la parte triangular de la matriz.
+\date 26 de julio de 2009: Creación de la función.
+*/
+size_t PosMatTriEmVec(const size_t dim,
+ const enum GEOC_MATR_ID_TRI supInf,
+ const size_t fil,
+ const size_t col);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula la posición de un elemento de una matriz triangular banda en el
+ vector en el que está almacenada.
+\param[in] diag Número de superdiagonales o subdiagonales de la matriz.
+\param[in] supInf Identificador de matriz triangular superior o inferior. Ha de
+ ser un elemento perteneciente al tipo enumerado #GEOC_MATR_ID_TRI.
+\param[in] fil Fila del elemento de trabajo.
+\param[in] col Columna del elemento de trabajo.
+\return Posición del elemento de trabajo en el vector que almacena la matriz.
+\note Esta función comprueba internamente el tipo de almacenamiento utilizado.
+\note Esta función no comprueba si el argumento \em supInf es correcto.
+\note Esta función no comprueba si la posición del elemento de trabajo concuerda
+ con las dimensiones y la parte que contiene datos de la matriz.
+\date 27 de septiembre de 2009: Creación de la función.
+*/
+size_t PosMatTriBanVec(const size_t diag,
+ const enum GEOC_MATR_ID_TRI supInf,
+ const size_t fil,
+ const size_t col);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula la posición de un elemento de una matriz simétrica empaquetada en
+ el vector en el que está almacenada.
+\param[in] dim Dimensiones de la matriz (filas==columnas).
+\param[in] supInf Identificador de la parte de matriz simétrica almacenada:
+ superior o inferior. Ha de ser un elemento perteneciente al tipo
+ enumerado #GEOC_MATR_ID_TRI.
+\param[in] fil Fila del elemento de trabajo.
+\param[in] col Columna del elemento de trabajo.
+\return Posición del elemento de trabajo en el vector que almacena la matriz.
+\note Esta función comprueba internamente el tipo de almacenamiento utilizado.
+\note Esta función no comprueba si el argumento \em supInf es correcto.
+\note Esta función no comprueba si la posición del elemento de trabajo concuerda
+ con las dimensiones y la parte triangular de la matriz.
+\date 30 de enero de 2010: Creación de la función.
+*/
+size_t PosMatSimEmVec(const size_t dim,
+ const enum GEOC_MATR_ID_TRI supInf,
+ const size_t fil,
+ const size_t col);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Calcula la posición de un elemento de una matriz simétrica banda en el
+ vector en el que está almacenada.
+\param[in] diag Número de superdiagonales o subdiagonales de la matriz.
+\param[in] supInf Identificador de la parte de matriz simétrica almacenada:
+ superior o inferior. Ha de ser un elemento perteneciente al tipo
+ enumerado #GEOC_MATR_ID_TRI.
+\param[in] fil Fila del elemento de trabajo.
+\param[in] col Columna del elemento de trabajo.
+\return Posición del elemento de trabajo en el vector que almacena la matriz.
+\note Esta función comprueba internamente el tipo de almacenamiento utilizado.
+\note Esta función no comprueba si el argumento \em supInf es correcto.
+\note Esta función no comprueba si la posición del elemento de trabajo concuerda
+ con las dimensiones y la parte que contiene datos de la matriz.
+\date 27 de septiembre de 2009: Creación de la función.
+*/
+size_t PosMatSimBanVec(const size_t diag,
+ const enum GEOC_MATR_ID_TRI supInf,
+ const size_t fil,
+ const size_t col);
+/******************************************************************************/
+/******************************************************************************/
+#ifdef __cplusplus
+}
+#endif
+/******************************************************************************/
+/******************************************************************************/
+#endif
+/******************************************************************************/
+/******************************************************************************/
+/** @} */
+/******************************************************************************/
+/******************************************************************************/
+/* kate: encoding utf-8; end-of-line unix; syntax c; indent-mode cstyle; */
+/* kate: replace-tabs on; space-indent on; tab-indents off; indent-width 4; */
+/* kate: line-numbers on; folding-markers on; remove-trailing-space on; */
+/* kate: backspace-indents on; show-tabs on; */
+/* kate: word-wrap-column 80; word-wrap-marker-color #D2D2D2; word-wrap off; */
diff --git a/src/libgeoc/proyecaux.h b/src/libgeoc/proyecaux.h
new file mode 100644
index 0000000..85d00b8
--- /dev/null
+++ b/src/libgeoc/proyecaux.h
@@ -0,0 +1,90 @@
+/* -*- coding: utf-8 -*- */
+/**
+\ingroup gshhs geom proyec
+@{
+\file proyecaux.h
+\brief Declaración de funciones de algunas proyecciones cartográficas para no
+ usar PROJ.4.
+\author José Luis García Pallero, jgpallero@gmail.com
+\date 16 de agosto de 2013
+\copyright
+Copyright (c) 2013, José Luis García Pallero. All rights reserved.
+\par
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+\par
+- Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+- Neither the name of the copyright holders nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+\par
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/******************************************************************************/
+/******************************************************************************/
+#ifndef _PROYECAUX_H_
+#define _PROYECAUX_H_
+/******************************************************************************/
+/******************************************************************************/
+#include<math.h>
+/******************************************************************************/
+/******************************************************************************/
+#ifdef __cplusplus
+extern "C" {
+#endif
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Proyecta un punto según la proyección cilíndrica equivalente de Lambert,
+ siendo el paralelo origen el ecuador.
+\param[in] lat Latitud geodésica del punto de trabajo, en radianes.
+\param[in] lon Longitud geodésica del punto de trabajo, en radianes.
+\param[in] lon0 Longitud geodésica origen, en radianes.
+\param[in] a Semieje mayor del elipsoide, en metros.
+\param[in] f Aplanamiento del elipsoide.
+\param[out] x Coordenada X proyectada.
+\param[out] y Coordenada Y proyectada.
+\note El incremento \em lon-lon0 no puede estar fuera del intervalo
+ \f$[-\pi,\pi]\f$.
+\date 22 de junio de 2011: Creación de la función.
+\date 15 de noviembre de 2013: Adición de la capacidad de cálculo con puntos
+ sobre la esfera.
+*/
+void ProjCilinEquivLambertLat0Ec(const double lat,
+ const double lon,
+ const double lon0,
+ const double a,
+ const double f,
+ double* x,
+ double* y);
+/******************************************************************************/
+/******************************************************************************/
+#ifdef __cplusplus
+}
+#endif
+/******************************************************************************/
+/******************************************************************************/
+#endif
+/******************************************************************************/
+/******************************************************************************/
+/** @} */
+/******************************************************************************/
+/******************************************************************************/
+/* kate: encoding utf-8; end-of-line unix; syntax c; indent-mode cstyle; */
+/* kate: replace-tabs on; space-indent on; tab-indents off; indent-width 4; */
+/* kate: line-numbers on; folding-markers on; remove-trailing-space on; */
+/* kate: backspace-indents on; show-tabs on; */
+/* kate: word-wrap-column 80; word-wrap-marker-color #D2D2D2; word-wrap off; */
diff --git a/src/libgeoc/ptopol.h b/src/libgeoc/ptopol.h
index 6f82b3a..a884db0 100755..100644
--- a/src/libgeoc/ptopol.h
+++ b/src/libgeoc/ptopol.h
@@ -23,20 +23,21 @@ variable, se usará un tipo <tt>long int</tt> para los cálculos intermedios. En
procesadores de 32 bits puede hacer que las funciones se ejecuten hasta 10 veces
más lentamente que si se utiliza el tipo <tt>long int</tt>. Con cálculos
internos de 32 bits las coordenadas de los vértices del polígono no han de estar
-más lejos de las de los puntos de trabajo de unas 40000 unidades. Con cálculos
-de 64 bits, los polígonos pueden estar alejados de los puntos de trabajo unas
-3000000000 unidades, lo que corresponde a coordenadas Y UTM ajustadas al
-centímetro. Con esto podríamos chequear un punto en un polo con respecto a un
-polígono en el ecuador en coordenadas UTM expresadas en centímetros.
+más lejos de las de los puntos de trabajo de unas #GEOC_PTO_POLIG_LEJOS_32
+unidades. Con cálculos de 64 bits, los polígonos pueden estar alejados de los
+puntos de trabajo unas #GEOC_PTO_POLIG_LEJOS_64 unidades, lo que corresponde a
+coordenadas Y UTM ajustadas al centímetro. Con esto podríamos chequear un punto
+en un polo con respecto a un polígono en el ecuador en coordenadas UTM
+expresadas en centímetros.
\author José Luis García Pallero, jgpallero@gmail.com
\note Este fichero contiene funciones paralelizadas con OpenMP.
\date 05 de abril de 2010
-\section Licencia Licencia
-Copyright (c) 2009-2011, José Luis García Pallero. All rights reserved.
-
+\copyright
+Copyright (c) 2010-2020, José Luis García Pallero. All rights reserved.
+\par
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
-
+\par
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this
@@ -45,7 +46,7 @@ are permitted provided that the following conditions are met:
- Neither the name of the copyright holders nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
-
+\par
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -108,6 +109,62 @@ extern "C" {
/******************************************************************************/
/******************************************************************************/
/**
+\def GEOC_PTO_POLIG_LEJOS_32
+\brief Número de unidades máximas que puede estar alejado un punto de un
+ polígono trabajando con variables reales de 32 bits para que los cálculos
+ de inclusión en polígonos de forma arbitraria seas correctos.
+\date 11 de mayo de 2020: Creación de la constante.
+*/
+#define GEOC_PTO_POLIG_LEJOS_32 40000
+/******************************************************************************/
+/******************************************************************************/
+/**
+\def GEOC_PTO_POLIG_LEJOS_64
+\brief Número de unidades máximas que puede estar alejado un punto de un
+ polígono trabajando con variables reales de 64 bits para que los cálculos
+ de inclusión en polígonos de forma arbitraria seas correctos.
+\date 11 de mayo de 2020: Creación de la constante.
+*/
+#define GEOC_PTO_POLIG_LEJOS_64 3000000000
+/******************************************************************************/
+/******************************************************************************/
+/**
+\def GEOC_PTO_POLIG_LEJOS_ESCALA_DIST
+\brief Factor de escala a aplicar a #GEOC_PTO_POLIG_LEJOS_32 o
+ #GEOC_PTO_POLIG_LEJOS_64 para calcular el factor de multiplicación para
+ el escalado de puntos y polígonos automáticaente.
+\date 11 de mayo de 2020: Creación de la constante.
+*/
+#define GEOC_PTO_POLIG_LEJOS_ESCALA_DIST 0.75
+/******************************************************************************/
+/******************************************************************************/
+/**
+\def GEOC_RECT_DISJUNTOS
+\brief Comprueba si dos rectángulos son disjuntos.
+\param[in] xMin1 Coordenada X mínima del rectángulo 1.
+\param[in] xMax1 Coordenada X máxima del rectángulo 1.
+\param[in] yMin1 Coordenada Y mínima del rectángulo 1.
+\param[in] yMax1 Coordenada Y máxima del rectángulo 1.
+\param[in] xMin2 Coordenada X mínima del rectángulo 2.
+\param[in] xMax2 Coordenada X máxima del rectángulo 2.
+\param[in] yMin2 Coordenada Y mínima del rectángulo 2.
+\param[in] yMax2 Coordenada Y máxima del rectángulo 2.
+\return Dos posibilidades:
+ - 0: Los rectángulos no son disjuntos, es decir, tienen alguna parte
+ común (se cortan o se tocan) o uno está completamente contenido en
+ el otro.
+ - Distinto de 0: Los rectángulos son disjuntos.
+\note Esta función asume que \em xMin1<xMax1, \em yMin1<yMax1, \em xMin2<xMax2 e
+ \em yMin2<yMax2.
+\date 09 de junio de 2012: Creación de la macro.
+\todo Esta macro no está probada.
+*/
+#define GEOC_RECT_DISJUNTOS(xMin1,xMax1,yMin1,yMax1,xMin2,xMax2,yMin2,yMax2) \
+(!(((xMin1)<=(xMax2))&&((xMax1)>=(xMin2))&& \
+((yMin1)<=(yMax2))&&((yMax1)>=(yMin2))))
+/******************************************************************************/
+/******************************************************************************/
+/**
\typedef ptopol_long
\brief Nombre del tipo <tt>long int</tt> o <tt>long long int</tt> para utilizar
en los cálculos intermedios de las funciones
@@ -225,45 +282,15 @@ int RectanguloEnRectangulo(const int borde,
/******************************************************************************/
/******************************************************************************/
/**
-\brief Comprueba si dos rectángulos son disjuntos.
-\param[in] xMin1 Coordenada X mínima del rectángulo 1.
-\param[in] xMax1 Coordenada X máxima del rectángulo 1.
-\param[in] yMin1 Coordenada Y mínima del rectángulo 1.
-\param[in] yMax1 Coordenada Y máxima del rectángulo 1.
-\param[in] xMin2 Coordenada X mínima del rectángulo 2.
-\param[in] xMax2 Coordenada X máxima del rectángulo 2.
-\param[in] yMin2 Coordenada Y mínima del rectángulo 2.
-\param[in] yMax2 Coordenada Y máxima del rectángulo 2.
-\return Dos posibilidades:
- - 0: Los rectángulos no son disjuntos, es decir, tienen alguna parte
- común (se cortan o se tocan) o uno está completamente contenido en
- el otro.
- - Distinto de 0: Los rectángulos son disjuntos.
-\note Esta función asume que \em xMin1<xMax1, \em yMin1<yMax1, \em xMin2<xMax2 e
- \em yMin2<yMax2.
-\date 13 de junio de 2010: Creación de la función.
-\todo Esta función no está probada.
-*/
-int RectDisjuntos(const double xMin1,
- const double xMax1,
- const double yMin1,
- const double yMax1,
- const double xMin2,
- const double xMax2,
- const double yMin2,
- const double yMax2);
-/******************************************************************************/
-/******************************************************************************/
-/**
-\brief Comprueba si un punto está contenido en un polígono de un número
- arbitrario de lados. Esta función puede no dar resultados correctos para
- puntos en los bordes y/o los vértices del polígono.
+\brief Comprueba si un punto está contenido en un polígono o polígonos de un
+ número arbitrario de lados. Esta función puede no dar resultados
+ correctos para puntos en los bordes y/o los vértices de los polígonos.
\param[in] x Coordenada X del punto de trabajo.
\param[in] y Coordenada Y del punto de trabajo.
\param[in] coorX Vector que contiene las coordenadas X de los vértices del
- polígono. Puede contener varios polígonos.
+ polígono. Puede contener varios polígonos (ver la nota al respecto).
\param[in] coorY Vector que contiene las coordenadas Y de los vértices del
- polígono. Puede contener varios polígonos.
+ polígono. Puede contener varios polígonos (ver la nota al respecto).
\param[in] N Número de elementos que contienen los vectores \em coorX y
\em coorY.
\param[in] incX Posiciones de separación entre los elementos del vector
@@ -271,29 +298,35 @@ int RectDisjuntos(const double xMin1,
\param[in] incY Posiciones de separación entre los elementos del vector
\em coorY. Este argumento siempre ha de ser un número positivo.
\return Dos posibilidades:
- - #GEOC_PTO_FUERA_POLIG: El punto está fuera del polígono.
- - #GEOC_PTO_DENTRO_POLIG: El punto está dentro del polígono.
+ - #GEOC_PTO_FUERA_POLIG: El punto está fuera de los polígonos de trabajo
+ o pertenece a un hueco.
+ - #GEOC_PTO_DENTRO_POLIG: El punto está dentro de alguno de los
+ polígonos de trabajo.
\note El código de esta función ha sido tomado de
http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html y
se han hecho pequeñas modificaciones para permitir el trabajo con vectores
- que contengan elementos separados entre sí por varias posiciones.
+ que contengan elementos separados entre sí por varias posiciones y se ha
+ sustituido el separador de polígonos O=(0,0) por
+ NaN=(#GEOC_NAN, #GEOC_NAN) que, a efectos de código, produce el mismo
+ resultado.
\note Esta función no comprueba si el número de elementos de los vectores
\em coorX y \em coorY es congruente con los valores pasados en \em N,
\em incX e \em incY. Tampoco comprueba si \em N es un valor mayor o igual
- a 3, que es el número mínimo de vértices que ha de tener un polígono.
+ a 3, que es el número mínimo de vértices que ha de tener un polígono, ni
+ si la definición de estos está hecha de manera correcta.
\note Esta función no detecta el caso de que el punto de trabajo esté en el
- borde o en un vértice del polígono. En este caso, el test puede dar el
+ borde o en un vértice de los polígonos. En este caso, el test puede dar el
punto dentro o fuera, indistintamente (el chequeo del mismo punto con el
mismo polígono siempre dará el mismo resultado).
\note La estructura de los vectores de coordenadas puede contener uno o varios
- polígonos, de la siguiente manera:
- -# Los vectores de vértices pasados puedes contener elementos aislados
+ polígonos o huecos de la siguiente manera:
+ -# Los vectores de vértices pasados pueden contener elementos aislados
(varios polígonos) y/o agujeros en los elementos. En los vectores de
entrada se han de separar los polígonos y los agujeros mediante un
vértice de coordenadas NaN=(#GEOC_NAN, #GEOC_NAN), de la siguiente
forma:
- -# Primero, se incluye un vértice NaN.
- -# A continuación, se incluyen las coordenadas de los vértices del
+ -# Primero se incluye un vértice NaN.
+ -# A continuación se incluyen las coordenadas de los vértices del
primer elemento, repitiendo el primer vértice después del último.
-# Se incluye otro vértice NaN.
-# Se incluye otro elemento, repitiendo el primer vértice después del
@@ -328,38 +361,105 @@ int PtoEnPoligono(const double x,
/******************************************************************************/
/******************************************************************************/
/**
-\brief Comprueba si un punto está contenido o es un vértice de un polígono de un
- número arbitrario de lados. Esta función puede no dar resultados
- correctos para puntos en los bordes del polígono.
+\brief Comprueba si una serie de puntos están contenidos en un polígono o
+ polígonos de un número arbitrario de lados. Esta función puede no dar
+ resultados correctos para puntos en los bordes y/o los vértices de los
+ polígonos.
+\param[in] x Vector que contiene las coordenadas X de los puntos de trabajo.
+\param[in] y Vector que contiene las coordenadas Y de los puntos de trabajo.
+\param[in] nPtos Número de elementos que contienen los vectores \em X e \em Y.
+\param[in] incX Posiciones de separación entre los elementos del vector \em X.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] incY Posiciones de separación entre los elementos del vector \em Y.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] coorX Vector que contiene las coordenadas X de los vértices del
+ polígono. Puede contener varios polígonos (en el mismo formato que el
+ argumento correspondiente de la función \ref PtoEnPoligono).
+\param[in] coorY Vector que contiene las coordenadas Y de los vértices del
+ polígono. Puede contener varios polígonos (en el mismo formato que el
+ argumento correspondiente de la función \ref PtoEnPoligono).
+\param[in] N Número de elementos que contienen los vectores \em coorX y
+ \em coorY.
+\param[in] incCoorX Posiciones de separación entre los elementos del vector
+ \em coorX. Este argumento siempre ha de ser un número positivo.
+\param[in] incCoorY Posiciones de separación entre los elementos del vector
+ \em coorY. Este argumento siempre ha de ser un número positivo.
+\param[out] situacion Vector de \em nPtos elementos que almacena la situación
+ de los puntos con respecto a los polígonos de trabajo. Cada posición
+ del vector se refiere a un punto de trabajo y puede almacenar dos
+ valores:
+ - #GEOC_PTO_FUERA_POLIG: El punto está fuera de los polígonos de
+ trabajo o pertenece a un hueco.
+ - #GEOC_PTO_DENTRO_POLIG: El punto está dentro de alguno de los
+ polígonos de trabajo.
+\param[in] incSituacion Posiciones de separación entre los elementos del vector
+ \em situacion. Este argumento siempre ha de ser un número positivo.
+\note Esta función se puede ejecutar en paralelo con OpenMP.
+\note Esta función utiliza internamente la función \ref PtoEnPoligono, por lo
+ que todos sus casos especiales lo serán también de la nueva función.
+\note Esta función no comprueba si el número de elementos de los vectores \em X,
+ \em Y y \em situacion es congruente con los valores padados en \em nPtos,
+ \em incX, \em incY e \em incSituacion. Tampoco si el número de elementos
+ de los vectores \em coorX y \em coorY es congruente con los valores
+ pasados en \em N, \em incX e \em incY. Tampoco comprueba si \em N es un
+ valor mayor o igual a 3, que es el número mínimo de vértices que ha de
+ tener un polígono, ni si la definición de estos está hecha de manera
+ correcta.
+\date 22 de enero de 2015: Creación de la función.
+\todo Esta función no está probada.
+*/
+void PtosEnPoligono(const double* x,
+ const double* y,
+ const size_t nPtos,
+ const size_t incX,
+ const size_t incY,
+ const double* coorX,
+ const double* coorY,
+ const size_t N,
+ const size_t incCoorX,
+ const size_t incCoorY,
+ int* situacion,
+ const size_t incSituacion);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Comprueba si un punto está contenido o es un vértice de un polígono o
+ polígonos de un número arbitrario de lados. Esta función puede no dar
+ resultados correctos para puntos en los bordes del polígono.
\param[in] x Coordenada X del punto de trabajo.
\param[in] y Coordenada Y del punto de trabajo.
\param[in] coorX Vector que contiene las coordenadas X de los vértices del
- polígono. Sólo puede contener un polígono.
+ polígono. Puede contener varios polígonos (en el mismo formato que el
+ argumento correspondiente de la función \ref PtoEnPoligono).
\param[in] coorY Vector que contiene las coordenadas Y de los vértices del
- polígono. Sólo puede contener un polígono.
+ polígono. Puede contener varios polígonos (en el mismo formato que el
+ argumento correspondiente de la función \ref PtoEnPoligono).
\param[in] N Número de elementos que contienen los vectores \em coorX y
\em coorY.
\param[in] incX Posiciones de separación entre los elementos del vector
\em coorX. Este argumento siempre ha de ser un número positivo.
\param[in] incY Posiciones de separación entre los elementos del vector
\em coorY. Este argumento siempre ha de ser un número positivo.
-\return Dos posibilidades:
- - #GEOC_PTO_FUERA_POLIG: El punto está fuera del polígono.
- - #GEOC_PTO_DENTRO_POLIG: El punto está dentro del polígono.
- - #GEOC_PTO_VERTICE_POLIG: El punto es un vértice del polígono.
+\return Tres posibilidades:
+ - #GEOC_PTO_FUERA_POLIG: El punto está fuera de los polígonos de trabajo
+ o pertenece a un hueco.
+ - #GEOC_PTO_DENTRO_POLIG: El punto está dentro de alguno de los
+ polígonos de trabajo.
+ - #GEOC_PTO_VERTICE_POLIG: El punto es un vértice de alguno de los
+ polígonos de trabajo o de un hueco.
+\note Esta función utiliza internamente la función \ref PtoEnPoligono, por lo
+ que todos sus casos especiales lo serán también de la nueva función.
\note Esta función no comprueba si el número de elementos de los vectores
\em coorX y \em coorY es congruente con los valores pasados en \em N,
\em incX e \em incY. Tampoco comprueba si \em N es un valor mayor o igual
a 3, que es el número mínimo de vértices que ha de tener un polígono.
-\note Esta función utiliza en uno de sus pasos la función \ref PtoEnPoligono y
- se comporta igual que ella en el caso de puntos en el borde.
-\note La estructura de los vectores de coordenadas es idéntica a la de la
- función \ref PtoEnPoligono.
\date 09 de abril de 2010: Creación de la función.
\date 10 de abril de 2011: Adición de los argumentos de entrada \em incX e
\em incY.
\date 12 de abril de 2011: Las variables de salida son ahora constantes
simbólicas.
+\date 22 de enero de 2015: Los vectores de definición de polígonos pueden ahora
+ contener varios elementos y huecos.
\todo Esta función no está probada.
*/
int PtoEnPoligonoVertice(const double x,
@@ -372,6 +472,70 @@ int PtoEnPoligonoVertice(const double x,
/******************************************************************************/
/******************************************************************************/
/**
+\brief Comprueba si una serie de puntos están contenidos o son un vértice en un
+ polígono o polígonos de un número arbitrario de lados. Esta función puede
+ no dar resultados correctos para puntos en los bordes de los polígonos.
+\param[in] x Vector que contiene las coordenadas X de los puntos de trabajo.
+\param[in] y Vector que contiene las coordenadas Y de los puntos de trabajo.
+\param[in] nPtos Número de elementos que contienen los vectores \em X e \em Y.
+\param[in] incX Posiciones de separación entre los elementos del vector \em X.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] incY Posiciones de separación entre los elementos del vector \em Y.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] coorX Vector que contiene las coordenadas X de los vértices del
+ polígono. Puede contener varios polígonos (en el mismo formato que el
+ argumento correspondiente de la función \ref PtoEnPoligono).
+\param[in] coorY Vector que contiene las coordenadas Y de los vértices del
+ polígono. Puede contener varios polígonos (en el mismo formato que el
+ argumento correspondiente de la función \ref PtoEnPoligono).
+\param[in] N Número de elementos que contienen los vectores \em coorX y
+ \em coorY.
+\param[in] incCoorX Posiciones de separación entre los elementos del vector
+ \em coorX. Este argumento siempre ha de ser un número positivo.
+\param[in] incCoorY Posiciones de separación entre los elementos del vector
+ \em coorY. Este argumento siempre ha de ser un número positivo.
+\param[out] situacion Vector de \em nPtos elementos que almacena la situación
+ de los puntos con respecto a los polígonos de trabajo. Cada posición
+ del vector se refiere a un punto de trabajo y puede almacenar tres
+ valores:
+ - #GEOC_PTO_FUERA_POLIG: El punto está fuera de los polígonos de
+ trabajo o pertenece a un hueco.
+ - #GEOC_PTO_DENTRO_POLIG: El punto está dentro de alguno de los
+ polígonos de trabajo.
+ - #GEOC_PTO_VERTICE_POLIG: El punto es un vértice de alguno de los
+ polígonos de trabajo o de un hueco.
+\param[in] incSituacion Posiciones de separación entre los elementos del vector
+ \em situacion. Este argumento siempre ha de ser un número positivo.
+\note Esta función se puede ejecutar en paralelo con OpenMP.
+\note Esta función utiliza internamente la función \ref PtoEnPoligonoVertice,
+ por lo que todos sus casos especiales lo serán también de la nueva
+ función.
+\note Esta función no comprueba si el número de elementos de los vectores \em X,
+ \em Y y \em situacion es congruente con los valores padados en \em nPtos,
+ \em incX, \em incY e \em incSituacion. Tampoco si el número de elementos
+ de los vectores \em coorX y \em coorY es congruente con los valores
+ pasados en \em N, \em incX e \em incY. Tampoco comprueba si \em N es un
+ valor mayor o igual a 3, que es el número mínimo de vértices que ha de
+ tener un polígono, ni si la definición de estos está hecha de manera
+ correcta.
+\date 22 de enero de 2015: Creación de la función.
+\todo Esta función no está probada.
+*/
+void PtosEnPoligonoVertice(const double* x,
+ const double* y,
+ const size_t nPtos,
+ const size_t incX,
+ const size_t incY,
+ const double* coorX,
+ const double* coorY,
+ const size_t N,
+ const size_t incCoorX,
+ const size_t incCoorY,
+ int* situacion,
+ const size_t incSituacion);
+/******************************************************************************/
+/******************************************************************************/
+/**
\brief Comprueba si un punto está contenido en un polígono de un número
arbitrario de lados. Esta función trata correctamente los puntos situados
en los bordes y/o los vértices del polígono, pero sólo trabaja con datos
@@ -412,11 +576,12 @@ int PtoEnPoligonoVertice(const double x,
encabezado de este fichero.</b>
\note Con cálculos internos de 32 bits las coordenadas de los vértices del
polígono no han de estar más lejos de las de los puntos de trabajo de unas
- 40000 unidades. Con cálculos de 64 bits, los polígonos pueden estar
- alejados de los puntos de trabajo unas 3000000000 unidades, lo que
- corresponde a coordenadas Y UTM ajustadas al centímetro. Con esto
- podríamos chequear un punto en un polo con respecto a un polígono en el
- ecuador en coordenadas UTM expresadas en centímetros.
+ #GEOC_PTO_POLIG_LEJOS_32 unidades. Con cálculos de 64 bits, los polígonos
+ pueden estar alejados de los puntos de trabajo unas
+ #GEOC_PTO_POLIG_LEJOS_64 unidades, lo que corresponde a coordenadas Y UTM
+ ajustadas al centímetro. Con esto podríamos chequear un punto en un polo
+ con respecto a un polígono en el ecuador en coordenadas UTM expresadas en
+ centímetros.
\date 06 de abril de 2010: Creación de la función.
\date 10 de abril de 2011: Adición de los argumentos de entrada \em incX e
\em incY.
@@ -437,6 +602,87 @@ int PtoEnPoligonoVerticeBorde(const long x,
/******************************************************************************/
/******************************************************************************/
/**
+\brief Comprueba si una serie de puntos están contenidos en un polígono de un
+ número arbitrario de lados. Esta función trata correctamente los puntos
+ situados en los bordes y/o los vértices del polígono, pero sólo trabaja
+ con datos de tipo entero.
+\param[in] x Vector que contiene las coordenadas X de los puntos de trabajo.
+\param[in] y Vector que contiene las coordenadas Y de los puntos de trabajo.
+\param[in] nPtos Número de elementos que contienen los vectores \em X e \em Y.
+\param[in] incX Posiciones de separación entre los elementos del vector \em X.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] incY Posiciones de separación entre los elementos del vector \em Y.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] coorX Vector que contiene las coordenadas X de los vértices del
+ polígono. <b> Sólo puede contener un polígono. </b>
+\param[in] coorY Vector que contiene las coordenadas Y de los vértices del
+ polígono. <b> Sólo puede contener un polígono. </b>
+\param[in] N Número de elementos que contienen los vectores \em coorX y
+ \em coorY.
+\param[in] incCoorX Posiciones de separación entre los elementos del vector
+ \em coorX. Este argumento siempre ha de ser un número positivo.
+\param[in] incCoorY Posiciones de separación entre los elementos del vector
+ \em coorY. Este argumento siempre ha de ser un número positivo.
+\param[out] situacion Vector de \em nPtos elementos que almacena la situación
+ de los puntos con respecto al polígono de trabajo. Cada posición del
+ vector se refiere a un punto de trabajo y puede almacenar cuatro
+ valores:
+ - #GEOC_PTO_FUERA_POLIG: El punto está fuera del polígono.
+ - #GEOC_PTO_DENTRO_POLIG: El punto está dentro del polígono.
+ - #GEOC_PTO_VERTICE_POLIG: El punto es un vértice del polígono.
+ - #GEOC_PTO_BORDE_POLIG: El punto pertenece a la frontera del
+ polígono, pero no es un vértice.
+\param[in] incSituacion Posiciones de separación entre los elementos del vector
+ \em situacion. Este argumento siempre ha de ser un número positivo.
+\note Esta función se puede ejecutar en paralelo con OpenMP.
+\note El código de esta función ha sido tomado del texto Joseph O'Rourke (2001),
+ Computational geometry in C, 2a edición, Cambridge University Press,
+ página 244.
+\note Esta función utiliza internamente la función
+ \ref PtoEnPoligonoVerticeBorde, por lo que todos sus casos especiales lo
+ serán también de la nueva función.
+\note Esta función no comprueba si el número de elementos de los vectores \em X,
+ \em Y y \em situacion es congruente con los valores padados en \em nPtos,
+ \em incX, \em incY e \em incSituacion. Tampoco si el número de elementos
+ de los vectores \em coorX y \em coorY es congruente con los valores
+ pasados en \em N, \em incX e \em incY. Tampoco comprueba si \em N es un
+ valor mayor o igual a 3, que es el número mínimo de vértices que ha de
+ tener un polígono, ni si la definición de éste está hecha de manera
+ correcta.
+\note <b>El polígono de trabajo ha de ser único, sin huecos. Es opcional repetir
+ las coordenadas del primer punto al final del listado.</b>
+\note Los vértices del polígono pueden listarse en sentido dextrógiro o
+ levógiro.
+\note <b>Esta función puede dar resultados incorrectos para puntos muy alejados
+ de los polígonos de trabajo. Para intentar mitigar este efecto, puede
+ seleccionarse mediante una variable del preprocesador la precisión de
+ algunas variables intermedias. Para más información se recomienda leer el
+ encabezado de este fichero.</b>
+\note Con cálculos internos de 32 bits las coordenadas de los vértices del
+ polígono no han de estar más lejos de las de los puntos de trabajo de unas
+ #GEOC_PTO_POLIG_LEJOS_32 unidades. Con cálculos de 64 bits, los polígonos
+ pueden estar alejados de los puntos de trabajo unas
+ #GEOC_PTO_POLIG_LEJOS_64 unidades, lo que corresponde a coordenadas Y UTM
+ ajustadas al centímetro. Con esto podríamos chequear un punto en un polo
+ con respecto a un polígono en el ecuador en coordenadas UTM expresadas en
+ centímetros.
+\date 22 de enero de 2015: Creación de la función.
+*/
+void PtosEnPoligonoVerticeBorde(const long* x,
+ const long* y,
+ const size_t nPtos,
+ const size_t incX,
+ const size_t incY,
+ const long* coorX,
+ const long* coorY,
+ const size_t N,
+ const size_t incCoorX,
+ const size_t incCoorY,
+ int* situacion,
+ const size_t incSituacion);
+/******************************************************************************/
+/******************************************************************************/
+/**
\brief Comprueba si un punto está contenido en un polígono de un número
arbitrario de lados. Esta función trata correctamente los puntos situados
en los bordes y/o los vértices del polígono. Trabaja con datos de tipo
@@ -455,11 +701,13 @@ int PtoEnPoligonoVerticeBorde(const long x,
\param[in] incY Posiciones de separación entre los elementos del vector
\em coorY. Este argumento siempre ha de ser un número positivo.
\param[in] factor Factor de multiplicación para aplicar a las coordenadas del
- punto de trabajo y de los vértices del polígono, con el fin de
+ punto de trabajo y de los vértices del polígono con el fin de
aumentar su resolución antes de convertirlas en valores de tipo
entero (\p long \p int). El uso de factores muy grandes puede
provocar resultados erróneos. Ver la nota al final de la
- documentación de esta función.
+ documentación de esta función. Si se pasa el valor \p 0 el factor de
+ escala se calcula automáticamente, lo que puede hacer a la función un
+ poco más lenta.
\param[in] redondeo Identificador de redondeo o truncamiento en la conversión
interna de variables de tipo \p double en variables de tipo
\p long \p int. Dos posibilidades:
@@ -494,13 +742,19 @@ int PtoEnPoligonoVerticeBorde(const long x,
encabezado de este fichero.</b>
\note Con cálculos internos de 32 bits las coordenadas de los vértices del
polígono no han de estar más lejos de las de los puntos de trabajo de unas
- 40000 unidades. Con cálculos de 64 bits, los polígonos pueden estar
- alejados de los puntos de trabajo unas 3000000000 unidades, lo que
- corresponde a coordenadas Y UTM ajustadas al centímetro. Con esto
- podríamos chequear un punto en un polo con respecto a un polígono en el
- ecuador en coordenadas UTM expresadas en centímetros. En este caso nos
- referimos a las coordenadas una vez aplicado el factor de escala
- \em factor.
+ #GEOC_PTO_POLIG_LEJOS_32 unidades. Con cálculos de 64 bits los polígonos
+ pueden estar alejados de los puntos de trabajo unas
+ #GEOC_PTO_POLIG_LEJOS_64 unidades, lo que corresponde a coordenadas Y UTM
+ ajustadas al centímetro. Con esto podríamos chequear un punto en un polo
+ con respecto a un polígono en el ecuador en coordenadas UTM expresadas en
+ centímetros. En este caso nos referimos a las coordenadas una vez aplicado
+ el factor de escala \em factor. El cálculo automático del factor de escala
+ si se pasa el valor \p 0 a \em factor se realiza de tal modo que la
+ distancia entre el punto de trabajo y el vértice más alejado del polígono
+ se ajuste lo más posible a los límites indicados para cada tipo de
+ variable multiplicados por #GEOC_PTO_POLIG_LEJOS_ESCALA_DIST (se hace para
+ ser conservador y asegurar, por eso el valor de
+ #GEOC_PTO_POLIG_LEJOS_ESCALA_DIST es recomendable que sea menor que 1).
\date 10 de abril de 2011: Creación de la función.
\date 11 de abril de 2011: Adición del argumento de entrada \em redondeo.
\date 12 de abril de 2011: Las variables de salida son ahora constantes
@@ -508,6 +762,8 @@ int PtoEnPoligonoVerticeBorde(const long x,
\date 18 de abril de 2011: Reescritura de la función, siguiendo la página 244
del libro de O'Rourke. La versión anterior la había adaptado del código de
la web de O'Rourke, y lo había hecho mal.
+\date 11 de mayo de 2020:Adición de la capacidad de cálculo automático del
+ factor de multiplicación.
\todo Esta función no está probada.
*/
int PtoEnPoligonoVerticeBordeDouble(const double x,
@@ -522,6 +778,115 @@ int PtoEnPoligonoVerticeBordeDouble(const double x,
/******************************************************************************/
/******************************************************************************/
/**
+\brief Comprueba si una serie de puntos están contenidos en un polígono de un
+ número arbitrario de lados. Esta función trata correctamente los puntos
+ situados en los bordes y/o los vértices del polígono. Trabaja con datos
+ de tipo real, que convierte a enteros (por redondeo o truncamiento)
+ intermamente, mediante la aplicación de un factor de escala.
+\param[in] x Vector que contiene las coordenadas X de los puntos de trabajo.
+\param[in] y Vector que contiene las coordenadas Y de los puntos de trabajo.
+\param[in] nPtos Número de elementos que contienen los vectores \em X e \em Y.
+\param[in] incX Posiciones de separación entre los elementos del vector \em X.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] incY Posiciones de separación entre los elementos del vector \em Y.
+ Este argumento siempre ha de ser un número positivo.
+\param[in] coorX Vector que contiene las coordenadas X de los vértices del
+ polígono. <b> Sólo puede contener un polígono. </b>
+\param[in] coorY Vector que contiene las coordenadas Y de los vértices del
+ polígono. <b> Sólo puede contener un polígono. </b>
+\param[in] N Número de elementos que contienen los vectores \em coorX y
+ \em coorY.
+\param[in] incCoorX Posiciones de separación entre los elementos del vector
+ \em coorX. Este argumento siempre ha de ser un número positivo.
+\param[in] incCoorY Posiciones de separación entre los elementos del vector
+ \em coorY. Este argumento siempre ha de ser un número positivo.
+\param[in] factor Factor de multiplicación para aplicar a las coordenadas de los
+ puntos de trabajo y de los vértices del polígono, con el fin de
+ aumentar su resolución antes de convertirlas en valores de tipo
+ entero (\p long \p int). El uso de factores muy grandes puede
+ provocar resultados erróneos. Ver la nota al final de la
+ documentación de esta función. Si se pasa el valor \p 0 el factor de
+ escala se calcula automáticamente, lo que puede hacer a la función un
+ poco más lenta.
+\param[in] redondeo Identificador de redondeo o truncamiento en la conversión
+ interna de variables de tipo \p double en variables de tipo
+ \p long \p int. Dos posibilidades:
+ - 0: La conversión se hace por truncamiento.
+ - Distinto de 0: La conversión se hace por redondeo.
+\param[out] situacion Vector de \em nPtos elementos que almacena la situación
+ de los puntos con respecto al polígono de trabajo. Cada posición del
+ vector se refiere a un punto de trabajo y puede almacenar cuatro
+ valores:
+ - #GEOC_PTO_FUERA_POLIG: El punto está fuera del polígono.
+ - #GEOC_PTO_DENTRO_POLIG: El punto está dentro del polígono.
+ - #GEOC_PTO_VERTICE_POLIG: El punto es un vértice del polígono.
+ - #GEOC_PTO_BORDE_POLIG: El punto pertenece a la frontera del
+ polígono, pero no es un vértice.
+\param[in] incSituacion Posiciones de separación entre los elementos del vector
+ \em situacion. Este argumento siempre ha de ser un número positivo.
+\note Esta función se puede ejecutar en paralelo con OpenMP.
+\note El código de esta función ha sido tomado del texto Joseph O'Rourke (2001),
+ Computational geometry in C, 2a edición, Cambridge University Press,
+ página 244.
+\note Esta función utiliza internamente la función
+ \ref PtoEnPoligonoVerticeBordeDouble, por lo que todos sus casos
+ especiales lo serán también de la nueva función.
+\note Esta función no comprueba si el número de elementos de los vectores \em X,
+ \em Y y \em situacion es congruente con los valores padados en \em nPtos,
+ \em incX, \em incY e \em incSituacion. Tampoco si el número de elementos
+ de los vectores \em coorX y \em coorY es congruente con los valores
+ pasados en \em N, \em incX e \em incY. Tampoco comprueba si \em N es un
+ valor mayor o igual a 3, que es el número mínimo de vértices que ha de
+ tener un polígono, ni si la definición de éste está hecha de manera
+ correcta.
+\note <b>El polígono de trabajo ha de ser único, sin huecos. Es opcional repetir
+ las coordenadas del primer punto al final del listado.</b>
+\note Los vértices del polígono pueden listarse en sentido dextrógiro o
+ levógiro.
+\note Las variables se redondean internamente con la orden
+ <tt>(long)(round(factor*variable))</tt>, y se truncan con la orden
+ <tt>(long)(factor*variable)</tt>.
+\note <b>Esta función puede dar resultados incorrectos para puntos muy alejados
+ de los polígonos de trabajo. Para intentar mitigar este efecto, puede
+ seleccionarse mediante una variable del preprocesador la precisión de
+ algunas variables intermedias. Para más información se recomienda leer el
+ encabezado de este fichero.</b>
+\note Con cálculos internos de 32 bits las coordenadas de los vértices del
+ polígono no han de estar más lejos de las de los puntos de trabajo de unas
+ #GEOC_PTO_POLIG_LEJOS_32 unidades. Con cálculos de 64 bits los polígonos
+ pueden estar alejados de los puntos de trabajo unas
+ #GEOC_PTO_POLIG_LEJOS_64 unidades, lo que corresponde a coordenadas Y UTM
+ ajustadas al centímetro. Con esto podríamos chequear un punto en un polo
+ con respecto a un polígono en el ecuador en coordenadas UTM expresadas en
+ centímetros. En este caso nos referimos a las coordenadas una vez aplicado
+ el factor de escala \em factor. El cálculo automático del factor de escala
+ si se pasa el valor \p 0 a \em factor se realiza de tal modo que la
+ distancia entre el punto de trabajo y el vértice más alejado del polígono
+ se ajuste lo más posible a los límites indicados para cada tipo de
+ variable multiplicados por #GEOC_PTO_POLIG_LEJOS_ESCALA_DIST (se hace para
+ ser conservador y asegurar, por eso el valor de
+ #GEOC_PTO_POLIG_LEJOS_ESCALA_DIST es recomendable que sea menor que 1).
+\date 22 de enero de 2015: Creación de la función.
+\date 11 de mayo de 2020:Adición de la capacidad de cálculo automático del
+ factor de multiplicación.
+*/
+void PtosEnPoligonoVerticeBordeDouble(const double* x,
+ const double* y,
+ const size_t nPtos,
+ const size_t incX,
+ const size_t incY,
+ const double* coorX,
+ const double* coorY,
+ const size_t N,
+ const size_t incCoorX,
+ const size_t incCoorY,
+ const double factor,
+ const int redondeo,
+ int* situacion,
+ const size_t incSituacion);
+/******************************************************************************/
+/******************************************************************************/
+/**
\brief Busca valores #GEOC_NAN es uno o dos vectores de datos. Esta función
está pensada para el chequeo en paralelo de la inclusión de puntos en
polígonos.
@@ -809,11 +1174,12 @@ int PtoEnPoligonoVerticeInd(const double x,
encabezado de este fichero.</b>
\note Con cálculos internos de 32 bits las coordenadas de los vértices del
polígono no han de estar más lejos de las de los puntos de trabajo de unas
- 40000 unidades. Con cálculos de 64 bits, los polígonos pueden estar
- alejados de los puntos de trabajo unas 3000000000 unidades, lo que
- corresponde a coordenadas Y UTM ajustadas al centímetro. Con esto
- podríamos chequear un punto en un polo con respecto a un polígono en el
- ecuador en coordenadas UTM expresadas en centímetros.
+ #GEOC_PTO_POLIG_LEJOS_32 unidades. Con cálculos de 64 bits, los polígonos
+ pueden estar alejados de los puntos de trabajo unas
+ #GEOC_PTO_POLIG_LEJOS_64 unidades, lo que corresponde a coordenadas Y UTM
+ ajustadas al centímetro. Con esto podríamos chequear un punto en un polo
+ con respecto a un polígono en el ecuador en coordenadas UTM expresadas en
+ centímetros.
\date 14 de abril de 2011: Creación de la función.
\todo Esta función no está probada.
*/
@@ -855,7 +1221,9 @@ int PtoEnPoligonoVerticeBordeInd(const long x,
aumentar su resolución antes de convertirlas en valores de tipo
entero (\p long \p int). El uso de factores muy grandes puede
provocar resultados erróneos. Ver la nota al final de la
- documentación de esta función.
+ documentación de esta función. Si se pasa el valor \p 0 el factor de
+ escala se calcula automáticamente, lo que puede hacer a la función un
+ poco más lenta.
\param[in] redondeo Identificador de redondeo o truncamiento en la conversión
interna de variables de tipo \p double en variables de tipo
\p long \p int. Dos posibilidades:
@@ -905,14 +1273,22 @@ int PtoEnPoligonoVerticeBordeInd(const long x,
encabezado de este fichero.</b>
\note Con cálculos internos de 32 bits las coordenadas de los vértices del
polígono no han de estar más lejos de las de los puntos de trabajo de unas
- 40000 unidades. Con cálculos de 64 bits, los polígonos pueden estar
- alejados de los puntos de trabajo unas 3000000000 unidades, lo que
- corresponde a coordenadas Y UTM ajustadas al centímetro. Con esto
- podríamos chequear un punto en un polo con respecto a un polígono en el
- ecuador en coordenadas UTM expresadas en centímetros. En este caso nos
- referimos a las coordenadas una vez aplicado el factor de escala
- \em factor.
+ #GEOC_PTO_POLIG_LEJOS_32 unidades. Con cálculos de 64 bits los polígonos
+ pueden estar alejados de los puntos de trabajo unas
+ #GEOC_PTO_POLIG_LEJOS_64 unidades, lo que corresponde a coordenadas Y UTM
+ ajustadas al centímetro. Con esto podríamos chequear un punto en un polo
+ con respecto a un polígono en el ecuador en coordenadas UTM expresadas en
+ centímetros. En este caso nos referimos a las coordenadas una vez aplicado
+ el factor de escala \em factor. El cálculo automático del factor de escala
+ si se pasa el valor \p 0 a \em factor se realiza de tal modo que la
+ distancia entre el punto de trabajo y el vértice más alejado del polígono
+ se ajuste lo más posible a los límites indicados para cada tipo de
+ variable multiplicados por #GEOC_PTO_POLIG_LEJOS_ESCALA_DIST (se hace para
+ ser conservador y asegurar, por eso el valor de
+ #GEOC_PTO_POLIG_LEJOS_ESCALA_DIST es recomendable que sea menor que 1).
\date 14 de abril de 2011: Creación de la función.
+\date 11 de mayo de 2020:Adición de la capacidad de cálculo automático del
+ factor de multiplicación.
\todo Esta función no está probada.
*/
int PtoEnPoligonoVerticeBordeDoubleInd(const double x,
@@ -929,6 +1305,60 @@ int PtoEnPoligonoVerticeBordeDoubleInd(const double x,
size_t* poli);
/******************************************************************************/
/******************************************************************************/
+/**
+\brief Genera un punto en el interior de un polígono simple (sin huecos).
+\param[in] coorX Vector que contiene las coordenadas X de los vértices del
+ polígono. Sólo puede contener un polígono.
+\param[in] coorY Vector que contiene las coordenadas Y de los vértices del
+ polígono. Sólo puede contener un polígono.
+\param[in] N Número de elementos que contienen los vectores \em coorX y
+ \em coorY.
+\param[in] incX Posiciones de separación entre los elementos del vector
+ \em coorX. Este argumento siempre ha de ser un número positivo.
+\param[in] incY Posiciones de separación entre los elementos del vector
+ \em coorY. Este argumento siempre ha de ser un número positivo.
+\param[in] factor Factor de multiplicación interno para aplicar a las
+ coordenadas de puntos y vértices en el chequeo de inclusión de punto
+ en polígono. Ver la ayuda de la función
+ \ref PtoEnPoligonoVerticeBordeDouble para más información.
+\param[in] redondeo Identificador de redondeo o truncamiento en la conversión
+ interna de variables de tipo \p double en variables de tipo
+ \p long \p int. Dos posibilidades:
+ - 0: La conversión se hace por truncamiento.
+ - Distinto de 0: La conversión se hace por redondeo.
+ Ver la ayuda de la función \ref PtoEnPoligonoVerticeBordeDouble para
+ más información.
+\param[out] x Coordenada X de un punto situado estrictamente en el interior (no
+ en un vértice o borde) del polígono de trabajo. Si ha ocurrido algún
+ error o no se han podido determinar coordenadas contiene #GEOC_NAN.
+\param[out] y Coordenada Y de un punto situado estrictamente en el interior (no
+ en un vértice o borde) del polígono de trabajo. Si ha ocurrido algún
+ error o no se han podido determinar coordenadas contiene #GEOC_NAN.
+\note El polígono ha de ser único, sin huecos. Es opcional repetir las
+ coordenadas del primer punto al final del listado
+\note Esta función asume que el polígono está correctamente definido (que tiene
+ los vértices suficientes para considerarse tal) Puede tener
+ autointersecciones.
+\note El punto generado \b*NO* es aleatorio, sino que se busca a partir de la
+ generación de triángulos con los vértices del polígono. Queda garantizado
+ que ejecuciones con los mismos parámetros producirán siempre idéntico
+ resultado.
+\note Los vértices del polígono pueden listarse en sentido dextrógiro o
+ levógiro.
+\date 11 de mayo de 2020: Creación de la función.
+\todo Esta función no está probada.
+*/
+void GeneraPtoEnPoligono(const double* coorX,
+ const double* coorY,
+ const size_t N,
+ const size_t incX,
+ const size_t incY,
+ const double factor,
+ const int redondeo,
+ double* x,
+ double* y);
+/******************************************************************************/
+/******************************************************************************/
#ifdef __cplusplus
}
#endif
diff --git a/src/libgeoc/recpolil.h b/src/libgeoc/recpolil.h
index 6957b92..188f934 100755..100644
--- a/src/libgeoc/recpolil.h
+++ b/src/libgeoc/recpolil.h
@@ -7,12 +7,12 @@
polilíneas por medio de polígonos.
\author José Luis García Pallero, jgpallero@gmail.com
\date 04 de junio de 2011
-\section Licencia Licencia
-Copyright (c) 2011, José Luis García Pallero. All rights reserved.
-
+\copyright
+Copyright (c) 2011-2020, José Luis García Pallero. All rights reserved.
+\par
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
-
+\par
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this
@@ -21,7 +21,7 @@ are permitted provided that the following conditions are met:
- Neither the name of the copyright holders nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
-
+\par
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -155,13 +155,11 @@ vertPolilClip* CreaVertPolilClip(const double x,
\return Puntero al primer vértice de la lista. Si se devuelve \p NULL, ha
ocurrido un error de asignación de memoria.
\note Esta función asume que el argumento \em nCoor es mayor que 0.
-\note Si en los vectores de coordenadas \em x e \em y hay valores #GEOC_NAN,
- éstos no se tienen en cuenta a la hora de la creación de la estructura de
- salida.
-\note Que los vectores de coordenadas \em x e \em y admitan vértices con
- coordenadas (#GEOC_NAN,#GEOC_NAN) no quiere decir que éstos sean
- separadores de múltiples polilíneas. \em x e \em y \b *SÓLO* deben
- almacenar una única polilínea.
+\note Si en los vectores de coordenadas \em x e \em y hay valores #GEOC_NAN
+ éstos \b*NO* serán considerados como separadores de múltiples polilíneas,
+ por lo que en la estructura de salida se asumirá que se almacena una
+ polilínea única cuyos vértices son los pasados sin tener en cuenta los
+ pares (#GEOC_NAN,#GEOC_NAN).
\note Esta función asigna el valor 0 a todos los campos _vertPolilClip::pos de
los elementos creados.
\date 04 de junio de 2011: Creación de la función.
@@ -279,8 +277,7 @@ size_t NumeroVertPolilClip(vertPolilClip* poli);
\brief Realiza el paso número 1 del algoritmo de recorte de polilíneas, que
consiste en el cálculo de los puntos de intersección de la polilínea de
trabajo con el polígono de recorte.
-
- Este paso está inspirado en el primer paso del algoritmo de
+\brief Este paso está inspirado en el primer paso del algoritmo de
Greiner-Hormann.
\param[in,out] poli Polilínea de trabajo, representada como una lista doblemente
enlazada de elementos \ref _vertPolilClip. Al término de la
@@ -353,6 +350,9 @@ polil* Paso2Recpolil(vertPolilClip* poli,
polígono de recorte.
\note Esta función asume que los puntos de borde sólo pertenecen al exterior del
polígono de recorte cuando son principio o final de polilínea recortada.
+\note Esta función asume que tanto \em poli como \em poliRec almacenan cada una
+ un elemento único (polilínea y polígono respectivamente).
+\note La polilínea y el polígono pueden tener autointersecciones.
\date 06 de junio de 2011: Creación de la función.
\todo Esta función no está probada.
*/
@@ -392,6 +392,7 @@ polil* RecortaPolil(vertPolilClip* poli,
\note Esta función asume que los puntos de borde sólo pertenecen al exterior de
los polígonos de recorte cuando son principio o final de polilínea
recortada.
+\note Las polilíneas y los polígonos pueden tener autointersecciones.
\date 06 de junio de 2011: Creación de la función.
\todo Esta función no está probada.
*/
diff --git a/src/libgeoc/segmento.h b/src/libgeoc/segmento.h
index 3b3ef04..7ec3dab 100755..100644
--- a/src/libgeoc/segmento.h
+++ b/src/libgeoc/segmento.h
@@ -6,12 +6,12 @@
\brief Declaración de funciones para la realización de cálculos con segmentos.
\author José Luis García Pallero, jgpallero@gmail.com
\date 22 de abril de 2011
-\section Licencia Licencia
-Copyright (c) 2011, José Luis García Pallero. All rights reserved.
-
+\copyright
+Copyright (c) 2011-2013, José Luis García Pallero. All rights reserved.
+\par
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
-
+\par
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this
@@ -20,7 +20,7 @@ are permitted provided that the following conditions are met:
- Neither the name of the copyright holders nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
-
+\par
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -67,19 +67,30 @@ extern "C" {
/**
\def GEOC_SEG_INTERSEC_EXTREMO_NO_COLIN
\brief Identificador de que dos segmentos se cortan en un punto, el cual es un
- extremo que está encima del otro segmento, pero no son colineales.
+ extremo que está encima del otro segmento (excluidos los extremos de este
+ otro segmento), pero no son colineales.
\date 14 de mayo de 2011: Creación de la constante.
*/
#define GEOC_SEG_INTERSEC_EXTREMO_NO_COLIN 2
/******************************************************************************/
/******************************************************************************/
/**
-\def GEOC_SEG_INTERSEC_EXTREMO_COLIN
-\brief Identificador de que dos segmentos tienen un punto común y son
+\def GEOC_SEG_INTERSEC_EXTREMOS_NO_COLIN
+\brief Identificador de que dos segmentos tienen un extremo común, pero no son
+ colineales.
+\date 10 de agosto de 2013: Creación de la constante.
+*/
+#define GEOC_SEG_INTERSEC_EXTREMOS_NO_COLIN 3
+/******************************************************************************/
+/******************************************************************************/
+/**
+\def GEOC_SEG_INTERSEC_EXTREMOS_COLIN
+\brief Identificador de que dos segmentos tienen un solo extremo común y son
colineales.
\date 14 de mayo de 2011: Creación de la constante.
+\date 10 de agosto de 2013: Cambio de nombre de la constante.
*/
-#define GEOC_SEG_INTERSEC_EXTREMO_COLIN 3
+#define GEOC_SEG_INTERSEC_EXTREMOS_COLIN 4
/******************************************************************************/
/******************************************************************************/
/**
@@ -88,18 +99,20 @@ extern "C" {
común.
\date 21 de mayo de 2011: Creación de la constante.
*/
-#define GEOC_SEG_INTERSEC_MISMO_SEG 4
+#define GEOC_SEG_INTERSEC_MISMO_SEG 5
/******************************************************************************/
/******************************************************************************/
/**
\def GEOC_SEG_INTERSEC_COLIN
-\brief Identificador de que dos segmentos tienen más de un punto en común.
+\brief Identificador de que dos segmentos tienen más de un punto en común, es
+ decir, se solapan, pero no son el mismo segmento.
\date 14 de mayo de 2011: Creación de la constante.
*/
-#define GEOC_SEG_INTERSEC_COLIN 5
+#define GEOC_SEG_INTERSEC_COLIN 6
/******************************************************************************/
/******************************************************************************/
/**
+\def POS_PTO_RECTA_2D
\brief Calcula la posición relativa de un punto con respecto a una recta en el
plano.
\param[in] x Coordenada X del punto de trabajo.
@@ -115,20 +128,19 @@ extern "C" {
\note Para la definición de derecha e izquierda, se considera que el sentido de
la recta es aquél que se define del punto de inicio al punto final del
segmento de trabajo.
-\note El resultado de esta función no es robusto, es decir, puede dar resultados
+\note El resultado de esta macro no es robusto, es decir, puede dar resultados
incorrectos debido a errores de redondeo (salvo que todas las coordenadas
pasadas sean números enteros).
-\note El código de esta función ha sido tomado de la función orient2dfast(), de
+\note Para evitar errores por desbordamiento, es conveniente utilizar esta macro
+ con las coordenadas de los argumentos de entrada reducidas al centroide.
+\note El código de esta macro ha sido tomado de la función orient2dfast(), de
http://www.cs.cmu.edu/afs/cs/project/quake/public/code/predicates.c
\date 20 de abril de 2010: Creación de la función.
\date 14 de mayo de 2011: Cambio de nombre a la función.
+\date 10 de agosto de 2013: Conversión de la antigua función en esta macro.
*/
-double PosPtoRecta2D(const double x,
- const double y,
- const double xIni,
- const double yIni,
- const double xFin,
- const double yFin);
+#define POS_PTO_RECTA_2D(x,y,xIni,yIni,xFin,yFin) \
+(((xIni)-(x))*((yFin)-(y))-((xFin)-(x))*((yIni)-(y)))
/******************************************************************************/
/******************************************************************************/
/**
@@ -142,10 +154,13 @@ double PosPtoRecta2D(const double x,
\return Dos posibilidades:
- 0: Los puntos no son colineales.
- Distinto de 0: Los puntos son colineales.
-\note Esta función utiliza internamente la función \ref PtoComunSegmParalelos2D,
- que no es robusta. En consecuencia, los resultados de esta función tampoco
- lo son.
-\note Estafunción sirve de apoyo para \ref PtoComunSegmParalelos2D.
+\note Esta función utiliza internamente la macro \ref POS_PTO_RECTA_2D, que no
+ es robusta. En consecuencia, los resultados de esta función tampoco lo
+ son.
+\note Esta función sirve de apoyo para \ref PtoComunSegmParalelos2D.
+\note Para evitar errores por desbordamiento, es conveniente utilizar esta
+ función con las coordenadas de los argumentos de entrada reducidas al
+ centroide.
\date 14 de mayo de 2011: Creación de la función.
\todo Esta función no está probada.
*/
@@ -159,7 +174,7 @@ int TresPuntosColineales2D(const double xA,
/******************************************************************************/
/**
\brief Comprueba si un punto está situado entre dos puntos (pero no es igual a
- ninguno de ellos) en el plano. Se asume que los tres puntos con
+ ninguno de ellos) en el plano. Se asume que los tres puntos son
colineales.
\param[in] x Coordenada X del punto a comprobar.
\param[in] y Coordenada Y del punto a comprobar.
@@ -198,7 +213,7 @@ int PuntoEntreDosPuntos2DColin(const double x,
\param[out] y Coordenada Y del punto común.
\return Dos posibilidades:
- #GEOC_SEG_NO_INTERSEC: Los segmentos no tienen ningún punto en común.
- - #GEOC_SEG_INTERSEC_EXTREMO_COLIN: Los segmentos tienen un extremo
+ - #GEOC_SEG_INTERSEC_EXTREMOS_COLIN: Los segmentos tienen un extremo
común y son colineales.
- #GEOC_SEG_INTERSEC_MISMO_SEG: Los dos segmentos son idénticos.
- #GEOC_SEG_INTERSEC_COLIN: Los segmentos tienen más de un punto en
@@ -214,9 +229,12 @@ int PuntoEntreDosPuntos2DColin(const double x,
un segmento. Este punto extremo se intentará que sea uno de los puntos
iniciales de algún segmento, anque si no lo es, será uno de los finales.
El orden de preferencia de las coordenadas de salida es: A, C, B, D.
+\note Para evitar errores por desbordamiento, es conveniente utilizar esta
+ función con las coordenadas de los argumentos de entrada reducidas al
+ centroide.
\date 14 de mayo de 2011: Creación de la función.
\date 21 de mayo de 2011: Adición de nuevos valores de salida:
- #GEOC_SEG_INTERSEC_EXTREMO_COLIN y #GEOC_SEG_INTERSEC_MISMO_SEG.
+ #GEOC_SEG_INTERSEC_EXTREMOS_COLIN y #GEOC_SEG_INTERSEC_MISMO_SEG.
\todo Esta función no está probada.
*/
int PtoComunSegmParalelos2D(const double xA,
@@ -243,12 +261,15 @@ int PtoComunSegmParalelos2D(const double xA,
\param[in] yD Coordenada Y del punto D.
\param[out] x Coordenada X del punto común.
\param[out] y Coordenada Y del punto común.
-\return Cinco posibilidades:
+\return Siete posibilidades:
- #GEOC_SEG_NO_INTERSEC: Los segmentos no tienen ningún punto en común.
- #GEOC_SEG_INTERSEC: Los segmentos se cortan en un punto.
- - #GEOC_SEG_INTERSEC_EXTREMO_NO_COLIN: El extremo de un segmento toca
- al otro segmento, pero los segmentos no son colineales.
- - #GEOC_SEG_INTERSEC_EXTREMO_COLIN: Los segmentos tienen un extremo
+ - #GEOC_SEG_INTERSEC_EXTREMO_NO_COLIN: El extremo de un segmento toca al
+ otro segmento en un punto (excluidos los extremos del segungo), pero
+ los segmentos no son colineales.
+ - #GEOC_SEG_INTERSEC_EXTREMOS_NO_COLIN: Los segmentos tienen un extremo
+ común, pero no son colineales.
+ - #GEOC_SEG_INTERSEC_EXTREMOS_COLIN: Los segmentos tienen un extremo
común y son colineales.
- #GEOC_SEG_INTERSEC_MISMO_SEG: Los dos segmentos son idénticos.
- #GEOC_SEG_INTERSEC_COLIN: Los segmentos tienen más de un punto en
@@ -263,11 +284,15 @@ int PtoComunSegmParalelos2D(const double xA,
un segmento. Este punto extremo se intentará que sea uno de los puntos
iniciales de algún segmento, anque si no lo es, será uno de los finales.
El orden de preferencia de las coordenadas de salida es: A, C, B, D.
+\note Si los segmentos no se tocan, los valores devueltos en \em x e \em y no
+ tienen sentido.
\date 14 de mayo de 2011: Creación de la función.
\date 21 de mayo de 2011: Adición de un nuevo valor de salida:
#GEOC_SEG_INTERSEC_MISMO_SEG.
\date 06 de julio de 2011: Adición de chequeo rápido al principio de la función
para descartar que los segmentos no tienen ningún punto en común.
+\date 10 de agosto de 2013: Adición de un nuevo valor de salida:
+ #GEOC_SEG_INTERSEC_EXTREMOS_NO_COLIN.
*/
int IntersecSegmentos2D(const double xA,
const double yA,
@@ -281,6 +306,59 @@ int IntersecSegmentos2D(const double xA,
double* y);
/******************************************************************************/
/******************************************************************************/
+/**
+\brief Calcula la intersección, de manera simplificada, de dos segmentos AB y CD
+ en el plano.
+\param[in] xA Coordenada X del punto A.
+\param[in] yA Coordenada Y del punto A.
+\param[in] xB Coordenada X del punto B.
+\param[in] yB Coordenada Y del punto B.
+\param[in] xC Coordenada X del punto C.
+\param[in] yC Coordenada Y del punto C.
+\param[in] xD Coordenada X del punto D.
+\param[in] yD Coordenada Y del punto D.
+\return Dos posibilidades:
+ - #GEOC_SEG_NO_INTERSEC: No hay intersección, los segmentos no tienen
+ ningún punto en común.
+ - #GEOC_SEG_INTERSEC: Los segmentos se cortan; tienen, al menos, un
+ punto en común.
+\note Esta función utiliza internamente la macro \ref POS_PTO_RECTA_2D y la
+ función \ref PuntoEntreDosPuntos2DColin, las cuales no son robustas. En
+ consecuencia, los resultados de esta función tampoco lo son.
+\note Para casos de intersección limpia, esta función es, como término medio, un
+ 20% más rápida que \ref IntersecSegmentos2D. El hardware en el que se han
+ hecho las pruebas es Intel Pentium M 1.3 GHz.
+\date 10 de agosto de 2013: Creación de la función.
+*/
+int IntersecSegmentos2DSimple(const double xA,
+ const double yA,
+ const double xB,
+ const double yB,
+ const double xC,
+ const double yC,
+ const double xD,
+ const double yD);
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Convierte el valor de salida de la función \ref IntersecSegmentos2D en el
+ equivalente de la función \ref IntersecSegmentos2DSimple.
+\param[in] cod2D Código de salida de la función \ref IntersecSegmentos2D.
+\return Código de salida equivalente de la función
+ \ref IntersecSegmentos2DSimple. Las equivalencias son:
+ - #GEOC_SEG_NO_INTERSEC -> #GEOC_SEG_NO_INTERSEC.
+ - #GEOC_SEG_INTERSEC -> #GEOC_SEG_INTERSEC.
+ - #GEOC_SEG_INTERSEC_EXTREMO_NO_COLIN -> #GEOC_SEG_INTERSEC.
+ - #GEOC_SEG_INTERSEC_EXTREMOS_NO_COLIN -> #GEOC_SEG_INTERSEC.
+ - #GEOC_SEG_INTERSEC_EXTREMOS_COLIN -> #GEOC_SEG_INTERSEC.
+ - #GEOC_SEG_INTERSEC_MISMO_SEG -> #GEOC_SEG_INTERSEC.
+ - #GEOC_SEG_INTERSEC_COLIN -> #GEOC_SEG_INTERSEC.
+ - Otro valor cualquiera -> #GEOC_SEG_NO_INTERSEC.
+\date 10 de agosto de 2013: Creación de la función.
+*/
+int CodIntSeg2DCodIntSeg2DSimple(const int cod2D);
+/******************************************************************************/
+/******************************************************************************/
#ifdef __cplusplus
}
#endif
diff --git a/src/libgeoc/ventorno.h b/src/libgeoc/ventorno.h
index d330d35..d330d35 100755..100644
--- a/src/libgeoc/ventorno.h
+++ b/src/libgeoc/ventorno.h
diff --git a/src/mate.c b/src/mate.c
new file mode 100644
index 0000000..a87f82f
--- /dev/null
+++ b/src/mate.c
@@ -0,0 +1,813 @@
+/* -*- coding: utf-8 -*- */
+/**
+\ingroup anespec gshhs mate legendre
+@{
+\file mate.c
+\brief Definición de funciones para la realización de cálculos matemáticos
+ generales.
+\author José Luis García Pallero, jgpallero@gmail.com
+\date 17 de mayo de 2010
+\copyright
+Copyright (c) 2009-2016, José Luis García Pallero. All rights reserved.
+\par
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+\par
+- Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+- Neither the name of the copyright holders nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+\par
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/******************************************************************************/
+/******************************************************************************/
+#include"libgeoc/mate.h"
+/******************************************************************************/
+/******************************************************************************/
+/**
+\brief Array que almacena de manera explícita los factoriales de los números que
+ van de \em 0 a #GEOC_MATE_CONST_LDBL_NMAXFAC.
+
+ Este array se basa en el array \p fact_table, que se puede encontrar en
+ el fichero \p gamma.c, de la biblioteca GSL.
+*/
+static __mateFactExpl __tablaFacExpl[GEOC_MATE_CONST_LDBL_NMAXFAC+1]=
+{
+ { 0, 1.0 },
+ { 1, 1.0 },
+ { 2, 2.0 },
+ { 3, 6.0 },
+ { 4, 24.0 },
+ { 5, 120.0 },
+ { 6, 720.0 },
+ { 7, 5040.0 },
+ { 8, 40320.0 },
+ { 9, 362880.0 },
+ { 10, 3628800.0 },
+ { 11, 39916800.0 },
+ { 12, 479001600.0 },
+ { 13, 6227020800.0 },
+ { 14, 87178291200.0 },
+ { 15, 1307674368000.0 },
+ { 16, 20922789888000.0 },
+ { 17, 355687428096000.0 },
+ { 18, 6402373705728000.0 },
+ { 19, 121645100408832000.0 },
+ { 20, 2432902008176640000.0 },
+ { 21, 51090942171709440000.0 },
+ { 22, 1124000727777607680000.0 },
+ { 23, 25852016738884976640000.0 },
+ { 24, 620448401733239439360000.0 },
+ { 25, 15511210043330985984000000.0 },
+ { 26, 403291461126605635584000000.0 },
+ { 27, 10888869450418352160768000000.0 },
+ { 28, 304888344611713860501504000000.0 },
+ { 29, 8841761993739701954543616000000.0 },
+ { 30, 265252859812191058636308480000000.0 },
+ { 31, 8222838654177922817725562880000000.0 },
+ { 32, 263130836933693530167218012160000000.0 },
+ { 33, 8683317618811886495518194401280000000.0 },
+ { 34, 2.95232799039604140847618609644e38 },
+ { 35, 1.03331479663861449296666513375e40 },
+ { 36, 3.71993326789901217467999448151e41 },
+ { 37, 1.37637530912263450463159795816e43 },
+ { 38, 5.23022617466601111760007224100e44 },
+ { 39, 2.03978820811974433586402817399e46 },
+ { 40, 8.15915283247897734345611269600e47 },
+ { 41, 3.34525266131638071081700620534e49 },
+ { 42, 1.40500611775287989854314260624e51 },
+ { 43, 6.04152630633738356373551320685e52 },
+ { 44, 2.65827157478844876804362581101e54 },
+ { 45, 1.19622220865480194561963161496e56 },
+ { 46, 5.50262215981208894985030542880e57 },
+ { 47, 2.58623241511168180642964355154e59 },
+ { 48, 1.24139155925360726708622890474e61 },
+ { 49, 6.08281864034267560872252163321e62 },
+ { 50, 3.04140932017133780436126081661e64 },
+ { 51, 1.55111875328738228022424301647e66 },
+ { 52, 8.06581751709438785716606368564e67 },
+ { 53, 4.27488328406002556429801375339e69 },
+ { 54, 2.30843697339241380472092742683e71 },
+ { 55, 1.26964033536582759259651008476e73 },
+ { 56, 7.10998587804863451854045647464e74 },
+ { 57, 4.05269195048772167556806019054e76 },
+ { 58, 2.35056133128287857182947491052e78 },
+ { 59, 1.38683118545689835737939019720e80 },
+ { 60, 8.32098711274139014427634118320e81 },
+ { 61, 5.07580213877224798800856812177e83 },
+ { 62, 3.14699732603879375256531223550e85 },
+ { 63, 1.982608315404440064116146708360e87 },
+ { 64, 1.268869321858841641034333893350e89 },
+ { 65, 8.247650592082470666723170306800e90 },
+ { 66, 5.443449390774430640037292402480e92 },
+ { 67, 3.647111091818868528824985909660e94 },
+ { 68, 2.480035542436830599600990418570e96 },
+ { 69, 1.711224524281413113724683388810e98 },
+ { 70, 1.197857166996989179607278372170e100 },
+ { 71, 8.504785885678623175211676442400e101 },
+ { 72, 6.123445837688608686152407038530e103 },
+ { 73, 4.470115461512684340891257138130e105 },
+ { 74, 3.307885441519386412259530282210e107 },
+ { 75, 2.480914081139539809194647711660e109 },
+ { 76, 1.885494701666050254987932260860e111 },
+ { 77, 1.451830920282858696340707840860e113 },
+ { 78, 1.132428117820629783145752115870e115 },
+ { 79, 8.946182130782975286851441715400e116 },
+ { 80, 7.156945704626380229481153372320e118 },
+ { 81, 5.797126020747367985879734231580e120 },
+ { 82, 4.753643337012841748421382069890e122 },
+ { 83, 3.945523969720658651189747118010e124 },
+ { 84, 3.314240134565353266999387579130e126 },
+ { 85, 2.817104114380550276949479442260e128 },
+ { 86, 2.422709538367273238176552320340e130 },
+ { 87, 2.107757298379527717213600518700e132 },
+ { 88, 1.854826422573984391147968456460e134 },
+ { 89, 1.650795516090846108121691926250e136 },
+ { 90, 1.485715964481761497309522733620e138 },
+ { 91, 1.352001527678402962551665687590e140 },
+ { 92, 1.243841405464130725547532432590e142 },
+ { 93, 1.156772507081641574759205162310e144 },
+ { 94, 1.087366156656743080273652852570e146 },
+ { 95, 1.032997848823905926259970209940e148 },
+ { 96, 9.916779348709496892095714015400e149 },
+ { 97, 9.619275968248211985332842594960e151 },
+ { 98, 9.426890448883247745626185743100e153 },
+ { 99, 9.332621544394415268169923885600e155 },
+ { 100,9.33262154439441526816992388563e157 },
+ { 101,9.42594775983835942085162312450e159 },
+ { 102,9.61446671503512660926865558700e161 },
+ { 103,9.90290071648618040754671525458e163 },
+ { 104,1.02990167451456276238485838648e166 },
+ { 105,1.08139675824029090050410130580e168 },
+ { 106,1.146280563734708354534347384148e170 },
+ { 107,1.226520203196137939351751701040e172 },
+ { 108,1.324641819451828974499891837120e174 },
+ { 109,1.443859583202493582204882102460e176 },
+ { 110,1.588245541522742940425370312710e178 },
+ { 111,1.762952551090244663872161047110e180 },
+ { 112,1.974506857221074023536820372760e182 },
+ { 113,2.231192748659813646596607021220e184 },
+ { 114,2.543559733472187557120132004190e186 },
+ { 115,2.925093693493015690688151804820e188 },
+ { 116,3.393108684451898201198256093590e190 },
+ { 117,3.96993716080872089540195962950e192 },
+ { 118,4.68452584975429065657431236281e194 },
+ { 119,5.57458576120760588132343171174e196 },
+ { 120,6.68950291344912705758811805409e198 },
+ { 121,8.09429852527344373968162284545e200 },
+ { 122,9.87504420083360136241157987140e202 },
+ { 123,1.21463043670253296757662432419e205 },
+ { 124,1.50614174151114087979501416199e207 },
+ { 125,1.88267717688892609974376770249e209 },
+ { 126,2.37217324288004688567714730514e211 },
+ { 127,3.01266001845765954480997707753e213 },
+ { 128,3.85620482362580421735677065923e215 },
+ { 129,4.97450422247728744039023415041e217 },
+ { 130,6.46685548922047367250730439554e219 },
+ { 131,8.47158069087882051098456875820e221 },
+ { 132,1.11824865119600430744996307608e224 },
+ { 133,1.48727070609068572890845089118e226 },
+ { 134,1.99294274616151887673732419418e228 },
+ { 135,2.69047270731805048359538766215e230 },
+ { 136,3.65904288195254865768972722052e232 },
+ { 137,5.01288874827499166103492629211e234 },
+ { 138,6.91778647261948849222819828311e236 },
+ { 139,9.61572319694108900419719561353e238 },
+ { 140,1.34620124757175246058760738589e241 },
+ { 141,1.89814375907617096942852641411e243 },
+ { 142,2.69536413788816277658850750804e245 },
+ { 143,3.85437071718007277052156573649e247 },
+ { 144,5.55029383273930478955105466055e249 },
+ { 145,8.04792605747199194484902925780e251 },
+ { 146,1.17499720439091082394795827164e254 },
+ { 147,1.72724589045463891120349865931e256 },
+ { 148,2.55632391787286558858117801578e258 },
+ { 149,3.80892263763056972698595524351e260 },
+ { 150,5.71338395644585459047893286526e262 },
+ { 151,8.62720977423324043162318862650e264 },
+ { 152,1.31133588568345254560672467123e267 },
+ { 153,2.00634390509568239477828874699e269 },
+ { 154,3.08976961384735088795856467036e271 },
+ { 155,4.78914290146339387633577523906e273 },
+ { 156,7.47106292628289444708380937294e275 },
+ { 157,1.17295687942641442819215807155e278 },
+ { 158,1.85327186949373479654360975305e280 },
+ { 159,2.94670227249503832650433950735e282 },
+ { 160,4.71472363599206132240694321176e284 },
+ { 161,7.59070505394721872907517857094e286 },
+ { 162,1.22969421873944943411017892849e289 },
+ { 163,2.00440157654530257759959165344e291 },
+ { 164,3.28721858553429622726333031164e293 },
+ { 165,5.42391066613158877498449501421e295 },
+ { 166,9.00369170577843736647426172359e297 },
+ { 167,1.50361651486499904020120170784e300 },
+ { 168,2.52607574497319838753801886917e302 },
+ { 169,4.26906800900470527493925188890e304 },
+ { 170,7.25741561530799896739672821113e306 },
+ { 171,1.24101807021766782342484052410e309L },
+ { 172,2.13455108077438865629072570146e311L },
+ { 173,3.69277336973969237538295546352e313L },
+ { 174,6.42542566334706473316634250653e315L },
+ { 175,1.12444949108573632830410993864e318L },
+ { 176,1.97903110431089593781523349201e320L },
+ { 177,3.50288505463028580993296328086e322L },
+ { 178,6.23513539724190874168067463993e324L },
+ { 179,1.11608923610630166476084076055e327L },
+ { 180,2.00896062499134299656951336898e329L },
+ { 181,3.63621873123433082379081919786e331L },
+ { 182,6.61791809084648209929929094011e333L },
+ { 183,1.21107901062490622417177024204e336L },
+ { 184,2.22838537954982745247605724535e338L },
+ { 185,4.12251295216718078708070590390e340L },
+ { 186,7.66787409103095626397011298130e342L },
+ { 187,1.43389245502278882136241112750e345L },
+ { 188,2.69571781544284298416133291969e347L },
+ { 189,5.09490667118697324006491921822e349L },
+ { 190,9.68032267525524915612334651460e351L },
+ { 191,1.84894163097375258881955918429e354L },
+ { 192,3.54996793146960497053355363384e356L },
+ { 193,6.85143810773633759312975851330e358L },
+ { 194,1.32917899290084949306717315158e361L },
+ { 195,2.59189903615665651148098764559e363L },
+ { 196,5.08012211086704676250273578535e365L },
+ { 197,1.00078405584080821221303894971e368L },
+ { 198,1.98155243056480026018181712043e370L },
+ { 199,3.94328933682395251776181606966e372L },
+ { 200,7.88657867364790503552363213932e374L }
+};
+/******************************************************************************/
+/******************************************************************************/
+int GeocTipoCalcProd(void)
+{
+ //distingimos los tipos de cálculo
+#if defined(CALCULO_PRODUCTO_MULT)
+ return GEOC_PROD_MULT;
+#elif defined(CALCULO_PRODUCTO_LOG)
+ return GEOC_PROD_LOG;
+#else
+ #error *****No se ha definido el método de cálculo de la función Producto()
+#endif
+}
+/******************************************************************************/
+/******************************************************************************/
+double Media(const double* datos,
+ const size_t nDatos,
+ const int inc)
+{
+ //índice para recorrer un bucle
+ size_t i=0;
+ //posición del elemento de trabajo
+ size_t pos=0;
+ //variable para almacenar el resultado
+ double resultado=0.0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //calculamos la posición del elemento inicial del vector
+ pos = GEOC_INICIO_VEC(nDatos,inc);
+ //recorremos el vector
+ for(i=0;i<nDatos;i++)
+ {
+ //vamos sumando los valores del vector
+ resultado += datos[pos];
+ //aumentamos el contador de posiciones
+ pos = inc>0 ? pos+(size_t)inc : pos-(size_t)abs(inc);
+ }
+ //calculamos la media
+ resultado /= (double)nDatos;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return resultado;
+}
+/******************************************************************************/
+/******************************************************************************/
+double Varianza(const double* datos,
+ const size_t nDatos,
+ const int inc,
+ const double media)
+{
+ //índice para recorrer un bucle
+ size_t i=0;
+ //posición del elemento de trabajo
+ size_t pos=0;
+ //residuo
+ double res=0.0;
+ //variable para almacenar el resultado
+ double resultado=0.0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //calculamos la posición del elemento inicial del vector
+ pos = GEOC_INICIO_VEC(nDatos,inc);
+ //recorremos el vector
+ for(i=0;i<nDatos;i++)
+ {
+ //calculamos el residuo
+ res = datos[pos]-media;
+ //vamos sumando los cuadrados del valor menos la media
+ resultado += res*res;
+ //aumentamos el contador de posiciones
+ pos = inc>0 ? pos+(size_t)inc : pos-(size_t)abs(inc);
+ }
+ //calculamos la varianza
+ resultado /= (double)(nDatos-1);
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return resultado;
+}
+/******************************************************************************/
+/******************************************************************************/
+double MediaPonderada(const double* datos,
+ const size_t nDatos,
+ const int incDatos,
+ const double* pesos,
+ const int incPesos)
+{
+ //índice para recorrer un bucle
+ size_t i=0;
+ //posiciones de los elementos de trabajo
+ size_t posDatos=0,posPesos;
+ //variable auxiliar
+ double sumaPesos=0.0;
+ //variable para almacenar el resultado
+ double resultado=0.0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //calculamos la posición del elemento inicial de los vectores
+ posDatos = GEOC_INICIO_VEC(nDatos,incDatos);
+ posPesos = GEOC_INICIO_VEC(nDatos,incPesos);
+ //recorremos el vector
+ for(i=0;i<nDatos;i++)
+ {
+ //vamos sumando los valores del vector
+ resultado += datos[posDatos]*pesos[posPesos];
+ //aumentamos el contador de posiciones
+ posDatos = incDatos>0 ? posDatos+(size_t)incDatos
+ : posDatos-(size_t)abs(incDatos);
+ posPesos = incPesos>0 ? posPesos+(size_t)incPesos
+ : posPesos-(size_t)abs(incPesos);
+ //vamos sumando los pesos
+ sumaPesos += pesos[posPesos];
+ }
+ //calculamos la media
+ resultado /= sumaPesos;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return resultado;
+}
+/******************************************************************************/
+/******************************************************************************/
+double Mediana(const double* datos,
+ const size_t nDatos,
+ const int inc)
+{
+ //posición del elemento central
+ size_t pos=0;
+ //posición de inicio del vector
+ size_t posInicio;
+ //variable auxiliar
+ size_t posAux=0;
+ //variable para almacenar el resultado
+ double resultado=0.0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //calculamos la posición del elemento inicial del vector
+ posInicio = GEOC_INICIO_VEC(nDatos,inc);
+ //distinguimos entre número par o impar de datos
+ if(nDatos%2)
+ {
+ //el número de datos es impar, calculamos la posición del punto medio
+ pos = (size_t)ceil((double)nDatos/2.0)-1;
+ //calculamos la posición en memoria
+ pos = inc>0 ? posInicio+pos*(size_t)inc
+ : posInicio-pos*(size_t)abs(inc);
+ //extraemos el dato
+ resultado = datos[pos];
+ }
+ else
+ {
+ //el número de datos es par, calculamos la posición de los puntos medios
+ pos = (size_t)((double)nDatos/2.0)-1;
+ //calculamos la posición en memoria
+ pos = inc>0 ? posInicio+pos*(size_t)inc
+ : posInicio-pos*(size_t)abs(inc);
+ //calculamos la posición del siguiente elemento del vector
+ posAux = inc>0 ? pos+(size_t)inc : pos-(size_t)abs(inc);
+ //calculamos la mediana
+ resultado = (datos[pos]+datos[posAux])/2.0;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return resultado;
+}
+/******************************************************************************/
+/******************************************************************************/
+double ProductoMult(size_t inicio,
+ size_t fin)
+{
+ //variables intermedias
+ size_t menor=0.0,mayor=0.0;
+ //variable para almacenar el resultado
+ double resultado=1.0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //resolvemos el problema de forma iterativa
+ if((inicio==0)||(fin==0))
+ {
+ resultado = 0.0;
+ }
+ else
+ {
+ //seleccionamos los elementos mayor y menor
+ menor = inicio<=fin ? inicio : fin;
+ mayor = inicio>fin ? inicio : fin;
+ //multiplicamos
+ while(menor<=mayor)
+ {
+ resultado *= (double)menor;
+ menor++;
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return resultado;
+}
+/******************************************************************************/
+/******************************************************************************/
+long double ProductoMultLD(size_t inicio,
+ size_t fin)
+{
+ //variables intermedias
+ size_t menor=0.0,mayor=0.0;
+ //variable para almacenar el resultado
+ long double resultado=1.0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //resolvemos el problema de forma iterativa
+ if((inicio==0)||(fin==0))
+ {
+ resultado = 0.0;
+ }
+ else
+ {
+ //seleccionamos los elementos mayor y menor
+ menor = inicio<=fin ? inicio : fin;
+ mayor = inicio>fin ? inicio : fin;
+ //multiplicamos
+ while(menor<=mayor)
+ {
+ resultado *= (long double)menor;
+ menor++;
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return resultado;
+}
+/******************************************************************************/
+/******************************************************************************/
+double ProductoLog(size_t inicio,
+ size_t fin)
+{
+ //variables intermedias
+ size_t menor=0.0,mayor=0.0;
+ //variable para almacenar el resultado
+ double resultado=0.0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //resolvemos el problema de forma iterativa
+ if((inicio==0)||(fin==0))
+ {
+ resultado = 0.0;
+ }
+ else
+ {
+ //seleccionamos los elementos mayor y menor
+ menor = inicio<=fin ? inicio : fin;
+ mayor = inicio>fin ? inicio : fin;
+ //multiplicamos
+ while(menor<=mayor)
+ {
+ resultado += log((double)menor);
+ menor++;
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return round(pow(GEOC_CONST_E,resultado));
+}
+/******************************************************************************/
+/******************************************************************************/
+long double ProductoLogLD(size_t inicio,
+ size_t fin)
+{
+ //variables intermedias
+ size_t menor=0.0,mayor=0.0;
+ //variable para almacenar el resultado
+ long double resultado=0.0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //resolvemos el problema de forma iterativa
+ if((inicio==0)||(fin==0))
+ {
+ resultado = 0.0;
+ }
+ else
+ {
+ //seleccionamos los elementos mayor y menor
+ menor = inicio<=fin ? inicio : fin;
+ mayor = inicio>fin ? inicio : fin;
+ //multiplicamos
+ while(menor<=mayor)
+ {
+ resultado += (long double)log((double)menor);
+ menor++;
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return roundl(powl((long double)GEOC_CONST_E,resultado));
+}
+/******************************************************************************/
+/******************************************************************************/
+double Producto(size_t inicio,
+ size_t fin)
+{
+ //variable para almacenar el resultado
+ double resultado=0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //método de cálculo para números mayores que GEOC_MATE_CONST_NMAXFAC
+#if defined(CALCULO_PRODUCTO_MULT)
+ resultado = ProductoMult(inicio,fin);
+#elif defined(CALCULO_PRODUCTO_LOG)
+ resultado = ProductoLog(inicio,fin);
+#else
+ #error *****No se ha definido el método de cálculo de la función Producto()
+#endif
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return resultado;
+}
+/******************************************************************************/
+/******************************************************************************/
+long double ProductoLD(size_t inicio,
+ size_t fin)
+{
+ //variable para almacenar el resultado
+ long double resultado=0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //método de cálculo para números mayores que GEOC_MATE_CONST_NMAXFAC
+#if defined(CALCULO_PRODUCTO_MULT)
+ resultado = ProductoMultLD(inicio,fin);
+#elif defined(CALCULO_PRODUCTO_LOG)
+ resultado = ProductoLogLD(inicio,fin);
+#else
+ #error *****No se ha definido el método de cálculo de la función Producto()
+#endif
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return resultado;
+}
+/******************************************************************************/
+/******************************************************************************/
+double FactorialMult(size_t numero)
+{
+ //variable para almacenar el resultado
+ double resultado=1.0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //resolvemos el problema
+ if(numero)
+ {
+ resultado = ProductoMult((size_t)1,numero);
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return resultado;
+}
+/******************************************************************************/
+/******************************************************************************/
+long double FactorialMultLD(size_t numero)
+{
+ //variable para almacenar el resultado
+ long double resultado=1.0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //resolvemos el problema
+ if(numero)
+ {
+ resultado = ProductoMultLD((size_t)1,numero);
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return resultado;
+}
+/******************************************************************************/
+/******************************************************************************/
+double FactorialLog(size_t numero)
+{
+ //variable para almacenar el resultado
+ double resultado=1.0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //resolvemos el problema
+ if(numero)
+ {
+ resultado = ProductoLog((size_t)1,numero);
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return resultado;
+}
+/******************************************************************************/
+/******************************************************************************/
+long double FactorialLogLD(size_t numero)
+{
+ //variable para almacenar el resultado
+ long double resultado=1.0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //resolvemos el problema
+ if(numero)
+ {
+ resultado = ProductoLogLD((size_t)1,numero);
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return resultado;
+}
+/******************************************************************************/
+/******************************************************************************/
+double Factorial(size_t numero)
+{
+ //variable para almacenar el resultado
+ double resultado=0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //calculamos el factorial
+ if(numero<=GEOC_MATE_CONST_DBL_NMAXFAC)
+ {
+ resultado = (double)__tablaFacExpl[numero].valor;
+ }
+ else
+ {
+ //método de cálculo para números mayores que GEOC_MATE_CONST_DBL_NMAXFAC
+#if defined(CALCULO_PRODUCTO_MULT)
+ resultado = FactorialMult(numero);
+#elif defined(CALCULO_PRODUCTO_LOG)
+ resultado = FactorialLog(numero);
+#else
+ #error *****No se ha definido el método de cálculo de la función Factorial()
+#endif
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return resultado;
+}
+/******************************************************************************/
+/******************************************************************************/
+long double FactorialLD(size_t numero)
+{
+ //variable para almacenar el resultado
+ long double resultado=0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //calculamos el factorial
+ if(numero<=GEOC_MATE_CONST_LDBL_NMAXFAC)
+ {
+ resultado = __tablaFacExpl[numero].valor;
+ }
+ else
+ {
+ //cálculo para números mayores que GEOC_MATE_CONST_LDBL_NMAXFAC
+#if defined(CALCULO_PRODUCTO_MULT)
+ resultado = FactorialMultLD(numero);
+#elif defined(CALCULO_PRODUCTO_LOG)
+ resultado = FactorialLogLD(numero);
+#else
+ #error *****No se ha definido el método de cálculo de la función Factorial()
+#endif
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return resultado;
+}
+/******************************************************************************/
+/******************************************************************************/
+void ProductoVectorial(const double x1,
+ const double y1,
+ const double z1,
+ const double x2,
+ const double y2,
+ const double z2,
+ double* x,
+ double* y,
+ double* z)
+{
+ //calculamos las componentes
+ *x = y1*z2-y2*z1;
+ *y = x2*z1-x1*z2;
+ *z = x1*y2-x2*y1;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return;
+}
+/******************************************************************************/
+/******************************************************************************/
+void SinCosRecurrencia(const double anguloIni,
+ const double incAngulo,
+ const size_t numValores,
+ double* seno,
+ const size_t incSeno,
+ double* coseno,
+ const size_t incCoseno)
+{
+ //índice para recorrer bucles
+ size_t i=0;
+ //posiciones en los vectores de trabajo
+ size_t pS=0,pC=0;
+ //variables auxiliares
+ double aux=sin(incAngulo/2.0);
+ double alfa=2.0*aux*aux,beta=sin(incAngulo);
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //seno y coseno del primero elemento de la serie
+ seno[pS] = sin(anguloIni);
+ coseno[pC] = cos(anguloIni);
+ //recorremos el resto de valores
+ for(i=1;i<numValores;i++)
+ {
+ //calculamos las posiciones en los vectores de salida
+ pS += incSeno;
+ pC += incCoseno;
+ //vamos calculando los senos y los cosenos
+ seno[pS] = seno[pS-incSeno]-
+ (alfa*seno[pS-incSeno]-beta*coseno[pC-incCoseno]);
+ coseno[pC] = coseno[pC-incCoseno]-
+ (alfa*coseno[pC-incCoseno]+beta*seno[pS-incSeno]);
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return;
+}
+/******************************************************************************/
+/******************************************************************************/
+void SplineCubicoNatural(double* x,
+ double* y,
+ size_t nDatos,
+ double* xInterp,
+ size_t nInterp)
+{
+ //sentencias para que no salgan avisos en la compilación
+ x = x;
+ y = y;
+ nDatos = nDatos;
+ xInterp = xInterp;
+ nInterp = nInterp;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return;
+}
+/******************************************************************************/
+/******************************************************************************/
+/** @} */
+/******************************************************************************/
+/******************************************************************************/
+/* kate: encoding utf-8; end-of-line unix; syntax c; indent-mode cstyle; */
+/* kate: replace-tabs on; space-indent on; tab-indents off; indent-width 4; */
+/* kate: line-numbers on; folding-markers on; remove-trailing-space on; */
+/* kate: backspace-indents on; show-tabs on; */
+/* kate: word-wrap-column 80; word-wrap-marker-color #D2D2D2; word-wrap off; */
diff --git a/src/polig.c b/src/polig.c
index 4cb3df9..1252999 100755..100644
--- a/src/polig.c
+++ b/src/polig.c
@@ -7,12 +7,12 @@
\author José Luis García Pallero, jgpallero@gmail.com
\note Este fichero contiene funciones paralelizadas con OpenMP.
\date 20 de abril de 2011
-\section Licencia Licencia
-Copyright (c) 2011, José Luis García Pallero. All rights reserved.
-
+\copyright
+Copyright (c) 2011-2020, José Luis García Pallero. All rights reserved.
+\par
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
-
+\par
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this
@@ -21,7 +21,7 @@ are permitted provided that the following conditions are met:
- Neither the name of the copyright holders nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
-
+\par
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -93,6 +93,7 @@ polig* IniciaPoligVacio(void)
sal->yMin = NULL;
sal->yMax = NULL;
sal->area = NULL;
+ sal->atr = NULL;
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
//salimos de la función
@@ -342,6 +343,8 @@ polig* CreaPolig(const double* x,
const size_t incY,
int* idError)
{
+ //variable para recorrer bucles
+ size_t i=0;
//número de puntos
size_t ptos=0;
//número máximo de elementos de los vectores de coordenadas
@@ -383,7 +386,7 @@ polig* CreaPolig(const double* x,
//paralelización con OpenMP
#if defined(_OPENMP)
#pragma omp parallel sections default(none) \
- shared(posNanX,x,nNanX,posNanY,y,nNanY)
+ shared(posNanX,nElem,incX,x,nNanX,posNanY,incY,y,nNanY)
#endif
{
#if defined(_OPENMP)
@@ -548,6 +551,29 @@ polig* CreaPolig(const double* x,
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
+ //inicializamos el vector de atributos
+ sal->atr = (int*)malloc(sal->nPolig*sizeof(int));
+ //comprobamos los posibles errores
+ if(sal->atr==NULL)
+ {
+ //liberamos la memoria asignada
+ LibMemPolig(sal);
+ free(posNanX);
+ free(posNanY);
+ //asignamos la variable de error
+ *idError = GEOC_ERR_ASIG_MEMORIA;
+ //mensaje de error
+ GEOC_ERROR("Error de asignación de memoria");
+ //salimos de la función
+ return NULL;
+ }
+ //Inicializamos el vector de atributos a 0
+ for(i=0;i<sal->nPolig;i++)
+ {
+ sal->atr[i] = 0;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
//liberamos la memoria asignada
free(posNanX);
free(posNanY);
@@ -569,11 +595,12 @@ void EnlazaCamposPolig(polig* poliEnt,
free(poliSal->x);
free(poliSal->y);
}
- //comprobamos si hay algún polígono en los vectores de posiciones
+ //compruebo si hay algún polígono en los vectores de posiciones y atributos
if(poliSal->nPolig)
{
free(poliSal->posIni);
free(poliSal->nVert);
+ free(poliSal->atr);
}
//comprobamos si hay límites calculados
if(poliSal->hayLim)
@@ -604,6 +631,7 @@ void EnlazaCamposPolig(polig* poliEnt,
poliSal->yMax = poliEnt->yMax;
poliSal->hayArea = poliEnt->hayArea;
poliSal->area = poliEnt->area;
+ poliSal->atr = poliEnt->atr;
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
//salimos de la función
@@ -683,7 +711,7 @@ polig* CopiaPolig(const polig* poli,
if(poli->hayArea)
{
//calculamos las áreas
- *idError = CalcAreaPolig(sal);
+ *idError = CalcAreaPolig(sal,1.0,0,0.0,0.0);
//comprobamos los posibles errores
if((*idError)!=GEOC_ERR_NO_ERROR)
{
@@ -741,6 +769,7 @@ int AnyadePoligPolig(polig* poli,
poli->y = (double*)realloc(poli->y,nElem*sizeof(double));
poli->posIni = (size_t*)realloc(poli->posIni,nPolig*sizeof(size_t));
poli->nVert = (size_t*)realloc(poli->nVert,nPolig*sizeof(size_t));
+ poli->atr = (int*)realloc(poli->atr,nPolig*sizeof(int));
//reasignamos también para los posibles vectores de límites y superficies
if(poli->hayLim)
{
@@ -755,7 +784,7 @@ int AnyadePoligPolig(polig* poli,
}
//comprobamos los posibles errores en las asignaciones obligatorias
if((poli->x==NULL)||(poli->y==NULL)||(poli->posIni==NULL)||
- (poli->nVert==NULL))
+ (poli->nVert==NULL)||(poli->atr==NULL))
{
//mensaje de error
GEOC_ERROR("Error de asignación de memoria");
@@ -810,6 +839,7 @@ int AnyadePoligPolig(polig* poli,
//copiamos las posiciones de inicio actualizadas y el número de vértices
poli->posIni[poli->nPolig+i] = anyade->posIni[i]+pos;
poli->nVert[poli->nPolig+i] = anyade->nVert[i];
+ poli->atr[poli->nPolig+i] = anyade->atr[i];
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
@@ -997,6 +1027,11 @@ void LibMemPolig(polig* datos)
{
free(datos->area);
}
+ //liberamos la memoria asignada al vector de atributos
+ if(datos->atr!=NULL)
+ {
+ free(datos->atr);
+ }
//liberamos la memoria asignada a la estructura
free(datos);
}
@@ -1088,7 +1123,7 @@ void LimitesPoligono(const double* x,
//paralelización con OpenMP
#if defined(_OPENMP)
#pragma omp parallel sections default(none) \
- shared(x,posXMin,posXMax,y,posYMin,posYMax)
+ shared(incX,x,nElem,posXMin,posXMax,incY,y,posYMin,posYMax)
#endif
{
//posiciones en el vector X
@@ -1136,7 +1171,7 @@ void LimitesPoligonosPolig(const double* x,
//paralelización con OpenMP
#if defined(_OPENMP)
#pragma omp parallel for default(none) schedule(dynamic) \
- shared(posIni,x,y,nVert,xMin,xMax,yMin,yMax) \
+ shared(nPolig,posIni,restaPosIni,incX,x,incY,y,nVert,xMin,xMax,yMin,yMax) \
private(i,pI)
#endif
//recorremos el número de polígonos
@@ -1155,38 +1190,121 @@ void LimitesPoligonosPolig(const double* x,
}
/******************************************************************************/
/******************************************************************************/
-int CalcAreaPolig(polig* poli)
+int CalcAreaPolig(polig* poli,
+ const double facCoor,
+ const int geo,
+ const double a,
+ const double f)
{
+ //índices para recorrer bucles
+ size_t i=0,j=0;
+ //variable de posición
+ size_t pos=0;
+ //longitud origen
+ double lon0=0.0;
+ //coordenadas de trabajo
+ double* x=NULL;
+ double* y=NULL;
//variable de estado (salida)
int estado=GEOC_ERR_NO_ERROR;
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
//comprobamos salida rápida
- if((poli->nPolig==0)||(poli->hayArea))
+ if(poli->nPolig==0)
{
- //salimos de la función si la estructura no contiene polígonos o si
- //éstos ya tienen calculada su superficie
+ //salimos de la función si la estructura
return estado;
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
- //asignamos memoria para el vector de superficies
- poli->area = (double*)malloc((poli->nPolig)*sizeof(double));
- //comprobamos los posibles errores
- if(poli->area==NULL)
+ //comprobamos si la estructura no contiene área calculada
+ if(!(poli->hayArea))
{
- //mensaje de error
- GEOC_ERROR("Error de asignación de memoria");
- //salimos de la función
- return GEOC_ERR_ASIG_MEMORIA;
+ //asignamos memoria para el vector de superficies
+ poli->area = (double*)malloc((poli->nPolig)*sizeof(double));
+ //comprobamos los posibles errores
+ if(poli->area==NULL)
+ {
+ //mensaje de error
+ GEOC_ERROR("Error de asignación de memoria");
+ //salimos de la función
+ return GEOC_ERR_ASIG_MEMORIA;
+ }
+ //indicamos que sí hay superficies
+ poli->hayArea = 1;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //comprobamos si trabajamos sobre la superficie del elipsoide
+ if(geo||(facCoor!=1.0))
+ {
+ //asignamos memoria para los vectores auxiliares
+ x = (double*)malloc((poli->nElem)*sizeof(double));
+ y = (double*)malloc((poli->nElem)*sizeof(double));
+ //comprobamos posibles errores
+ if((x==NULL)||(y==NULL))
+ {
+ //volvemos a indicar que no hay áreas
+ poli->hayArea = 0;
+ //liberamos la memoria asignada
+ free(poli->area);
+ free(x);
+ free(y);
+ //mensaje de error
+ GEOC_ERROR("Error de asignación de memoria");
+ //salimos de la función
+ return GEOC_ERR_ASIG_MEMORIA;
+ }
+ //copiamos las coordenadas y aplicamos factor de escala
+ //si estamos sobre el elipsoide, este paso se hace luego
+ if(!geo)
+ {
+ for(i=0;i<poli->nElem;i++)
+ {
+ x[i] = poli->x[i]*facCoor;
+ y[i] = poli->y[i]*facCoor;
+ }
+ }
+ else
+ {
+ //recorremos los polígonos
+ for(i=0;i<poli->nPolig;i++)
+ {
+ //posición de inicio en los vectores de coordenadas
+ pos = poli->posIni[i];
+ //calculamos la longitud media del polígono de trabajo
+ lon0 = Media(&(poli->x[pos]),poli->nVert[i],1);
+ //recorremos los vértices del polígono
+ for(j=0;j<poli->nVert[i];j++)
+ {
+ //proyectamos, aplicando el factor de escala
+ ProjCilinEquivLambertLat0Ec(poli->y[pos+j]*facCoor,
+ poli->x[pos+j]*facCoor,
+ lon0*facCoor,a,f,&x[pos+j],
+ &y[pos+j]);
+ }
+ }
+ }
+ }
+ else
+ {
+ //no hace falta copiarlas a los vectores auxiliares, sólo enlazarlas
+ x = poli->x;
+ y = poli->y;
}
- //indicamos que sí hay superficies
- poli->hayArea = 1;
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
//calculamos las superficies de todos los polígonos
- AreaPoligonosSimplesPolig(poli->x,poli->y,1,1,poli->posIni,poli->nVert,
- poli->nPolig,0,poli->area);
+ AreaPoligonosSimplesPolig(x,y,1,1,poli->posIni,poli->nVert,poli->nPolig,0,
+ poli->area);
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //liberamos la memoria utilizada
+ if(geo||(facCoor!=1.0))
+ {
+ free(x);
+ free(y);
+ }
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
//salimos de la función
@@ -1208,7 +1326,7 @@ double AreaPoligonoSimple(const double* x,
double area=0.0;
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
- //si el primero punto es el mismo que el último, restamos una unidad al
+ //si el primer punto es el mismo que el último, restamos una unidad al
//número de elementos pasado, ya que el algoritmo está preparado para
//trabajar con un vector en el que no se repite el primer punto
if((x[0]==x[(nElem-1)*incX])&&(y[0]==y[(nElem-1)*incY]))
@@ -1255,7 +1373,7 @@ void AreaPoligonosSimplesPolig(const double* x,
//paralelización con OpenMP
#if defined(_OPENMP)
#pragma omp parallel for default(none) schedule(dynamic) \
- shared(posIni,area,x,y,nVert) \
+ shared(nPolig,posIni,restaPosIni,area,incX,x,incY,y,nVert) \
private(i,pI)
#endif
//recorremos el número de polígonos
@@ -1285,7 +1403,7 @@ void EscalaYTrasladaPolig(polig* poli,
//paralelización con OpenMP
#if defined(_OPENMP)
#pragma omp parallel sections default(none) \
- shared(poli)
+ shared(poli,escalaX,trasladaX,escalaY,trasladaY)
#endif
{
#if defined(_OPENMP)
@@ -1338,7 +1456,7 @@ void TrasladaYEscalaPolig(polig* poli,
//paralelización con OpenMP
#if defined(_OPENMP)
#pragma omp parallel sections default(none) \
- shared(poli)
+ shared(poli,escalaX,trasladaX,escalaY,trasladaY)
#endif
{
#if defined(_OPENMP)
@@ -1410,20 +1528,34 @@ void MuevePolig(polig* poli,
/******************************************************************************/
/******************************************************************************/
int AligeraPolig(polig* poli,
+ const int esf,
+ const double facCoor,
const double tol,
+ const int paralelizaTol,
const enum GEOC_DPEUCKER_ROBUSTO robusto,
- const size_t nPtosRobusto,
- const size_t nSegRobusto)
+ const size_t nSegRobOrig,
+ const size_t nSegRobAuto,
+ const double a,
+ const double f)
{
//índices para recorrer bucles
size_t i=0,j=0;
+ //tolerancia angular
+ double tolAng=fabs(GEOC_ARC_RES_ANG);
//posición inicial del polígono de trabajo y número de puntos del aligerado
- size_t posIni=0,nPtos=0;
+ size_t posIni=0,nVert=0,nPtos=0;
//puntos colineales
int colin=0;
//coordenadas de los polígonos aligerados
double* x=NULL;
double* y=NULL;
+ double* xF=NULL;
+ double* yF=NULL;
+ //vértices del polígono de entrada más largo
+ size_t nVertMax=0;
+ //matriz de rotación y coordenadas en el sistema rotado
+ double mRot[3][3];
+ double latCR=0.0;
//estructura auxiliar
polig* aux=NULL;
//vector de posiciones después del aligerado
@@ -1452,20 +1584,65 @@ int AligeraPolig(polig* poli,
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
+ //comprobamos si hay factor de escala para las coordenadas
+ if(facCoor!=1.0)
+ {
+ //vértices del polígono más largo
+ nVertMax = MaximoSizeT(poli->nVert,poli->nPolig,1);
+ //asignamos memoria para las coordenadas con factor de escala
+ xF = (double*)malloc(nVertMax*sizeof(double));
+ yF = (double*)malloc(nVertMax*sizeof(double));
+ //comprobamos posibles errores
+ if((xF==NULL)||(yF==NULL))
+ {
+ //liberamos la memoria asignada
+ LibMemPolig(aux);
+ free(xF);
+ free(yF);
+ //mensaje de error
+ GEOC_ERROR("Error de asignación de memoria");
+ //salimos de la función
+ return GEOC_ERR_ASIG_MEMORIA;
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
//recorremos el número de polígonos almacenados
for(i=0;i<poli->nPolig;i++)
{
//extraemos la posición inicial del polígono de trabajo
posIni = poli->posIni[i];
+ //número de vértices del polígono
+ nVert = poli->nVert[i];
+ //comprobamos si hay factor de escala para las coordenadas
+ if(facCoor!=1.0)
+ {
+ //copiamos las coordenadas y aplicamos el factor de escala
+ for(j=0;j<nVert;j++)
+ {
+ xF[j] = facCoor*(poli->x[posIni+j]);
+ yF[j] = facCoor*(poli->y[posIni+j]);
+ }
+ }
+ else
+ {
+ //las coordenadas del polígono se quedan como están
+ xF = &(poli->x[posIni]);
+ yF = &(poli->y[posIni]);
+ }
//aligeramos el polígono de trabajo
- pos = AligeraPolilinea(&(poli->x[posIni]),&(poli->y[posIni]),
- poli->nVert[i],1,1,tol,robusto,nPtosRobusto,
- nSegRobusto,&nPtos);
+ pos = AligeraPolilinea(xF,yF,nVert,1,1,tol,paralelizaTol,robusto,
+ nSegRobOrig,nSegRobAuto,esf,&nPtos);
//comprobamos posibles errores
if(pos==NULL)
{
//liberamos la memoria asignada
LibMemPolig(aux);
+ if(facCoor!=1.0)
+ {
+ free(xF);
+ free(yF);
+ }
//mensaje de error
GEOC_ERROR("Error de asignación de memoria");
//salimos de la función
@@ -1474,13 +1651,35 @@ int AligeraPolig(polig* poli,
//comprobamos si el polígono se ha quedado en tres puntos
if(nPtos==3)
{
- //comprobamos si los tres puntos son colineales
- colin = TresPuntosColineales2D(poli->x[posIni+pos[0]],
- poli->y[posIni+pos[0]],
- poli->x[posIni+pos[1]],
- poli->y[posIni+pos[1]],
- poli->x[posIni+pos[2]],
- poli->y[posIni+pos[2]]);
+ //distinguimos entre trabajo sobre la esfera y sobre el plano
+ if(esf)
+ {
+ //calculamos la rotación para pasar a un sistema que contenga a
+ //los dos primeros puntos en el ecuador, con el primero en
+ //(lat=0,lon=0)
+ RotaArco00Ecuador(tolAng,
+ yF[pos[0]],xF[pos[0]],yF[pos[1]],xF[pos[1]],
+ mRot,NULL);
+ //calculamos la latitud del tercer punto
+ AplicaMatrizRotacionCoorGeod(1,yF[pos[2]],xF[pos[2]],mRot,
+ &latCR,NULL);
+ //comprobamos si la latitud es 0.0
+ if(GEOC_ES_CERO(latCR,GEOC_ARC_RES_ANG))
+ {
+ //los puntos son colineales
+ colin = 1;
+ }
+ }
+ else
+ {
+ //comprobamos si los tres puntos son colineales
+ colin = TresPuntosColineales2D(poli->x[posIni+pos[0]],
+ poli->y[posIni+pos[0]],
+ poli->x[posIni+pos[1]],
+ poli->y[posIni+pos[1]],
+ poli->x[posIni+pos[2]],
+ poli->y[posIni+pos[2]]);
+ }
}
//comprobamos si después del aligerado queda algún polígono
if((nPtos>3)||((nPtos==3)&&(!colin)))
@@ -1497,6 +1696,11 @@ int AligeraPolig(polig* poli,
free(pos);
free(x);
free(y);
+ if(facCoor!=1.0)
+ {
+ free(xF);
+ free(yF);
+ }
//mensaje de error
GEOC_ERROR("Error de asignación de memoria");
//salimos de la función
@@ -1520,6 +1724,11 @@ int AligeraPolig(polig* poli,
free(pos);
free(x);
free(y);
+ if(facCoor!=1.0)
+ {
+ free(xF);
+ free(yF);
+ }
//escribimos el mensaje de error
GEOC_ERROR("Error de asignación de memoria");
//salimos de la función
@@ -1544,6 +1753,11 @@ int AligeraPolig(polig* poli,
{
//liberamos la memoria asignada
LibMemPolig(aux);
+ if(facCoor!=1.0)
+ {
+ free(xF);
+ free(yF);
+ }
//mensaje de error
GEOC_ERROR("Error de asignación de memoria");
//salimos de la función
@@ -1554,7 +1768,7 @@ int AligeraPolig(polig* poli,
if(poli->hayArea)
{
//calculamos las áreas
- estado = CalcAreaPolig(aux);
+ estado = CalcAreaPolig(aux,facCoor,esf,a,f);
//comprobamos los posibles errores
if(estado!=GEOC_ERR_NO_ERROR)
{
@@ -1571,9 +1785,15 @@ int AligeraPolig(polig* poli,
//enlazamos los campos de la estructura auxiliar a los de la estructura de
//salida
EnlazaCamposPolig(aux,poli);
- //liberamos la memoria asignada a la estructura auxiliar (pero no a sus
- //campos)
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //liberamos la memoria asignada
free(aux);
+ if(facCoor!=1.0)
+ {
+ free(xF);
+ free(yF);
+ }
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
//salimos de la función
@@ -1588,6 +1808,8 @@ void ImprimeCabeceraPoligFichero(const polig* poli,
const char formCoor[],
const int impArea,
const char formArea[],
+ const int impAtr,
+ const char formAtr[],
const double factorX,
const double factorY,
const int repitePrimerPunto,
@@ -1713,6 +1935,15 @@ shared(poli,pos,nVert,posXMin,posXMax,posYMin,posYMax)
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
+ //comprobamos si hay que imprimir los atributos
+ if(impAtr)
+ {
+ //imprimimos el valor del atributo
+ fprintf(idFich," ");
+ fprintf(idFich,formAtr,poli->atr[indice]);
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
//salto de línea final
fprintf(idFich,"\n");
////////////////////////////////////////////////////////////////////////////
@@ -1734,6 +1965,8 @@ void ImprimePoligFichero(const polig* poli,
const int impLim,
const int impArea,
const char formArea[],
+ const int impAtr,
+ const char formAtr[],
FILE* idFich)
{
//índices para recorrer bucles
@@ -1773,7 +2006,7 @@ void ImprimePoligFichero(const polig* poli,
{
//imprimos la cabecera
ImprimeCabeceraPoligFichero(poli,i,iniCab,impLim,formCoor,impArea,
- formArea,factorX,factorY,
+ formArea,impAtr,formAtr,factorX,factorY,
repitePrimerPunto,idFich);
}
//posición del punto inicial del polígono
diff --git a/src/polil.c b/src/polil.c
index 1da9d89..b819dc3 100755..100644
--- a/src/polil.c
+++ b/src/polil.c
@@ -7,12 +7,12 @@
\author José Luis García Pallero, jgpallero@gmail.com
\note Este fichero contiene funciones paralelizadas con OpenMP.
\date 03 de junio de 2011
-\section Licencia Licencia
-Copyright (c) 2011, José Luis García Pallero. All rights reserved.
-
+\copyright
+Copyright (c) 2011-2020, José Luis García Pallero. All rights reserved.
+\par
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
-
+\par
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this
@@ -21,7 +21,7 @@ are permitted provided that the following conditions are met:
- Neither the name of the copyright holders nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
-
+\par
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -379,7 +379,7 @@ polil* CreaPolil(const double* x,
//paralelización con OpenMP
#if defined(_OPENMP)
#pragma omp parallel sections default(none) \
- shared(posNanX,x,nNanX,posNanY,y,nNanY)
+ shared(posNanX,nElem,incX,x,nNanX,posNanY,incY,y,nNanY)
#endif
{
#if defined(_OPENMP)
@@ -1010,7 +1010,7 @@ void EscalaYTrasladaPolil(polil* poli,
//paralelización con OpenMP
#if defined(_OPENMP)
#pragma omp parallel sections default(none) \
- shared(poli)
+ shared(poli,escalaX,trasladaX,escalaY,trasladaY)
#endif
{
#if defined(_OPENMP)
@@ -1055,7 +1055,7 @@ void TrasladaYEscalaPolil(polil* poli,
//paralelización con OpenMP
#if defined(_OPENMP)
#pragma omp parallel sections default(none) \
- shared(poli)
+ shared(poli,escalaX,trasladaX,escalaY,trasladaY)
#endif
{
#if defined(_OPENMP)
@@ -1119,20 +1119,27 @@ void MuevePolil(polil* poli,
/******************************************************************************/
/******************************************************************************/
int AligeraPolil(polil* poli,
+ const int esf,
+ const double facCoor,
const double tol,
+ const int paralelizaTol,
const enum GEOC_DPEUCKER_ROBUSTO robusto,
- const size_t nPtosRobusto,
- const size_t nSegRobusto)
+ const size_t nSegRobOrig,
+ const size_t nSegRobAuto)
{
//índices para recorrer bucles
size_t i=0,j=0;
//posición inicial de la polilínea de trabajo y número de puntos aligerados
- size_t posIni=0,nPtos=0;
+ size_t posIni=0,nVert=0,nPtos=0;
//polilínea que es un mismo punto
int pmp=0;
- //coordenadas de las polilíneas aligeradas
+ //coordenadas de trabajo
double* x=NULL;
double* y=NULL;
+ double* xF=NULL;
+ double* yF=NULL;
+ //vértices de la polilínea de entrada más larga
+ size_t nVertMax=0;
//estructura auxiliar
polil* aux=NULL;
//vector de posiciones después del aligerado
@@ -1161,20 +1168,65 @@ int AligeraPolil(polil* poli,
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
+ //comprobamos si hay factor de escala para las coordenadas
+ if(facCoor!=1.0)
+ {
+ //vértices de la polilínea más larga
+ nVertMax = MaximoSizeT(poli->nVert,poli->nPolil,1);
+ //asignamos memoria para las coordenadas con factor de escala
+ xF = (double*)malloc(nVertMax*sizeof(double));
+ yF = (double*)malloc(nVertMax*sizeof(double));
+ //comprobamos posibles errores
+ if((xF==NULL)||(yF==NULL))
+ {
+ //liberamos la memoria asignada
+ LibMemPolil(aux);
+ free(xF);
+ free(yF);
+ //mensaje de error
+ GEOC_ERROR("Error de asignación de memoria");
+ //salimos de la función
+ return GEOC_ERR_ASIG_MEMORIA;
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
//recorremos el número de polilíneas almacenadas
for(i=0;i<poli->nPolil;i++)
{
//extraemos la posición inicial de la polilínea de trabajo
posIni = poli->posIni[i];
+ //número de vértices de la polilínea
+ nVert = poli->nVert[i];
+ //comprobamos si hay factor de escala para las coordenadas
+ if(facCoor!=1.0)
+ {
+ //copiamos las coordenadas y aplicamos el factor de escala
+ for(j=0;j<nVert;j++)
+ {
+ xF[j] = facCoor*(poli->x[posIni+j]);
+ yF[j] = facCoor*(poli->y[posIni+j]);
+ }
+ }
+ else
+ {
+ //las coordenadas de la polilínea se quedan como están
+ xF = &(poli->x[posIni]);
+ yF = &(poli->y[posIni]);
+ }
//aligeramos la polilínea de trabajo
- pos = AligeraPolilinea(&(poli->x[posIni]),&(poli->y[posIni]),
- poli->nVert[i],1,1,tol,robusto,nPtosRobusto,
- nSegRobusto,&nPtos);
+ pos = AligeraPolilinea(xF,yF,nVert,1,1,tol,paralelizaTol,robusto,
+ nSegRobOrig,nSegRobAuto,esf,&nPtos);
//comprobamos posibles errores
if(pos==NULL)
{
//liberamos la memoria asignada
LibMemPolil(aux);
+ if(facCoor!=1.0)
+ {
+ free(xF);
+ free(yF);
+ }
//mensaje de error
GEOC_ERROR("Error de asignación de memoria");
//salimos de la función
@@ -1183,7 +1235,7 @@ int AligeraPolil(polil* poli,
//comprobamos si la polilínea se ha quedado en dos puntos
if(nPtos==2)
{
- //comprobamos si los tres puntos son colineales
+ //comprobamos si los dos puntos son el mismo
pmp = ((poli->x[posIni+pos[0]])==(poli->x[posIni+pos[1]]))&&
((poli->y[posIni+pos[0]])==(poli->y[posIni+pos[1]]));
}
@@ -1191,8 +1243,7 @@ int AligeraPolil(polil* poli,
//no sea un único punto
if((nPtos>2)||((nPtos==2)&&(!pmp)))
{
- //asignamos memoria para los vectores de coordenadas de la polilínea
- //aligerada
+ //memoria para los vectores de coordenadas de la polilínea aligerada
x = (double*)malloc(nPtos*sizeof(double));
y = (double*)malloc(nPtos*sizeof(double));
//comprobamos posibles errores
@@ -1203,6 +1254,11 @@ int AligeraPolil(polil* poli,
free(pos);
free(x);
free(y);
+ if(facCoor!=1.0)
+ {
+ free(xF);
+ free(yF);
+ }
//mensaje de error
GEOC_ERROR("Error de asignación de memoria");
//salimos de la función
@@ -1226,6 +1282,11 @@ int AligeraPolil(polil* poli,
free(pos);
free(x);
free(y);
+ if(facCoor!=1.0)
+ {
+ free(xF);
+ free(yF);
+ }
//escribimos el mensaje de error
GEOC_ERROR("Error de asignación de memoria");
//salimos de la función
@@ -1250,6 +1311,11 @@ int AligeraPolil(polil* poli,
{
//liberamos la memoria asignada
LibMemPolil(aux);
+ if(facCoor!=1.0)
+ {
+ free(xF);
+ free(yF);
+ }
//mensaje de error
GEOC_ERROR("Error de asignación de memoria");
//salimos de la función
@@ -1261,9 +1327,15 @@ int AligeraPolil(polil* poli,
//enlazamos los campos de la estructura auxiliar a los de la estructura de
//salida
EnlazaCamposPolil(aux,poli);
- //liberamos la memoria asignada a la estructura auxiliar (pero no a sus
- //campos)
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //liberamos la memoria asignada
free(aux);
+ if(facCoor!=1.0)
+ {
+ free(xF);
+ free(yF);
+ }
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
//salimos de la función
diff --git a/src/posmatvec.c b/src/posmatvec.c
new file mode 100644
index 0000000..9e5db45
--- /dev/null
+++ b/src/posmatvec.c
@@ -0,0 +1,292 @@
+/* -*- coding: utf-8 -*- */
+/**
+\ingroup algebra anespec geopot gshhs matriz mmcc snx
+@{
+\file posmatvec.c
+\brief Definición de funciones para realizar cálculos de posiciones de
+ elementos en matrices almacenadas en formato vector.
+\author José Luis García Pallero, jgpallero@gmail.com
+\date 14 de enero de 2009
+\section Licencia Licencia
+Copyright (c) 2009-2013, José Luis García Pallero. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+- Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+- Neither the name of the copyright holders nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/******************************************************************************/
+/******************************************************************************/
+#include"libgeoc/posmatvec.h"
+/******************************************************************************/
+/******************************************************************************/
+int EsAlmMatVecCMO(void)
+{
+ //determinamos la salida dependiendo del tipo de almacenamiento
+#if defined(ROW_MAJOR_ORDER_MATVEC)
+ //el almacenamiento no es column major order
+ return 0;
+#elif defined(COLUMN_MAJOR_ORDER_MATVEC)
+ //el almacenamiento es column major order
+ return 1;
+#else
+ #error *****No se ha definido el tipo de almacenamiento matricial
+#endif
+}
+/******************************************************************************/
+/******************************************************************************/
+void TipoAlmMatVec(char tipo[])
+{
+ //determinamos la cadena de código dependiendo del tipo de almacenamiento
+#if defined(ROW_MAJOR_ORDER_MATVEC)
+ //asignamos la cadena correspondiente al tipo row major order
+ strcpy(tipo,GEOC_MATR_COD_ALM_RMO);
+#elif defined(COLUMN_MAJOR_ORDER_MATVEC)
+ //asignamos la cadena correspondiente al tipo column major order
+ strcpy(tipo,GEOC_MATR_COD_ALM_CMO);
+#else
+ #error *****No se ha definido el tipo de almacenamiento matricial
+#endif
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return;
+}
+/******************************************************************************/
+/******************************************************************************/
+size_t Lmfc(const size_t filMem,
+ const size_t colMem)
+{
+ //distinguimos según el tipo de almacenamiento
+#if defined(ROW_MAJOR_ORDER_MATVEC)
+ //almacenamiento row major order
+ return GEOC_LMFC_RMO(filMem,colMem);
+#elif defined(COLUMN_MAJOR_ORDER_MATVEC)
+ //almacenamiento column major order
+ return GEOC_LMFC_CMO(filMem,colMem);
+#else
+ #error *****No se ha definido el tipo de almacenamiento matricial
+#endif
+}
+/******************************************************************************/
+/******************************************************************************/
+size_t IncElemFil(const size_t filMem)
+{
+ //distinguimos según el tipo de almacenamiento
+#if defined(ROW_MAJOR_ORDER_MATVEC)
+ //almacenamiento row major order
+ //0*filMem para que el compilador no dé warning por variable no usada
+ return 1+0*filMem;
+#elif defined(COLUMN_MAJOR_ORDER_MATVEC)
+ //almacenamiento column major order
+ return filMem;
+#else
+ #error *****No se ha definido el tipo de almacenamiento matricial
+#endif
+}
+/******************************************************************************/
+/******************************************************************************/
+size_t IncElemCol(const size_t colMem)
+{
+ //distinguimos según el tipo de almacenamiento
+#if defined(ROW_MAJOR_ORDER_MATVEC)
+ //almacenamiento row major order
+ return colMem;
+#elif defined(COLUMN_MAJOR_ORDER_MATVEC)
+ //almacenamiento column major order
+ //0*colMem para que el compilador no dé warning por variable no usada
+ return 1+0*colMem;
+#else
+ #error *****No se ha definido el tipo de almacenamiento matricial
+#endif
+}
+/******************************************************************************/
+/******************************************************************************/
+size_t PosMatVec(const size_t filMem,
+ const size_t colMem,
+ const size_t fil,
+ const size_t col)
+{
+ //calculamos la posición en el vector dependiendo del tipo de almacenamiento
+#if defined(ROW_MAJOR_ORDER_MATVEC)
+ //almacenamiento row major order
+ return GEOC_POSMATVEC_RMO(filMem,colMem,fil,col);
+#elif defined(COLUMN_MAJOR_ORDER_MATVEC)
+ //almacenamiento column major order
+ return GEOC_POSMATVEC_CMO(filMem,colMem,fil,col);
+#else
+ #error *****No se ha definido el tipo de almacenamiento matricial
+#endif
+}
+/******************************************************************************/
+/******************************************************************************/
+void PosVecMat(const size_t filMem,
+ const size_t colMem,
+ const size_t posVec,
+ size_t* fil,
+ size_t* col)
+
+{
+ //calculamos la posición en la matriz dependiendo del tipo de almacenamiento
+#if defined(ROW_MAJOR_ORDER_MATVEC)
+ //calculamos la fila
+ //la division se realiza entre elementos del mismo tipo, por lo que el
+ //resultado tambien lo es (el redondeo de la division se hace por
+ //truncamiento)
+ //se añade el factor 0*filMem para que el compilador no emita un warning por
+ //variable no usada
+ *fil = posVec/colMem+0*filMem;
+ //calculamos la columna
+ *col = posVec%colMem;
+#elif defined(COLUMN_MAJOR_ORDER_MATVEC)
+ //calculamos la fila
+ *fil = posVec%filMem;
+ //calculamos la columna
+ //la division se realiza entre elementos del mismo tipo, por lo que el
+ //resultado tambien lo es (el redondeo de la division se hace por
+ //truncamiento)
+ //se añade el factor 0*colMem para que el compilador no emita un warning por
+ //variable no usada
+ *col = posVec/filMem+0*colMem;
+#else
+ #error *****No se ha definido el tipo de almacenamiento matricial
+#endif
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return;
+}
+/******************************************************************************/
+/******************************************************************************/
+size_t PosMatGenBanVec(const size_t diagInf,
+ const size_t diagSup,
+ const size_t fil,
+ const size_t col)
+{
+ //filas de la matriz empaquetada si el almacenamiento es COLUMN MAJOR ORDER
+ //y columnas si es ROW MAJOR ORDER
+ size_t lda=diagSup+diagInf+1;
+ //calculamos la posición en el vector dependiendo del tipo de almacenamiento
+#if defined(ROW_MAJOR_ORDER_MATVEC)
+ //columna en la matriz empaquetada donde se encuentra el elemento de trabajo
+ size_t colAux=diagInf-fil+col;
+ //calculamos la posición en el vector
+ return fil*lda+colAux;
+#elif defined(COLUMN_MAJOR_ORDER_MATVEC)
+ //fila en la matriz empaquetada donde se encuentra el elemento de trabajo
+ size_t filAux=diagSup+fil-col;
+ //calculamos la posición en el vector
+ return col*lda+filAux;
+#else
+ #error *****No se ha definido el tipo de almacenamiento matricial
+#endif
+}
+/******************************************************************************/
+/******************************************************************************/
+size_t PosMatTriEmVec(const size_t dim,
+ const enum GEOC_MATR_ID_TRI supInf,
+ const size_t fil,
+ const size_t col)
+{
+ //calculamos la posición en el vector dependiendo del tipo de almacenamiento
+#if defined(ROW_MAJOR_ORDER_MATVEC)
+ //distinguimos entre matriz triangular superior e inferior
+ if(supInf==GeocMatTriSup)
+ {
+ //calculamos la posición
+ return GEOC_POSMATVEC_TRIEM_SUP_RMO(dim,fil,col);
+ }
+ else
+ {
+ //calculamos la posición
+ return GEOC_POSMATVEC_TRIEM_INF_RMO(dim,fil,col);
+ }
+#elif defined(COLUMN_MAJOR_ORDER_MATVEC)
+ //distinguimos entre matriz triangular superior e inferior
+ if(supInf==GeocMatTriSup)
+ {
+ //calculamos la posición
+ return GEOC_POSMATVEC_TRIEM_SUP_CMO(dim,fil,col);
+ }
+ else
+ {
+ //calculamos la posición
+ return GEOC_POSMATVEC_TRIEM_INF_CMO(dim,fil,col);
+ }
+#else
+ #error *****No se ha definido el tipo de almacenamiento matricial
+#endif
+}
+/******************************************************************************/
+/******************************************************************************/
+size_t PosMatTriBanVec(const size_t diag,
+ const enum GEOC_MATR_ID_TRI supInf,
+ const size_t fil,
+ const size_t col)
+{
+ //diagonales de la matriz de trabajo
+ size_t diagInf=0,diagSup=0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //calculamos las diagonales de la matriz de trabajo
+ if(supInf==GeocMatTriSup)
+ {
+ diagSup = diag;
+ }
+ else if(supInf==GeocMatTriInf)
+ {
+ diagInf = diag;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //calculamos la posicion
+ return PosMatGenBanVec(diagInf,diagSup,fil,col);
+}
+/******************************************************************************/
+/******************************************************************************/
+size_t PosMatSimEmVec(const size_t dim,
+ const enum GEOC_MATR_ID_TRI supInf,
+ const size_t fil,
+ const size_t col)
+{
+ //calculamos y salimos de la función
+ return PosMatTriEmVec(dim,supInf,fil,col);
+}
+/******************************************************************************/
+/******************************************************************************/
+size_t PosMatSimBanVec(const size_t diag,
+ const enum GEOC_MATR_ID_TRI supInf,
+ const size_t fil,
+ const size_t col)
+{
+ //calculamos y salimos de la función
+ return PosMatTriBanVec(diag,supInf,fil,col);
+}
+/******************************************************************************/
+/******************************************************************************/
+/** @} */
+/******************************************************************************/
+/******************************************************************************/
+/* kate: encoding utf-8; end-of-line unix; syntax c; indent-mode cstyle; */
+/* kate: replace-tabs on; space-indent on; tab-indents off; indent-width 4; */
+/* kate: line-numbers on; folding-markers on; remove-trailing-space on; */
+/* kate: backspace-indents on; show-tabs on; */
+/* kate: word-wrap-column 80; word-wrap-marker-color #D2D2D2; word-wrap off; */
diff --git a/src/proyecaux.c b/src/proyecaux.c
new file mode 100644
index 0000000..9dc11d9
--- /dev/null
+++ b/src/proyecaux.c
@@ -0,0 +1,92 @@
+/* -*- coding: utf-8 -*- */
+/**
+\ingroup gshhs geom proyec
+@{
+\file proyecaux.c
+\brief Definición de funciones de algunas proyecciones cartográficas para no
+ usar PROJ.4.
+\author José Luis García Pallero, jgpallero@gmail.com
+\date 16 de agosto de 2013
+\copyright
+Copyright (c) 2013, José Luis García Pallero. All rights reserved.
+\par
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+\par
+- Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+- Neither the name of the copyright holders nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+\par
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/******************************************************************************/
+/******************************************************************************/
+#include"libgeoc/proyecaux.h"
+/******************************************************************************/
+/******************************************************************************/
+void ProjCilinEquivLambertLat0Ec(const double lat,
+ const double lon,
+ const double lon0,
+ const double a,
+ const double f,
+ double* x,
+ double* y)
+{
+ //variables auxiliares
+ double k0=0.0,q=0.0,sLat=0.0,e=0.0,e2=0.0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //ASUMIMOS QUE EL PARALELO ORIGEN ES EL ECUADOR
+ //distinguimos entre la esfera y el elipsoide
+ if(f==0.0)
+ {
+ //proyectamos
+ *x = a*(lon-lon0);
+ *y = a*sin(lat);
+ }
+ else
+ {
+ //calculamos el seno de la latitud geodésica
+ sLat = sin(lat);
+ //calculamos la primera excentricidad del elipsoide
+ e = sqrt(2.0*f-f*f);
+ e2 = e*e;
+ //el parámetro k0 porque el paralelo estándar es el ecuador
+ k0 = 1.0;
+ //calculamos el parámetro q
+ q = (1.0-e2)*
+ (sLat/(1.0-e2*sLat*sLat)-
+ 1.0/(2.0*e)*log((1.0-e*sLat)/(1.0+e*sLat)));
+ //proyectamos
+ *x = a*k0*(lon-lon0);
+ *y = a*q/(2.0*k0);
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return;
+}
+/******************************************************************************/
+/******************************************************************************/
+/** @} */
+/******************************************************************************/
+/******************************************************************************/
+/* kate: encoding utf-8; end-of-line unix; syntax c; indent-mode cstyle; */
+/* kate: replace-tabs on; space-indent on; tab-indents off; indent-width 4; */
+/* kate: line-numbers on; folding-markers on; remove-trailing-space on; */
+/* kate: backspace-indents on; show-tabs on; */
+/* kate: word-wrap-column 80; word-wrap-marker-color #D2D2D2; word-wrap off; */
diff --git a/src/ptopol.c b/src/ptopol.c
index a44d9e0..035ac4b 100755..100644
--- a/src/ptopol.c
+++ b/src/ptopol.c
@@ -23,20 +23,21 @@ variable, se usará un tipo <tt>long int</tt> para los cálculos intermedios. En
procesadores de 32 bits puede hacer que las funciones se ejecuten hasta 10 veces
más lentamente que si se utiliza el tipo <tt>long int</tt>. Con cálculos
internos de 32 bits las coordenadas de los vértices del polígono no han de estar
-más lejos de las de los puntos de trabajo de unas 40000 unidades. Con cálculos
-de 64 bits, los polígonos pueden estar alejados de los puntos de trabajo unas
-3000000000 unidades, lo que corresponde a coordenadas Y UTM ajustadas al
-centímetro. Con esto podríamos chequear un punto en un polo con respecto a un
-polígono en el ecuador en coordenadas UTM expresadas en centímetros.
+más lejos de las de los puntos de trabajo de unas #GEOC_PTO_POLIG_LEJOS_32
+unidades. Con cálculos de 64 bits, los polígonos pueden estar alejados de los
+puntos de trabajo unas #GEOC_PTO_POLIG_LEJOS_64 unidades, lo que corresponde a
+coordenadas Y UTM ajustadas al centímetro. Con esto podríamos chequear un punto
+en un polo con respecto a un polígono en el ecuador en coordenadas UTM
+expresadas en centímetros.
\author José Luis García Pallero, jgpallero@gmail.com
\note Este fichero contiene funciones paralelizadas con OpenMP.
\date 05 de abril de 2010
-\section Licencia Licencia
-Copyright (c) 2009-2011, José Luis García Pallero. All rights reserved.
-
+\copyright
+Copyright (c) 2010-2020, José Luis García Pallero. All rights reserved.
+\par
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
-
+\par
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this
@@ -45,7 +46,7 @@ are permitted provided that the following conditions are met:
- Neither the name of the copyright holders nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
-
+\par
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -169,32 +170,6 @@ int RectanguloEnRectangulo(const int borde,
}
/******************************************************************************/
/******************************************************************************/
-int RectDisjuntos(const double xMin1,
- const double xMax1,
- const double yMin1,
- const double yMax1,
- const double xMin2,
- const double xMax2,
- const double yMin2,
- const double yMax2)
-{
- //variable de salida, que inicializamos como polígonos no disjuntos
- int sal=0;
- ////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////
- //comprobamos si son disjuntos
- if((xMin1>xMax2)||(xMax1<xMin2)||(yMin1>yMax2)||(yMax1<yMin2))
- {
- //los restángulos son disjuntos
- sal = 1;
- }
- ////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////
- //salimos de la función
- return sal;
-}
-/******************************************************************************/
-/******************************************************************************/
int PtoEnPoligono(const double x,
const double y,
const double* coorX,
@@ -245,6 +220,44 @@ int PtoEnPoligono(const double x,
}
/******************************************************************************/
/******************************************************************************/
+void PtosEnPoligono(const double* x,
+ const double* y,
+ const size_t nPtos,
+ const size_t incX,
+ const size_t incY,
+ const double* coorX,
+ const double* coorY,
+ const size_t N,
+ const size_t incCoorX,
+ const size_t incCoorY,
+ int* situacion,
+ const size_t incSituacion)
+{
+ //índice para recorrer bucles
+ size_t i=0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //paralelización con OpenMP
+#if defined(_OPENMP)
+#pragma omp parallel for default(none) \
+ shared(nPtos,incSituacion,situacion,incX,x,incY,y,N,incCoorX,coorX,incCoorY, \
+ coorY) \
+ private(i)
+#endif
+ //recorremos los puntos a chequear
+ for(i=0;i<nPtos;i++)
+ {
+ //compruebo la situación del punto de trabajo
+ situacion[i*incSituacion] = PtoEnPoligono(x[i*incX],y[i*incY],coorX,
+ coorY,N,incCoorX,incCoorY);
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return;
+}
+/******************************************************************************/
+/******************************************************************************/
int PtoEnPoligonoVertice(const double x,
const double y,
const double* coorX,
@@ -259,7 +272,9 @@ int PtoEnPoligonoVertice(const double x,
int pos=GEOC_PTO_FUERA_POLIG;
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
- //comprobamos si el punto es un vértice
+ //calculamos la posición general
+ pos = PtoEnPoligono(x,y,coorX,coorY,N,incX,incY);
+ //comprobamos si el polígono es un vértice
for(i=0;i<N;i++)
{
//comprobamos las coordenadas
@@ -271,16 +286,49 @@ int PtoEnPoligonoVertice(const double x,
break;
}
}
- //sólo continuamos si el punto no es un vértice
- if(pos!=GEOC_PTO_VERTICE_POLIG)
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return pos;
+}
+/******************************************************************************/
+/******************************************************************************/
+void PtosEnPoligonoVertice(const double* x,
+ const double* y,
+ const size_t nPtos,
+ const size_t incX,
+ const size_t incY,
+ const double* coorX,
+ const double* coorY,
+ const size_t N,
+ const size_t incCoorX,
+ const size_t incCoorY,
+ int* situacion,
+ const size_t incSituacion)
+{
+ //índice para recorrer bucles
+ size_t i=0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //paralelización con OpenMP
+#if defined(_OPENMP)
+#pragma omp parallel for default(none) \
+ shared(nPtos,incSituacion,situacion,incX,x,incY,y,N,incCoorX,coorX,incCoorY, \
+ coorY) \
+ private(i)
+#endif
+ //recorremos los puntos a chequear
+ for(i=0;i<nPtos;i++)
{
- //calculamos la posición sin tener en cuenta el borde
- pos = PtoEnPoligono(x,y,coorX,coorY,N,incX,incY);
+ //compruebo la situación del punto de trabajo
+ situacion[i*incSituacion] = PtoEnPoligonoVertice(x[i*incX],y[i*incY],
+ coorX,coorY,N,
+ incCoorX,incCoorY);
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
//salimos de la función
- return pos;
+ return;
}
/******************************************************************************/
/******************************************************************************/
@@ -372,6 +420,47 @@ int PtoEnPoligonoVerticeBorde(const long x,
}
/******************************************************************************/
/******************************************************************************/
+void PtosEnPoligonoVerticeBorde(const long* x,
+ const long* y,
+ const size_t nPtos,
+ const size_t incX,
+ const size_t incY,
+ const long* coorX,
+ const long* coorY,
+ const size_t N,
+ const size_t incCoorX,
+ const size_t incCoorY,
+ int* situacion,
+ const size_t incSituacion)
+{
+ //índice para recorrer bucles
+ size_t i=0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //paralelización con OpenMP
+#if defined(_OPENMP)
+#pragma omp parallel for default(none) \
+ shared(nPtos,incSituacion,situacion,incX,x,incY,y,N,incCoorX,coorX,incCoorY, \
+ coorY) \
+ private(i)
+#endif
+ //recorremos los puntos a chequear
+ for(i=0;i<nPtos;i++)
+ {
+ //compruebo la situación del punto de trabajo
+ situacion[i*incSituacion] = PtoEnPoligonoVerticeBorde(x[i*incX],
+ y[i*incY],
+ coorX,coorY,N,
+ incCoorX,
+ incCoorY);
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return;
+}
+/******************************************************************************/
+/******************************************************************************/
int PtoEnPoligonoVerticeBordeDouble(const double x,
const double y,
const double* coorX,
@@ -396,8 +485,10 @@ int PtoEnPoligonoVerticeBordeDouble(const double x,
ptopol_long cx=0,cy=0,cx1=0,cy1=0;
//número de elementos de trabajo del polígono
size_t n=N;
- //variable auxiliar
- double X=0.0;
+ //factor de escala de trabajo
+ double fmult=1.0;
+ //variables auxiliares
+ double X=0.0,aux=0.0,dmax=0.0;
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
//comprobamos si el primer vértice se repite al final
@@ -408,18 +499,52 @@ int PtoEnPoligonoVerticeBordeDouble(const double x,
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
+ //comprobamos si hay que calcular el factor de escala
+ if(factor==0.0)
+ {
+ //recorro todos los vértices del polígono
+ for(i=0;i<n;i++)
+ {
+ //calculo la distancia del punto al vértice
+ aux = sqrt(coorX[i*incX]*coorX[i*incX]+coorY[i*incY]*coorY[i*incY]);
+ //compruebo si es la máxima
+ if(aux>dmax)
+ {
+ dmax = aux;
+ }
+ }
+ //compruebo la precisión de trabajo
+ if(sizeof(ptopol_long)==4)
+ {
+ //precisión de 32 bits (4 bytes)
+ fmult = floor(GEOC_PTO_POLIG_LEJOS_ESCALA_DIST*
+ GEOC_PTO_POLIG_LEJOS_32/dmax);
+ }
+ else
+ {
+ //precisión de 64 bits (8 bytes)
+ fmult = floor(GEOC_PTO_POLIG_LEJOS_ESCALA_DIST*
+ GEOC_PTO_POLIG_LEJOS_64/dmax);
+ }
+ }
+ else
+ {
+ fmult = factor;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
//pasamos a número entero el punto a evaluar
if(redondeo)
{
//redondeo
- fX = (ptopol_long)(round(factor*x));
- fY = (ptopol_long)(round(factor*y));
+ fX = (ptopol_long)(round(fmult*x));
+ fY = (ptopol_long)(round(fmult*y));
}
else
{
//truncamiento
- fX = (ptopol_long)(factor*x);
- fY = (ptopol_long)(factor*y);
+ fX = (ptopol_long)(fmult*x);
+ fY = (ptopol_long)(fmult*y);
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
@@ -428,25 +553,25 @@ int PtoEnPoligonoVerticeBordeDouble(const double x,
{
//calculamos el índice del punto anterior en el polígono
i1 = (i) ? i-1 : n-1;
- //para referir los vértices de trabajo al punto, comprobamos si hay que
+ //para referir los vértices de trabajo al punto comprobamos si hay que
//redondear o truncar
if(redondeo)
{
//redondeo del vértice actual
- cx = (ptopol_long)(round(factor*coorX[i*incX]))-fX;
- cy = (ptopol_long)(round(factor*coorY[i*incY]))-fY;
+ cx = (ptopol_long)(round(fmult*coorX[i*incX]))-fX;
+ cy = (ptopol_long)(round(fmult*coorY[i*incY]))-fY;
//redondeo del vértice anterior
- cx1 = (ptopol_long)(round(factor*coorX[i1*incX]))-fX;
- cy1 = (ptopol_long)(round(factor*coorY[i1*incY]))-fY;
+ cx1 = (ptopol_long)(round(fmult*coorX[i1*incX]))-fX;
+ cy1 = (ptopol_long)(round(fmult*coorY[i1*incY]))-fY;
}
else
{
//truncamiento del vértice actual
- cx = (ptopol_long)(factor*coorX[i*incX])-fX;
- cy = (ptopol_long)(factor*coorY[i*incY])-fY;
+ cx = (ptopol_long)(fmult*coorX[i*incX])-fX;
+ cy = (ptopol_long)(fmult*coorY[i*incY])-fY;
//redondeo del vértice anterior
- cx1 = (ptopol_long)(factor*coorX[i1*incX])-fX;
- cy1 = (ptopol_long)(factor*coorY[i1*incY])-fY;
+ cx1 = (ptopol_long)(fmult*coorX[i1*incX])-fX;
+ cy1 = (ptopol_long)(fmult*coorY[i1*incY])-fY;
}
//comprobamos si el punto es un vértice del polígono
if((cx==0)&&(cy==0))
@@ -494,6 +619,51 @@ int PtoEnPoligonoVerticeBordeDouble(const double x,
}
/******************************************************************************/
/******************************************************************************/
+void PtosEnPoligonoVerticeBordeDouble(const double* x,
+ const double* y,
+ const size_t nPtos,
+ const size_t incX,
+ const size_t incY,
+ const double* coorX,
+ const double* coorY,
+ const size_t N,
+ const size_t incCoorX,
+ const size_t incCoorY,
+ const double factor,
+ const int redondeo,
+ int* situacion,
+ const size_t incSituacion)
+{
+ //índice para recorrer bucles
+ size_t i=0;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //paralelización con OpenMP
+#if defined(_OPENMP)
+#pragma omp parallel for default(none) \
+ shared(nPtos,incSituacion,situacion,incX,x,incY,y,N,incCoorX,coorX,incCoorY, \
+ coorY,factor,redondeo) \
+ private(i)
+#endif
+ //recorremos los puntos a chequear
+ for(i=0;i<nPtos;i++)
+ {
+ //compruebo la situación del punto de trabajo
+ situacion[i*incSituacion] = PtoEnPoligonoVerticeBordeDouble(x[i*incX],
+ y[i*incY],
+ coorX,coorY,
+ N,incCoorX,
+ incCoorY,
+ factor,
+ redondeo);
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return;
+}
+/******************************************************************************/
+/******************************************************************************/
size_t* BuscaGeocNanEnVectores(const double* x,
const double* y,
const size_t N,
@@ -607,7 +777,7 @@ int PtoEnPoligonoInd(const double x,
//variable auxiliar de situación de punto
int posAux=0;
//variable indicadora de continuación de chequeos
- size_t continuar=1;
+ int continuar=1;
//variable de salida
int pos=GEOC_PTO_FUERA_POLIG;
////////////////////////////////////////////////////////////////////////////
@@ -617,6 +787,10 @@ int PtoEnPoligonoInd(const double x,
//comprobamos si hay valores NaN
if(nNan)
{
+ //inicializamos el indicador de continuación de chequeos (si se compila
+ //versión en serie, esta sentencia sólo vale para que no dé warning en
+ //compilación por variable no usada)
+ continuar = 1;
//paralelización con OpenMP
//utilizo schedule(dynamic) para que los polígonos vayan siendo
//chequeados uno a uno según los hilos de ejecución van quedándose
@@ -626,38 +800,55 @@ int PtoEnPoligonoInd(const double x,
//polígonos pequeños mientras se testea uno grande
#if defined(_OPENMP)
#pragma omp parallel for default(none) schedule(dynamic) \
- shared(continuar,posNan,coorX,coorY,pos,poli) \
+ shared(nNan,continuar,posNan,incX,x,coorX,incY,y,coorY,pos,poli) \
private(i,iniX,iniY,nElem,posAux)
#endif
//recorremos desde el primer NaN hasta el penúltimo
for(i=0;i<(nNan-1);i++)
{
- //hacemos que todos los hilos vean la variable continuar actualizada
+ //si compilamos para OpenMP no podemos usar la sentencia break
+ //en cambio, comprobamos si hay que continuar o no haciendo pruebas
+ //para que las vueltas del bucle hagan todos los cálculos o no
#if defined(_OPENMP)
+ //hacemos que todos los hilos vean la variable continuar actualizada
#pragma omp flush(continuar)
-#endif
- //comprobamos si hay que continuar chequeando polígonos
+ //comprobamos si hay que continuar chequeando polígonos en OpenMP
if(continuar)
{
+#endif
//extraemos los datos de definición del polígono
DatosPoliIndividualEnVecInd(posNan,i,incX,incY,&iniX,&iniY,
&nElem);
//comprobamos la inclusión para el polígono de trabajo
posAux = PtoEnPoligono(x,y,&coorX[iniX],&coorY[iniY],nElem,incX,
incY);
+ //distinguimos entre algoritmo en serie y en paralelo
+#if !defined(_OPENMP)
+ //comprobamos si el punto no está fuera del polígono
+ if(posAux!=GEOC_PTO_FUERA_POLIG)
+ {
+ //asignamos la variable de salida
+ pos = posAux;
+ //asignamos el polígono que contiene al punto
+ *poli = i;
+ //esta asignación sólo está aquí para que no dé warning en
+ //la compilación
+ continuar = continuar;
+ //salimos del bucle
+ break;
+ }
+#else
//me aseguro de que las variables involucradas sean actualizadas
//por un hilo cada vez, sin posibilidad de modificación por
//varios al mismo tiempo
-#if defined(_OPENMP)
-#pragma omp critical
-#endif
+#pragma omp critical(paraSiPuntoDentro)
{
//si el punto no está fuera, no se han de hacer más operaciones
- //el continuar==1 asegura que nos quedemos con el primer
+ //el chequear 'continuar' asegura que nos quedemos con el primer
//polígono en que está incluido el punto, ya que una vez que el
//hilo con punto encontrado actualice la variable continuar, el
//resto con posibles resultados positivos no pasarán este if()
- if((continuar==1)&&(posAux!=GEOC_PTO_FUERA_POLIG))
+ if(continuar&&(posAux!=GEOC_PTO_FUERA_POLIG))
{
//asignamos la variable de salida
pos = posAux;
@@ -668,12 +859,14 @@ int PtoEnPoligonoInd(const double x,
continuar = 0;
//hacemos que todos los hilos vean la variable continuar
//actualizada
-#if defined(_OPENMP)
#pragma omp flush(continuar)
-#endif
}
}
- }
+#endif
+ //llave de cierre del if(continuar) si compilamos para OpenMP
+#if defined(_OPENMP)
+ } // --> cierro el if(continuar) si compilamos para OpenMP
+#endif
} // --> fin del #pragma omp parallel for
}
else
@@ -727,7 +920,7 @@ int PtoEnPoligonoVerticeInd(const double x,
//polígonos pequeños mientras se testea uno grande
#if defined(_OPENMP)
#pragma omp parallel for default(none) schedule(dynamic) \
- shared(continuar,posNan,coorX,coorY,pos,poli) \
+ shared(nNan,continuar,posNan,incX,x,coorX,incY,y,coorY,pos,poli) \
private(i,iniX,iniY,nElem,posAux)
#endif
//recorremos desde el primer NaN hasta el penúltimo
@@ -750,15 +943,15 @@ int PtoEnPoligonoVerticeInd(const double x,
//por un hilo cada vez, sin posibilidad de modificación por
//varios al mismo tiempo
#if defined(_OPENMP)
-#pragma omp critical
+#pragma omp critical(paraSiPuntoDentro)
#endif
{
//si el punto no está fuera, no se han de hacer más operaciones
- //el continuar==1 asegura que nos quedemos con el primer
+ //el chequear 'continuar' asegura que nos quedemos con el primer
//polígono en que está incluido el punto, ya que una vez que el
//hilo con punto encontrado actualice la variable continuar, el
//resto con posibles resultados positivos no pasarán este if()
- if((continuar==1)&&(posAux!=GEOC_PTO_FUERA_POLIG))
+ if(continuar&&(posAux!=GEOC_PTO_FUERA_POLIG))
{
//asignamos la variable de salida
pos = posAux;
@@ -828,7 +1021,7 @@ int PtoEnPoligonoVerticeBordeInd(const long x,
//polígonos pequeños mientras se testea uno grande
#if defined(_OPENMP)
#pragma omp parallel for default(none) schedule(dynamic) \
- shared(continuar,posNan,coorX,coorY,pos,poli) \
+ shared(nNan,continuar,posNan,incX,x,coorX,incY,y,coorY,pos,poli) \
private(i,iniX,iniY,nElem,posAux)
#endif
//recorremos desde el primer NaN hasta el penúltimo
@@ -852,15 +1045,15 @@ int PtoEnPoligonoVerticeBordeInd(const long x,
//por un hilo cada vez, sin posibilidad de modificación por
//varios al mismo tiempo
#if defined(_OPENMP)
-#pragma omp critical
+#pragma omp critical(paraSiPuntoDentro)
#endif
{
//si el punto no está fuera, no se han de hacer más operaciones
- //el continuar==1 asegura que nos quedemos con el primer
+ //el chequear 'continuar' asegura que nos quedemos con el primer
//polígono en que está incluido el punto, ya que una vez que el
//hilo con punto encontrado actualice la variable continuar, el
//resto con posibles resultados positivos no pasarán este if()
- if((continuar==1)&&(posAux!=GEOC_PTO_FUERA_POLIG))
+ if(continuar&&(posAux!=GEOC_PTO_FUERA_POLIG))
{
//asignamos la variable de salida
pos = posAux;
@@ -932,7 +1125,8 @@ int PtoEnPoligonoVerticeBordeDoubleInd(const double x,
//polígonos pequeños mientras se testea uno grande
#if defined(_OPENMP)
#pragma omp parallel for default(none) schedule(dynamic) \
- shared(continuar,posNan,coorX,coorY,pos,poli) \
+ shared(nNan,continuar,posNan,incX,x,coorX,incY,y,coorY,pos,factor,redondeo, \
+ poli) \
private(i,iniX,iniY,nElem,posAux)
#endif
//recorremos desde el primer NaN hasta el penúltimo
@@ -957,15 +1151,15 @@ int PtoEnPoligonoVerticeBordeDoubleInd(const double x,
//por un hilo cada vez, sin posibilidad de modificación por
//varios al mismo tiempo
#if defined(_OPENMP)
-#pragma omp critical
+#pragma omp critical(paraSiPuntoDentro)
#endif
{
//si el punto no está fuera, no se han de hacer más operaciones
- //el continuar==1 asegura que nos quedemos con el primer
+ //el chequear 'continuar' asegura que nos quedemos con el primer
//polígono en que está incluido el punto, ya que una vez que el
//hilo con punto encontrado actualice la variable continuar, el
//resto con posibles resultados positivos no pasarán este if()
- if((continuar==1)&&(posAux!=GEOC_PTO_FUERA_POLIG))
+ if(continuar&&(posAux!=GEOC_PTO_FUERA_POLIG))
{
//asignamos la variable de salida
pos = posAux;
@@ -997,6 +1191,137 @@ int PtoEnPoligonoVerticeBordeDoubleInd(const double x,
}
/******************************************************************************/
/******************************************************************************/
+void GeneraPtoEnPoligono(const double* coorX,
+ const double* coorY,
+ const size_t N,
+ const size_t incX,
+ const size_t incY,
+ const double factor,
+ const int redondeo,
+ double* x,
+ double* y)
+{
+ //número de vértices de trabajo
+ size_t n=N;
+ //coordenadas de los vértices de un triángulo y centroide
+ double x1=0.0,y1=0.0,x2=0.0,y2=0.0,x3=0.0,y3=0.0,xc=0.0,yc=0.0;
+ //identificador de inclusión en polígono
+ int dentro=GEOC_PTO_FUERA_POLIG;
+ //variables auxiliares
+ int camina=0;
+ size_t pos1=0,pos2=0,pos3=0;
+ //inicializo las coordenadas de salida
+ *x = GeocNan();
+ *y = GeocNan();
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //comprobamos si el primer vértice se repite al final
+ if((coorX[0]==coorX[(N-1)*incX])&&(coorY[0]==coorY[(N-1)*incY]))
+ {
+ //trabajamos con todos los vértices, menos el último
+ n = N-1;
+ }
+ //compruebo si hay un número suficiente de vértices
+ if(n<3)
+ {
+ //salimos de la función
+ return;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //inicializo el primer triángulo
+ x1 = coorX[0];
+ y1 = coorY[0];
+ x2 = coorX[incX];
+ y2 = coorY[incY];
+ x3 = coorX[2*incX];
+ y3 = coorY[2*incY];
+ //identificador de punto a mover y posiciones
+ camina = 3;
+ pos1 = 0;
+ pos2 = 1;
+ pos3 = 2;
+ //entramos en un bucle infinito
+ while(1)
+ {
+ //calculamos las coordenadas del centroide del triángulo, que siempre
+ //está dentro de él
+ xc = (x1+x2+x3)/3.0;
+ yc = (y1+y2+y3)/3.0;
+ //comprobamos si el punto está dentro del polígono
+ dentro = PtoEnPoligonoVerticeBordeDouble(xc,yc,coorX,coorY,N,incX,incY,
+ factor,redondeo);
+ //si está dentro salgo del bucle
+ if(dentro==GEOC_PTO_DENTRO_POLIG)
+ {
+ //asigno las coordenadas
+ *x = xc;
+ *y = yc;
+ //salgo del bucle
+ break;
+ }
+ //compruebo qué punto he de mover
+ if(camina==3)
+ {
+ //muevo el punto 3
+ pos3++;
+ //comprobamos si se ha llegado al final
+ if(pos3==n)
+ {
+ //hay que empezar a mover el punto 2
+ camina = 2;
+ //devuelvo la posición del tercer punto al último de la lista
+ pos3 = n-1;
+ //siguiente vuelta, aunque se repita el cálculo anterior
+ continue;
+ }
+ }
+ else if(camina==2)
+ {
+ //muevo el punto 2
+ pos2++;
+ //compruebo si he llegado al final para el punto 2
+ if(pos2==(n-1))
+ {
+ //hay que empezar a mover el punto 1
+ camina = 1;
+ //posición del segundo punto al penúltimo de la lista
+ pos2 = n-2;
+ //siguiente vuelta, aunque se repita el cálculo anterior
+ continue;
+ }
+ }
+ else
+ {
+ //nuevo punto 1
+ pos1++;
+ //los puntos 2 y 3 son los que vienen a continuación de él
+ pos2 = pos1+1;
+ pos3 = pos2+1;
+ //compruebo si he llegado al final para el punto 1
+ if(pos1==(n-2))
+ {
+ //salimos del bucle
+ break;
+ }
+ //en la siguiente vuelta moveremos el tercer vértice
+ camina = 3;
+ }
+ //extraigo las coordenadas de los puntos del triángulo
+ x1 = coorX[pos1*incX];
+ y1 = coorY[pos1*incY];
+ x2 = coorX[pos2*incX];
+ y2 = coorY[pos2*incY];
+ x3 = coorX[pos3*incX];
+ y3 = coorY[pos3*incY];
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return;
+}
+/******************************************************************************/
+/******************************************************************************/
/** @} */
/******************************************************************************/
/******************************************************************************/
diff --git a/src/recpolil.c b/src/recpolil.c
index c7ba145..c6cbe40 100755..100644
--- a/src/recpolil.c
+++ b/src/recpolil.c
@@ -7,12 +7,12 @@
polígonos.
\author José Luis García Pallero, jgpallero@gmail.com
\date 05 de junio de 2011
-\section Licencia Licencia
+\copyright
Copyright (c) 2011, José Luis García Pallero. All rights reserved.
-
+\par
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
-
+\par
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this
@@ -21,7 +21,7 @@ are permitted provided that the following conditions are met:
- Neither the name of the copyright holders nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
-
+\par
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -498,7 +498,8 @@ int Paso1Recpolil(vertPolilClip* poli,
//añadimos el punto de intersección
InsertaVertPolilClip(insPolil,auxA,auxB);
}
- else if(intersec==GEOC_SEG_INTERSEC_EXTREMO_NO_COLIN)
+ else if((intersec==GEOC_SEG_INTERSEC_EXTREMO_NO_COLIN)||
+ (intersec==GEOC_SEG_INTERSEC_EXTREMOS_NO_COLIN))
{
//EL EXTREMO DE UN SEGMENTO TOCA AL OTRO SEGMENTO, PERO
//LOS SEGMENTOS NO SON COLINEALES
@@ -552,7 +553,7 @@ int Paso1Recpolil(vertPolilClip* poli,
}
}
}
- else if(intersec==GEOC_SEG_INTERSEC_EXTREMO_COLIN)
+ else if(intersec==GEOC_SEG_INTERSEC_EXTREMOS_COLIN)
{
//LOS SEGMENTOS SON COLINEALES PERO SÓLO SE TOCAN EN EL
//EXTREMO
@@ -1209,10 +1210,10 @@ polil* RecortaPolilMult(const polil* poli,
{
//comprobamos si los restángulos que encierran a la polilínea y
//al polígono son disjuntos o no
- pr = RectDisjuntos(poli->xMin[i],poli->xMax[i],poli->yMin[i],
- poli->yMax[i],
- poliRec->xMin[j],poliRec->xMax[j],
- poliRec->yMin[j],poliRec->yMax[j]);
+ pr = GEOC_RECT_DISJUNTOS(poli->xMin[i],poli->xMax[i],
+ poli->yMin[i],poli->yMax[i],
+ poliRec->xMin[j],poliRec->xMax[j],
+ poliRec->yMin[j],poliRec->yMax[j]);
//comprobamos los casos particulares si los rectángulos son
//disjuntos
if(pr&&(op==GeocOpBoolDentro))
diff --git a/src/segmento.c b/src/segmento.c
index 6bb5220..836b5cc 100755..100644
--- a/src/segmento.c
+++ b/src/segmento.c
@@ -6,12 +6,12 @@
\brief Definición de funciones para la realización de cálculos con segmentos.
\author José Luis García Pallero, jgpallero@gmail.com
\date 22 de abril de 2011
-\section Licencia Licencia
-Copyright (c) 2011, José Luis García Pallero. All rights reserved.
-
+\copyright
+Copyright (c) 2011-2013, José Luis García Pallero. All rights reserved.
+\par
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
-
+\par
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this
@@ -20,7 +20,7 @@ are permitted provided that the following conditions are met:
- Neither the name of the copyright holders nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
-
+\par
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -37,18 +37,6 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include"libgeoc/segmento.h"
/******************************************************************************/
/******************************************************************************/
-double PosPtoRecta2D(const double x,
- const double y,
- const double xIni,
- const double yIni,
- const double xFin,
- const double yFin)
-{
- //calculamos y salimos de la función
- return (xIni-x)*(yFin-y)-(xFin-x)*(yIni-y);
-}
-/******************************************************************************/
-/******************************************************************************/
int TresPuntosColineales2D(const double xA,
const double yA,
const double xB,
@@ -56,18 +44,11 @@ int TresPuntosColineales2D(const double xA,
const double xC,
const double yC)
{
- //variable de salida
- int colin=0;
- ////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////
- //utilizamos la función de posición de punto con respecto a una recta,
- //aunque no es una función robusta
+ //utilizamos la macro de posición de punto con respecto a una recta, aunque
+ //no es una macro robusta
//son colineales si el resultado es 0.0
- colin = (PosPtoRecta2D(xA,yA,xB,yB,xC,yC)==0.0) ? 1 : 0;
- ////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////
- //salimos de la función
- return colin;
+ //calculamos y salimos de la función
+ return (POS_PTO_RECTA_2D(xA,yA,xB,yB,xC,yC)==0.0);
}
/******************************************************************************/
/******************************************************************************/
@@ -177,7 +158,7 @@ int PtoComunSegmParalelos2D(const double xA,
*x = xA;
*y = yA;
//los segmentos comparten un extremo
- return GEOC_SEG_INTERSEC_EXTREMO_COLIN;
+ return GEOC_SEG_INTERSEC_EXTREMOS_COLIN;
}
//comprobamos si sólo comparten el extremo B
if(((xB==xC)&&(yB==yC))||((xB==xD)&&(yB==yD)))
@@ -186,7 +167,7 @@ int PtoComunSegmParalelos2D(const double xA,
*x = xB;
*y = yB;
//los segmentos comparten un extremo
- return GEOC_SEG_INTERSEC_EXTREMO_COLIN;
+ return GEOC_SEG_INTERSEC_EXTREMOS_COLIN;
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
@@ -206,55 +187,98 @@ int IntersecSegmentos2D(const double xA,
double* x,
double* y)
{
+ //centroide del conjunto de puntos implicados
+ double xc=0.0,yc=0.0;
+ //coordenadas reducidas al centroide
+ double xAc=0.0,yAc=0.0,xBc=0.0,yBc=0.0,xCc=0.0,yCc=0.0,xDc=0.0,yDc=0.0;
//parámetros de las ecuaciones
double s=0.0,t=0.0,num=0.0,den=0.0;
//variable de salida
- int cod=0;
+ int cod=GEOC_SEG_NO_INTERSEC;
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
- //comprobamos si los rectángulos que encierran a los segmentos son disjuntos
- if(RectDisjuntos(GEOC_MIN(xA,xB),GEOC_MAX(xA,xB),GEOC_MIN(yA,yB),
- GEOC_MAX(yA,yB),GEOC_MIN(xC,xD),GEOC_MAX(xC,xD),
- GEOC_MIN(yC,yD),GEOC_MAX(yC,yD)))
+ //si los rectángulos son disjuntos, los segmentos no se tocan
+ if(GEOC_RECT_DISJUNTOS(GEOC_MIN(xA,xB),GEOC_MAX(xA,xB),GEOC_MIN(yA,yB),
+ GEOC_MAX(yA,yB),GEOC_MIN(xC,xD),GEOC_MAX(xC,xD),
+ GEOC_MIN(yC,yD),GEOC_MAX(yC,yD)))
{
- //si los rectángulos son disjuntos, los segmentos no se tocan
+ //código de salida
cod = GEOC_SEG_NO_INTERSEC;
//salimos de la función
return cod;
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
+ //calculamos el centroide del conjunto de puntos de trabajo
+ xc = (xA+xB+xC+xD)/4.0;
+ yc = (yA+yB+yC+yD)/4.0;
+ //reducimos las coordenadas de trabajo al centroide, para que los números
+ //sean más pequeños y evitar posibles errores de desbordamiento
+ xAc = xA-xc;
+ xBc = xB-xc;
+ xCc = xC-xc;
+ xDc = xD-xc;
+ yAc = yA-yc;
+ yBc = yB-yc;
+ yCc = yC-yc;
+ yDc = yD-yc;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //a partir de aquí, trabajamos con las coordenadas reducidas al centroide
//calculamos el denominador
- den = xA*(yD-yC)+xB*(yC-yD)+xD*(yB-yA)+xC*(yA-yB);
+ den = xAc*(yDc-yCc)+xBc*(yCc-yDc)+xDc*(yBc-yAc)+xCc*(yAc-yBc);
//si el denominador es 0.0, los segmentos son paralelos
if(den==0.0)
{
//calculamos el punto común
- cod = PtoComunSegmParalelos2D(xA,yA,xB,yB,xC,yC,xD,yD,x,y);
+ cod = PtoComunSegmParalelos2D(xAc,yAc,xBc,yBc,xCc,yCc,xDc,yDc,x,y);
+ //deshacemos el cambio del centroide
+ *x += xc;
+ *y += yc;
//salimos de la función
return cod;
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
//calculamos el numerador
- num = xA*(yD-yC)+xC*(yA-yD)+xD*(yC-yA);
+ num = xAc*(yDc-yCc)+xCc*(yAc-yDc)+xDc*(yCc-yAc);
//un extremo de un segmento puede estar encima del otro segmento, pero los
//segmentos no son colineales
if((num==0.0)||(num==den))
{
- //asignamos la variable de salida
- cod = GEOC_SEG_INTERSEC_EXTREMO_NO_COLIN;
+ //comprobamos si se tocan en un extremo
+ if(((xAc==xCc)&&(yAc==yCc))||((xAc==xDc)&&(yAc==yDc))||
+ ((xBc==xCc)&&(yBc==yCc))||((xBc==xDc)&&(yBc==yDc)))
+ {
+ //asignamos la variable de salida
+ cod = GEOC_SEG_INTERSEC_EXTREMOS_NO_COLIN;
+ }
+ else
+ {
+ //asignamos la variable de salida
+ cod = GEOC_SEG_INTERSEC_EXTREMO_NO_COLIN;
+ }
}
//calculamos el parámetro s
s = num/den;
//calculamos de nuevo el numerador
- num = -(xA*(yC-yB)+xB*(yA-yC)+xC*(yB-yA));
+ num = -(xAc*(yCc-yBc)+xBc*(yAc-yCc)+xCc*(yBc-yAc));
//un extremo de un segmento puede estar encima del otro segmento, pero los
//segmentos no son colineales
if((num==0.0)||(num==den))
{
- //asignamos la variable de salida
- cod = GEOC_SEG_INTERSEC_EXTREMO_NO_COLIN;
+ //comprobamos si se tocan en un extremo
+ if(((xAc==xCc)&&(yAc==yCc))||((xAc==xDc)&&(yAc==yDc))||
+ ((xBc==xCc)&&(yBc==yCc))||((xBc==xDc)&&(yBc==yDc)))
+ {
+ //asignamos la variable de salida
+ cod = GEOC_SEG_INTERSEC_EXTREMOS_NO_COLIN;
+ }
+ else
+ {
+ //asignamos la variable de salida
+ cod = GEOC_SEG_INTERSEC_EXTREMO_NO_COLIN;
+ }
}
//calculamos el parámetro t
t = num/den;
@@ -272,9 +296,10 @@ int IntersecSegmentos2D(const double xA,
//asignamos la variable de salida
cod = GEOC_SEG_NO_INTERSEC;
}
- //calculamos las coordenadas del punto intersección
- *x = xA+s*(xB-xA);
- *y = yA+s*(yB-yA);
+ //calculamos las coordenadas del punto intersección y deshacemos el cambio
+ //del centroide
+ *x = xc+xAc+s*(xBc-xAc);
+ *y = yc+yAc+s*(yBc-yAc);
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
//salimos de la función
@@ -282,6 +307,165 @@ int IntersecSegmentos2D(const double xA,
}
/******************************************************************************/
/******************************************************************************/
+int IntersecSegmentos2DSimple(const double xA,
+ const double yA,
+ const double xB,
+ const double yB,
+ const double xC,
+ const double yC,
+ const double xD,
+ const double yD)
+{
+ //centroide del conjunto de puntos implicados
+ double xc=0.0,yc=0.0;
+ //coordenadas reducidas al centroide
+ double xAc=0.0,yAc=0.0,xBc=0.0,yBc=0.0,xCc=0.0,yCc=0.0,xDc=0.0,yDc=0.0;
+ //identificadores de posición
+ double posA=0.0,posB=0.0,posC=0.0,posD=0.0;
+ //identificadores de punto enmedio de un segmento
+ int enmA=0,enmB=0,enmC=0,enmD=0;
+ //variable de salida (por defecto, no hay intersección)
+ int cod=GEOC_SEG_NO_INTERSEC;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //si los rectángulos son disjuntos, los segmentos no se tocan
+ if(GEOC_RECT_DISJUNTOS(GEOC_MIN(xA,xB),GEOC_MAX(xA,xB),GEOC_MIN(yA,yB),
+ GEOC_MAX(yA,yB),GEOC_MIN(xC,xD),GEOC_MAX(xC,xD),
+ GEOC_MIN(yC,yD),GEOC_MAX(yC,yD)))
+ {
+ //salimos de la función (usamos el valor por defecto de no intersección
+ return cod;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //calculamos el centroide del conjunto de puntos de trabajo
+ xc = (xA+xB+xC+xD)/4.0;
+ yc = (yA+yB+yC+yD)/4.0;
+ //reducimos las coordenadas de trabajo al centroide, para que los números
+ //sean más pequeños y evitar posibles errores de desbordamiento
+ xAc = xA-xc;
+ xBc = xB-xc;
+ xCc = xC-xc;
+ xDc = xD-xc;
+ yAc = yA-yc;
+ yBc = yB-yc;
+ yCc = yC-yc;
+ yDc = yD-yc;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //calculamos las posiciones de los puntos con respecto a las rectas
+ posA = POS_PTO_RECTA_2D(xAc,yAc,xCc,yCc,xDc,yDc);
+ posB = POS_PTO_RECTA_2D(xBc,yBc,xCc,yCc,xDc,yDc);
+ posC = POS_PTO_RECTA_2D(xCc,yCc,xAc,yAc,xBc,yBc);
+ posD = POS_PTO_RECTA_2D(xDc,yDc,xAc,yAc,xBc,yBc);
+ //comprobamos si hay tres puntos alineados, que dan lugar a casos especiales
+ if((posA==0.0)||(posB==0.0)||(posC==0.0)||(posD==0.0))
+ {
+ //comprobamos si alguno de los extremos son coincidentes
+ if(((xA==xC)&&(yA==yC))||((xA==xD)&&(yA==yD))||
+ ((xB==xC)&&(yB==yC))||((xB==xD)&&(yB==yD)))
+ {
+ //código de salida
+ cod = GEOC_SEG_INTERSEC;
+ }
+ else
+ {
+ //comprobamos si A está en el segmento CD, pero no es un extremo
+ if(posA==0.0)
+ {
+ enmA = PuntoEntreDosPuntos2DColin(xAc,yAc,xCc,yCc,xDc,yDc);
+ }
+ //comprobamos si B está en el segmento CD, pero no es un extremo
+ if(posB==0.0)
+ {
+ enmB = PuntoEntreDosPuntos2DColin(xBc,yBc,xCc,yCc,xDc,yDc);
+ }
+ //comprobamos si C está en el segmento AB, pero no es un extremo
+ if(posC==0.0)
+ {
+ enmC = PuntoEntreDosPuntos2DColin(xCc,yCc,xAc,yAc,xBc,yBc);
+ }
+ //comprobamos si C está en el segmento AB, pero no es un extremo
+ if(posD==0.0)
+ {
+ enmD = PuntoEntreDosPuntos2DColin(xDc,yDc,xAc,yAc,xBc,yBc);
+ }
+ //si hay algún punto enmedio de algún segmento, existe intersección
+ if(enmA||enmB||enmC||enmD)
+ {
+ //código de salida
+ cod = GEOC_SEG_INTERSEC;
+ }
+ }
+ }
+ else
+ {
+ //para que ocurra intersección pura, las rectas han de dividirse
+ //mutuamente en dos, es decir, los puntos de cada una han de estar uno a
+ //cada lado de la otra
+ if((((posA<0.0)&&(posB>0.0))||((posA>0.0)&&(posB<0.0)))&&
+ (((posC<0.0)&&(posD>0.0))||((posC>0.0)&&(posD<0.0))))
+ {
+ //código de salida
+ cod = GEOC_SEG_INTERSEC;
+ }
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return cod;
+}
+/******************************************************************************/
+/******************************************************************************/
+int CodIntSeg2DCodIntSeg2DSimple(const int cod2D)
+{
+ //variable de salida
+ int sal=GEOC_SEG_NO_INTERSEC;
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //comprobamos los posibles valores de entrada
+ switch(cod2D)
+ {
+ case GEOC_SEG_NO_INTERSEC:
+ //no hay intersección
+ sal = GEOC_SEG_NO_INTERSEC;
+ break;
+ case GEOC_SEG_INTERSEC:
+ //intersección pura
+ sal = GEOC_SEG_INTERSEC;
+ break;
+ case GEOC_SEG_INTERSEC_EXTREMO_NO_COLIN:
+ //el vértice de un segmento se apoya en el otro segmento, aunque no
+ //en alguno de sus vértices
+ sal = GEOC_SEG_INTERSEC;
+ break;
+ case GEOC_SEG_INTERSEC_EXTREMOS_NO_COLIN:
+ //los segmentos comparten un vértice, pero no son colineales
+ sal = GEOC_SEG_INTERSEC;
+ break;
+ case GEOC_SEG_INTERSEC_EXTREMOS_COLIN:
+ //los segmentos comparten un vértice y son colineales
+ sal = GEOC_SEG_INTERSEC;
+ break;
+ case GEOC_SEG_INTERSEC_MISMO_SEG:
+ //ambos son el mismo segmento
+ sal = GEOC_SEG_INTERSEC;
+ break;
+ case GEOC_SEG_INTERSEC_COLIN:
+ //los segmentos se solapan
+ sal = GEOC_SEG_INTERSEC;
+ break;
+ default:
+ sal = GEOC_SEG_NO_INTERSEC;
+ break;
+ }
+ ////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////
+ //salimos de la función
+ return sal;
+}
+/******************************************************************************/
+/******************************************************************************/
/** @} */
/******************************************************************************/
/******************************************************************************/
diff --git a/src/ventorno.c b/src/ventorno.c
index d5ca57f..d5ca57f 100755..100644
--- a/src/ventorno.c
+++ b/src/ventorno.c