From cd21136507d238aae7b71191124c0e321835436b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Laboissi=C3=A8re?= Date: Tue, 26 May 2020 05:46:48 -0300 Subject: Import octave-octclip_2.0.1-1.debian.tar.xz [dgit import tarball octave-octclip 2.0.1-1 octave-octclip_2.0.1-1.debian.tar.xz] --- changelog | 90 ++++++++++++++++++++++++++++ control | 23 +++++++ copyright | 73 ++++++++++++++++++++++ octave-octclip.doc-base | 11 ++++ octave-octclip.docs | 1 + patches/do-not-strip-debugging-symbols.patch | 18 ++++++ patches/series | 2 + patches/spelling-doc-oc-polybool.patch | 16 +++++ rules | 9 +++ source/format | 1 + upstream/metadata | 3 + watch | 2 + 12 files changed, 249 insertions(+) create mode 100644 changelog create mode 100644 control create mode 100644 copyright create mode 100644 octave-octclip.doc-base create mode 100644 octave-octclip.docs create mode 100644 patches/do-not-strip-debugging-symbols.patch create mode 100644 patches/series create mode 100644 patches/spelling-doc-oc-polybool.patch create mode 100755 rules create mode 100644 source/format create mode 100644 upstream/metadata create mode 100644 watch diff --git a/changelog b/changelog new file mode 100644 index 0000000..8f312ff --- /dev/null +++ b/changelog @@ -0,0 +1,90 @@ +octave-octclip (2.0.1-1) unstable; urgency=medium + + * New upstream version 2.0.1 + * d/copyright: Reflect upstream changes + * d/p/compile-with-gcc-9.patch: Drop patch (fixed upstream) + * d/p/do-not-strip-debugging-symbols.patch: Refresh for new upstream version + * d/p/spelling-doc-oc-polybool.patch: New patch + * d/control: + + Bump Standards-Version to 4.5.0 (no changes needed) + + Bump debhelper compatibitlity level to 13 + * d/u/metadata: New file + + -- Rafael Laboissière Tue, 26 May 2020 05:46:48 -0300 + +octave-octclip (1.0.8-8) unstable; urgency=medium + + * d/control: + + Bump Standards-Version to 4.4.1 (no changes needed) + + Bump dependency on dh-octave to >= 0.7.1 + This allows the injection of the virtual package octave-abi-N + into the package's list of dependencies. + + -- Rafael Laboissiere Thu, 07 Nov 2019 18:23:55 -0300 + +octave-octclip (1.0.8-7) unstable; urgency=medium + + * d/p/compile-with-gcc-9.patch: Refresh for compilation with gcc version < 9 + (Closes: #935584) + + -- Rafael Laboissiere Sat, 24 Aug 2019 08:58:16 -0300 + +octave-octclip (1.0.8-6) unstable; urgency=medium + + * d/control: Bump Standards-Version to 4.4.0 (no changes needed) + * d/p/compile-with-gcc-9.patch: New patch (Closes: #925791) + + -- Rafael Laboissiere Wed, 21 Aug 2019 08:46:32 -0300 + +octave-octclip (1.0.8-5) unstable; urgency=medium + + [ Mike Miller ] + * d/control, d/copyright: Use secure URL for upstream source. + + [ Rafael Laboissiere ] + * d/control: + + Add Rules-Requires-Root: no + + Bump Standards-Version to 4.3.0 + + Bump to debhelper compat level 12 + * Build-depend on debhelper-compat instead of using d/compat + * d/p/do-not-strip-debugging-symbols.patch: New patch + + -- Rafael Laboissiere Wed, 02 Jan 2019 22:56:56 -0200 + +octave-octclip (1.0.8-4) unstable; urgency=medium + + * Use dh-octave for building the package + * d/control: + + Use Debian's GitLab URLs in Vcs-* headers + + Change Maintainer to team+pkg-octave-team@tracker.debian.org + + -- Rafael Laboissiere Sat, 10 Feb 2018 07:36:23 -0200 + +octave-octclip (1.0.8-3) unstable; urgency=medium + + * Use the dh-based version of octave-pkg-dev + * Set debhelper compatibility level to >= 11 + * d/control: + + Bump Standards-Version to 4.1.3 (no changes needed) + + Add Testsuite field + + -- Rafael Laboissiere Fri, 29 Dec 2017 22:14:15 -0200 + +octave-octclip (1.0.8-2) unstable; urgency=medium + + [ Rafael Laboissiere ] + * d/control: + + Use cgit instead of gitweb in Vcs-Browser URL + + Bump Standards-Version to 4.0.1 (no changes needed) + + [ Sébastien Villemot ] + * d/copyright: use secure URL for format. + * d/watch: bump to format version 4. + + -- Rafael Laboissiere Mon, 21 Aug 2017 17:49:51 -0300 + +octave-octclip (1.0.8-1) unstable; urgency=low + + * Initial release (closes: #814773) + + -- Rafael Laboissiere Sun, 31 Jul 2016 10:48:51 -0300 diff --git a/control b/control new file mode 100644 index 0000000..80bc2d6 --- /dev/null +++ b/control @@ -0,0 +1,23 @@ +Source: octave-octclip +Section: math +Priority: optional +Maintainer: Debian Octave Group +Uploaders: Rafael Laboissière +Build-Depends: debhelper-compat (= 13), + dh-octave (>= 0.7.1) +Standards-Version: 4.5.0 +Homepage: https://octave.sourceforge.io/octclip/ +Vcs-Git: https://salsa.debian.org/pkg-octave-team/octave-octclip.git +Vcs-Browser: https://salsa.debian.org/pkg-octave-team/octave-octclip +Testsuite: autopkgtest-pkg-octave +Rules-Requires-Root: no + +Package: octave-octclip +Architecture: any +Depends: ${misc:Depends}, ${octave:Depends}, ${shlibs:Depends} +Description: boolean operations with polygons in Octave + The octclip package contain functions for performing boolean + operations (intersection, union, difference, and exclusive or) between + two polygons in Octave using the Greiner-Hormann algorithm. + . + This Octave add-on package is part of the Octave-Forge project. diff --git a/copyright b/copyright new file mode 100644 index 0000000..aac9922 --- /dev/null +++ b/copyright @@ -0,0 +1,73 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: GNU Octave clipping polygons tool +Upstream-Contact: The Octave Community +Source: https://octave.sourceforge.io/octclip/ + +Files: * +Copyright: 2009-2020, José Luis García Pallero +License: BSD-3-clause + 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 listed + in this license 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 THE COPYRIGHT + OWNER OR CONTRIBUTORS 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. + +Files: doc/octclip.* +Copyright: 2011-2020 José Luis García Pallero +License: GFDL-NIV + This document is free documentation; you can redistribute it and/or + modify it under the terms of the GNU Free Documentation License as + published by the Free Software Foundation, with no version specified and + no cover texts, invariant sections and whatever else. + . + On Debian systems, the complete text of the GNU Free Documentation + License, version 1.3, can be found in the file + `/usr/share/common-licenses/GFDL-1.3'. + +Files: inst/oc_polybool.m src/_oc_polybool.cc src/octclip.h +Copyright: 2011-2020, José Luis García Pallero, +License: GPL-3+ + +Files: debian/* +Copyright: 2016-2020 Rafael Laboissiere +License: GPL-3+ + +License: GPL-3+ + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + . + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + . + You should have received a copy of the GNU General Public License along + with this program. If not, see . + . + On Debian systems, the complete text of the GNU General Public + License, version 3, can be found in the file + `/usr/share/common-licenses/GPL-3'. diff --git a/octave-octclip.doc-base b/octave-octclip.doc-base new file mode 100644 index 0000000..931202a --- /dev/null +++ b/octave-octclip.doc-base @@ -0,0 +1,11 @@ +Document: octave-octclip-manual +Title: Clipping polygons from GNU Octave +Author: José Luis García Pallero +Abstract: This is a small introduction to using the octclip package. + In this text, you can overview the basic usage of the functions in + GNU Octave. If you need a detailed description about the + Greiner-Hormann implemented algorithm. +Section: Science/Mathematics + +Format: PDF +Files: /usr/share/doc/octave-octclip/octclip.pdf.gz diff --git a/octave-octclip.docs b/octave-octclip.docs new file mode 100644 index 0000000..50d87d8 --- /dev/null +++ b/octave-octclip.docs @@ -0,0 +1 @@ +doc/octclip.pdf diff --git a/patches/do-not-strip-debugging-symbols.patch b/patches/do-not-strip-debugging-symbols.patch new file mode 100644 index 0000000..920948a --- /dev/null +++ b/patches/do-not-strip-debugging-symbols.patch @@ -0,0 +1,18 @@ +Description: Do not strip the debugging symbols from _oc_polybool.oct + Also, include the -g option to enable debugging option for all + compilers. +Author: Rafael Laboissiere +Forwarded: https://savannah.gnu.org/bugs/index.php?55343 +Last-Update: 2020-05-26 + +--- octave-octclip-1.0.8.orig/src/Makefile ++++ octave-octclip-1.0.8/src/Makefile +@@ -40,7 +40,7 @@ compile: + $(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 ++ $(MKOCTFILE) -g -I. _oc_polybool.cc *.o + + .PHONY: clean + clean: diff --git a/patches/series b/patches/series new file mode 100644 index 0000000..6d05119 --- /dev/null +++ b/patches/series @@ -0,0 +1,2 @@ +do-not-strip-debugging-symbols.patch +spelling-doc-oc-polybool.patch diff --git a/patches/spelling-doc-oc-polybool.patch b/patches/spelling-doc-oc-polybool.patch new file mode 100644 index 0000000..91baee1 --- /dev/null +++ b/patches/spelling-doc-oc-polybool.patch @@ -0,0 +1,16 @@ +Description: Fix documentation in doc string of function _oc_polybool +Author: Rafael Laboissière +Forwarded: https://savannah.gnu.org/bugs/index.php?58446 +Last-Update: 2020-05-26 + +--- octave-octclip-2.0.1.orig/src/_oc_polybool.cc ++++ octave-octclip-2.0.1/src/_oc_polybool.cc +@@ -72,7 +72,7 @@ polygons they are separated by rows os ( + @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\ ++@var{p} where the polygon end, and the third column 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\ diff --git a/rules b/rules new file mode 100755 index 0000000..18d01a3 --- /dev/null +++ b/rules @@ -0,0 +1,9 @@ +#!/usr/bin/make -f +# -*- makefile -*- + +%: + dh $@ --buildsystem=octave --with=octave + +override_dh_auto_clean: + make -C src cleanall + dh_auto_clean diff --git a/source/format b/source/format new file mode 100644 index 0000000..46ebe02 --- /dev/null +++ b/source/format @@ -0,0 +1 @@ +3.0 (quilt) \ No newline at end of file diff --git a/upstream/metadata b/upstream/metadata new file mode 100644 index 0000000..b042922 --- /dev/null +++ b/upstream/metadata @@ -0,0 +1,3 @@ +Bug-Database: https://savannah.gnu.org/bugs/?group=octave +Bug-Submit: https://savannah.gnu.org/bugs/?func=additem&group=octave +Repository-Browse: https://octave.sourceforge.io/pkg-repository/octclip/ diff --git a/watch b/watch new file mode 100644 index 0000000..3c44a4e --- /dev/null +++ b/watch @@ -0,0 +1,2 @@ +version=4 +http://sf.net/octave/octclip-(.+)\.tar\.gz -- cgit v1.2.3 From d109b848ad8eff44ef33e19f5510059b81b20b90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Laboissi=C3=A8re?= Date: Tue, 26 May 2020 05:46:48 -0300 Subject: Import octave-octclip_2.0.1.orig.tar.gz [dgit import orig octave-octclip_2.0.1.orig.tar.gz] --- COPYING | 674 +++++++++++++++ DESCRIPTION | 12 + INDEX | 5 + NEWS | 47 ++ doc/octclip.pdf | Bin 0 -> 212089 bytes doc/octclip.tex | 146 ++++ inst/oc_polybool.m | 456 +++++++++++ src/Makefile | 51 ++ src/_oc_polybool.cc | 288 +++++++ src/arco.c | 910 ++++++++++++++++++++ src/calctopo.c | 71 ++ src/compilador.c | 82 ++ src/dpeucker.c | 304 +++++++ src/dpeuckera.c | 204 +++++ src/dpeuckere.c | 1495 +++++++++++++++++++++++++++++++++ src/dpeuckerp.c | 1114 +++++++++++++++++++++++++ src/errores.c | 119 +++ src/eucli.c | 238 ++++++ src/fgeneral.c | 884 ++++++++++++++++++++ src/geocnan.c | 184 +++++ src/geocomp.c | 129 +++ src/greiner.c | 1922 +++++++++++++++++++++++++++++++++++++++++++ src/libgeoc/arco.h | 617 ++++++++++++++ src/libgeoc/calctopo.h | 81 ++ src/libgeoc/compilador.h | 96 +++ src/libgeoc/constantes.h | 264 ++++++ src/libgeoc/dpeucker.h | 333 ++++++++ src/libgeoc/dpeuckera.h | 210 +++++ src/libgeoc/dpeuckere.h | 1002 +++++++++++++++++++++++ src/libgeoc/dpeuckerp.h | 774 ++++++++++++++++++ src/libgeoc/errores.h | 1058 ++++++++++++++++++++++++ src/libgeoc/eucli.h | 237 ++++++ src/libgeoc/fgeneral.h | 736 +++++++++++++++++ src/libgeoc/general.h | 61 ++ src/libgeoc/geocnan.h | 233 ++++++ src/libgeoc/geocomp.h | 208 +++++ src/libgeoc/geom.h | 64 ++ src/libgeoc/greiner.h | 855 +++++++++++++++++++ src/libgeoc/mate.h | 482 +++++++++++ src/libgeoc/polig.h | 1215 +++++++++++++++++++++++++++ src/libgeoc/polil.h | 836 +++++++++++++++++++ src/libgeoc/posmatvec.h | 512 ++++++++++++ src/libgeoc/proyecaux.h | 90 ++ src/libgeoc/ptopol.h | 1377 +++++++++++++++++++++++++++++++ src/libgeoc/recpolil.h | 440 ++++++++++ src/libgeoc/segmento.h | 377 +++++++++ src/libgeoc/ventorno.h | 100 +++ src/mate.c | 813 ++++++++++++++++++ src/octclip.h | 31 + src/polig.c | 2048 ++++++++++++++++++++++++++++++++++++++++++++++ src/polil.c | 1535 ++++++++++++++++++++++++++++++++++ src/posmatvec.c | 292 +++++++ src/proyecaux.c | 92 +++ src/ptopol.c | 1332 ++++++++++++++++++++++++++++++ src/recpolil.c | 1403 +++++++++++++++++++++++++++++++ src/segmento.c | 476 +++++++++++ src/ventorno.c | 86 ++ 57 files changed, 29701 insertions(+) create mode 100644 COPYING create mode 100644 DESCRIPTION create mode 100644 INDEX create mode 100644 NEWS create mode 100644 doc/octclip.pdf create mode 100644 doc/octclip.tex create mode 100644 inst/oc_polybool.m create mode 100644 src/Makefile create mode 100644 src/_oc_polybool.cc create mode 100644 src/arco.c create mode 100644 src/calctopo.c create mode 100644 src/compilador.c create mode 100644 src/dpeucker.c create mode 100644 src/dpeuckera.c create mode 100644 src/dpeuckere.c create mode 100644 src/dpeuckerp.c create mode 100644 src/errores.c create mode 100644 src/eucli.c create mode 100644 src/fgeneral.c create mode 100644 src/geocnan.c create mode 100644 src/geocomp.c create mode 100644 src/greiner.c create mode 100644 src/libgeoc/arco.h create mode 100644 src/libgeoc/calctopo.h create mode 100644 src/libgeoc/compilador.h create mode 100644 src/libgeoc/constantes.h create mode 100644 src/libgeoc/dpeucker.h create mode 100644 src/libgeoc/dpeuckera.h create mode 100644 src/libgeoc/dpeuckere.h create mode 100644 src/libgeoc/dpeuckerp.h create mode 100644 src/libgeoc/errores.h create mode 100644 src/libgeoc/eucli.h create mode 100644 src/libgeoc/fgeneral.h create mode 100644 src/libgeoc/general.h create mode 100644 src/libgeoc/geocnan.h create mode 100644 src/libgeoc/geocomp.h create mode 100644 src/libgeoc/geom.h create mode 100644 src/libgeoc/greiner.h create mode 100644 src/libgeoc/mate.h create mode 100644 src/libgeoc/polig.h create mode 100644 src/libgeoc/polil.h create mode 100644 src/libgeoc/posmatvec.h create mode 100644 src/libgeoc/proyecaux.h create mode 100644 src/libgeoc/ptopol.h create mode 100644 src/libgeoc/recpolil.h create mode 100644 src/libgeoc/segmento.h create mode 100644 src/libgeoc/ventorno.h create mode 100644 src/mate.c create mode 100644 src/octclip.h create mode 100644 src/polig.c create mode 100644 src/polil.c create mode 100644 src/posmatvec.c create mode 100644 src/proyecaux.c create mode 100644 src/ptopol.c create mode 100644 src/recpolil.c create mode 100644 src/segmento.c create mode 100644 src/ventorno.c diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/DESCRIPTION b/DESCRIPTION new file mode 100644 index 0000000..0f11518 --- /dev/null +++ b/DESCRIPTION @@ -0,0 +1,12 @@ +Name: OctCLIP +Version: 2.0.1 +Date: 2020-05-16 +Author: José Luis García Pallero +Maintainer: José Luis García Pallero +Title: GNU Octave clipping polygons tool +Description: This package allows to do boolean operations with polygons using + the Greiner-Hormann algorithm. +Depends: Octave (>= 3.6.0) +Url: https://bitbucket.org/jgpallero/octclip +Autoload: no +License: GPLv3+, modified BSD diff --git a/INDEX b/INDEX new file mode 100644 index 0000000..23fe7c2 --- /dev/null +++ b/INDEX @@ -0,0 +1,5 @@ +toolbox >> OctCLIP +Category Kernel functions + _oc_polybool +Category Driver functions + oc_polybool diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..3c40549 --- /dev/null +++ b/NEWS @@ -0,0 +1,47 @@ +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: +------------------------------------------------------------ + +** Minor changes in src/Makefile + +Summary of important user-visible changes for version 1.0.7: +------------------------------------------------------------ + +** Minor changes and corrections in help strings + +Summary of important user-visible changes for version 1.0.6: +------------------------------------------------------------ + +** All calls to ismatrix() are changed by isnumeric() + +Summary of important user-visible changes for version 1.0.5: +------------------------------------------------------------ + +** Only minor changes in Mercurial repository managment + +Summary of important user-visible changes for version 1.0.3: +------------------------------------------------------------ + +** Change 'autoload' option to 'no' by default + +** Correct the way of calculation of the minumum perturbation number + +** Add number of polygons output argument + +** Fix number of input arguments control + +** Documentation updates diff --git a/doc/octclip.pdf b/doc/octclip.pdf new file mode 100644 index 0000000..c0afbef Binary files /dev/null and b/doc/octclip.pdf differ diff --git a/doc/octclip.tex b/doc/octclip.tex new file mode 100644 index 0000000..c39623c --- /dev/null +++ b/doc/octclip.tex @@ -0,0 +1,146 @@ +\documentclass[10pt,a4paper]{article} +\usepackage{tocbibind} +\usepackage{hyperref} +\hypersetup{colorlinks,citecolor=red,linkcolor=red,urlcolor=red} + +\newcommand{\octclip}{\texttt{OctCLIP}} +\newcommand{\octave}{GNU Octave} + +\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{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)\\ + May 24, 2011 (version 1.0.0)} + +\begin{document} +\maketitle +% \tableofcontents + +\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 +\octave\footnote{\url{http://www.octave.org}}. If you need a detailed +description about the Greiner-Hormann implemented algorithm, please read +\cite{greiner1998} and visit \url{http://davis.wpi.edu/~matt/courses/clipping/}. +\end{abstract} + +\section{Overview} + +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 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} + +As most of \octave{} packages, \octclip{} installation consists in compiling the +C++ kernel sources, link them against \octave{} library to generate +\texttt{*.oct} functions and copy this \texttt{*.oct} executables and other +\texttt{*.m} functions into a working directory. + +The automagic procedure can be easily done by running the command: + +\begin{verbatim} +octave:1> pkg install octclip-x.x.x.tar.gz +\end{verbatim} +where \texttt{x.x.x} is the version number. + +After that, the functions and documentation are installed in your machine and +you are ready for use the package. + +\section{\octave{} functions} + +Two types of functions are programmed for \octave: one \texttt{*.oct} function +and one \texttt{*.m} function. + +\subsection{\texttt{*.oct} function} +\label{op-of} + +This function are linked with the C code that actually make the computations. +You can use it, but is no recommended because the input arguments are more +strict than \texttt{*.m} functions and don't check for some errors. + +The function is: +\begin{itemize} +\item \texttt{\_oc\_polybool}: Performs boolean operation between two polygons. +\end{itemize} + +\subsection{\texttt{*.m} function} + +This function makes the computations by calling the \texttt{*.oct} function. You +must call this function because you can use different number of input arguments +and checking of input arguments is performed. + +The function is the same as in section \ref{op-of} (without the \texttt{\_} at +the beginning of the name): +\begin{itemize} +\item \texttt{oc\_polybool}: Performs boolean operation between two polygons + by calling the \texttt{\_oc\_polybool}. +\end{itemize} + +\texttt{oc\_polybool} includes too some demonstration code in order to test the +functionality of the functions. The demo code can be executed as: +\begin{verbatim} +octave:1> demo oc_polybool +\end{verbatim} + +\subsection{Error handling} + +\texttt{*.oct} and \texttt{*.m} functions can emit errors, some due to errors +with input arguments and other due to errors in functions from the +C\footnote{The algorithm is internally implemented in C (C99 standard).} code. + +Errors due to wrong input arguments (data types, dimensions, etc.) can be only +given for \texttt{*.m} function and this is the reason because the use of this +function is recommended. In this case, the execution is aborted and nothing is +stored in output arguments. + +The \texttt{*.oct} function can emit errors due to wrong number of input +arguments, wrong value of the operation identifier and internal errors of memory +allocation. + +\section{Caveats of Greiner-Hormann algorithm} + +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/}. + +\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/}. +\end{thebibliography} + +\end{document} + +%Copyright (C) 2011-2020, José Luis García Pallero, +%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 new file mode 100644 index 0000000..92b85af --- /dev/null +++ b/inst/oc_polybool.m @@ -0,0 +1,456 @@ +## Copyright (C) 2011-2020, José Luis García Pallero, +## +## This file is part of OctCLIP. +## +## OctCLIP is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 3 of the License, or (at +## your option) any later version. +## +## This program is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, see +## . + +## -*- texinfo -*- +## @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 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 (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(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}. This value is set by default. +## @item @var{'OR'} +## 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, 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{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{details} is a struct containing details of the computation. Its fields +## (IN LOWERCASE!) are: +## +## @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 +## +## This function does not check if the dimensions of @var{sub} and @var{clip} +## are correct. +## +## @end deftypefn + +function [p,details] = oc_polybool(sub,clip,op,hor) + +try + functionName = 'oc_polybool'; + minArg = 2; + maxArg = 4; + +%******************************************************************************* +%NUMBER OF INPUT ARGUMENTS CHECKING +%******************************************************************************* + + %number of input arguments checking + if (narginmaxArg) + error(['Incorrect number of input arguments (%d)\n\t ',... + 'Correct number of input arguments = %d or %d'],... + nargin,minArg,maxArg); + end + %values by default + opDef = 'AND'; + horDef = 1; + %check if we omit some input arguments + if nargin + * + * This file is part of OctCLIP. + * + * OctCLIP is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, see + * . + */ +/******************************************************************************/ +/******************************************************************************/ +#define HELPTEXT "\ +-*- texinfo -*-\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\ +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 (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(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\ +@itemize @bullet\n\ +@item @var{'AND'}\n\ +Intersection of @var{sub} and @var{clip}.\n\n\ +@item @var{'OR'}\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\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, 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{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\ +correct.\n\ +\n\ +@end deftypefn" +/******************************************************************************/ +/******************************************************************************/ +#include +#include +#include +#include +#include +#include"octclip.h" +/******************************************************************************/ +/******************************************************************************/ +#define ERRORTEXT 1000 +/******************************************************************************/ +/******************************************************************************/ +DEFUN_DLD(_oc_polybool,args,,HELPTEXT) +{ + //error message + char errorText[ERRORTEXT+1]="_oc_polybool:\n\t"; + //output list + octave_value_list outputList; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //checking input arguments + if(args.length()!=4) + { + //error text + sprintf(&errorText[strlen(errorText)], + "Incorrect number of input arguments\n\t" + "See help _oc_polybool"); + //error message + error(errorText); + } + else + { + //loop index + size_t i=0; + //polygons and operation + ColumnVector xSubj=args(0).matrix_value().column(0); + ColumnVector ySubj=args(0).matrix_value().column(1); + 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; + double* xB=NULL; + double* yB=NULL; + //double linked lists + vertPoliClip* polA=NULL; + vertPoliClip* polB=NULL; + //operation identifier + enum GEOC_OP_BOOL_POLIG op=GeocOpBoolInter; + //output struct + polig* result=NULL; + //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,posStart=0,posEnd=0,pos=0; + //////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////// + //pointers to data + xA = xSubj.fortran_vec(); + yA = ySubj.fortran_vec(); + xB = xClip.fortran_vec(); + yB = yClip.fortran_vec(); + //create double linked lists for subject and clipper polygons + polA = CreaPoliClip(xA,yA,static_cast(xSubj.numel()),1,1); + polB = CreaPoliClip(xB,yB,static_cast(xClip.numel()),1,1); + //error checking + if((polB==NULL)||(polB==NULL)) + { + //free peviously allocated memory + LibMemPoliClip(polA); + LibMemPoliClip(polB); + //error text + sprintf(&errorText[strlen(errorText)],"Error in memory allocation"); + //error message + error(errorText); + //exit + return outputList; + } + //////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////// + //select operation + if((!strcmp(opchar.c_str(),"AND"))||(!strcmp(opchar.c_str(),"and"))) + { + op = GeocOpBoolInter; + } + else if((!strcmp(opchar.c_str(),"OR"))||(!strcmp(opchar.c_str(),"or"))) + { + op = GeocOpBoolUnion; + } + else if((!strcmp(opchar.c_str(),"AB"))||(!strcmp(opchar.c_str(),"ab"))) + { + op = GeocOpBoolAB; + } + else if((!strcmp(opchar.c_str(),"BA"))||(!strcmp(opchar.c_str(),"ba"))) + { + op = GeocOpBoolBA; + } + else if((!strcmp(opchar.c_str(),"XOR"))|| + (!strcmp(opchar.c_str(),"xor"))) + { + op = GeocOpBoolXor; + } + else + { + //free peviously allocated memory + LibMemPoliClip(polA); + LibMemPoliClip(polB); + //error text + sprintf(&errorText[strlen(errorText)], + "The third input argument (op=%s) is not correct", + opchar.c_str()); + //error message + error(errorText); + //exit + return outputList; + } + //////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////// + //clipping + result = PoliBoolGreiner(polA,polB,op,GEOC_GREINER_FAC_EPS_PERTURB,sfh, + &nInter,&nPert); + //error checking + if(result==NULL) + { + //free peviously allocated memory + LibMemPoliClip(polA); + LibMemPoliClip(polB); + //error text + sprintf(&errorText[strlen(errorText)],"Error in memory allocation"); + //error message + error(errorText); + //exit + return outputList; + } + //////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////// + //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;iposIni[i]+1-posStart; + pp(i,1) = pp(i,0)+result->nVert[i]-1; + pp(i,2) = result->atr[i]; + } + } + else + { + nElem = 0; + } + //output matrix + Matrix p(nElem,2); + //copy output data + pos = 0; + for(i=posStart;i<=posEnd;i++) + { + p(pos,0) = result->x[i]; + p(pos,1) = result->y[i]; + pos++; + } + //////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////// + //output parameters list + outputList(0) = p; + outputList(1) = pp; + outputList(2) = nInter; + outputList(3) = nPert; + //////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////// + //free memory + LibMemPoliClip(polA); + LibMemPoliClip(polB); + LibMemPolig(result); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //exit + return outputList; +} 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)&&(lonP1lonB-tol))) + { + //asigno el código de salida + cod = GEOC_ARC_INTERSEC; + //longitud de la intersección + lonPI = lonP1; + } + else if(((lonP2>-tol)&&(lonP2lonB-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/calctopo.c b/src/calctopo.c new file mode 100644 index 0000000..ab3c595 --- /dev/null +++ b/src/calctopo.c @@ -0,0 +1,71 @@ +/* -*- coding: utf-8 -*- */ +/** +\ingroup geodesia geom +@{ +\file calctopo.c +\brief Definición de funciones para cálculos de topografía. +\author José Luis García Pallero, jgpallero@gmail.com +\date 05 de julio de 2011 +\section Licencia Licencia +Copyright (c) 2011, 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/calctopo.h" +/******************************************************************************/ +/******************************************************************************/ +double AcimutTopografico(const double x1, + const double y1, + const double x2, + const double y2) +{ + //acimut calculado + double acimut=0.0; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //calculamos el acimut en el dominio [-pi pi] + acimut = atan2(x2-x1,y2-y1); + //comprobamos si ha salido un valor negativo + if(acimut<0.0) + { + //metemos el valor en dominio + acimut += 2.0*GEOC_CONST_PI; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return acimut; +} +/******************************************************************************/ +/******************************************************************************/ +/** @} */ +/******************************************************************************/ +/******************************************************************************/ +/* 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 new file mode 100644 index 0000000..aa35e74 --- /dev/null +++ b/src/compilador.c @@ -0,0 +1,82 @@ +/* -*- coding: utf-8 -*- */ +/** +\ingroup general geopot +@{ +\file compilador.c +\brief Definición de funciones para la detección de compiladores. +\author José Luis García Pallero, jgpallero@gmail.com +\date 28 de abril de 2011 +\version 1.0 +\section Licencia Licencia +Copyright (c) 2011, 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/compilador.h" +/******************************************************************************/ +/******************************************************************************/ +int EsCompiladorGNU(int* noGnu) +{ + //variable de salida + int salida=0; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //inicializamos la variable noGnu, si ha lugar + if(noGnu!=NULL) + { + //inicializamos la variable a 0 + *noGnu = 0; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //para que sea GCC, la constante __GNUC__ ha de estar definida +#if defined(__GNUC__) + //el compilador es GCC + salida = 1; + //comprobamos si es el compilador de intel +#if defined(__INTEL_COMPILER) + if(noGnu!=NULL) + { + //el compilador es de intel + *noGnu = 1; + } +#endif +#endif + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //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/dpeucker.c b/src/dpeucker.c new file mode 100644 index 0000000..1d06156 --- /dev/null +++ b/src/dpeucker.c @@ -0,0 +1,304 @@ +/* -*- coding: utf-8 -*- */ +/** +\ingroup geom +@{ +\file dpeucker.c +\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 +\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 + 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/dpeucker.h" +/******************************************************************************/ +/******************************************************************************/ +size_t* AligeraPolilinea(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, + const int esf, + size_t* nPtosSal) +{ + //identificador de caso especial + int hayCasoEspecial=0; + //valor absoluto de la tolerancia + double atol=fabs(tol); + //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 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(nPtos&&(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; +} +/******************************************************************************/ +/******************************************************************************/ +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) +{ + //índice para recorrer bucles + size_t i=0; + //valor absoluto de la tolerancia + double atol=fabs(tol); + //variables auxiliares + int aux=0; + size_t pos=0; + //vector de identificadores de elementos usados + char* usados=NULL; + //vector de salida + size_t* sal=NULL; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //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 NULL; + } + //indico el primer punto y el último como usados + usados[0] = 1; + usados[nPtos-1] = 1; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //comprobamos si trabajamos sobre la esfera o sobre el plano + if(esf) + { + //aplico el algoritmo original sobre la esfera + DouglasPeuckerOriginalEsfera(x,y,nPtos,incX,incY,atol,0,nPtos-1,usados); + } + else + { + //aplico el algoritmo original sobre el plano + DouglasPeuckerOriginalPlano(x,y,nPtos,incX,incY,atol,0,nPtos-1,usados); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //cuento los puntos usados + for(i=0;istol) + { + //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;i1) + { + //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(j1)) + { + //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 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)) + { + //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;idist) + { + //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)&&(lonVRatol) + { + //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(j1)) + { + //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 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)) + { + //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;ilon) + { + //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 new file mode 100644 index 0000000..4b7788a --- /dev/null +++ b/src/errores.c @@ -0,0 +1,119 @@ +/* -*- coding: utf-8 -*- */ +/** +\ingroup anespec errores eop fichero general geodesia geom geopot gshhs marea +\ingroup matriz mmcc orden snx texto +@{ +\file errores.c +\brief Definición de funciones para el tratamiento de errores. + +En el momento de la compilación ha de seleccionarse el comportamiento de la +función \ref GeocError. Para realizar la selección es necesario definir las +variables para el preprocesador \em ESCRIBE_MENSAJE_ERROR si se quiere que la +función imprima un mensaje de error y/o \em FIN_PROGRAMA_ERROR si se quiere que +la función termine la ejecución del programa en curso. Si no se define ninguna +variable, la función no ejecuta ninguna acción. 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 09 de enero de 2011 +\section Licencia Licencia +Copyright (c) 2009-2011, 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/errores.h" +/******************************************************************************/ +/******************************************************************************/ +int GeocTipoError(void) +{ + //variable de salida + int valor=GEOC_TIPO_ERR_NADA; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //distinguimos los posibles casos según las variables del preprocesador +#if defined(ESCRIBE_MENSAJE_ERROR) && defined(FIN_PROGRAMA_ERROR) + //mensaje de error y terminación del programa + valor = GEOC_TIPO_ERR_MENS_Y_EXIT; +#elif defined(ESCRIBE_MENSAJE_ERROR) + //mensaje de error + valor = GEOC_TIPO_ERR_MENS; +#elif defined(FIN_PROGRAMA_ERROR) + //terminación del programa + valor = GEOC_TIPO_ERR_EXIT; +#endif + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return valor; +} +/******************************************************************************/ +/******************************************************************************/ +void GeocError(const char mensaje[], + const char funcion[]) +{ + //hacemos una copia para que en la compilación no dé warning si sólo se + //termina la ejecución del programa o no se hace nada + mensaje = mensaje; + funcion = funcion; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //distinguimos los posibles casos según las variables del preprocesador +#if defined(ESCRIBE_MENSAJE_ERROR) && defined(FIN_PROGRAMA_ERROR) + //imprimimos el nombre de la función y el mensaje + fprintf(stderr,"En la función '%s'\n",funcion); + fprintf(stderr,"%s\n",mensaje); + //indicamos que el programa finalizará + fprintf(stderr,"El programa finalizará mediante la llamada a la función " + "'exit(EXIT_FAILURE)'\n"); + //detenemos la ejecución del programa + exit(EXIT_FAILURE); +#elif defined(ESCRIBE_MENSAJE_ERROR) + //imprimimos el nombre de la función y el mensaje + fprintf(stderr,"En la función '%s'\n",funcion); + fprintf(stderr,"%s\n",mensaje); + //salimos de la función + return; +#elif defined(FIN_PROGRAMA_ERROR) + //indicamos que el programa finalizará + fprintf(stderr,"El programa finalizará mediante la llamada a la función " + "'exit(EXIT_FAILURE)'\n"); + //detenemos la ejecución del programa + exit(EXIT_FAILURE); +#else + //salimos de la función + return; +#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/eucli.c b/src/eucli.c new file mode 100644 index 0000000..fcd8cd7 --- /dev/null +++ b/src/eucli.c @@ -0,0 +1,238 @@ +/* -*- coding: utf-8 -*- */ +/** +\ingroup geom interp +@{ +\file eucli.c +\brief Definición de funciones para la realización de cálculos de geometría + euclídea. +\author José Luis García Pallero, jgpallero@gmail.com +\date 27 de octubre de 2009 +\section Licencia Licencia +Copyright (c) 2009-2011, 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/eucli.h" +/******************************************************************************/ +/******************************************************************************/ +double Dist2D(const double x1, + const double y1, + const double x2, + const double y2) +{ + //calculamos y salimos de la función + return sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)); +} +/******************************************************************************/ +/******************************************************************************/ +void Dist2DVC(const double x1, + const double y1, + const double x2, + const double y2, + const double varx1, + const double varx1y1, + const double vary1, + const double varx2, + const double varx2y2, + const double vary2, + double* dist, + double* varDist) +{ + //matrices auxiliares + double j[4],jvc[4]; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //calculamos la distancia + *dist = Dist2D(x1,y1,x2,y2); + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //rellenamos la matriz jacobiana + j[0] = -(x2-x1)/(*dist); + j[1] = -(y2-y1)/(*dist); + j[2] = -j[0]; + j[3] = -j[1]; + //producto de la matriz jacobiana por la matriz de varianza-covarianza + jvc[0] = j[0]*varx1+j[1]*varx1y1; + jvc[1] = j[0]*varx1y1+j[1]*vary1; + jvc[2] = j[2]*varx2+j[3]*varx2y2; + jvc[3] = j[2]*varx2y2+j[3]*vary2; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //realizamos la propagación de errores + *varDist = jvc[0]*j[0]+jvc[1]*j[1]+jvc[2]*j[2]+jvc[3]*j[3]; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return; +} +/******************************************************************************/ +/******************************************************************************/ +double Dist3D(const double x1, + const double y1, + const double z1, + const double x2, + const double y2, + const double z2) +{ + //calculamos y salimos de la función + return sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)+(z2-z1)*(z2-z1)); +} +/******************************************************************************/ +/******************************************************************************/ +void Dist3DVC(const double x1, + const double y1, + const double z1, + const double x2, + const double y2, + const double z2, + const double varx1, + const double varx1y1, + const double varx1z1, + const double vary1, + const double vary1z1, + const double varz1, + const double varx2, + const double varx2y2, + const double varx2z2, + const double vary2, + const double vary2z2, + const double varz2, + double* dist, + double* varDist) +{ + //matrices auxiliares + double j[6],jvc[6]; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //calculamos la distancia + *dist = Dist3D(x1,y1,z1,x2,y2,z2); + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //rellenamos la matriz jacobiana + j[0] = -(x2-x1)/(*dist); + j[1] = -(y2-y1)/(*dist); + j[2] = -(z2-z1)/(*dist); + j[3] = -j[0]; + j[4] = -j[1]; + j[5] = -j[2]; + //producto de la matriz jacobiana por la matriz de varianza-covarianza + jvc[0] = j[0]*varx1+j[1]*varx1y1+j[2]*varx1z1; + jvc[1] = j[0]*varx1y1+j[1]*vary1+j[2]*vary1z1; + jvc[2] = j[0]*varx1z1+j[1]*vary1z1+j[2]*varz1; + jvc[3] = j[3]*varx2+j[4]*varx2y2+j[5]*varx2z2; + jvc[4] = j[3]*varx2y2+j[4]*vary2+j[5]*vary2z2; + jvc[5] = j[3]*varx2z2+j[4]*vary2z2+j[5]*varz2; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //realizamos la propagación de errores + *varDist = jvc[0]*j[0]+jvc[1]*j[1]+jvc[2]*j[2]+jvc[3]*j[3]+jvc[4]*j[4]+ + jvc[5]*j[5]; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return; +} +/******************************************************************************/ +/******************************************************************************/ +double AnguloVecPlano(const double x1, + const double y1, + const double x2, + const double y2) +{ + //variables auxiliares + double num=0.0,den=0.0; + //variable de salida + double alfa=0.0; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //calculamos el numerador de la fórmula que da el coseno del ángulo + num = x1*x2+y1*y2; + //calculamos el denominador de la fórmula que da el coseno del ángulo + den = sqrt((x1*x1+y1*y1)*(x2*x2+y2*y2)); + //calculamos el coseno del ángulo, teniendo en cuenta casos singulares + if(den==0.0) + { + //si el denominador es 0.0, el ángulo es 0.0 y su coseno 1.0 + alfa = 1.0; + } + else + { + //no hay singularidad + alfa = num/den; + } + //calculamos el ángulo + alfa = acos(alfa); + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return alfa; +} +/******************************************************************************/ +/******************************************************************************/ +double AlturaTriangulo(const double xVert, + const double yVert, + const double xBase1, + const double yBase1, + const double xBase2, + const double yBase2) +{ + //ángulo entra la base en el punto 1 y el vértice + double alfa=0.0; + //longitud del punto 1 de la base al vértice + double lon=0.0; + //variables auxiliares + double dxv=0.0,dyv=0.0,dxb=0.0,dyb=0.0; + //variable de salida + double h=0.0; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //calculamos los incrementos de coordenadas auxiliares + dxv = xVert-xBase1; + dyv = yVert-yBase1; + dxb = xBase2-xBase1; + dyb = yBase2-yBase1; + //calculamos el ángulo entre la base y el segmento que une el punto inicial + //de ésta con el vértice + alfa = AnguloVecPlano(dxv,dyv,dxb,dyb); + //longitud del lado que une la base con el vértice 1 de la base + lon = sqrt(dxv*dxv+dyv*dyv); + //calculamos la altura + h = fabs(lon*sin(alfa)); + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return h; +} +/******************************************************************************/ +/******************************************************************************/ +/** @} */ +/******************************************************************************/ +/******************************************************************************/ +/* 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/fgeneral.c b/src/fgeneral.c new file mode 100644 index 0000000..1479d5f --- /dev/null +++ b/src/fgeneral.c @@ -0,0 +1,884 @@ +/* -*- coding: utf-8 -*- */ +/** +\ingroup eop general geom geopot matriz +@{ +\file fgeneral.c +\brief Definición de funciones de utilidad general. +\author José Luis García Pallero, jgpallero@gmail.com +\note Este fichero contiene funciones paralelizadas con OpenMP. +\date 10 de octubre de 2009 +\version 1.0 +\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 + 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/fgeneral.h" +/******************************************************************************/ +/******************************************************************************/ +int GeocParOmpFgeneral(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 +} +/******************************************************************************/ +/******************************************************************************/ +double PonAnguloDominio(const double angulo) +{ + //signo del ángulo de trabajo + double signo=0.0; + //2.0*pi + double dosPi=2.0*GEOC_CONST_PI; + //variable auxiliar + double aux=angulo; + //variable de salida + double sal=0.0; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //sólo trabajamos si el valor de entrada está fuera de los límites + if((angulo<=-dosPi)||(angulo>=dosPi)) + { + //extraemos el signo del ángulo pasado + signo = GEOC_SIGNO(angulo); + //valor absoluto del ángulo pasado + aux = fabs(angulo); + //metemos el ángulo en dominio eliminando la cantidad que se pase de + //2.0*pi + sal = signo*(aux-floor(aux/dosPi)*dosPi); + } + else + { + //el valor de entrada no cambia + sal = angulo; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return sal; +} +/******************************************************************************/ +/******************************************************************************/ +void BuscaSegmento1DInc(const double valor, + const double* lista, + const size_t nDatos, + const size_t incDatos, + size_t* posInicio, + size_t* posFin) +{ + //variable para recorrer bucles + size_t i=0; + //variable indicadora de búsqueda secuencial + int busca=0; + //variables para calcular posiciones + size_t pos1=0,pos2=0; + //posiciones en memoria + size_t posm=0,pos1m=0,pos2m=0; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //CONSIDERAMOS QUE LA LISTA CONTIENE ENTEROS EQUIESPACIADOS UNA UNIDAD + //posición del valor anterior al de trabajo + pos1 = (size_t)(floor(valor)-lista[0]); + //posición del valor posterior al de trabajo + pos2 = (size_t)(ceil(valor)-lista[0]); + //si pos1==pos2, valor puede ser un extremo de la lista + if(pos1==pos2) + { + if(pos1!=(nDatos-1)) + { + //calculamos el punto final del segmento + pos2++; + } + else + { + //calculamos el punto inicial del segmento + pos1--; + } + } + //calculamos las posiciones en memoria + pos1m = pos1*incDatos; + pos2m = pos2*incDatos; + //comprobamos si el segmento detectado es válido + if((lista[pos1m]!=round(lista[pos1m]))|| + (lista[pos2m]!=round(lista[pos2m]))|| + ((lista[pos2m]-lista[pos1m])!=1.0)|| + (valorlista[pos2m])) + { + //indicamos que se ha de hacer una búsqueda secuencial + busca = 1; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //LA LISTA CONTIENE REALES NO EQUIESPACIADOS + if(busca) + { + //recorremos todos los elementos de la lista + for(i=0;i=valor) + { + //comprobamos el tipo de límite + if(lista[posm]>valor) + { + //extraemos las posiciones + pos1 = i-1; + pos2 = i; + } + else + { + //comprobamos si estamos trabajando con el último elemento + if(i==(nDatos-1)) + { + //extraemos las posiciones + pos1 = i-1; + pos2 = i; + } + else + { + //extraemos las posiciones + pos1 = i; + pos2 = i+1; + } + } + //salimos del bucle + break; + } + } + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //asignamos las variables de salida + *posInicio = pos1; + *posFin = pos2; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return; +} +/******************************************************************************/ +/******************************************************************************/ +void BuscaSegmento1D(const double valor, + const double* lista, + const size_t nDatos, + size_t* posInicio, + size_t* posFin) +{ + //realizamos la búsqueda con incremento igual a 1 + BuscaSegmento1DInc(valor,lista,nDatos,1,posInicio,posFin); +} +/******************************************************************************/ +/******************************************************************************/ +void BuscaPosNWEnMalla(const double xPto, + const double yPto, + const double xMin, + const double xMax, + const double yMin, + const double yMax, + const double pasoX, + const double pasoY, + size_t* fil, + size_t* col) +{ + //dimensiones de la matriz + size_t f=0,c=0; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //calculamos las dimensiones de la matriz de trabajo + f = (size_t)(round((yMax-yMin)/pasoY)+1.0); + c = (size_t)(round((xMax-xMin)/pasoX)+1.0); + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //calculamos la fila y comprobamos si es el extremo S + *fil = (size_t)(fabs(yPto-yMax)/pasoY); + if(*fil==(f-1)) + { + //retrasamos una fila + (*fil)--; + } + //calculamos la columna y comprobamos si es el extremo E + *col = (size_t)((xPto-xMin)/pasoX); + if(*col==(c-1)) + { + //retrasamos una columna + (*col)--; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return; +} +/******************************************************************************/ +/******************************************************************************/ +double Minimo(const double* lista, + const size_t nDatos, + const size_t incDatos) +{ + //índice para recorrer bucles + size_t i=0; + //variable de posición + size_t pos=0; + //variable de salida, inicializada como el máximo valor para un double + double salida=DBL_MAX; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //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(nDatos,incDatos,lista) \ + private(i,pos) \ + reduction(min:salida) +#endif + //recorremos el resto de elementos de la lista + for(i=0;i fin del #pragma omp parallel for + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return salida; +} +/******************************************************************************/ +/******************************************************************************/ +double Maximo(const double* lista, + const size_t nDatos, + const size_t incDatos) +{ + //índice para recorrer bucles + size_t i=0; + //variable de posición + size_t pos=0; + //variable de salida, inicializada como el mínimo valor para un double + double salida=DBL_MIN; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //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(max:) +#if defined(_OPENMP)&&(_OPENMP>=GEOC_OMP_F_3_1) +#pragma omp parallel for default(none) \ + shared(nDatos,incDatos,lista) \ + private(i,pos) \ + reduction(max:salida) +#endif + //recorremos el resto de elementos de la lista + for(i=0;isalida) + { + //asignamos el nuevo valor menor + salida = lista[pos]; + } + } // --> fin del #pragma omp parallel for + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return salida; +} +/******************************************************************************/ +/******************************************************************************/ +double MinimoAbs(const double* lista, + const size_t nDatos, + const size_t incDatos) +{ + //índice para recorrer bucles + size_t i=0; + //variable de posición + size_t pos=0; + //variable de salida, inicializada como el máximo valor para un double + double salida=DBL_MAX; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //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(nDatos,incDatos,lista) \ + private(i,pos) \ + reduction(min:salida) +#endif + //recorremos el resto de elementos de la lista + for(i=0;i fin del #pragma omp parallel for + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return salida; +} +/******************************************************************************/ +/******************************************************************************/ +double MaximoAbs(const double* lista, + const size_t nDatos, + const size_t incDatos) +{ + //índice para recorrer bucles + size_t i=0; + //variable de posición + size_t pos=0; + //variable de salida, inicializada como 0.0 (trabajamos en valor absoluto) + double salida=0.0; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //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(max:) +#if defined(_OPENMP)&&(_OPENMP>=GEOC_OMP_F_3_1) +#pragma omp parallel for default(none) \ + shared(nDatos,incDatos,lista) \ + private(i,pos) \ + reduction(max:salida) +#endif + //recorremos el resto de elementos de la lista + for(i=0;isalida) + { + //asignamos el nuevo valor menor + salida = fabs(lista[pos]); + } + } // --> fin del #pragma omp parallel for + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return salida; +} +/******************************************************************************/ +/******************************************************************************/ +size_t MinimoSizeT(const size_t* lista, + const size_t nDatos, + const size_t incDatos) +{ + //índice para recorrer bucles + size_t i=0; + //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(nDatos,incDatos,lista) \ + private(i,pos) \ + reduction(min:salida) +#endif + //recorremos el resto de elementos de la lista + for(i=0;i fin del #pragma omp parallel for + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return salida; +} +/******************************************************************************/ +/******************************************************************************/ +size_t MaximoSizeT(const size_t* lista, + const size_t nDatos, + const size_t incDatos) +{ + //índice para recorrer bucles + size_t i=0; + //variable de posición + size_t pos=0; + //variable de salida, inicializada como 0 (size_t es sólo positivo) + size_t salida=0; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //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(max:) +#if defined(_OPENMP)&&(_OPENMP>=GEOC_OMP_F_3_1) +#pragma omp parallel for default(none) \ + shared(nDatos,incDatos,lista) \ + private(i,pos) \ + reduction(max:salida) +#endif + //recorremos el resto de elementos de la lista + for(i=0;isalida) + { + //asignamos el nuevo valor menor + salida = lista[pos]; + } + } // --> fin del #pragma omp parallel for + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return salida; +} +/******************************************************************************/ +/******************************************************************************/ +void MinMax(const double* lista, + const size_t nDatos, + const size_t incDatos, + size_t* posMin, + size_t* posMax) +{ + //índice para recorrer bucles + size_t i=0; + //variable de posición + size_t pos=0; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //consideramos que el primer elemento es el mayor y el menor + *posMin = 0; + *posMax = 0; + //recorremos el resto de elementos de la lista + for(i=1;ilista[(*posMax)*incDatos]) + { + //asignamos la nueva posición + *posMax = i; + } + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return; +} +/******************************************************************************/ +/******************************************************************************/ +void MinMaxAbs(const double* lista, + const size_t nDatos, + const size_t incDatos, + size_t* posMin, + size_t* posMax) +{ + //índice para recorrer bucles + size_t i=0; + //variable de posición + size_t pos=0; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //consideramos que el primer elemento es el mayor y el menor + *posMin = 0; + *posMax = 0; + //recorremos el resto de elementos de la lista + for(i=1;ifabs(lista[(*posMax)*incDatos])) + { + //asignamos la nueva posición + *posMax = i; + } + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return; +} +/******************************************************************************/ +/******************************************************************************/ +void MinMaxSizeT(const size_t* lista, + const size_t nDatos, + const size_t incDatos, + size_t* posMin, + size_t* posMax) +{ + //índice para recorrer bucles + size_t i=0; + //variable de posición + size_t pos=0; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //consideramos que el primer elemento es el mayor y el menor + *posMin = 0; + *posMax = 0; + //recorremos el resto de elementos de la lista + for(i=1;ilista[(*posMax)*incDatos]) + { + //asignamos la nueva posición + *posMax = i; + } + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return; +} +/******************************************************************************/ +/******************************************************************************/ +double** AsigMemMatrizC(const size_t fil, + const size_t col) +{ + //índices para recorrer bucles + size_t i=0; + //matriz de salida + double** matriz=NULL; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //asignamos memoria para el array principal + matriz = (double**)malloc(fil*sizeof(double*)); + //comprobamos los errores + if(matriz==NULL) + { + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return NULL; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //asignamos toda la memoria al primer puntero + matriz[0] = (double*)malloc(fil*col*sizeof(double)); + //comprobamos los errores + if(matriz[0]==NULL) + { + //liberamos la memoria previamente asignada + free(matriz); + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return NULL; + } + //recorremos el resto de filas + for(i=1;ianterior = anterior; + nuevoVert->siguiente = siguiente; + //si anterior es un vértice bueno + if(anterior!=NULL) + { + //lo apuntamos al vértice creado + nuevoVert->anterior->siguiente = nuevoVert; + } + //si siguiente es un vértice bueno + if(siguiente!=NULL) + { + //indicamos que el vértice creado es el anterior + nuevoVert->siguiente->anterior = nuevoVert; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //asignamos el resto de campos + nuevoVert->x = x; + nuevoVert->y = y; + nuevoVert->xP = x; + nuevoVert->yP = y; + nuevoVert->vecino = vecino; + nuevoVert->ini = ini; + nuevoVert->interseccion = interseccion; + nuevoVert->entrada = entrada; + nuevoVert->visitado = visitado; + nuevoVert->alfa = alfa; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return nuevoVert; +} +/******************************************************************************/ +/******************************************************************************/ +vertPoliClip* CreaPoliClip(const double* x, + const double* y, + const size_t nCoor, + const size_t incX, + const size_t incY) +{ + //índice para recorrer bucles + size_t i=0; + //variables auxiliares de posición + size_t posIni=0,posFin=0; + //otra variable auxiliar + int hayVert=0; + //estructura auxiliar + vertPoliClip* aux=NULL; + //variable de salida + vertPoliClip* poli=NULL; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //buscamos el primer punto que sea distinto de NaN + for(i=0;isiguiente; + //liberamos la memoria + free(aux); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return; +} +/******************************************************************************/ +/******************************************************************************/ +vertPoliClip* ReiniciaPoliClip(vertPoliClip* poli) +{ + //estructura que apunta al espacio en memoria a liberar + vertPoliClip* borra=NULL; + //estructura auxiliar + vertPoliClip* aux=NULL; + //estructura de salida + vertPoliClip* sal=NULL; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //inicializamos la estructura auxiliar + aux = poli; + //comprobamos una posible salida rápida + if(aux==NULL) + { + //salimos de la función + return NULL; + } + //buscamos para la estructura de salida el primer vértice que no sea una + //intersección + while(aux!=NULL) + { + //comprobamos si estamos ante un vértice bueno + if(aux->interseccion==0) + { + //asignamos la variable de salida + sal = aux; + //salimos del bucle + break; + } + //siguiente vértice + aux = aux->siguiente; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //volvemos a inicializar la variable auxiliar + aux = poli; + //mientras la variable de trabajo no apunte a NULL + while(aux!=NULL) + { + //comprobamos si estamos ante un vértice a borrar + if(aux->interseccion) + { + //lo almacenamos en la estructura de borrado + borra = aux; + //actualizamos el puntero de vértice siguiente + if(aux->anterior!=NULL) + { + //cuando el vértice a borrar no es el primero de la lista + aux->anterior->siguiente = aux->siguiente; + } + else if(aux->siguiente!=NULL) + { + //cuando el vértice a borrar es el primero de la lista + aux->siguiente->anterior = NULL; + } + //actualizamos el puntero de vértice anterior + if(aux->siguiente!=NULL) + { + //cuando el vértice a borrar no es el último de la lista + aux->siguiente->anterior = aux->anterior; + } + else if(aux->anterior!=NULL) + { + //cuando el vértice a borrar es el último de la lista + aux->anterior->siguiente = NULL; + } + //apuntamos al siguiente elemento + aux = aux->siguiente; + //liberamos la memoria + free(borra); + } + else + { + //reinicializamos el resto de miembros, menos las coordenadas + //originales y el identificador de primer elemento + aux->xP = aux->x; + aux->yP = aux->y; + aux->vecino = NULL; + aux->interseccion = 0; + aux->entrada = 0; + aux->visitado = 0; + aux->alfa = 0.0; + //siguiente elemento + aux = aux->siguiente; + } + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return sal; +} +/******************************************************************************/ +/******************************************************************************/ +vertPoliClip* ReiniciaVerticesPoliClip(vertPoliClip* poli) +{ + //estructura auxiliar + vertPoliClip* aux=NULL; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //inicializamos la estructura de auxiliar con la dirección de entrada + aux = poli; + //mientras no lleguemos al final + while(aux!=NULL) + { + //vamos poniendo a 0 el campo 'visitado' + aux->visitado = 0; + //vamos poniendo a 0 el campo 'entrada' + aux->entrada = 0; + //nos posicionamos en el siguiente vértice + aux = aux->siguiente; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return poli; +} +/******************************************************************************/ +/******************************************************************************/ +vertPoliClip* SiguienteVertOrigPoliClip(vertPoliClip* vert) +{ + //variable de salida, que inicializamos con la dirección de entrada + vertPoliClip* sal=vert; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //si estamos ante un vértice original, pasamos al siguiente + if((sal!=NULL)&&(sal->interseccion==0)) + { + //apuntamos al siguiente vértice + sal = sal->siguiente; + } + //vamos rechazando intersecciones (el bucle se para cuando llegamos al final + //o a un vértice que no es intersección) + while((sal!=NULL)&&(sal->interseccion!=0)) + { + //pasamos al siguiente vértice + sal = sal->siguiente; + } + //si hemos llegado a un vértice que no es original, apuntamos a NULL + if((sal!=NULL)&&(sal->interseccion!=0)) + { + //asignamos NULL + sal = NULL; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return sal; +} +/******************************************************************************/ +/******************************************************************************/ +vertPoliClip* SiguienteIntersecNoVisitadaPoliClip(vertPoliClip* vert) +{ + //variable de salida, que inicializamos con la dirección de entrada + vertPoliClip* sal=vert; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //si estamos ante una intersección no visitada o ante el vértice original + //del polígono, pasamos al siguiente vértice + if((sal!=NULL)&& + (((sal->interseccion!=0)&&(sal->visitado==0))||(sal->ini!=0))) + { + //apuntamos al siguiente vértice + sal = sal->siguiente; + } + //vamos rechazando vértices originales e intersecciones visitadas: el bucle + //se para cuando llegamos al final (si la lista no es circular), cuando + //volvamos al principio (si la lista es circular) o cuando lleguemos a una + //intersección no visitada + while(((sal!=NULL)&&(sal->ini==0))&& + ((sal->interseccion==0)|| + ((sal->interseccion!=0)&&(sal->visitado!=0)))) + { + //pasamos al siguiente vértice + sal = sal->siguiente; + } + //si hemos llegado a un vértice que no es una intersección no visitada o es + //de nuevo el punto inicial (lista circular), apuntamos a NULL + if((sal!=NULL)&& + (((sal->interseccion!=0)&&(sal->visitado!=0))||(sal->ini!=0))) + { + //asignamos NULL + sal = NULL; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return sal; +} +/******************************************************************************/ +/******************************************************************************/ +vertPoliClip* UltimoVertPoliClip(vertPoliClip* poli) +{ + //variable de salida, que inicializamos con la dirección de entrada + vertPoliClip* sal=poli; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //sólo trabajamos si la entrada es distinta de NULL + if(sal!=NULL) + { + //mientras el siguiente vértice sea distinto de NULL + while(sal->siguiente!=NULL) + { + //avanzamos un vértice + sal = sal->siguiente; + } + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return sal; +} +/******************************************************************************/ +/******************************************************************************/ +void InsertaVertPoliClip(vertPoliClip* ins, + vertPoliClip* extremoIni, + vertPoliClip* extremoFin) +{ + //estructura auxiliar + vertPoliClip* aux=NULL; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //inicializamos el vértice auxiliar como el extremo inicial pasado + aux = extremoIni; + //mientras no lleguemos al extremo final y el punto a insertar esté más + //lejos del origen que el punto de trabajo + while((aux!=extremoFin)&&((aux->alfa)<=(ins->alfa))) + { + //avanzamos al siguiente vértice + aux = aux->siguiente; + } + //insertamos el punto y ordenamos los punteros de vértices anterior y + //posterior + ins->siguiente = aux; + ins->anterior = aux->anterior; + ins->anterior->siguiente = ins; + ins->siguiente->anterior = ins; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return; +} +/******************************************************************************/ +/******************************************************************************/ +vertPoliClip* CierraPoliClip(vertPoliClip* poli) +{ + //estructura auxiliar + vertPoliClip* aux=NULL; + //variable de salida: último vértice de la lista original + vertPoliClip* ultimo=NULL; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //comprobamos si se ha pasado NULL + if(poli==NULL) + { + //salimos de la función + return NULL; + } + //buscamos el último vértice de la lista original + ultimo = UltimoVertPoliClip(poli); + //almacenamos el penúltimo vértice en la estructura auxiliar + aux = ultimo->anterior; + //apuntamos el penúltimo vértice al primero + aux->siguiente = poli; + //le decimos al primer vértice cuál es el anterior + aux->siguiente->anterior = aux; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return ultimo; +} +/******************************************************************************/ +/******************************************************************************/ +void AbrePoliClip(vertPoliClip* poli, + vertPoliClip* ultimo) +{ + //estructuras auxiliares + vertPoliClip* aux=poli; + vertPoliClip* ult=NULL; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //buscamos el vértice inicial + while((aux!=NULL)&&(aux->ini==0)) + { + //pasamos al siguiente vértice + aux = aux->siguiente; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //último vértice + ult = aux->anterior; + //le decimos al falso último vértice cuál es el último verdadero + ult->siguiente = ultimo; + //ajustamos los parámetros del nuevo último vértice + ultimo->anterior = ult; + ultimo->siguiente = NULL; + //le decimos al primer vértice que el anterior es NULL + aux->anterior = NULL; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return; +} +/******************************************************************************/ +/******************************************************************************/ +int PtoEnPoliClip(const double x, + const double y, + vertPoliClip* poli) +{ + //estructuras auxiliares + vertPoliClip* aux=NULL; + vertPoliClip* aux1=NULL; + //coordenadas auxiliares + double x1=0.0,y1=0.0,x2=0.0,y2=0.0; + //variable de salida + int c=0; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //inicializamos la estructura auxiliar con la dirección de entrada + aux = poli; + //comprobamos si no es un vértice original + if(aux->interseccion!=0) + { + //nos posicionamos en el siguiente vértice original + aux = SiguienteVertOrigPoliClip(aux); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //entramos en un bucle infinito + while(1) + { + //nos posicionamos en el siguiente vértice original + aux1 = SiguienteVertOrigPoliClip(aux); + //sólo continuamos si el siguiente vértice no es NULL + if(aux1!=NULL) + { + //extraemos las coordenadas de trabajo + x1 = aux->xP; + y1 = aux->yP; + x2 = aux1->xP; + y2 = aux1->yP; + //actalizamos el vértice inicial de trabajo para la siguiente vuelta + aux = aux1; + //calculamos + if(((y1>y)!=(y2>y))&&(x<(x2-x1)*(y-y1)/(y2-y1)+x1)) + { + c = !c; + } + } + else + { + //salimos del bucle + break; + } + } + //asignamos el elemento de salida + if(c) + { + //el punto está dentro del polígono + c = GEOC_PTO_DENTRO_POLIG; + } + else + { + //el punto está fuera del polígono + c = GEOC_PTO_FUERA_POLIG; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return c; +} +/******************************************************************************/ +/******************************************************************************/ +int PtoEnPoliClipVertice(const double x, + const double y, + vertPoliClip* poli) +{ + //estructura auxiliar + vertPoliClip* aux=NULL; + //variable de salida, que inicializamos fuera del polígono + int pos=GEOC_PTO_FUERA_POLIG; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //inicializamos la estructura auxiliar con la dirección de entrada + aux = poli; + //comprobamos si no es un vértice original + if(aux->interseccion!=0) + { + //nos posicionamos en el siguiente vértice original + aux = SiguienteVertOrigPoliClip(aux); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //comprobamos si el punto es un vértice + while(aux!=NULL) + { + //comprobamos si las coordenadas coinciden + if((aux->xP==x)&&(aux->yP==y)) + { + //indicamos que el punto es un vértice + pos = GEOC_PTO_VERTICE_POLIG; + //salimos del bucle + break; + } + //nos posicionamos en el siguiente vértice original + aux = SiguienteVertOrigPoliClip(aux); + } + //sólo continuamos si el punto no es un vértice + if(pos!=GEOC_PTO_VERTICE_POLIG) + { + //calculamos la posición sin tener en cuenta el borde + pos = PtoEnPoliClip(x,y,poli); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return pos; +} +/******************************************************************************/ +/******************************************************************************/ +size_t NumeroVertOrigPoliClip(vertPoliClip* poli) +{ + //estructura auxiliar + vertPoliClip* aux=NULL; + //variable de salida + size_t num=0; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //inicializamos la estructura auxiliar con la dirección de entrada + aux = poli; + //comprobamos si estamos ante un vértice original + if(aux->interseccion!=0) + { + //si no es un vértice original, nos posicionamos en el siguiente que sí + //lo sea + aux = SiguienteVertOrigPoliClip(aux); + } + //mientras no lleguemos al final + while(aux!=NULL) + { + //aumentamos el contador de vértices originales + num++; + //nos posicionamos en el siguiente vértice original + aux = SiguienteVertOrigPoliClip(aux); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return num; +} +/******************************************************************************/ +/******************************************************************************/ +size_t NumeroVertPoliClip(vertPoliClip* poli) +{ + //estructura auxiliar + vertPoliClip* aux=NULL; + //variable de salida + size_t num=0; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //inicializamos la estructura auxiliar con la dirección de entrada + aux = poli; + //mientras no lleguemos al final + while(aux!=NULL) + { + //aumentamos el contador de vértices + num++; + //nos posicionamos en el siguiente vértice + aux = aux->siguiente; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return num; +} +/******************************************************************************/ +/******************************************************************************/ +double CantPerturbMin(const double x, + const double factor) +{ + //valor absoluto del argumento de entrada + double xAbs=fabs(x); + //variable auxiliar + double aux=0.0; + //variable de salida, que inicializamos como el épsilon para el tipo de dato + double sal=fabs(DBL_EPSILON); + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //mientras la variable auxiliar sea igual a la de antrada (la primera vuelta + //del bucle se ejecuta siempre) + do + { + //escalamos la variable de salida + sal *= factor; + //sumamos el nuevo valor a la coordenada de entrada + //esta suma es necesario realizarla aquí, en lugar de en la propia + //comparación del while, para obligar al resultado a almacenarse en una + //variable y evitar errores porque las variables intermedias de la + //comparación puede que se almacenen en registros de más precisión que + //el tipo de dato + aux = xAbs+sal; + }while(aux==xAbs); + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return sal; +} +/******************************************************************************/ +/******************************************************************************/ +double PerturbaPuntoMin(const double x, + const double factor) +{ + //variable para almacenar un número seudoaleatorio + int aleat=0; + //cantidad perturbadora + double perturb=0.0; + //signo para multiplicar por la cantidad perturbadora + double signo=0.0; + //variable de salida + double sal=0.0; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //plantamos la semilla para la función rand() + srand((unsigned int)time(NULL)); + //generamos el número seudoaleatorio + aleat = rand(); + //calculamos el signo para la multiplicación, basándonos en la paridad del + //número seudoaleatorio generado: si es par vale 1 y si es impar -1 + signo = (aleat%2) ? -1.0 : 1.0; + //calculamos la cantidad perturbadora + perturb = CantPerturbMin(x,factor); + //perturbamos la coordenada + sal = x+signo*perturb; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return sal; +} +/******************************************************************************/ +/******************************************************************************/ +int Paso1Greiner(vertPoliClip* poliBas, + vertPoliClip* poliRec, + const double facPer, + size_t* nIntersec, + size_t* nPerturb) +{ + //estructuras auxiliares que apuntan a los polígonos pasados + vertPoliClip* auxA=NULL; + vertPoliClip* auxC=NULL; + //estructuras auxiliares para trabajar con el siguiente vértice + vertPoliClip* auxB=NULL; + vertPoliClip* auxD=NULL; + //vértices de intersección a insertar + vertPoliClip* insBas=NULL; + vertPoliClip* insRec=NULL; + //coordenadas de la intersección de dos segmentos + double xI=0.0,yI=0.0; + //longitudes de segmentos y parámetros alfa + double lonAB=0.0,lonCD=0.0,alfaAB=0.0,alfaCD=0.0; + //código de intersección de segmentos + int intersec=0; + //variable de salida + int salida=GEOC_ERR_NO_ERROR; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //inicializamos el número de intersecciones a 0 + *nIntersec = 0; + //inicializamos el número de puntos perturbados a 0 + *nPerturb = 0; + //EL PRIMER PASO DEL ALGORITMO DE GREINER-HORMANN ES EL CÁLCULO DE TODOS LOS + //PUNTOS DE INTERSECCIÓN ENTRE LOS POLÍGONOS + //recorremos los vértices del polígono base + for(auxA=poliBas;auxA->siguiente!=NULL;auxA=auxA->siguiente) + { + //sólo trabajamos si el vértice es original + if(auxA->interseccion==0) + { + //recorremos los vértices del polígono de recorte + for(auxC=poliRec;auxC->siguiente!=NULL;auxC=auxC->siguiente) + { + //sólo trabajamos si el vértice es original + if(auxC->interseccion==0) + { + //siguiente vértice de los segmentos + auxB = SiguienteVertOrigPoliClip(auxA); + auxD = SiguienteVertOrigPoliClip(auxC); + //calculamos la intersección de los segmentos + intersec = IntersecSegmentos2D(auxA->xP,auxA->yP,auxB->xP, + auxB->yP,auxC->xP,auxC->yP, + auxD->xP,auxD->yP,&xI,&yI); + //perturbamos las coordenadas de los extremos de los + //segmentos mientras haya una intersección no limpia + while((intersec!=GEOC_SEG_NO_INTERSEC)&& + (intersec!=GEOC_SEG_INTERSEC)) + { + //distinguimos entre intersecciones donde sólo se toca + //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_EXTREMOS_NO_COLIN)|| + (intersec==GEOC_SEG_INTERSEC_EXTREMOS_COLIN)) + { + if((xI==auxC->xP)&&(yI==auxC->yP)) + { + //perturbamos el extremo C + auxC->xP = PerturbaPuntoMin(auxC->x,facPer); + auxC->yP = PerturbaPuntoMin(auxC->y,facPer); + //aumentamos el contador de puntos perturbados + (*nPerturb)++; + } + else if((xI==auxD->xP)&&(yI==auxD->yP)) + { + //perturbamos el extremo D + auxD->xP = PerturbaPuntoMin(auxD->x,facPer); + auxD->yP = PerturbaPuntoMin(auxD->y,facPer); + //aumentamos el contador de puntos perturbados + (*nPerturb)++; + } + else + { + //si el punto de contacto es un extremo de AB y + //los segmentos no son paralelos, perturbamos + //todo el segmento CD + auxC->xP = PerturbaPuntoMin(auxC->x,facPer); + auxC->yP = PerturbaPuntoMin(auxC->y,facPer); + auxD->xP = PerturbaPuntoMin(auxD->x,facPer); + auxD->yP = PerturbaPuntoMin(auxD->y,facPer); + //aumentamos el contador de puntos perturbados + (*nPerturb) += 2; + } + } + else if((intersec==GEOC_SEG_INTERSEC_MISMO_SEG)|| + (intersec==GEOC_SEG_INTERSEC_COLIN)) + { + //perturbamos todo el segmento CD + auxC->xP = PerturbaPuntoMin(auxC->x,facPer); + auxC->yP = PerturbaPuntoMin(auxC->y,facPer); + auxD->xP = PerturbaPuntoMin(auxD->x,facPer); + auxD->yP = PerturbaPuntoMin(auxD->y,facPer); + //aumentamos el contador de puntos perturbados + (*nPerturb) += 2; + } + //volvemos a calcular la intersección de los segmentos + intersec = IntersecSegmentos2D(auxA->xP,auxA->yP, + auxB->xP,auxB->yP, + auxC->xP,auxC->yP, + auxD->xP,auxD->yP, + &xI,&yI); + } + //comprobamos si los segmentos se cortan limpiamente + if(intersec==GEOC_SEG_INTERSEC) + { + //aumentamos el contador de intersecciones + (*nIntersec)++; + //calculamos las longitudes de los segmentos + lonAB = Dist2D(auxA->xP,auxA->yP,auxB->xP,auxB->yP); + lonCD = Dist2D(auxC->xP,auxC->yP,auxD->xP,auxD->yP); + //calculamos los parámetros alfa + alfaAB = Dist2D(auxA->xP,auxA->yP,xI,yI)/lonAB; + alfaCD = Dist2D(auxC->xP,auxC->yP,xI,yI)/lonCD; + //creamos los nuevos vértices a insertar + insBas = CreaVertPoliClip(xI,yI,NULL,NULL,NULL,0,1,0,0, + alfaAB); + insRec = CreaVertPoliClip(xI,yI,NULL,NULL,NULL,0,1,0,0, + alfaCD); + //comprobamos los posibles errores + if((insBas==NULL)||(insRec==NULL)) + { + //liberamos la memoria previamente asignada + free(insBas); + free(insRec); + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //asignamos el código de error + salida = GEOC_ERR_ASIG_MEMORIA; + //salimos de la función + return salida; + } + //enlazamos los vértices mediante el campo 'vecino' + insBas->vecino = insRec; + insRec->vecino = insBas; + //los insertamos en los polígonos + InsertaVertPoliClip(insBas,auxA,auxB); + InsertaVertPoliClip(insRec,auxC,auxD); + } + } + } + } + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return salida; +} +/******************************************************************************/ +/******************************************************************************/ +void Paso2Greiner(vertPoliClip* poliBas, + vertPoliClip* poliRec, + const enum GEOC_OP_BOOL_POLIG op) +{ + //estructuras auxiliares que apuntan a los polígonos pasados + vertPoliClip* auxA=NULL; + vertPoliClip* auxC=NULL; + //identificador de si una intersección es de entrada o salida + char entrada=0; + //variables auxiliares + char entA=0,entC=0; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //asignamos los valores iniciales a los identificadores de intersección + switch(op) + { + //distinguimos los tipos de operación + case GeocOpBoolInter: + //intersección + entA = 1; + entC = 1; + break; + case GeocOpBoolUnion: + //unión + entA = 0; + entC = 0; + break; + case GeocOpBoolAB: + //A-B + entA = 0; + entC = 1; + break; + case GeocOpBoolBA: + //B-A + entA = 1; + entC = 0; + break; + default: + //por defecto, intersección + entA = 1; + entC = 1; + break; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //EL SEGUNDO PASO DEL ALGORITMO DE GREINER-HORMANN ES LA IDENTIFICACIÓN DE + //INTERSECCIONES COMO ENTRADA-SALIDA + //comprobamos si el primer punto del polígono base está fuera del polígono + //de recorte + if(PtoEnPoliClipVertice(poliBas->xP,poliBas->yP,poliRec)) + { + //si el punto está fuera, la siguiente intersección es de entrada + entrada = !entA; + } + else + { + entrada = entA; + } + //recorremos los vértices del polígono de recorte + for(auxA=poliBas;auxA->siguiente!=NULL;auxA=auxA->siguiente) + { + //sólo trabajamos si el vértice es intersección + if(auxA->interseccion!=0) + { + //indicamos la dirección + auxA->entrada = entrada; + //actualizamos la variable de entrada para la siguiente vuelta + entrada = !entrada; + } + } + //comprobamos si el primer punto del polígono de recorte está fuera del + //polígono base + if(PtoEnPoliClipVertice(poliRec->xP,poliRec->yP,poliBas)) + { + //si el punto está fuera, la siguiente intersección es de entrada + entrada = !entC; + } + else + { + entrada = entC; + } + //recorremos los vértices del polígono base + for(auxC=poliRec;auxC->siguiente!=NULL;auxC=auxC->siguiente) + { + //sólo trabajamos si el vértice es intersección + if(auxC->interseccion!=0) + { + //indicamos la dirección + auxC->entrada = entrada; + //actualizamos la variable de entrada para la siguiente vuelta + entrada = !entrada; + } + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return; +} +/******************************************************************************/ +/******************************************************************************/ +polig* Paso3Greiner(vertPoliClip* poliBas, + vertPoliClip* poliRec) +{ + //vértices colgados al cerrar los polígonos + vertPoliClip* ultBas=NULL; + vertPoliClip* ultRec=NULL; + //estructura auxiliar + vertPoliClip* aux=NULL; + //vectores de coordenadas de los vértices del resultado + double* x=NULL; + double* y=NULL; + //número de elementos de los vectores x e y + size_t nPtos=0; + //número de elementos para los que ha sido asignada memoria + size_t nElem=0; + //variable de estado + int estado=GEOC_ERR_NO_ERROR; + //polígono de salida + polig* resultado=NULL; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //cerramos los polígonos, convirtiéndolos en listas circulares + ultBas = CierraPoliClip(poliBas); + ultRec = CierraPoliClip(poliRec); + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //mientras queden intersecciones sin visitar + while((aux = SiguienteIntersecNoVisitadaPoliClip(poliBas))!=NULL) + { + //aumentamos el contador de elementos para los vectores x e y en 2 + //unidades: una para el marcador de inicio de polígono y la otra para + //las coordenadas del primer vértice + nPtos+=2; + //comprobamos si hay que reasignar memoria a los vectores de coordenadas + if(nPtos>nElem) + { + //actualizamos el número de elementos de los vectores de puntos + nElem += GEOC_GREINER_BUFFER_PTOS; + //reasignamos memoria para los vectores + x = (double*)realloc(x,nElem*sizeof(double)); + y = (double*)realloc(y,nElem*sizeof(double)); + //comprobamos si ha ocurrido algún error + if((x==NULL)||(y==NULL)) + { + //liberamos la posible memoria asignada + free(x); + free(y); + //reabrimos los polígonos + AbrePoliClip(poliBas,ultBas); + AbrePoliClip(poliRec,ultRec); + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return NULL; + } + } + //asignamos el marcador NaN como identificador de comienzo de polígono + x[nPtos-2] = GeocNan(); + y[nPtos-2] = GeocNan(); + //asignamos las coordenadas del punto de intersección + x[nPtos-1] = aux->xP; + y[nPtos-1] = aux->yP; + //EN ESTE NIVEL SIEMPRE ESTAMOS ANTE UN PUNTO DE INTERSECCIÓN + //mientras el punto no haya sido visitado con anterioridad + do + { + //lo marcamos como visitado + aux->visitado = 1; + aux->vecino->visitado = 1; + //comprobamos si el punto es de entrada o no + if(aux->entrada!=0) + { + //mientras no encontremos otra intersección + do + { + //caminamos en la lista hacia adelante + aux = aux->siguiente; + //aumentamos el contador de elementos para x e y + nPtos++; + //comprobamos si hay que reasignar memoria a los vectores de + //coordenadas + if(nPtos>nElem) + { + //actualizamos el número de elementos de los vectores de + //puntos + nElem += GEOC_GREINER_BUFFER_PTOS; + //reasignamos memoria para los vectores + x = (double*)realloc(x,nElem*sizeof(double)); + y = (double*)realloc(y,nElem*sizeof(double)); + //comprobamos si ha ocurrido algún error + if((x==NULL)||(y==NULL)) + { + //liberamos la posible memoria asignada + free(x); + free(y); + //reabrimos los polígonos + AbrePoliClip(poliBas,ultBas); + AbrePoliClip(poliRec,ultRec); + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return NULL; + } + } + //asignamos las coordenadas del punto de intersección + x[nPtos-1] = aux->xP; + y[nPtos-1] = aux->yP; + } + while(aux->interseccion==0); //mientras no sea intersección + } + else + { + ////mientras no encontremos otra intersección + do + { + //caminamos hacia atrás + aux = aux->anterior; + //aumentamos el contador de elementos para x e y + nPtos++; + //comprobamos si hay que reasignar memoria a los vectores de + //coordenadas + if(nPtos>nElem) + { + //actualizamos el número de elementos de los vectores de + //puntos + nElem += GEOC_GREINER_BUFFER_PTOS; + //reasignamos memoria para los vectores + x = (double*)realloc(x,nElem*sizeof(double)); + y = (double*)realloc(y,nElem*sizeof(double)); + //comprobamos si ha ocurrido algún error + if((x==NULL)||(y==NULL)) + { + //liberamos la posible memoria asignada + free(x); + free(y); + //reabrimos los polígonos + AbrePoliClip(poliBas,ultBas); + AbrePoliClip(poliRec,ultRec); + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return NULL; + } + } + //asignamos las coordenadas del punto de intersección + x[nPtos-1] = aux->xP; + y[nPtos-1] = aux->yP; + } + while(aux->interseccion==0); //mientras no sea intersección + } + //saltamos al otro polígono + aux = aux->vecino; + }while(aux->visitado==0); //mientras el punto no haya sido visitado + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //creamos la estructura de salida + resultado = CreaPolig(x,y,nPtos,1,1,&estado); + //comprobamos los posibles errores + if(resultado==NULL) + { + //liberamos la memoria asignada + free(x); + free(y); + //reabrimos los polígonos + AbrePoliClip(poliBas,ultBas); + AbrePoliClip(poliRec,ultRec); + //comprobamos el error + if(estado==GEOC_ERR_ASIG_MEMORIA) + { + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + } + else + { + //mensaje de error + GEOC_ERROR("Error en la llamada a 'CreaPolig()'\nEste error no " + "puede producirse aquí porque los NaN deben estar " + "bien puestos"); + } + //salimos de la función + return NULL; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //reabrimos los polígonos + AbrePoliClip(poliBas,ultBas); + AbrePoliClip(poliRec,ultRec); + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //liberamos la memoria asignada + free(x); + free(y); + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return resultado; +} +/******************************************************************************/ +/******************************************************************************/ +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; + //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; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //comprobamos si se ha pasado factor de perturbación + if(facPer<=1.0) + { + //utilizamos el valor por defecto + factor = GEOC_GREINER_FAC_EPS_PERTURB; + } + else + { + //utilizamos el valor pasado + factor = facPer; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //PRIMER PASO DEL ALGORITMO DE GREINER-HORMANN: CÁLCULO DE TODOS LOS PUNTOS + //DE INTERSECCIÓN ENTRE LOS POLÍGONOS + //calculamos los puntos de intersección + idError = Paso1Greiner(poliBas,poliRec,factor,nIntersec,nPerturb); + //comprobamos los posibles errores + if(idError==GEOC_ERR_ASIG_MEMORIA) + { + //mensaje de error + GEOC_ERROR("Error de asignación de memoria en la llamada a " + "'Paso1Greiner'"); + //salimos de la función + return NULL; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //comprobamos si no hay intersecciones + if(!(*nIntersec)) + { + //calculo la situación relativa entre los polígonos + posBas = PtoEnPoliClipVertice(poliBas->xP,poliBas->yP,poliRec); + posRec = PtoEnPoliClipVertice(poliRec->xP,poliRec->yP,poliBas); + //comprobamos las posibles situaciones relativas entre los polígonos que + //pueden producir cero intersecciones + if((posBas==GEOC_PTO_DENTRO_POLIG)||(posBas==GEOC_PTO_VERTICE_POLIG)) + { + //EL POLÍGONO BASE ESTÁ DENTRO DEL POLÍGONO DE RECORTE + //distinguimos las operaciones (por defecto, intersección) + if(op==GeocOpBoolUnion) + { + //el resultado es el polígono de recorte + resultado = CreaPoligPoliClip(poliRec,0); + } + else if(op==GeocOpBoolAB) + { + //el resultado es un polígono vacío + resultado = CreaPoligPoliClip(NULL,0); + } + else if((op==GeocOpBoolBA)||(op==GeocOpBoolXor)) + { + //el resultado son los dos polígonos + //polígono base + resultado = CreaPoligPoliClip(poliBas,0); + //añadimos el polígono de recorte + AnyadePoligClipPolig(resultado,poliRec,0); + } + else + { + //el resultado es el polígono base + resultado = CreaPoligPoliClip(poliBas,0); + } + } + else if((posRec==GEOC_PTO_DENTRO_POLIG)|| + (posRec==GEOC_PTO_VERTICE_POLIG)) + { + //EL POLÍGONO DE RECORTE ESTÁ DENTRO DEL POLÍGONO BASE + //distinguimos las operaciones (por defecto, intersección) + if(op==GeocOpBoolUnion) + { + //el resultado es el polígono base + resultado = CreaPoligPoliClip(poliBas,0); + } + else if((op==GeocOpBoolAB)||(op==GeocOpBoolXor)) + { + //el resultado son los dos polígonos + //polígono base + resultado = CreaPoligPoliClip(poliBas,0); + //añadimos el polígono de recorte + AnyadePoligClipPolig(resultado,poliRec,0); + } + else if(op==GeocOpBoolBA) + { + //el resultado es un polígono vacío + resultado = CreaPoligPoliClip(NULL,0); + } + else + { + //el resultado es el polígono de recorte + resultado = CreaPoligPoliClip(poliRec,0); + } + } + else + { + //NINGÚN POLÍGONO ESTÁ DENTRO DEL OTRO + //distinguimos las operaciones (por defecto, intersección) + if((op==GeocOpBoolUnion)||(op==GeocOpBoolXor)) + { + //el resultado son los dos polígonos + //polígono base + resultado = CreaPoligPoliClip(poliBas,0); + //añadimos el polígono de recorte + AnyadePoligClipPolig(resultado,poliRec,0); + } + else if(op==GeocOpBoolAB) + { + //el resultado es el polígono base + resultado = CreaPoligPoliClip(poliBas,0); + } + else if(op==GeocOpBoolBA) + { + //el resultado es el polígono de recorte + resultado = CreaPoligPoliClip(poliRec,0); + } + else + { + //el resultado es un polígono vacío + resultado = CreaPoligPoliClip(NULL,0); + } + } + //comprobamos los posibles errores + if(resultado==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 resultado; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //distinguimos entre XOR y el resto de operaciones + if(op!=GeocOpBoolXor) + { + //SEGUNDO PASO DEL ALGORITMO DE GREINER-HORMANN: IDENTIFICACIÓN DE + //INTERSECCIONES COMO ENTRADA-SALIDA + //marcamos los puntos como entrada o salida + Paso2Greiner(poliBas,poliRec,op); + //TERCER PASO DEL ALGORITMO DE GREINER-HORMANN: EXTRACCIÓN DE LOS POLÍGONOS + //RESULTADO DE LA OPERACIÓN + //extraemos los polígonos + resultado = Paso3Greiner(poliBas,poliRec); + //comprobamos los posibles errores + if(resultado==NULL) + { + //mensaje de error + GEOC_ERROR("Error de asignación de memoria en la llamada a " + "'Paso3Greiner'"); + //salimos de la función + return NULL; + } + } + else + { + //LA OPERCIÓN XOR LA HACEMOS COMO LA UNIÓN DE LA OPERACIÓN A-B CON B-A + //marcamos los puntos como entrada o salida para la operación A-B + Paso2Greiner(poliBas,poliRec,GeocOpBoolAB); + //extraemos los polígonos + resultado = Paso3Greiner(poliBas,poliRec); + //comprobamos los posibles errores + if(resultado==NULL) + { + //mensaje de error + GEOC_ERROR("Error de asignación de memoria en la llamada a " + "'Paso3Greiner'"); + //salimos de la función + return NULL; + } + //reinicializamos los polígonos, pero manteniendo las intersecciones + poliBas = ReiniciaVerticesPoliClip(poliBas); + poliRec = ReiniciaVerticesPoliClip(poliRec); + //marcamos los puntos como entrada o salida para la operación B-A + Paso2Greiner(poliBas,poliRec,GeocOpBoolBA); + //extraemos los polígonos + ba = Paso3Greiner(poliBas,poliRec); + //comprobamos los posibles errores + if(ba==NULL) + { + //liberamos la memoria asignada + LibMemPolig(resultado); + //mensaje de error + GEOC_ERROR("Error de asignación de memoria en la llamada a " + "'Paso3Greiner'"); + //salimos de la función + return NULL; + } + //añadimos el resultado de la operación B-A al anterior de A-B + idError = AnyadePoligPolig(resultado,ba); + //comprobamos los posibles errores + if(idError==GEOC_ERR_ASIG_MEMORIA) + { + //liberamos la memoria asignada + LibMemPolig(resultado); + LibMemPolig(ba); + //mensaje de error + GEOC_ERROR("Error de asignación de memoria en la llamada a " + "'AnyadePoligPolig' para la operación XOR"); + //salimos de la función + return NULL; + } + //liberamos la memoria asociada a la estructura auxiliar ba + LibMemPolig(ba); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //inicializo los atributos a 1 + for(i=0;inPolig;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;inPolig;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; +} +/******************************************************************************/ +/******************************************************************************/ +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) +{ + //índices para recorrer bucles + size_t i=0,j=0; + //variable de posición + size_t pos=0; + //número de intersecciones y de puntos perturbados auxiliar + size_t nInt=0,nPer=0; + //posición de un rectángulo con respecto a otro + int pr=0; + //variables de error + int estado1=GEOC_ERR_NO_ERROR,estado2=GEOC_ERR_NO_ERROR; + //listas de trabajo + vertPoliClip* poligBas=NULL; + vertPoliClip* poligRec=NULL; + //polígono auxiliar + polig* poligAux=NULL; + //variable de salida + polig* resultado=NULL; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //inicializamos el número total de intersecciones y de puntos perturbados + *nIntersec = 0; + *nPerturb = 0; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //inicializamos la variable de salida + resultado = IniciaPoligVacio(); + //comprobamos los posibles errores + if(resultado==NULL) + { + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return NULL; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //recorremos los polígonos base + for(i=0;inPolig;i++) + { + //dirección de inicio de los vértices del polígono base + pos = poliBas->posIni[i]; + //creamos el polígono base de trabajo + poligBas = CreaPoliClip(&(poliBas->x[pos]),&(poliBas->y[pos]), + poliBas->nVert[i],1,1); + //comprobamos los posibles errores + if(poligBas==NULL) + { + //liberamos la memoria asignada hasta ahora + LibMemPolig(resultado); + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return NULL; + } + //recorremos los polígonos de recorte + for(j=0;jnPolig;j++) + { + //comprobamos si los polígonos tienen definidos sus límites + if((poliBas->hayLim)&&(poliRec->hayLim)) + { + //comprobamos si los restángulos que encierran a los polígonos + //son disjuntos o no + 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)) + { + //EN CASO DE INTERSECCIÓN, NO SE AÑADE NADA + //vamos a la siguiente vuelta del bucle + continue; + } + else if(pr&&((op==GeocOpBoolUnion)||(op==GeocOpBoolXor))) + { + //EN CASO DE UNIÓN O UNIÓN EXCLUSIVA, SE AÑADEN LOS DOS + //POLÍGONOS + //añadimos el polígono base + estado1 = AnyadeDatosPolig(resultado,&(poliBas->x[pos]), + &(poliBas->y[pos]), + poliBas->nVert[i],1,1); + //añadimos el polígono de recorte + pos = poliRec->posIni[j]; + estado2 = AnyadeDatosPolig(resultado,&(poliRec->x[pos]), + &(poliRec->y[pos]), + poliRec->nVert[j],1,1); + //comprobamos los posibles errores, que sólo pueden ser de + //asignación de memoria + if((estado1!=GEOC_ERR_NO_ERROR)|| + (estado2!=GEOC_ERR_NO_ERROR)) + { + //liberamos la posible memoria asignada hasta ahora + LibMemPoliClip(poligBas); + LibMemPolig(resultado); + //lanzamos el mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return NULL; + } + //vamos a la siguiente vuelta del bucle + continue; + } + else if(pr&&(op==GeocOpBoolAB)) + { + //EN CASO DE OPERACIÓN A-B, SE AÑADE EL POLÍGONO BASE + //añadimos el polígono base + estado1 = AnyadeDatosPolig(resultado,&(poliBas->x[pos]), + &(poliBas->y[pos]), + poliBas->nVert[i],1,1); + //comprobamos los posibles errores, que sólo pueden ser de + //asignación de memoria + if(estado1!=GEOC_ERR_NO_ERROR) + { + //liberamos la posible memoria asignada hasta ahora + LibMemPoliClip(poligBas); + LibMemPolig(resultado); + //lanzamos el mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return NULL; + } + //vamos a la siguiente vuelta del bucle + continue; + } + else if(pr&&(op==GeocOpBoolBA)) + { + //EN CASO DE OPERACIÓN B-A, SE AÑADE EL POLÍGONO DE RECORTE + //añadimos el polígono de recorte + pos = poliRec->posIni[j]; + estado1 = AnyadeDatosPolig(resultado,&(poliRec->x[pos]), + &(poliRec->y[pos]), + poliRec->nVert[j],1,1); + //comprobamos los posibles errores, que sólo pueden ser de + //asignación de memoria + if(estado1!=GEOC_ERR_NO_ERROR) + { + //liberamos la posible memoria asignada hasta ahora + LibMemPoliClip(poligBas); + LibMemPolig(resultado); + //lanzamos el mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return NULL; + } + //vamos a la siguiente vuelta del bucle + continue; + } + } + //dirección de inicio de los vértices del polígono de recorte + pos = poliRec->posIni[j]; + //creamos el polígono de recorte de trabajo + poligRec = CreaPoliClip(&(poliRec->x[pos]),&(poliRec->y[pos]), + poliRec->nVert[j],1,1); + //comprobamos los posibles errores + if(poligRec==NULL) + { + //liberamos la memoria asignada hasta ahora + LibMemPoliClip(poligBas); + LibMemPolig(resultado); + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return NULL; + } + //recortamos + poligAux = PoliBoolGreiner(poligBas,poligRec,op,facPer, + compruebaHuecosUnion,&nInt,&nPer); + //comprobamos los posibles errores + if(poligAux==NULL) + { + //liberamos la posible memoria asignada hasta ahora + LibMemPoliClip(poligBas); + LibMemPoliClip(poligRec); + LibMemPolig(resultado); + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return NULL; + } + //sumamos el número de intersecciones y de puntos perturbados + (*nIntersec) += nInt; + (*nPerturb) += nPer; + //añadimos los polígonos recortados a la variable de salida + if(AnyadePoligPolig(resultado,poligAux)==GEOC_ERR_ASIG_MEMORIA) + { + //liberamos la posible memoria asignada hasta ahora + LibMemPoliClip(poligBas); + LibMemPoliClip(poligRec); + LibMemPolig(poligAux); + LibMemPolig(resultado); + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return NULL; + } + //liberamos la memoria asignada al polígono de esta vuelta del bucle + LibMemPoliClip(poligRec); + //liberamos la memoria asignada al polígono auxiliar + LibMemPolig(poligAux); + //reinicializamos el polígono base + poligBas = ReiniciaPoliClip(poligBas); + } + //liberamos la memoria asignada al polígono de esta vuelta del bucle + LibMemPoliClip(poligBas); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return resultado; +} +/******************************************************************************/ +/******************************************************************************/ +polig* CreaPoligPoliClip(vertPoliClip* poli, + const int coorOrig) +{ + //índice para recorrer bucles + size_t i=0; + //número de elementos + size_t nVert=0,nElem=0; + //estructura auxiliar + vertPoliClip* aux=poli; + //variable de salida + polig* result=NULL; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //creamos la estructura vacía + result = IniciaPoligVacio(); + //comprobamos los posibles errores + if(result==NULL) + { + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return NULL; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //contamos todos los vértices del polígono + nVert = NumeroVertPoliClip(poli); + //contemplamos una posible salida rápida + if(nVert==0) + { + //devolvemos la estructura vacía + return result; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //número de elementos de los vectores de coordenadas + nElem = nVert+2; + //asignamos memoria para los vectores de coordenadas de la estructura + result->x = (double*)malloc(nElem*sizeof(double)); + result->y = (double*)malloc(nElem*sizeof(double)); + //asignamos memoria para los vectores de posición + result->posIni = (size_t*)malloc(sizeof(size_t)); + result->nVert = (size_t*)malloc(sizeof(size_t)); + //comprobamos los posibles errores de asignación de memoria + if((result->x==NULL)||(result->y==NULL)||(result->posIni==NULL)|| + (result->nVert==NULL)) + { + //liberamos la posible memoria asignada + LibMemPolig(result); + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return NULL; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //asignamos el número de elementos de los vectores de coordenadas y de + //polígonos + result->nElem = nElem; + result->nPolig = 1; + //asignamos la posición de inicio y el número de vértices + result->posIni[0] = 1; + result->nVert[0] = nVert; + //asignamos los separadores de polígono al principio y al final + result->x[0] = GeocNan(); + result->y[0] = GeocNan(); + result->x[nElem-1] = GeocNan(); + result->y[nElem-1] = GeocNan(); + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //recorremos los vértices del polígono + for(i=1;i<=nVert;i++) + { + //distinguimos el tipo de coordenadas a copiar + if(coorOrig) + { + //coordenadas originales + result->x[i] = aux->x; + result->y[i] = aux->y; + } + else + { + //coordenadas perturbadas + result->x[i] = aux->xP; + result->y[i] = aux->yP; + } + //siguiente vértice + aux = aux->siguiente; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return result; +} +/******************************************************************************/ +/******************************************************************************/ +int AnyadePoligClipPolig(polig* poli, + vertPoliClip* anyade, + const int coorOrig) +{ + //número de elementos a añadir + size_t nVert=0; + //polígono auxiliar + polig* aux=NULL; + //variable de estado (salida) + int estado=GEOC_ERR_NO_ERROR; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //contamos todos los vértices del polígono a añadir + nVert = NumeroVertPoliClip(anyade); + //contemplamos una posible salida rápida + if(nVert==0) + { + //devolvemos la estructura vacía + return estado; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //creamos un nuevo polígono con los datos a añadir + aux = CreaPoligPoliClip(anyade,coorOrig); + //comprobamos los posibles errores + if(aux==NULL) + { + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return GEOC_ERR_ASIG_MEMORIA; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //añadimos la nueva estructura + estado = AnyadePoligPolig(poli,aux); + //comprobamos los posibles errores + if(estado!=GEOC_ERR_NO_ERROR) + { + //liberamos la memoria asignada + LibMemPolig(aux); + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return estado; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //liberamos la memoria utilizada + LibMemPolig(aux); + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return estado; +} +/******************************************************************************/ +/******************************************************************************/ +/** @} */ +/******************************************************************************/ +/******************************************************************************/ +/* 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/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 +#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 lonMin1mRot[fil][com]. +\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 mRot[fil][com]. +\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 mRot[fil][com]. +\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 mRot[fil][com]. +\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/calctopo.h b/src/libgeoc/calctopo.h new file mode 100644 index 0000000..899cc8e --- /dev/null +++ b/src/libgeoc/calctopo.h @@ -0,0 +1,81 @@ +/* -*- coding: utf-8 -*- */ +/** +\ingroup geodesia geom +@{ +\file calctopo.h +\brief Declaración de funciones para cálculos de topografía. +\author José Luis García Pallero, jgpallero@gmail.com +\date 05 de julio de 2011 +\section Licencia Licencia +Copyright (c) 2011, 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 _CALCTOPO_H_ +#define _CALCTOPO_H_ +/******************************************************************************/ +/******************************************************************************/ +#include +#include"libgeoc/constantes.h" +/******************************************************************************/ +/******************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Calcula el acimut topográfico entre dos puntos. +\param[in] x1 Coordenada X del primer punto. +\param[in] y1 Coordenada y del primer punto. +\param[in] x2 Coordenada X del segundo punto. +\param[in] y2 Coordenada y del segundo punto. +\return Acimut del primer al segundo punto, en radianes. +\date 05 de julio de 2011: Creación de la función. +\todo Esta función todavía no ha sido probada. +*/ +double AcimutTopografico(const double x1, + const double y1, + const double x2, + const double y2); +/******************************************************************************/ +/******************************************************************************/ +#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 new file mode 100644 index 0000000..bdd9684 --- /dev/null +++ b/src/libgeoc/compilador.h @@ -0,0 +1,96 @@ +/* -*- coding: utf-8 -*- */ +/** +\ingroup general geopot +@{ +\file compilador.h +\brief Declaración de funciones para la detección de compiladores. +\author José Luis García Pallero, jgpallero@gmail.com +\date 28 de abril de 2011 +\version 1.0 +\section Licencia Licencia +Copyright (c) 2011, 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 _COMPILADOR_H_ +#define _COMPILADOR_H_ +/******************************************************************************/ +/******************************************************************************/ +#include +/******************************************************************************/ +/******************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Comprueba si el compilador utilizado para compilar este fichero es de la + familia GCC. +\param[out] noGnu Identificador de que estamos ante un compilador que no es de + la familia GCC, diga lo que diga la variable devuelta por la función + (ver nota al final de la documentación). Este argumento sólo es + utilizado si en la entrada su valor es distinto de \p NULL. Dos + posibles valores de salida: + - 0: El compilador \b *ES* de la familia GCC. + - Distinto de 0: El compilador \b *NO* \b *ES* de la familia GCC. +\return Dos posibilidades: + - 0: El compilador no pertenece a la familia GCC. + - Distinto de 0: El compilador sí pertenece a la familia GCC (para una + validez total de este valor hay que tener en cuenta el argumento + \em noGnu). +\note Esta función realiza la comprobación mediante el chequeo de la existencia + de la constante simbólica \p __GNUC__. Este hecho hace que la detección + del compilador se lleve a cabo durante la compilación del fichero que + contiene a esta función, por lo que hay que tener en cuenta si ésta es + llamada desde una función contenida en otro fichero que no fue compilado + con un compilador de la familia GCC. +\note Algunos compiladores, como el Intel C/C++ Compiler (\p icc), definen por + defecto la macro \p __GNUC__, por lo que la detección puede ser errónea. + Para estos casos ha de tenerse en cuenta el argumento \em noGnu. +\note En las versiones más recientes de \p icc, el argumento \p -no-gcc suprime + la definición de \p __GNUC__. +\date 11 de octubre de 2009: Creación de la función. +*/ +int EsCompiladorGNU(int* noGnu); +/******************************************************************************/ +/******************************************************************************/ +#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/constantes.h b/src/libgeoc/constantes.h new file mode 100644 index 0000000..294f5a6 --- /dev/null +++ b/src/libgeoc/constantes.h @@ -0,0 +1,264 @@ +/* -*- coding: utf-8 -*- */ +/** +\ingroup anespec astro eop general geodesia geom gravim marea +@{ +\file constantes.h +\brief Definición de constantes generales. +\author José Luis García Pallero, jgpallero@gmail.com +\date 02 de marzo de 2009 +\section Licencia Licencia +Copyright (c) 2009-2011, 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 _CONSTANTES_H_ +#define _CONSTANTES_H_ +/******************************************************************************/ +/******************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif +/******************************************************************************/ +/******************************************************************************/ +/** +\typedef geoc_char +\brief Nombre del tipo \p char para almacenar números en \p libgeoc. + + Se declara este tipo para dotar de portabilidad a la biblioteca, debido a + que en algunas implementaciones de C la declaración \p char a secas + corresponde a un tipo \p unsigned \p char en lugar de a un \p signed + \p char, que es el que necesita \p libgeoc cuando almacena un número en + un \p char. En la implementación de \p gcc para PowerPC, por ejemplo, el + tipo por defecto de un \p char es \p unsigned \p char, lo que hace que se + produzcan errores al intentar almacenar números negativos. +\date 02 de marzo de 2009: Creación del tipo. +*/ +typedef signed char geoc_char; +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_CONST_PI +\brief Constante \em PI. Tomada del fichero \p gsl_math.h, de la biblioteca GSL. +\date 02 de marzo de 2009: Creación de la constante. +*/ +#define GEOC_CONST_PI (3.14159265358979323846264338328) +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_CONST_E +\brief Constante \em e (base de los logaritmos naturales). Tomada del fichero + \p gsl_math.h, de la biblioteca GSL. +\date 03 de octubre de 2010: Creación de la constante. +*/ +#define GEOC_CONST_E (2.71828182845904523536028747135) +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_CONST_GR +\brief Paso de grados centesimales a radianes. +*/ +#define GEOC_CONST_GR ((GEOC_CONST_PI)/200.0) +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_CONST_RG +\brief Paso de radianes a grados centesimales. +\date 02 de marzo de 2009: Creación de la constante. +*/ +#define GEOC_CONST_RG (1.0/(GEOC_CONST_GR)) +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_CONST_DR +\brief Paso de grados sexagesimales en formato decimal a radianes. +\date 02 de marzo de 2009: Creación de la constante. +*/ +#define GEOC_CONST_DR ((GEOC_CONST_PI)/180.0) +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_CONST_RD +\brief Paso de radianes a grados sexagesimales en formato decimal. +\date 02 de marzo de 2009: Creación de la constante. +*/ +#define GEOC_CONST_RD (1.0/(GEOC_CONST_DR)) +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_CONST_SIMUGAL +\brief Paso de atracción gravitatoria en el SI (m/s^2) a microgales. +\date 05 de noviembre de 2009: Creación de la constante. +*/ +#define GEOC_CONST_SIMUGAL (1.0e8) +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_CONST_MJD +\brief Constante a sustraer a una fecha juliana (en días) para convertirla en + fecha juliana modificada (MJD). +\date 04 de octubre de 2009: Creación de la constante. +*/ +#define GEOC_CONST_MJD (2400000.5) +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_CONST_J2000 +\brief Constante a sustraer a una fecha juliana (en días) para convertirla en + fecha juliana referida a J2000. +\date 01 de diciembre de 2009: Creación de la constante. +*/ +#define GEOC_CONST_J2000 (2451545.0) +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_CONST_JISGPS +\brief Fecha juliana del día de inicio de las semanas GPS: 6 de enero de 1980, + 00:00:00 horas. +\date 02 de marzo de 2010: Creación de la constante. +*/ +#define GEOC_CONST_JISGPS (2444244.5) +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_CONST_MIN_HORA +\brief Número de minutos que contiene una hora. +\date 19 de diciembre de 2009: Creación de la constante. +*/ +#define GEOC_CONST_MIN_HORA (60.0) +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_CONST_SEG_HORA +\brief Número de segundos que contiene una hora. +\date 01 de diciembre de 2009: Creación de la constante. +*/ +#define GEOC_CONST_SEG_HORA (3600.0) +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_CONST_SEG_MIN +\brief Número de segundos que contiene un minuto +\date 19 de diciembre de 2009: Creación de la constante. +*/ +#define GEOC_CONST_SEG_MIN (60.0) +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_CONST_SEG_DIA +\brief Número de segundos que contiene un día. +\date 24 de octubre de 2009: Creación de la constante. +*/ +#define GEOC_CONST_SEG_DIA (86400.0) +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_CONST_HORAS_DIA +\brief Número de horas que contiene un día. +\date 01 de diciembre de 2009: Creación de la constante. +*/ +#define GEOC_CONST_HORAS_DIA (24.0) +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_CONST_DIAS_SIGLO_JUL +\brief Número de días que contiene un siglo juliano. +\date 01 de diciembre de 2009: Creación de la constante. +*/ +#define GEOC_CONST_DIAS_SIGLO_JUL (36525.0) +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_CONST_DIAS_SEMANA +\brief Número de días que contiene una semana. +\date 02 de marzo de 2010: Creación de la constante. +*/ +#define GEOC_CONST_DIAS_SEMANA (7.0) +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_CONST_DIAS_ANYO_NORM +\brief Número de días que contiene un año normal. +\date 02 de marzo de 2010: Creación de la constante. +*/ +#define GEOC_CONST_DIAS_ANYO_NORM (365.0) +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_CONST_DIAS_ANYO_BIS +\brief Número de días que contiene un año bisiesto. +\date 02 de marzo de 2010: Creación de la constante. +*/ +#define GEOC_CONST_DIAS_ANYO_BIS ((GEOC_CONST_DIAS_ANYO_NORM)+1.0) +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_CONST_CPD_RH +\brief Paso de ciclos por día a radianes por hora. +\date 20 de diciembre de 2009: Creación de la constante. + */ +#define GEOC_CONST_CPD_RH (2.0*(GEOC_CONST_PI)/(GEOC_CONST_HORAS_DIA)) +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_CONST_RH_CPD +\brief Paso de radianes por hora a ciclos por día. +\date 20 de diciembre de 2009: Creación de la constante. + */ +#define GEOC_CONST_RH_CPD (1.0/(GEOC_CONST_CPD_RH)) +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_CONST_G +\brief Constante de gravitación universal, en m^3/(kg*s^2). +\date 04 de noviembre de 2009: Creación de la constante. +*/ +#define GEOC_CONST_G (6.67428e-11) +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_CONST_VRT +\brief Velocidad de rotación de la Tierra, en radianes/s. +\date 21 de enero de 2011: Creación de la constante. +*/ +#define GEOC_CONST_VRT (7.292115e-5) +/******************************************************************************/ +/******************************************************************************/ +#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/dpeucker.h b/src/libgeoc/dpeucker.h new file mode 100644 index 0000000..4d79318 --- /dev/null +++ b/src/libgeoc/dpeucker.h @@ -0,0 +1,333 @@ +/* -*- coding: utf-8 -*- */ +/** +\ingroup geom +@{ +\file dpeucker.h +\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 +\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 + 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 _DPEUCKER_H_ +#define _DPEUCKER_H_ +/******************************************************************************/ +/******************************************************************************/ +#include +#include"libgeoc/dpeuckera.h" +#include"libgeoc/dpeuckere.h" +#include"libgeoc/dpeuckerp.h" +#include"libgeoc/errores.h" +/******************************************************************************/ +/******************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif +/******************************************************************************/ +/******************************************************************************/ +/** +\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. 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: 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/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 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 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, + 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, + const int esf, + size_t* nPtosSal); +/******************************************************************************/ +/******************************************************************************/ +/** +\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] 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 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. +*/ +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 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] 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 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. +*/ +size_t* DouglasPeuckerRobusto(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, + const int esf, + size_t* nPtosSal); +/******************************************************************************/ +/******************************************************************************/ +#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/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 +#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 +#endif +#include +#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 +#endif +#include +#include +#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 new file mode 100644 index 0000000..3b91f08 --- /dev/null +++ b/src/libgeoc/errores.h @@ -0,0 +1,1058 @@ +/* -*- coding: utf-8 -*- */ +/** +\defgroup errores Módulo ERRORES +\ingroup anespec eop fichero geodesia geom general geopot gshhs marea matriz +\ingroup mmcc orden snx texto +\brief En este módulo se reúnen los ficheros necesarios para realizar el + tratamiento de errores que puedan ocurrir en la biblioteca. +@{ +\file errores.h +\brief Declaración de funciones y constantes para el tratamiento de errores. + +En el momento de la compilación ha de seleccionarse el comportamiento de la +función \ref GeocError. Para realizar la selección es necesario definir las +variables para el preprocesador \em ESCRIBE_MENSAJE_ERROR si se quiere que la +función imprima un mensaje de error y/o \em FIN_PROGRAMA_ERROR si se quiere que +la función termine la ejecución del programa en curso. Si no se define ninguna +variable, la función no ejecuta ninguna acción. 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 06 de marzo de 2009 +\section Licencia Licencia +Copyright (c) 2009-2011, 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 +#include +/******************************************************************************/ +/******************************************************************************/ +#ifndef _ERRORES_H_ +#define _ERRORES_H_ +/******************************************************************************/ +/******************************************************************************/ +//GENERAL +#ifdef __cplusplus +extern "C" { +#endif +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_PLINEA +\brief Palabra \em Línea para ser utilizada en el mensaje que imprime la macro + #GEOC_ERROR. Esta constante se define porque el preprocesador del + compilador \p pgcc no soporta letras con tilde escritas directamente en + las órdenes a ejecutar por las macros. +\date 10 de enero de 2011: Creación de la constante. +*/ +#define GEOC_PLINEA "Línea" +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_TIPO_ERR_NADA +\brief Indicador de que la función \ref GeocError no hace nada. +\date 09 de enero de 2011: Creación de la constante. +*/ +#define GEOC_TIPO_ERR_NADA 0 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_TIPO_ERR_MENS_Y_EXIT +\brief Indicador de que la función \ref GeocError imprime un mensaje descriptivo + en la salida de error \em stderr y termina la ejecución del programa en + curso. +\date 09 de enero de 2011: Creación de la constante. +*/ +#define GEOC_TIPO_ERR_MENS_Y_EXIT 1 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_TIPO_ERR_MENS +\brief Indicador de que la función \ref GeocError imprime un mensaje descriptivo + en la salida de error \em stderr y no termina la ejecución del programa + en curso. +\date 09 de enero de 2011: Creación de la constante. +*/ +#define GEOC_TIPO_ERR_MENS 2 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_TIPO_ERR_EXIT +\brief Indicador de que la función \ref GeocError termina la ejecución del + programa en curso. +\date 09 de enero de 2011: Creación de la constante. +*/ +#define GEOC_TIPO_ERR_EXIT 3 +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Indica el tipo de acción que realiza la función \ref GeocError. +\return Cuatro posibles valores: + - #GEOC_TIPO_ERR_NADA: La función \ref GeocError no hace nada. + - #GEOC_TIPO_ERR_MENS_Y_EXIT: La función \ref GeocError imprime un + mensaje descriptivo en la salida de error \em stderr y termina la + ejecución del programa en curso. + - #GEOC_TIPO_ERR_MENS: La función \ref GeocError imprime un mensaje + descriptivo en la salida de error \em stderr y no detiene la ejecución + del programa en curso. + - #GEOC_TIPO_ERR_EXIT: La función \ref GeocError detiene la ejecución + del programa en curso. +\date 09 de enero de 2011: Creación de la función. +*/ +int GeocTipoError(void); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Imprime un mensaje en la salida de error \em stderr y/o sale del programa + en ejecución. +\param[in] mensaje Cadena de texto a imprimir. +\param[in] funcion Nombre de la función desde donde se ha invocado a esta + función. +\note Si este fichero se compila con las variables para el preprocesador + \em ESCRIBE_MENSAJE_ERROR y \em FIN_PROGRAMA_ERROR, esta función imprime + el mensaje de error y termina la ejecución del programa en curso mediante + la llamada a la función \em exit(EXIT_FAILURE), de la biblioteca estándar + de C. +\note Si este fichero se compila con la variable para el preprocesador + \em ESCRIBE_MENSAJE_ERROR, esta función imprime el mensaje de error. +\note Si este fichero se compila con la variable para el preprocesador + \em FIN_PROGRAMA_ERROR, esta función termina la ejecución del programa en + curso mediante la llamada a la función \em exit(EXIT_FAILURE), de la + biblioteca estándar de C. +\note Si este fichero se compila sin variables para el preprocesador, esta + función no hace nada. +\date 10 de enero de 2011: Creación de la función. +*/ +void GeocError(const char mensaje[], + const char funcion[]); +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERROR +\brief Macro para imprimir un mensaje en la salida de error \em stderr y/o sale + del programa en ejecución. +\param[in] mensaje Cadena de texto a imprimir. +\note Esta macro llama internamente a la función \ref GeocError. +\note Esta macro pasa como argumento \em funcion a \ref GeocError la variable + del preprocesador \em __func__, de C99. +\date 10 de enero de 2011: Creación de la macro. +*/ +#define GEOC_ERROR(mensaje) \ +{ \ + if(GeocTipoError()!=GEOC_TIPO_ERR_NADA) \ + { \ + fprintf(stderr,"\n\n"); \ + fprintf(stderr,"********************\n********************\n"); \ + fprintf(stderr,GEOC_PLINEA" %d del fichero '%s'\n",__LINE__,__FILE__); \ + GeocError(mensaje,(const char*)__func__); \ + fprintf(stderr,"********************\n********************\n\n"); \ + } \ + else \ + { \ + GeocError(mensaje,(const char*)__func__); \ + } \ +} +/******************************************************************************/ +/******************************************************************************/ +#ifdef __cplusplus +} +#endif +/******************************************************************************/ +/******************************************************************************/ +//GENERAL +#ifdef __cplusplus +extern "C" { +#endif +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_NO_ERROR +\brief Indicador de que no ha ocurrido ningun error. +\date 06 de marzo de 2009: Creación de la constante. +*/ +#define GEOC_ERR_NO_ERROR 0 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_LECTURA_FICHERO +\brief Indicador de que ha ocurrido un error en la lectura de un fichero. +\date 06 de marzo de 2009: Creación de la constante. +*/ +#define GEOC_ERR_LECTURA_FICHERO 1001 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_ESCRITURA_FICHERO +\brief Indicador de que ha ocurrido un error en escritura de un fichero. +\date 20 de agosto de 2009: Creación de la constante. +*/ +#define GEOC_ERR_ESCRITURA_FICHERO 1002 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_QUEDAN_DATOS_EN_FICHERO +\brief Indicador de que quedan datos por leer en un fichero. +\date 06 de marzo de 2009: Creación de la constante. +*/ +#define GEOC_ERR_QUEDAN_DATOS_EN_FICHERO 1003 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_NO_QUEDAN_DATOS_EN_FICHERO +\brief Indicador de que no quedan datos por leer en un fichero. +\date 25 de abril de 2010: Creación de la constante. +*/ +#define GEOC_ERR_NO_QUEDAN_DATOS_EN_FICHERO 1004 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_NO_HAY_DATOS_EN_FICHERO +\brief Indicador de que no hay datos a leer en un fichero. +\date 02 de diciembre de 2010: Creación de la constante. +*/ +#define GEOC_ERR_NO_HAY_DATOS_EN_FICHERO 1005 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_LINEA_LARGA_EN_FICHERO +\brief Indicador de que una línea de un fichero es demasiado larga. +\date 23 de noviembre de 2010: Creación de la constante. +*/ +#define GEOC_ERR_LINEA_LARGA_EN_FICHERO 1006 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_LINEA_CORTA_EN_FICHERO +\brief Indicador de que una línea de un fichero es demasiado corta. +\date 23 de noviembre de 2010: Creación de la constante. +*/ +#define GEOC_ERR_LINEA_CORTA_EN_FICHERO 1007 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_ARG_ENTRADA_INCORRECTO +\brief Indicador de que un argumento de entrada de una función es incorrecto. +\date 06 de marzo de 2009: Creación de la constante. +*/ +#define GEOC_ERR_ARG_ENTRADA_INCORRECTO 1008 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_ASIG_MEMORIA +\brief Indicador de que ha ocurrido un error en la asignación de memoria. +\date 06 de marzo de 2009: Creación de la constante. +*/ +#define GEOC_ERR_ASIG_MEMORIA 1009 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_FUERA_DOMINIO +\brief Indicador de que ha ocurrido un error porque un dato está fuera de + dominio. +\date 04 de octubre de 2009: Creación de la constante. +*/ +#define GEOC_ERR_FUERA_DOMINIO 1010 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_FUERA_DOMINIO_MAYOR +\brief Indicador de que ha ocurrido un error porque un dato está fuera de + dominio. En este caso, el dato se sale del dominio por arriba (porque es + demasiado grande). +\date 26 de octubre de 2009: Creación de la constante. +*/ +#define GEOC_ERR_FUERA_DOMINIO_MAYOR 1011 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_FUERA_DOMINIO_MENOR +\brief Indicador de que ha ocurrido un error porque un dato está fuera de + dominio. En este caso, el dato se sale del dominio por abajo (porque es + demasiado pequeño). +\date 26 de octubre de 2009: Creación de la constante. +*/ +#define GEOC_ERR_FUERA_DOMINIO_MENOR 1012 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_INTERP +\brief Indicador de que ha ocurrido un error en una interpolación. +\date 15 de mayo de 2010: Creación de la constante. +*/ +#define GEOC_ERR_INTERP 1013 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_INTERP_NO_DATO +\brief Indicador de que no hay datos para realizar una interpolación. +\date 30 de mayo de 2010: Creación de la constante. +*/ +#define GEOC_ERR_INTERP_NO_DATO 1014 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_DIV_ENTRE_CERO +\brief Indicador de que se ha realizado una división entre cero. +\date 26 de noviembre de 2010: Creación de la constante. +*/ +#define GEOC_ERR_DIV_ENTRE_CERO 1015 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_DIM_MATRIZ +\brief Indicador de dimensiones de una matriz erróneas. +\date 02 de diciembre de 2010: Creación de la constante. +*/ +#define GEOC_ERR_DIM_MATRIZ 1016 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_MATRIZ_SINGULAR +\brief Indicador de matriz singular. +\date 12 de marzo de 2011: Creación de la constante. +*/ +#define GEOC_ERR_MATRIZ_SINGULAR 1017 +/******************************************************************************/ +/******************************************************************************/ +#ifdef __cplusplus +} +#endif +/******************************************************************************/ +/******************************************************************************/ +//EOP +#ifdef __cplusplus +extern "C" { +#endif +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_EOP_ERRORES +\brief Indicador de que ha ocurrido un error porque una estructura eop no + contiene información de errores. +\date 04 de octubre de 2009: Creación de la constante. +*/ +#define GEOC_ERR_EOP_ERRORES 2001 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_EOP_DOS_PUNTOS +\brief Indicador de que ha ocurrido un error porque en una interpolación + cuadrática sólo hay dos puntos disponibles. +\date 12 de octubre de 2009: Creación de la constante. +*/ +#define GEOC_ERR_EOP_DOS_PUNTOS 2002 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_EOP_NO_DATOS +\brief Indicador de que una estructura eop no contiene datos. +\date 19 de junio de 2010: Creación de la constante. +*/ +#define GEOC_ERR_EOP_NO_DATOS 2003 +/******************************************************************************/ +/******************************************************************************/ +#ifdef __cplusplus +} +#endif +/******************************************************************************/ +/******************************************************************************/ +//SINEX +#ifdef __cplusplus +extern "C" { +#endif +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_LINEA_ILEGAL +\brief Indicador de que una línea de un fichero SINEX no comienza por una de las + cadenas permitidas (#GEOC_SNX_CAD_COMENTARIO, #GEOC_SNX_CAD_INI_CABECERA, + #GEOC_SNX_CAD_INI_BLOQUE, #GEOC_SNX_CAD_FIN_BLOQUE o + #GEOC_SNX_CAD_INI_DATOS). +\date 28 de diciembre de 2009: Creación de la constante. +*/ +#define GEOC_ERR_SNX_LINEA_ILEGAL 3001 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_LINEA_LARGA +\brief Indicador de que una línea de un fichero SINEX es demasiado larga (más de + #GEOC_SNX_LON_MAX_LIN_FICH carácteres). +\date 28 de diciembre de 2009: Creación de la constante. +*/ +#define GEOC_ERR_SNX_LINEA_LARGA 3002 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_LINEA_CORTA +\brief Indicador de que una línea de un fichero SINEX es demasiado corta. +\date 29 de diciembre de 2009: Creación de la constante. +*/ +#define GEOC_ERR_SNX_LINEA_CORTA 3003 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_NO_BLOQUES +\brief Indicador de que en un fichero SINEX no hay bloques válidos. +\date 28 de diciembre de 2009: Creación de la constante. +*/ +#define GEOC_ERR_SNX_NO_BLOQUES 3004 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_ID_BLOQUE_DISTINTO +\brief Indicador de que en un fichero SINEX los identificadores de bloque tras + las marcas de inicio y fin son distintos. +\date 28 de diciembre de 2009: Creación de la constante. +*/ +#define GEOC_ERR_SNX_ID_BLOQUE_DISTINTO 3005 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_BLOQUE_NO_INICIO +\brief Indicador de que en un fichero SINEX un bloque no tiene identificador de + inicio. +\date 28 de diciembre de 2009: Creación de la constante. +*/ +#define GEOC_ERR_SNX_BLOQUE_NO_INICIO 3006 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_BLOQUE_NO_FIN +\brief Indicador de que en un fichero SINEX un bloque no tiene identificador de + fin. +\date 28 de diciembre de 2009: Creación de la constante. +*/ +#define GEOC_ERR_SNX_BLOQUE_NO_FIN 3007 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_NO_FIN_FICH +\brief Indicador de que un fichero SINEX no tiene indicador de fin de fichero. +\date 28 de diciembre de 2009: Creación de la constante. +*/ +#define GEOC_ERR_SNX_NO_FIN_FICH 3008 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_NO_ID_CABECERA +\brief Indicador de que un fichero SINEX no tiene indicador cabecera. +\date 29 de diciembre de 2009: Creación de la constante. +*/ +#define GEOC_ERR_SNX_NO_ID_CABECERA 3009 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_FORMATO_CABECERA +\brief Indicador de que un fichero SINEX tiene una cabecera que no respeta el + formato. +\date 29 de diciembre de 2009: Creación de la constante. +*/ +#define GEOC_ERR_SNX_FORMATO_CABECERA 3010 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_CODFICH_INC +\brief Indicador de que un fichero SINEX tiene un indicador de código de tipo de + fichero incorrecto. +\date 05 de enero de 2010: Creación de la constante. +*/ +#define GEOC_ERR_SNX_CODFICH_INC 3011 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_TIPODOC_INC +\brief Indicador de que un fichero SINEX tiene un indicador de tipo de documento + incorrecto. +\date 05 de enero de 2010: Creación de la constante. +*/ +#define GEOC_ERR_SNX_TIPODOC_INC 3012 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_VERS_INC +\brief Indicador de que un fichero SINEX tiene un indicador de versión + incorrecto. +\date 30 de diciembre de 2009: Creación de la constante. +*/ +#define GEOC_ERR_SNX_VERS_INC 3013 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_FECHA_INC +\brief Indicador de que una fecha es incorrecta en un fichero SINEX. +\date 30 de diciembre de 2009: Creación de la constante. +*/ +#define GEOC_ERR_SNX_FECHA_INC 3014 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_CODOBS_INC +\brief Indicador de que el código de observación es incorrecto en un fichero + SINEX. +\date 30 de diciembre de 2009: Creación de la constante. +*/ +#define GEOC_ERR_SNX_CODOBS_INC 3015 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_CODCONSTR_INC +\brief Indicador de que el código de constreñimiento es incorrecto en un fichero + SINEX. +\date 30 de diciembre de 2009: Creación de la constante. +*/ +#define GEOC_ERR_SNX_CODCONSTR_INC 3016 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_SOLCONT_INC +\brief Indicador de que un código de solución contenida en un fichero SINEX es + incorrecto. +\date 31 de diciembre de 2009: Creación de la constante. +*/ +#define GEOC_ERR_SNX_SOLCONT_INC 3017 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_NSOLCONT_INC +\brief Indicador de que un código de solución contenida en un fichero SINEX es + incorrecto. +\date 31 de diciembre de 2009: Creación de la constante. +*/ +#define GEOC_ERR_SNX_NSOLCONT_INC 3018 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_FORM_LINEA_INC +\brief Indicador de que una línea de un fichero SINEX tiene un formato + incorrecto. +\date 01 de enero de 2010: Creación de la constante. +*/ +#define GEOC_ERR_SNX_FORM_LINEA_INC 3019 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_BFR_TIPOINF_INC +\brief Indicador de que el código de tipo de información de un bloque + FILE/REFERENCE de un fichero SINEX es incorrecto. +\date 01 de enero de 2010: Creación de la constante. +*/ +#define GEOC_ERR_SNX_BFR_TIPOINF_INC 3020 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_BND_CODNUT_INC +\brief Indicador de que el código de modelo de nutación de un bloque + NUTATION/DATA de un fichero SINEX es incorrecto. +\date 03 de enero de 2010: Creación de la constante. +*/ +#define GEOC_ERR_SNX_BND_CODNUT_INC 3021 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_BPD_CODPREC_INC +\brief Indicador de que el código de modelo de precesión de un bloque + PRECESSION/DATA de un fichero SINEX es incorrecto. +\date 03 de enero de 2010: Creación de la constante. +*/ +#define GEOC_ERR_SNX_BPD_CODPREC_INC 3022 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_BSII_GRADLATSEX_INC +\brief Indicador de que un valor de grados sexagesimales de latitud de un bloque + SITE/ID de un fichero SINEX es incorrecto. +\date 15 de enero de 2010: Creación de la constante. +*/ +#define GEOC_ERR_SNX_BSII_GRADLATSEX_INC 3023 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_BSII_GRADLONSEX_INC +\brief Indicador de que un valor de grados sexagesimales de longitud de un bloque + SITE/ID de un fichero SINEX es incorrecto. +\date 15 de enero de 2010: Creación de la constante. +*/ +#define GEOC_ERR_SNX_BSII_GRADLONSEX_INC 3024 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_BSII_MINSEX_INC +\brief Indicador de que un valor de minutos sexagesimales de un bloque SITE/ID + de un fichero SINEX es incorrecto. +\date 15 de enero de 2010: Creación de la constante. +*/ +#define GEOC_ERR_SNX_BSII_MINSEX_INC 3025 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_BSII_SEGSEX_INC +\brief Indicador de que un valor de segundos sexagesimales de un bloque SITE/ID + de un fichero SINEX es incorrecto. +\date 15 de enero de 2010: Creación de la constante. +*/ +#define GEOC_ERR_SNX_BSII_SEGSEX_INC 3026 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_BSE_CODSREX_INC +\brief Indicador de que un código del sistema de referencia utilizado para + definir la excentricidad de una antena de un bloque SITE/ECCENTRICITY de + un fichero SINEX es incorrecto. +\date 23 de enero de 2010: Creación de la constante. +*/ +#define GEOC_ERR_SNX_BSE_CODSREX_INC 3027 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_CODGNSS_INC +\brief Indicador de que un código de constelación GNSS utilizado en un fichero + SINEX es incorrecto. +\date 28 de enero de 2010: Creación de la constante. +*/ +#define GEOC_ERR_SNX_CODGNSS_INC 3028 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_BSAP_CODFREC_INC +\brief Indicador de que un código frecuencia de satélite GNSS de un bloque + SATELLITE/PHASE_CENTER de un fichero SINEX es incorrecto. +\date 28 de enero de 2010: Creación de la constante. +*/ +#define GEOC_ERR_SNX_BSAP_CODFREC_INC 3029 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_BSAP_TIPOPCV_INC +\brief Indicador de que un código indicador de tipo de variación del centro de + fase de un bloque SATELLITE/PHASE_CENTER de un fichero SINEX es + incorrecto. +\date 28 de enero de 2010: Creación de la constante. +*/ +#define GEOC_ERR_SNX_BSAP_TIPOPCV_INC 3030 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_BSAP_MODAPPCV_INC +\brief Indicador de que un código indicador de modelo de aplicación de las + variaciones del centro de fase de un bloque SATELLITE/PHASE_CENTER de un + fichero SINEX es incorrecto. +\date 28 de enero de 2010: Creación de la constante. +*/ +#define GEOC_ERR_SNX_BSAP_MODAPPCV_INC 3031 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_BSOES_IDPARAM_INC +\brief Indicador de que un identificador de parámetro estadístico de un bloque + SOLUTION/STATISTICS de un fichero SINEX es incorrecto. +\date 28 de enero de 2010: Creación de la constante. +*/ +#define GEOC_ERR_SNX_BSOES_IDPARAM_INC 3032 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_IDUNID_INC +\brief Indicador de que un identificador de unidades utilizado en un fichero + SINEX es incorrecto. +\date 29 de enero de 2010: Creación de la constante. +*/ +#define GEOC_ERR_SNX_IDUNID_INC 3033 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_TIPPAR_INC +\brief Indicador de que un identificador de tipo de parámetro utilizado en un + fichero SINEX es incorrecto. +\date 29 de enero de 2010: Creación de la constante. +*/ +#define GEOC_ERR_SNX_TIPPAR_INC 3034 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_PTRIAN_INC +\brief Indicador de que un identificador de parte triangular de una matriz + simétrica utilizado en un fichero SINEX es incorrecto. +\date 17 de abril de 2010: Creación de la constante. +*/ +#define GEOC_ERR_SNX_PTRIAN_INC 3035 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_TIPOMAT_INC +\brief Indicador de que un identificador de tipo de matriz utilizado en un + fichero SINEX es incorrecto. +\date 17 de abril de 2010: Creación de la constante. +*/ +#define GEOC_ERR_SNX_TIPOMAT_INC 3036 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_SNX_POSMAT_INC +\brief Indicador de que una posición en una matriz almacenada en un fichero + SINEX es incorrecta. +\date 17 de abril de 2010: Creación de la constante. +*/ +#define GEOC_ERR_SNX_POSMAT_INC 3037 +/******************************************************************************/ +/******************************************************************************/ +#ifdef __cplusplus +} +#endif +/******************************************************************************/ +/******************************************************************************/ +//GTS +#ifdef __cplusplus +extern "C" { +#endif +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_GTS_VERT_FHULL +\brief Indicador de que un vértice de una nube de puntos está fuera del + \em convex \em hull que la engloba. +\date 09 de abril de 2010: Creación de la constante. +*/ +#define GEOC_ERR_GTS_VERT_FHULL 4001 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_GTS_VERT_FSUP +\brief Indicador de que un vértice está fuera de una superficie. +\date 22 de abril de 2010: Creación de la constante. +*/ +#define GEOC_ERR_GTS_VERT_FSUP 4002 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_GTS_VERT_DUPL +\brief Indicador de que un vértice de una nube de puntos está duplicado. +\date 09 de abril de 2010: Creación de la constante. +*/ +#define GEOC_ERR_GTS_VERT_DUPL 4003 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_GTS_CONF_CONSTR +\brief Indicador de que ha habido un conflicto con un constreñimiento en un + proceso de triangulación. +\date 09 de abril de 2010: Creación de la constante. +*/ +#define GEOC_ERR_GTS_CONF_CONSTR 4004 +/******************************************************************************/ +/******************************************************************************/ +#ifdef __cplusplus +} +#endif +/******************************************************************************/ +/******************************************************************************/ +//PMAREA +#ifdef __cplusplus +extern "C" { +#endif +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_PMAREA_NO_HAY_BLOQUE +\brief Indicador de que no existe un bloque buscado en un fichero. +\date 24 de abril de 2010: Creación de la constante. +*/ +#define GEOC_ERR_PMAREA_NO_HAY_BLOQUE 5001 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_PMAREA_LIN_FICH_INC +\brief Indicador de que una línea de fichero de parámetros de marea es + incorrecta. +\date 25 de abril de 2010: Creación de la constante. +*/ +#define GEOC_ERR_PMAREA_LIN_FICH_INC 5002 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_PMAREA_DEF_BLOQUE_INC +\brief Indicador de que una definición de bloque de parámetros de marea en un + fichero es incorrecta. +\date 25 de abril de 2010: Creación de la constante. +*/ +#define GEOC_ERR_PMAREA_DEF_BLOQUE_INC 5003 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_PMAREA_LIM_FDOM +\brief Indicador de que alguno de los límites de la malla está fuera de dominio. +\date 25 de abril de 2010: Creación de la constante. +*/ +#define GEOC_ERR_PMAREA_LIM_FDOM 5004 +/******************************************************************************/ +/******************************************************************************/ +#ifdef __cplusplus +} +#endif +/******************************************************************************/ +/******************************************************************************/ +//GEOPOT +#ifdef __cplusplus +extern "C" { +#endif +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_GEOPOT_GRADO_ORDEN_MAL +\brief Indicador de que los grados y/u órdenes pasados a una función no son + correctos. +\date 25 de noviembre de 2010: Creación de la constante. +*/ +#define GEOC_ERR_GEOPOT_GRADO_ORDEN_MAL 6001 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_GEOPOT_GRACE_LINFO_NO +\brief Indicador de que no hay línea (o la que hay no es la primera) de + información general de un fichero de un desarrollo del potencial de la + Tierra en armónicos esféricos en formato de GRACE. +\date 16 de noviembre de 2010: Creación de la constante. +*/ +#define GEOC_ERR_GEOPOT_GRACE_LINFO_NO 6002 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_GEOPOT_GRACE_LINFO_REPE +\brief Indicador de que la línea de información general de un fichero de un + desarrollo del potencial de la Tierra en armónicos esféricos en formato + de GRACE está repetida. +\date 16 de noviembre de 2010: Creación de la constante. +*/ +#define GEOC_ERR_GEOPOT_GRACE_LINFO_REPE 6003 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_GEOPOT_GRACE_CAB_INCOMP +\brief Indicador de cabecera incompleta en un fichero de un desarrollo del + potencial de la Tierra en armónicos esféricos en formato de GRACE está + repetida. +\date 17 de noviembre de 2010: Creación de la constante. +*/ +#define GEOC_ERR_GEOPOT_GRACE_CAB_INCOMP 6004 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_GEOPOT_GRACE_MEZCLA_TIPO_COEF +\brief Indicador de que en un fichero de un desarrollo del potencial de la + Tierra en armónicos esféricos en formato de GRACE hay definiciones de + coeficientes de distintas versiones. +\date 23 de noviembre de 2010: Creación de la constante. +*/ +#define GEOC_ERR_GEOPOT_GRACE_MEZCLA_TIPO_COEF 6005 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_GEOPOT_GRACE_NLINEAS_DATOS_MAL +\brief Indicador de que en un fichero de un desarrollo del potencial de la + Tierra en armónicos esféricos en formato de GRACE no coinciden el número + de líneas de datos leídas en dos pasadas distintas sobre el fichero. +\date 24 de noviembre de 2010: Creación de la constante. +*/ +#define GEOC_ERR_GEOPOT_GRACE_NLINEAS_DATOS_MAL 6006 +/******************************************************************************/ +/******************************************************************************/ +#ifdef __cplusplus +} +#endif +/******************************************************************************/ +/******************************************************************************/ +//NUMLOVE +#ifdef __cplusplus +extern "C" { +#endif +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_NUMLOVE_NO_HAY_BLOQUE +\brief Indicador de que no existe un bloque buscado en un fichero. +\date 29 de noviembre de 2010: Creación de la constante. +*/ +#define GEOC_ERR_NUMLOVE_NO_HAY_BLOQUE 7001 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_NUMLOVE_DEF_BLOQUE_INC +\brief Indicador de que una línea de fichero de números de Love es incorrecta. +\date 29 de noviembre de 2010: Creación de la constante. +*/ +#define GEOC_ERR_NUMLOVE_DEF_BLOQUE_INC 7002 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_NUMLOVE_LIN_FICH_INC +\brief Indicador de que una definición de bloque de números de Love en un + fichero es incorrecta. +\date 29 de noviembre de 2010: Creación de la constante. +*/ +#define GEOC_ERR_NUMLOVE_LIN_FICH_INC 7003 +/******************************************************************************/ +/******************************************************************************/ +#ifdef __cplusplus +} +#endif +/******************************************************************************/ +/******************************************************************************/ +//GSHHS +#ifdef __cplusplus +extern "C" { +#endif +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_GSHHS_VERS_ANTIGUA +\brief Indicador de que la versión de un fichero de GSHHS es antigua. +\date 16 de abril de 2011: Creación de la constante. +*/ +#define GEOC_ERR_GSHHS_VERS_ANTIGUA 8001 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_GSHHS_CREA_POLI +\brief Indicador de que ha ocurrido un error de tipo + #GEOC_ERR_POLIG_VEC_DISTINTO_NUM_POLIG o + #GEOC_ERR_POLIG_VEC_DISTINTOS_POLIG al crear una estructura \ref polig o + \ref polil +\date 19 de junio de 2011: Creación de la constante. +*/ +#define GEOC_ERR_GSHHS_CREA_POLI 8002 +/******************************************************************************/ +/******************************************************************************/ +#ifdef __cplusplus +} +#endif +/******************************************************************************/ +/******************************************************************************/ +//POLIG +#ifdef __cplusplus +extern "C" { +#endif +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_POLIG_VEC_DISTINTO_NUM_POLIG +\brief Indicador de que dos vectores de coordenadas no contienen el mismo número + de polígonos. +\date 27 de mayo de 2011: Creación de la constante. +*/ +#define GEOC_ERR_POLIG_VEC_DISTINTO_NUM_POLIG 9001 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_POLIG_VEC_DISTINTOS_POLIG +\brief Indicador de que dos vectores de coordenadas no contienen los mismos + polígonos. +\date 27 de mayo de 2011: Creación de la constante. +*/ +#define GEOC_ERR_POLIG_VEC_DISTINTOS_POLIG 9002 +/******************************************************************************/ +/******************************************************************************/ +#ifdef __cplusplus +} +#endif +/******************************************************************************/ +/******************************************************************************/ +//POLIL +#ifdef __cplusplus +extern "C" { +#endif +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_POLIL_VEC_DISTINTO_NUM_POLIL +\brief Indicador de que dos vectores de coordenadas no contienen el mismo número + de polilíneas. +\date 03 de junio de 2011: Creación de la constante. +*/ +#define GEOC_ERR_POLIL_VEC_DISTINTO_NUM_POLIL 10001 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_POLIL_VEC_DISTINTAS_POLIL +\brief Indicador de que dos vectores de coordenadas no contienen las mismas + polilíneas. +\date 03 de junio de 2011: Creación de la constante. +*/ +#define GEOC_ERR_POLIL_VEC_DISTINTAS_POLIL 10002 +/******************************************************************************/ +/******************************************************************************/ +#ifdef __cplusplus +} +#endif +/******************************************************************************/ +/******************************************************************************/ +//PROYEC +#ifdef __cplusplus +extern "C" { +#endif +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_PROYEC_INI_PROJ +\brief Indicador de que ha ocurrido un error en la inicialización de una + proyección de PROJ.4. +\date 31 de mayo de 2011: Creación de la constante. +*/ +#define GEOC_ERR_PROYEC_INI_PROJ 11001 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_PROYEC_NO_INV_PROJ +\brief Indicador de que una proyección cartográfica de PROJ.4 no tiene paso + inverso. +\date 31 de mayo de 2011: Creación de la constante. +*/ +#define GEOC_ERR_PROYEC_NO_INV_PROJ 11002 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ERR_PROYEC_PROJ_ERROR +\brief Indicador de que ha ocurrido un error al proyectar un punto con PROJ.4. +\date 31 de mayo de 2011: Creación de la constante. +*/ +#define GEOC_ERR_PROYEC_PROJ_ERROR 11003 +/******************************************************************************/ +/******************************************************************************/ +#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/eucli.h b/src/libgeoc/eucli.h new file mode 100644 index 0000000..1ee7d7c --- /dev/null +++ b/src/libgeoc/eucli.h @@ -0,0 +1,237 @@ +/* -*- coding: utf-8 -*- */ +/** +\ingroup geom interp +@{ +\file eucli.h +\brief Declaración de funciones para la realización de cálculos de geometría + euclídea. +\author José Luis García Pallero, jgpallero@gmail.com +\date 27 de octubre de 2009 +\section Licencia Licencia +Copyright (c) 2009-2011, 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 _EUCLI_H_ +#define _EUCLI_H_ +/******************************************************************************/ +/******************************************************************************/ +#include +/******************************************************************************/ +/******************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Calcula la distancia euclídea entre dos puntos en el plano. +\param[in] x1 Coordenada X del punto inicial. +\param[in] y1 Coordenada Y del punto inicial. +\param[in] x2 Coordenada X del punto final. +\param[in] y2 Coordenada Y del punto final. +\return Distancia euclídea entre los dos puntos. +\note Esta función asume que todas las coordenadas vienen dadas en las mismas + unidades. +\date 27 de octubre de 2009: Creación de la función. +\todo Esta función todavía no está probada. +*/ +double Dist2D(const double x1, + const double y1, + const double x2, + const double y2); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Calcula la distancia euclídea entre dos puntos en el plano y realiza la + propagación de errores correspondiente. +\param[in] x1 Coordenada X del punto inicial. +\param[in] y1 Coordenada Y del punto inicial. +\param[in] x2 Coordenada X del punto final. +\param[in] y2 Coordenada Y del punto final. +\param[in] varx1 Varianza de la coordenada X del punto inicial. +\param[in] varx1y1 Covarianza entre las coordenadas X e Y del punto inicial. +\param[in] vary1 Varianza de la coordenada Y del punto inicial. +\param[in] varx2 Varianza de la coordenada X del punto final. +\param[in] varx2y2 Covarianza entre las coordenadas X e Y del punto final. +\param[in] vary2 Varianza de la coordenada Y del punto final. +\param[out] dist Distancia euclídea entre los dos puntos. +\param[out] varDist Varianza de la distancia calculada. +\note Esta función asume que todas las coordenadas vienen dadas en las mismas + unidades. +\note Las unidades de las matrices de varianza-covarianza han de ser congruentes + con las de las coordenadas pasadas. +\date 27 de octubre de 2009: Creación de la función. +\todo Esta función todavía no está probada. +*/ +void Dist2DVC(const double x1, + const double y1, + const double x2, + const double y2, + const double varx1, + const double varx1y1, + const double vary1, + const double varx2, + const double varx2y2, + const double vary2, + double* dist, + double* varDist); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Calcula la distancia euclídea entre dos puntos en el espacio. +\param[in] x1 Coordenada X del punto inicial. +\param[in] y1 Coordenada Y del punto inicial. +\param[in] z1 Coordenada Z del punto inicial. +\param[in] x2 Coordenada X del punto final. +\param[in] y2 Coordenada Y del punto final. +\param[in] z2 Coordenada Z del punto final. +\return Distancia euclídea entre los dos puntos. +\note Esta función asume que todas las coordenadas vienen dadas en las mismas + unidades. +\date 27 de octubre de 2009: Creación de la función. +\todo Esta función todavía no está probada. +*/ +double Dist3D(const double x1, + const double y1, + const double z1, + const double x2, + const double y2, + const double z2); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Calcula la distancia euclídea entre dos puntos en el espacio y realiza la + propagación de errores correspondiente. +\param[in] x1 Coordenada X del punto inicial. +\param[in] y1 Coordenada Y del punto inicial. +\param[in] z1 Coordenada Z del punto inicial. +\param[in] x2 Coordenada X del punto final. +\param[in] y2 Coordenada Y del punto final. +\param[in] z2 Coordenada Z del punto final. +\param[in] varx1 Varianza de la coordenada X del punto inicial. +\param[in] varx1y1 Covarianza entre las coordenadas X e Y del punto inicial. +\param[in] varx1z1 Covarianza entre las coordenadas X y Z del punto inicial. +\param[in] vary1 Varianza de la coordenada Y del punto inicial. +\param[in] vary1z1 Covarianza entre las coordenadas Y y Z del punto inicial. +\param[in] varz1 Varianza de la coordenada Z del punto inicial. +\param[in] varx2 Varianza de la coordenada X del punto final. +\param[in] varx2y2 Covarianza entre las coordenadas X e Y del punto final. +\param[in] varx2z2 Covarianza entre las coordenadas X y Z del punto final. +\param[in] vary2 Varianza de la coordenada Y del punto final. +\param[in] vary2z2 Covarianza entre las coordenadas Y y Z del punto final. +\param[in] varz2 Varianza de la coordenada Z del punto final. +\param[out] dist Distancia euclídea entre los dos puntos. +\param[out] varDist Varianza de la distancia calculada. +\note Esta función asume que todas las coordenadas vienen dadas en las mismas + unidades. +\note Las unidades de las matrices de varianza-covarianza han de ser congruentes + con las de las coordenadas pasadas. +\date 27 de octubre de 2009: Creación de la función. +\todo Esta función todavía no está probada. +*/ +void Dist3DVC(const double x1, + const double y1, + const double z1, + const double x2, + const double y2, + const double z2, + const double varx1, + const double varx1y1, + const double varx1z1, + const double vary1, + const double vary1z1, + const double varz1, + const double varx2, + const double varx2y2, + const double varx2z2, + const double vary2, + const double vary2z2, + const double varz2, + double* dist, + double* varDist); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Calcula el ángulo formado por dos vectores en el plano. +\param[in] x1 Coordenada X del primer vector. +\param[in] y1 Coordenada Y del primer vector. +\param[in] x2 Coordenada X del segundo vector. +\param[in] y2 Coordenada Y del segundo vector. +\return Ángulo formado por los dos vectores, en radianes. +\note Esta función asume que todas las coordenadas vienen dadas en las mismas + unidades. +\date 04 de julio de 2011: Creación de la función. +\todo Esta función todavía no está probada. +*/ +double AnguloVecPlano(const double x1, + const double y1, + const double x2, + const double y2); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Calcula la altura de un triángulo a partir de las coordenadas de sus + vértices. +\param[in] xVert Coordenada X del vértice a partir del cual se calculará la + altura. +\param[in] yVert Coordenada Y del vértice a partir del cual se calculará la + altura. +\param[in] xBase1 Coordenada X del primer punto de la base del triángulo. +\param[in] yBase1 Coordenada Y del primer punto de la base del triángulo. +\param[in] xBase2 Coordenada X del segundo punto de la base del triángulo. +\param[in] yBase2 Coordenada Y del segundo punto de la base del triángulo. +\return Altura del triángulo, dada como la longitud del segmento que, partiendo + del vértice pasado, corta en ángulo recto a la base. +\note Esta función asume que todas las coordenadas vienen dadas en las mismas + unidades. +\date 04 de julio de 2011: Creación de la función. +\todo Esta función todavía no está probada. +*/ +double AlturaTriangulo(const double xVert, + const double yVert, + const double xBase1, + const double yBase1, + const double xBase2, + const double yBase2); +/******************************************************************************/ +/******************************************************************************/ +#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/fgeneral.h b/src/libgeoc/fgeneral.h new file mode 100644 index 0000000..8634583 --- /dev/null +++ b/src/libgeoc/fgeneral.h @@ -0,0 +1,736 @@ +/* -*- coding: utf-8 -*- */ +/** +\ingroup eop general geom geopot matriz +@{ +\file fgeneral.h +\brief Declaración de macros y funciones de utilidad general. +\author José Luis García Pallero, jgpallero@gmail.com +\note Este fichero contiene funciones paralelizadas con OpenMP. +\date 25 de septiembre de 2009 +\version 1.0 +\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 + 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 _FGENERAL_H_ +#define _FGENERAL_H_ +/******************************************************************************/ +/******************************************************************************/ +#include +#include +#include +#include +#include +#include"libgeoc/constantes.h" +#include"libgeoc/errores.h" +#include"libgeoc/geocomp.h" +/******************************************************************************/ +/******************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif +/******************************************************************************/ +/******************************************************************************/ +/** +\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. +\return Signo del dato de entrada. Dos posibilidades: + - -1.0: El dato pasado es negativo. + - 1.0: El dato pasado es positivo o 0.0. +\date 10 de junio de 2011: Creación de la macro. +*/ +#define GEOC_SIGNO(a) ((a)>=0.0 ? 1.0 : -1.0) +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_MAX +\brief Macro para seleccionar el valor máximo entre dos escalares. +\param[in] a Un número. +\param[in] b Otro número. +\return El mayor de los dos argumentos de entrada. +\date 25 de septiembre de 2009: Creación de la macro. +*/ +#define GEOC_MAX(a,b) ((a)>(b) ? (a) : (b)) +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_MIN +\brief Macro para seleccionar el valor mínimo entre dos escalares. +\param[in] a Un número. +\param[in] b Otro número. +\return El menor de los dos argumentos de entrada. +\date 25 de septiembre de 2009: Creación de la macro. +*/ +#define GEOC_MIN(a,b) ((a)<(b) ? (a) : (b)) +/******************************************************************************/ +/******************************************************************************/ +/** +\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: + - 0: El número es impar. + - 1: El número es par. +\note Esta macro usa el operador \b % de C para calcular el resto de la división + del número pasado entre 2, por lo que el argumento de entrada ha de ser de + 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_ES_PAR(a) ((a)%2 ? 0 : 1) +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ES_CERO +\brief Macro para comprobar si un número puede considerarse cero con una cierta + tolerancia. +\param[in] num Número a comprobar. +\param[in] tol Tolerancia. Ha de ser un número \b POSITIVO. +\return Dos posibilidades: + - 0: \em num es distinto de 0, tal que \f$num<=-tol\f$ o \f$num>=tol\f$. + - 1: \em num es 0, tal que \f$ -tol < num < tol\f$. +\note Para que esta macro funcione correctamente, \em tol ha de ser un número + \b POSITIVO. +\date 13 de marzo de 2010: Creación de la macro. +\todo Esta macro todavía no está probada. +*/ +#define GEOC_ES_CERO(num,tol) (((num)>(-(tol)))&&((num)<(tol)) ? 1 : 0) +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_DBL +\brief Macro para realizar una conversión explícita a tipo de dato \p double. +\param[in] a Un número. +\return Órdenes para la conversión explícita del dato pasado a \p double. +\date 19 de junio de 2011: Creación de la macro. +*/ +#define GEOC_DBL(a) ((double)(a)) +/******************************************************************************/ +/******************************************************************************/ +/** +\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. + Este argumento sólo se utiliza si su valor de entrada es distinto de + \p NULL y si hay alguna función compilada con OpenMP. +\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 22 de agosto de 2011: Creación de la función. +\date 25 de agosto de 2011: Adición del argumento de entrada \em version. +*/ +int GeocParOmpFgeneral(char version[]); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Mete un ángulo en el dominio \f$]-2*\pi,2*\pi[\f$. +\param[in] angulo Valor angular, en radianes. +\return Valor angular de entrada, en el dominio \f$]-2*\pi,2*\pi[\f$, en + radianes. +\note Esta función elimina todas las vueltas completas a la circunferencia que + hacen que el posible valor de entrada esté fuera de los límites del + dominio de salida. +\date 10 de junio de 2011: Creación de la función. +*/ +double PonAnguloDominio(const double angulo); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Busca en una lista de coordenadas de una polilínea en una dimensión las + posiciones de inicio y fin del segmento que encierra a un punto dado. +\param[in] valor Coordenada del punto de trabajo, contenido en el segmento a + buscar. +\param[in] lista Lista con las coordenadas de la polilínea. +\param[in] nDatos Número de elementos de la lista de coordenadas pasadas. +\param[in] incDatos Posiciones de separación entre cada elemento de \em lista. + Ha de ser un número positivo. +\param[out] posInicio Posición en \em lista de la coordenada inicial del + segmento buscado. +\param[out] posFin Posición en \em lista de la coordenada final del segmento + buscado. +\note Para convertir las posiciones devueltas por la función en las posiciones + reales del array en memoria, han de ser multiplicadas por el valor + \em incDatos. +\note En las siguientes notas, cuando se habla de la longitud o el número de + elementos de \em lista quiere decir el número de datos de trabajo, no + todas las posiciones almacenadas en memoria. +\note Esta función no comprueba internamente si la longitud de \em lista es + congruente con el valor \em nDatos. +\note Esta función supone que \em lista contiene un número de elementos >= 2. +\note Esta función supone que los elementos almacenados en \em lista están + ordenados de menor a mayor. +\note Esta función supone que \em lista[0] <= \em valor >= \em lista[nDatos-1]. +\note Si algún elemento de \em lista es igual a \em valor, su posición será el + punto de inicio del segmento calculado, excepto si el elemento de + \em lista es el último, en cuyo caso será el punto final. +\date 06 de diciembre de 2010: Creación de la función. +*/ +void BuscaSegmento1DInc(const double valor, + const double* lista, + const size_t nDatos, + const size_t incDatos, + size_t* posInicio, + size_t* posFin); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Busca en una lista de coordenadas de una polilínea en una dimensión las + posiciones de inicio y fin del segmento que encierra a un punto dado. +\param[in] valor Coordenada del punto de trabajo, contenido en el segmento a + buscar. +\param[in] lista Lista con las coordenadas de la polilínea. +\param[in] nDatos Número de elementos de la lista de coordenadas pasadas. +\param[out] posInicio Posición en \em lista de la coordenada inicial del + segmento buscado. +\param[out] posFin Posición en \em lista de la coordenada final del segmento + buscado. +\note Esta función no comprueba internamente si la longitud de \em lista es + congruente con el valor \em nDatos. +\note Esta función supone que \em lista contiene un número de elementos >= 2. +\note Esta función supone que los elementos almacenados en \em lista están + ordenados de menor a mayor. +\note Esta función supone que \em lista[0] <= \em valor >= \em lista[nDatos-1]. +\note Si algún elemento de \em lista es igual a \em valor, su posición será el + punto de inicio del segmento calculado, excepto si el elemento de + \em lista es el último, en cuyo caso será el punto final. +\date 11 de octubre de 2009: Creación de la función. +*/ +void BuscaSegmento1D(const double valor, + const double* lista, + const size_t nDatos, + size_t* posInicio, + size_t* posFin); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Busca las posiciones fila y columna del elemento de una matriz + correspondiente a la esquina NW del cuadrado que encierra a un punto + dado. +\param[in] xPto Coordenada X del punto de trabajo. +\param[in] yPto Coordenada Y del punto de trabajo. +\param[in] xMin Coordenada X mínima (esquina W) de los puntos almacenados en la + matriz. +\param[in] xMax Coordenada X máxima (esquina E) de los puntos almacenados en la + matriz. +\param[in] yMin Coordenada Y mínima (esquina S) de los puntos almacenados en la + matriz. +\param[in] yMax Coordenada Y máxima (esquina N) de los puntos almacenados en la + matriz. +\param[in] pasoX Paso de malla (valor absoluto) en la dirección X. +\param[in] pasoY Paso de malla (valor absoluto) en la dirección Y. +\param[out] fil Fila del elemento NW del cuadrado que encierra al punto de + trabajo. +\param[out] col Columna del elemento NW del cuadrado que encierra al punto de + trabajo. +\note Esta función no comprueba internamente si las coordenadas del punto de + trabajo son congruentes con los límites de la matriz. +\note Esta función asume que los pasos de malla son congruentes con los límites + de la malla (supone que el cálculo del número de nodos es un número + entero o del tipo X.9... o X.0...). +\note Esta función asume que \em xMin < \em xMax y que \em yMin < \em yMax. +\note Esta función asume que \em pasoX y \em pasoY han sido introducidos en + valor absoluto. +\date 15 de mayo de 2010: Creación de la función. +\date 25 de septiembre de 2011: Corrección de error que hacía que se calculase + una fila de más en determinados casos. +\todo Esta función no está probada. +*/ +void BuscaPosNWEnMalla(const double xPto, + const double yPto, + const double xMin, + const double xMax, + const double yMin, + const double yMax, + const double pasoX, + const double pasoY, + size_t* fil, + size_t* col); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Busca el elemento de mínimo valor en una lista de tipo \p double. +\param[in] lista Lista de valores. +\param[in] nDatos Número de elementos de la lista de valores. +\param[in] incDatos Posiciones de separación entre los elementos del vector + \em lista. Este argumento siempre ha de ser un número positivo. +\return Elemento de mínimo valor. +\note Esta función se puede ejecutar en paralelo con OpenMP, versión 3.1 o + superior (se detecta automáticamente en la compilación). +\note Esta función no comprueba internamente si la longitud de \em lista es + congruente con los valores de \em nDatos e \em incDatos. +\note Esta función supone que \em lista contiene un número de elementos >= 1. +\date 22 de agosto de 2011: Creación de la función. +\todo Esta función todavía no está probada con OpenMP. +*/ +double Minimo(const double* lista, + const size_t nDatos, + const size_t incDatos); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Busca el elemento de máximo valor en una lista de tipo \p double. +\param[in] lista Lista de valores. +\param[in] nDatos Número de elementos de la lista de valores. +\param[in] incDatos Posiciones de separación entre los elementos del vector + \em lista. Este argumento siempre ha de ser un número positivo. +\return Elemento de máximo valor. +\note Esta función se puede ejecutar en paralelo con OpenMP, versión 3.1 o + superior (se detecta automáticamente en la compilación). +\note Esta función no comprueba internamente si la longitud de \em lista es + congruente con los valores de \em nDatos e \em incDatos. +\note Esta función supone que \em lista contiene un número de elementos >= 1. +\date 22 de agosto de 2011: Creación de la función. +\todo Esta función todavía no está probada con OpenMP. +*/ +double Maximo(const double* lista, + const size_t nDatos, + const size_t incDatos); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Busca el elemento de mínimo valor absoluto en una lista de tipo + \p double. +\param[in] lista Lista de valores. +\param[in] nDatos Número de elementos de la lista de valores. +\param[in] incDatos Posiciones de separación entre los elementos del vector + \em lista. Este argumento siempre ha de ser un número positivo. +\return Elemento de mínimo valor absoluto. +\note Esta función se puede ejecutar en paralelo con OpenMP, versión 3.1 o + superior (se detecta automáticamente en la compilación). +\note Esta función no comprueba internamente si la longitud de \em lista es + congruente con los valores de \em nDatos e \em incDatos. +\note Esta función supone que \em lista contiene un número de elementos >= 1. +\date 22 de agosto de 2011: Creación de la función. +\todo Esta función todavía no está probada con OpenMP. +*/ +double MinimoAbs(const double* lista, + const size_t nDatos, + const size_t incDatos); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Busca el elemento de máximo valor absoluto en una lista de tipo + \p double. +\param[in] lista Lista de valores. +\param[in] nDatos Número de elementos de la lista de valores. +\param[in] incDatos Posiciones de separación entre los elementos del vector + \em lista. Este argumento siempre ha de ser un número positivo. +\return Elemento de máximo valor absoluto. +\note Esta función se puede ejecutar en paralelo con OpenMP, versión 3.1 o + superior (se detecta automáticamente en la compilación). +\note Esta función no comprueba internamente si la longitud de \em lista es + congruente con los valores de \em nDatos e \em incDatos. +\note Esta función supone que \em lista contiene un número de elementos >= 1. +\date 22 de agosto de 2011: Creación de la función. +\todo Esta función todavía no está probada con OpenMP. +*/ +double MaximoAbs(const double* lista, + const size_t nDatos, + const size_t incDatos); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Busca el elemento de mínimo valor en una lista de tipo \p size_t. +\param[in] lista Lista de valores. +\param[in] nDatos Número de elementos de la lista de valores. +\param[in] incDatos Posiciones de separación entre los elementos del vector + \em lista. Este argumento siempre ha de ser un número positivo. +\return Elemento de mínimo valor. +\note Esta función se puede ejecutar en paralelo con OpenMP, versión 3.1 o + superior (se detecta automáticamente en la compilación). +\note Esta función no comprueba internamente si la longitud de \em lista es + congruente con los valores de \em nDatos e \em incDatos. +\note Esta función supone que \em lista contiene un número de elementos >= 1. +\date 24 de agosto de 2011: Creación de la función. +\todo Esta función todavía no está probada con OpenMP. +*/ +size_t MinimoSizeT(const size_t* lista, + const size_t nDatos, + const size_t incDatos); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Busca el elemento de máximo valor en una lista de tipo \p size_t. +\param[in] lista Lista de valores. +\param[in] nDatos Número de elementos de la lista de valores. +\param[in] incDatos Posiciones de separación entre los elementos del vector + \em lista. Este argumento siempre ha de ser un número positivo. +\return Elemento de máximo valor. +\note Esta función se puede ejecutar en paralelo con OpenMP, versión 3.1 o + superior (se detecta automáticamente en la compilación). +\note Esta función no comprueba internamente si la longitud de \em lista es + congruente con los valores de \em nDatos e \em incDatos. +\note Esta función supone que \em lista contiene un número de elementos >= 1. +\date 24 de agosto de 2011: Creación de la función. +\todo Esta función todavía no está probada con OpenMP. +*/ +size_t MaximoSizeT(const size_t* lista, + const size_t nDatos, + const size_t incDatos); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Busca las posiciones que ocupan en una lista de tipo \p double los + elementos de menor y mayor valor. +\param[in] lista Lista de valores. +\param[in] nDatos Número de elementos de la lista de valores. +\param[in] incDatos Posiciones de separación entre los elementos del vector + \em lista. Este argumento siempre ha de ser un número positivo. +\param[out] posMin Posición en \em lista del elemento de menor valor. +\param[out] posMax Posición en \em lista del elemento de mayor valor. +\note Esta función no comprueba internamente si la longitud de \em lista es + congruente con los valores de \em nDatos e \em incDatos. +\note Esta función supone que \em lista contiene un número de elementos >= 1. +\note Si hay varios elementos en la lista que se corresponden con el valor menor + o mayor, la posición devuelta es la correspondiente al primer elemento a + partir del inicio. +\note Las posiciones devueltas lo son atendiendo al parámetro \em nDatos, por lo + que para obtener las posiciones reales del elemento en memoria han de ser + multiplicadas por el valor \em incDatos. +\date 27 de octubre de 2009: Creación de la función. +\date 29 de mayo de 2011: Adición del argumento de entrada \em incDatos. +*/ +void MinMax(const double* lista, + const size_t nDatos, + const size_t incDatos, + size_t* posMin, + size_t* posMax); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Busca las posiciones que ocupan en una lista los elementos de menor y + mayor valor absoluto. +\param[in] lista Lista de valores. +\param[in] nDatos Número de elementos de la lista de valores. +\param[in] incDatos Posiciones de separación entre los elementos del vector + \em lista. Este argumento siempre ha de ser un número positivo. +\param[out] posMin Posición en \em lista del elemento de menor valor absoluto. +\param[out] posMax Posición en \em lista del elemento de mayor valor absoluto. +\note Esta función no comprueba internamente si la longitud de \em lista es + congruente con los valores de \em nDatos e \em incDatos. +\note Esta función supone que \em lista contiene un número de elementos >= 1. +\note Si hay varios elementos en la lista que se corresponden con el valor menor + o mayor, la posición devuelta es la correspondiente al primer elemento a + partir del inicio. +\note Las posiciones devueltas lo son atendiendo al parámetro \em nDatos, por lo + que para obtener las posiciones reales del elemento en memoria han de ser + multiplicadas por el valor \em incDatos. +\date 27 de octubre de 2009: Creación de la función. +\date 29 de mayo de 2011: Adición del argumento de entrada \em incDatos. +*/ +void MinMaxAbs(const double* lista, + const size_t nDatos, + const size_t incDatos, + size_t* posMin, + size_t* posMax); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Busca las posiciones que ocupan en una lista de tipo \p size_t los + elementos de menor y mayor valor. +\param[in] lista Lista de valores. +\param[in] nDatos Número de elementos de la lista de valores. +\param[in] incDatos Posiciones de separación entre los elementos del vector + \em lista. Este argumento siempre ha de ser un número positivo. +\param[out] posMin Posición en \em lista del elemento de menor valor. +\param[out] posMax Posición en \em lista del elemento de mayor valor. +\note Esta función no comprueba internamente si la longitud de \em lista es + congruente con los valores de \em nDatos e \em incDatos. +\note Esta función supone que \em lista contiene un número de elementos >= 1. +\note Si hay varios elementos en la lista que se corresponden con el valor menor + o mayor, la posición devuelta es la correspondiente al primer elemento a + partir del inicio. +\note Las posiciones devueltas lo son atendiendo al parámetro \em nDatos, por lo + que para obtener las posiciones reales del elemento en memoria han de ser + multiplicadas por el valor \em incDatos. +\date 08 de enero de 2010: Creación de la función. +\date 29 de mayo de 2011: Adición del argumento de entrada \em incDatos. +*/ +void MinMaxSizeT(const size_t* lista, + const size_t nDatos, + const size_t incDatos, + size_t* posMin, + size_t* posMax); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Asigna memoria para una matriz bidimensional en estilo C. +\param[in] fil Número de filas de la matriz. +\param[in] col Número de columnas de la matriz. +\return Puntero a la matriz creada. Si ocurre algún error de asignación de + memoria, se devuelve NULL. +\note La memoria asignada no se inicializa a ningún valor. +\note Los datos se almacenan en ROW MAJOR ORDER de forma contigua en memoria. +\note Esta función no controla si alguna de las dimensiones pasadas es 0. +\date 14 de enero de 2010: Creación de la función. +\date 02 de diciembre de 2010: Reprogramación de la función para que los datos + se almacenen en memoria de forma contigua. +*/ +double** AsigMemMatrizC(const size_t fil, + const size_t col); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Libera memoria de una matriz bidimensional en estilo C. +\param[in] matriz Puntero al espacio de memoria a liberar. +\date 14 de enero de 2010: Creación de la función. +\date 27 de febrero de 2010: Corregido bug que hacía que la función diese error + si se le pasaba un puntero a NULL. +*/ +void LibMemMatrizC(double** matriz); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Calcula las posiciones de comienzo de elementos repetidos en un vector. +\brief
    +
  • 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]. +
  • +
+\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 + \em datos. Este argumento siempre ha de ser un número positivo. +\param[out] nRepe Número de elementos del vector de posiciones de comienzo de + elementos repetidos devuelto por la función. +\return Vector, de \em nRepe elementos, que almacena las posiciones de comienzo + de elementos repetidos en el vector \em datos. Las posiciones devueltas + no tienen en cuenta el argumento \em incDatos, luego no son posiciones + en el array realmente almacenado en memoria. Los índices comienzan en 0. + Si ocurre un error de asignación de memoria se devuelve \p NULL. +\note Esta función no comprueba internamente el vector pasado contiene + suficiente memoria. +\note Esta función no comprueba internamente si las dimensiones del vector + pasado son congruentes con el espacio almacenado en memoria. +\note Esta función no comprueba internamente si el argumento \em nDatos es + igual a 0. +\note Para calcular con los valores de salida las posiciones reales en el vector + \em datos es necesario tener en cuenta el argumento \em incDatos. +\date 02 de febrero de 2011: Creación de la función. +*/ +size_t* PosRepeEnVector(const double* datos, + const size_t nDatos, + const size_t incDatos, + size_t* nRepe); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Calcula el número de elementos repetidos en un vector a partir de la + salida de la función \ref PosRepeEnVector. +\brief
    +
  • 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]. +
  • +
+\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. +\param[in] nElemVecOrig Número de elementos del vector de datos original. +\return Vector, de \em nPos elementos, que almacena el número de elementos + repetidos a partir de cada posición (incluida ésta) almacenada en el + vector \em pos. Si ocurre un error de asignación de memoria se devuelve + \p NULL. +\note Esta función no comprueba internamente el vector pasado contiene + suficiente memoria. +\note Esta función no comprueba internamente si las dimensiones del vector + pasado son congruentes con el espacio almacenado en memoria. +\note Esta función no comprueba internamente si el argumento \em nPos es igual a + 0. +\date 02 de febrero de 2011: Creación de la función. +*/ +size_t* NumElemRepeEnVector(const size_t* pos, + const size_t nPos, + const size_t nElemVecOrig); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Aplica un factor de escala y una traslación (en este orden) a los + elementos de un vector. +\param[in,out] vector Vector de datos. Al término de la ejecución de la función, + se ha aplicado un factor de escala y una traslación (en este + orden) a los elementos del vector. +\param[in] nElem Número de elementos de \em vector. +\param[in] inc Posiciones de separación entre los elementos del vector + \em vector. Este argumento siempre ha de ser un número positivo. +\param[in] escala Factor de escala a aplicar. +\param[in] traslada Traslación a aplicar. +\note Primero se aplica el factor de escala y luego la traslación. +\note Esta función asume que el vector de entrada \em vector tiene memoria + asignada. +\date 18 de junio de 2011: Creación de la función. +\note Esta función todavía no está probada. +*/ +void EscalaYTrasladaVector(double* vector, + const size_t nElem, + const size_t inc, + const double escala, + const double traslada); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Aplica una traslación y un factor de escala (en este orden) a los + elementos de un vector. +\param[in,out] vector Vector de datos. Al término de la ejecución de la función, + se ha aplicado una traslación y un factor de escala (en este + orden) a los elementos del vector. +\param[in] nElem Número de elementos de \em vector. +\param[in] inc Posiciones de separación entre los elementos del vector + \em vector. Este argumento siempre ha de ser un número positivo. +\param[in] escala Factor de escala a aplicar. +\param[in] traslada Traslación a aplicar. +\note Primero se aplica la traslación y luego el factor de escala. +\note Esta función asume que el vector de entrada \em vector tiene memoria + asignada. +\date 18 de junio de 2011: Creación de la función. +\note Esta función todavía no está probada. +*/ +void TrasladaYEscalaVector(double* vector, + const size_t nElem, + const size_t inc, + const double escala, + const double traslada); +/******************************************************************************/ +/******************************************************************************/ +#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/general.h b/src/libgeoc/general.h new file mode 100644 index 0000000..c7d5f0f --- /dev/null +++ b/src/libgeoc/general.h @@ -0,0 +1,61 @@ +/* -*- coding: utf-8 -*- */ +/** +\defgroup general Módulo GENERAL +\brief En este módulo se reúnen constantes, macros y funciones de utilidad + general. +@{ +\file general.h +\brief Inclusión de archivos de cabecera para la utilización de la biblioteca + GENERAL. +\author José Luis García Pallero, jgpallero@gmail.com +\date 16 de febrero de 2011 +\version 1.0 +\section Licencia Licencia +Copyright (c) 2009-2011, 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 _GENERAL_H_ +#define _GENERAL_H_ +/******************************************************************************/ +/******************************************************************************/ +#include"libgeoc/compilador.h" +#include"libgeoc/constantes.h" +#include"libgeoc/fgeneral.h" +#include"libgeoc/ventorno.h" +/******************************************************************************/ +/******************************************************************************/ +#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/geocnan.h b/src/libgeoc/geocnan.h new file mode 100644 index 0000000..c55c1ef --- /dev/null +++ b/src/libgeoc/geocnan.h @@ -0,0 +1,233 @@ +/* -*- coding: utf-8 -*- */ +/** +\defgroup geocnan Módulo GEOCNAN +\ingroup geom matriz gshhs +\brief En este módulo se reúnen constantes y funciones para el trabajo con + valores Not-a-Number. +@{ +\file geocnan.h +\brief Declaración de constantes y funciones para el trabajo con valores + Not-a-Number. +\author José Luis García Pallero, jgpallero@gmail.com +\date 26 de mayo de 2011 +\version 1.0 +\section Licencia Licencia +Copyright (c) 2010-2011, 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 _GEOCNAN_H_ +#define _GEOCNAN_H_ +/******************************************************************************/ +/******************************************************************************/ +#include +#include +#include +#include +#include"libgeoc/errores.h" +/******************************************************************************/ +/******************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_NAN +\brief Constante \em Not-a-Number (\em NaN). Se define como \em 0.0/0.0. +\date 21 de diciembre de 2010: Creación de la constante. +*/ +#define GEOC_NAN (0.0/0.0) +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_NAN_TXT +\brief Constante \em Not-a-Number (\em NaN), como cadena de texto. +\date 22 de septiembre de 2011: Creación de la constante. +*/ +#define GEOC_NAN_TXT "NaN" +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_NAN_LON_FORM_NUM_SIMPLE +\brief Longitud de una cadena de texto auxiliar para el cálculo de la longitud + de una cadena de formato numérico simple. +\date 22 de septiembre de 2011: Creación de la constante. +*/ +#define GEOC_NAN_LON_FORM_NUM_SIMPLE 100 +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Devuelve el número que representa el valor \em Not-a-Number (\em NaN), + que se define como el resultado de la evaluación de la operación + \em 0.0/0.0. +\return Valor NaN. +\note Esta función devuelve el valor almacenado en la constante #GEOC_NAN. +\date 21 de diciembre de 2010: Creación de la función. +\date 24 de mayo de 2011: Ahora la función devuelve el valor absoluto de + #GEOC_NAN, calculado con la función fabs() de C estándar. Se ha + hecho así porque, a veces, al imprimir un valor normal de #GEOC_NAN, éste + aparecía con un signo negativo delante. +\date 22 de septiembre de 2011: Lo del fabs() no funciona. Parece que + los problemas en la impresión dependen del compilador y los flags de + optimización utilizados. No obstante, se mantiene el uso de la función + fabs() en el código. +\todo Esta función todavía no está probada. +*/ +double GeocNan(void); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Comprueba si un número es \em Not-a-Number (\em NaN). +\param[in] valor Un número. +\return Dos posibilidades: + - 0: El número pasado no es NaN. + - Distinto de 0: El número pasado sí es NaN. +\note Esta función ha sido adaptada de LAPACK 3.2.1, disnan.f, + (http://www.netlib.org/lapack). +\date 21 de diciembre de 2010: Creación de la función. +\todo Esta función todavía no está probada. +*/ +int EsGeocNan(const double valor); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Busca valores #GEOC_NAN es un vector de datos. +\param[in] datos Vector de trabajo. +\param[in] nDatos Número de elementos que contiene el vector \em datos. +\param[in] incDatos Posiciones de separación entre los elementos del vector + \em datos. Este argumento siempre ha de ser un número positivo. +\param[out] nNan Número de valores #GEOC_NAN encontrados, que es el número de + elementos del vector de salida. +\return Varias posibilidades: + - Si todo ha ido bien, vector que contiene las posiciones en el vector + original donde se almacena el valor #GEOC_NAN. + - NULL: Pueden haber ocurrido dos cosas: + - Si \em nNan vale 0, en los datos de entrada no hay ningún valor + #GEOC_NAN. + - Si \em nNan es mayor que 0, ha ocurrido un error interno de + asignación de memoria. +\note Esta función no comprueba si el número de elementos del vector \em datos + es congruente con los valores pasados en \em nDatos e \em incDatos. +\note Las posiciones de los elementos #GEOC_NAN encontradas se refieren al + número de elementos \em nDatos del vector de trabajo. Para encontrar la + posición real en memoria es necesario tener en cuenta la variable + \em incDatos. +\date 26 de mayo de 2011: Creación de la función. +\todo Esta función no está probada. +*/ +size_t* PosGeocNanEnVector(const double* datos, + const size_t nDatos, + const size_t incDatos, + size_t* nNan); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Calcula el número de carácteres que ocupa un valor numérico imprimido con + determinado formato. +\param[in] formato Cadena de formato para imprimir \b *UN \b ÚNICO* valor + numérico (de cualquier tipo). +\return Número de carácteres que ocupa un valor numérico imprimido según el + formato pasado. +\note Esta función no comprueba internamente si la cadena de formato es + correcta. +\note \em formato no puede dar lugar a un texto impreso de más de + #GEOC_NAN_LON_FORM_NUM_SIMPLE carácteres. +\date 22 de septiembre de 2011: Creación de la función. +\todo Esta función todavía no está probada. +*/ +size_t LonFormatoNumSimple(const char formato[]); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Convierte una cadena de formato para imprimir un \b *ÚNICO* número en una + cadena para imprimir texto con el mismo ancho que el que tendría de haber + sido imprimida como número. +\param[in] formatoNum Cadena de formato para imprimir \b *UN \b ÚNICO* valor + numérico (de cualquier tipo). +\param[out] formatoTexto Cadena de texto que almacenará la cadena de formato + para la impresión en modo texto. +\note Esta función no comprueba internamente si la cadena de formato numérico es + correcta. +\note \em formatoNum no puede dar lugar a un texto impreso de más de + #GEOC_NAN_LON_FORM_NUM_SIMPLE carácteres. +\note Esta función asume que \em formatoTexto tiene espacio suficiente para + almacenar la cadena de salida. +\note Si \em formatoNum contiene al final carácteres de retorno de carro y salto + de línea, estos no son tenidos en cuenta en la creación de la cadena de + salida (no son tenidos en cuenta en el sentido de que no se añaden al + formato de salida, pero el espacio que ocupan sí se computa). +\date 22 de septiembre de 2011: Creación de la función. +\todo Esta función todavía no está probada. +*/ +void FormatoNumFormatoTexto(const char formatoNum[], + char formatoTexto[]); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Imprime valores Not-a-Number en modo texto (#GEOC_NAN_TXT) es un fichero. +\param[in] idFich Identificador del fichero de trabajo, abierto para escribir. +\param[in] nNan Número de veces que se ha de imprimir el valor #GEOC_NAN_TXT, + una a continuación de otra. +\param[in] formato Cadena de formato para la impresión de cada valor + #GEOC_NAN_TXT. +\param[in] retCarro Identificador para añadir un retorno de carro y cambio de + línea al final de la impresión de datos, independientemente del valor + pasado en el argumento \em formato. Dos posibilidades: + - 0: No se imprime retorno de carro y cambio de línea al final. + - Distinto de 0: Sí se imprime retorno de carro y cambio de línea al + final. +\note Esta función no comprueba internamente si el fichero de entrada está + abierto correctamente. +\note Esta función no comprueba internamente si la cadena de formato es + correcta. +\note Si se ha indicado que se imprima salto de línea y retorno de carro al + final, este se imprime aunque \em nNan valga 0. +\date 22 de septiembre de 2011: Creación de la función. +\todo Esta función no está probada. +*/ +void ImprimeGeocNanTexto(FILE* idFich, + const size_t nNan, + const char formato[], + const int retCarro); +/******************************************************************************/ +/******************************************************************************/ +#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/geocomp.h b/src/libgeoc/geocomp.h new file mode 100644 index 0000000..79768ba --- /dev/null +++ b/src/libgeoc/geocomp.h @@ -0,0 +1,208 @@ +/* -*- coding: utf-8 -*- */ +/** +\defgroup geocomp Módulo GEOC-OMP +\ingroup anespec general geodesia geom geopot gravim mmcc +\brief En este módulo se reúnen constantes y funciones para la obtención de + información de la implementación de OpenMP usada. +@{ +\file geocomp.h +\brief Declaración de macros y funciones para la obtención de información de la + implementación de OpenMP usada. +\author José Luis García Pallero, jgpallero@gmail.com +\date 25 de agosto de 2011 +\version 1.0 +\section Licencia Licencia +Copyright (c) 2011, 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 _GEOCOMP_H_ +#define _GEOCOMP_H_ +/******************************************************************************/ +/******************************************************************************/ +#include +/******************************************************************************/ +/******************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_OMP_F_1_0 +\brief Valor (fecha YYYYMM) de la macro \p _OPENMP para la versión 1.0 de + OpenMP. +\date 25 de agosto de 2011: Creación de la constante. +*/ +#define GEOC_OMP_F_1_0 (199810) +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_OMP_F_2_0 +\brief Valor (fecha YYYYMM) de la macro \p _OPENMP para la versión 2.0 de + OpenMP. +\date 25 de agosto de 2011: Creación de la constante. +*/ +#define GEOC_OMP_F_2_0 (200203) +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_OMP_F_2_5 +\brief Valor (fecha YYYYMM) de la macro \p _OPENMP para la versión 2.5 de + OpenMP. +\date 25 de agosto de 2011: Creación de la constante. +*/ +#define GEOC_OMP_F_2_5 (200505) +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_OMP_F_3_0 +\brief Valor (fecha YYYYMM) de la macro \p _OPENMP para la versión 3.0 de + OpenMP. +\date 22 de agosto de 2011: Creación de la constante. +*/ +#define GEOC_OMP_F_3_0 (200805) +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_OMP_F_3_1 +\brief Valor (fecha YYYYMM) de la macro \p _OPENMP para la versión 3.1 de + OpenMP. +\date 25 de agosto de 2011: Creación de la constante. +*/ +#define GEOC_OMP_F_3_1 (201107) +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_OMP_V_1_0 +\brief Cadena de texto identificadora de la versión 1.0 de OpenMP. +\date 25 de agosto de 2011: Creación de la constante. +*/ +#define GEOC_OMP_V_1_0 "1.0" +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_OMP_V_2_0 +\brief Cadena de texto identificadora de la versión 2.0 de OpenMP. +\date 25 de agosto de 2011: Creación de la constante. +*/ +#define GEOC_OMP_V_2_0 "2.0" +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_OMP_V_2_5 +\brief Cadena de texto identificadora de la versión 2.5 de OpenMP. +\date 25 de agosto de 2011: Creación de la constante. +*/ +#define GEOC_OMP_V_2_5 "2.5" +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_OMP_V_3_0 +\brief Cadena de texto identificadora de la versión 3.0 de OpenMP. +\date 22 de agosto de 2011: Creación de la constante. +*/ +#define GEOC_OMP_V_3_0 "3.0" +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_OMP_V_3_1 +\brief Cadena de texto identificadora de la versión 3.1 de OpenMP. +\date 25 de agosto de 2011: Creación de la constante. +*/ +#define GEOC_OMP_V_3_1 "3.1" +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_OMP_F_DESC +\brief Fecha de versión de OpenMP desconocida. +\date 25 de agosto de 2011: Creación de la constante. +*/ +#define GEOC_OMP_F_DESC (0) +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_OMP_V_DESC +\brief Versión de OpenMP correspondiente a un valor desconocido de la macro + \p _OPENMP. +\date 25 de agosto de 2011: Creación de la constante. +*/ +#define GEOC_OMP_V_DESC "0.0" +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_OMP_LON_CAD_VERS +\brief Longitud de la cadena de texto que almacena la versión de OpenMP. +\date 25 de agosto de 2011: Creación de la constante. +*/ +#define GEOC_OMP_LON_CAD_VERS (10) +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Calcula la versión de OpenMP a partir del valor de la macro \p _OPENMP. +\param[in] macro_OPENMP Valor de la macro \p _OPENMP. +\param[out] version Versión de OpenMP correspondiente al valor de la macro. Si + el argumento \em macro_OPENMP almacena un valor desconocido, se + devuelve #GEOC_OMP_V_DESC. +\note Esta función asume que \em version tiene asignada suficiente memoria: como + mínimo, espacio para una cadena de #GEOC_OMP_LON_CAD_VERS carácteres. +\date 25 de agosto de 2011: Creación de la función. +*/ +void VersionOpenMP(const int macro_OPENMP, + char version[]); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Calcula la fecha (el valor de la macro \p _OPENMP) de una versión de + OpenMP dada. +\param[in] version Cadena de versión de OpenMP, tal como es calculada por la + función \ref VersionOpenMP. +\return Fecha, en el formato YYYYMM, correspondiente a la versión. Este valor + debería coincidir con la macro \p _OPENMP de la implementación de OpenMP + usada. +\note En caso de pasar una cadena de versión errónea o desconocida, la función + devuelve #GEOC_OMP_F_DESC. +\date 25 de agosto de 2011: Creación de la función. +*/ +int FechaVersionOpenMP(const char version[]); +/******************************************************************************/ +/******************************************************************************/ +#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/geom.h b/src/libgeoc/geom.h new file mode 100644 index 0000000..134cb7b --- /dev/null +++ b/src/libgeoc/geom.h @@ -0,0 +1,64 @@ +/* -*- coding: utf-8 -*- */ +/** +\defgroup geom Módulo GEOMETRIA +\brief En este módulo se reúnen las funciones necesarias para el tratamiento de + problemas de geometría. +@{ +\file geom.h +\brief Inclusión de ficheros de cabecera para el trabajo con la biblioteca + GEOMETRIA. +\author José Luis García Pallero, jgpallero@gmail.com +\date 26 de diciembre de 2009 +\section Licencia Licencia +Copyright (c) 2009-2011, 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 _GEOM_H_ +#define _GEOM_H_ +/******************************************************************************/ +/******************************************************************************/ +#include"libgeoc/dpeucker.h" +#include"libgeoc/eucli.h" +#include"libgeoc/greiner.h" +#include"libgeoc/polig.h" +#include"libgeoc/polil.h" +#include"libgeoc/ptopol.h" +#include"libgeoc/recpolil.h" +#include"libgeoc/segmento.h" +/******************************************************************************/ +/******************************************************************************/ +#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/greiner.h b/src/libgeoc/greiner.h new file mode 100644 index 0000000..2a36011 --- /dev/null +++ b/src/libgeoc/greiner.h @@ -0,0 +1,855 @@ +/* -*- coding: utf-8 -*- */ +/** +\ingroup geom gshhs +@{ +\file greiner.h +\brief Definición de estructuras y declaración de funciones para el recorte de + polígonos mediante el algoritmo de Greiner-Hormann + (http://davis.wpi.edu/~matt/courses/clipping/). +\author José Luis García Pallero, jgpallero@gmail.com +\date 14 de mayo 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. +*/ +/******************************************************************************/ +/******************************************************************************/ +#ifndef _GREINER_H_ +#define _GREINER_H_ +/******************************************************************************/ +/******************************************************************************/ +#include +#include +#include +#include +#include"libgeoc/errores.h" +#include"libgeoc/eucli.h" +#include"libgeoc/geocnan.h" +#include"libgeoc/polig.h" +#include"libgeoc/ptopol.h" +#include"libgeoc/segmento.h" +/******************************************************************************/ +/******************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_GREINER_FAC_EPS_PERTURB +\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. +*/ +#define GEOC_GREINER_FAC_EPS_PERTURB 10.0 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_GREINER_BUFFER_PTOS +\brief Número de puntos para ir asignando memoria en bloques para los polígonos + de salida en la funcion \ref Paso3Greiner. Ha de ser un número mayor o + igual a 2. +\date 23 de mayo de 2011: Creación de la constante. +*/ +#define GEOC_GREINER_BUFFER_PTOS 100 +/******************************************************************************/ +/******************************************************************************/ +/** \enum GEOC_OP_BOOL_POLIG +\brief Operación booleana entre polígonos. +\date 21 de mayo de 2011: Creación del tipo. +*/ +enum GEOC_OP_BOOL_POLIG +{ + /** \brief Intersección entre polígonos. */ + GeocOpBoolInter=111, + /** \brief Unión de polígonos. */ + GeocOpBoolUnion=112, + /** \brief Unión exclusiva de polígonos. */ + GeocOpBoolXor=113, + /** \brief Operación A-B. */ + GeocOpBoolAB=114, + /** \brief Operación B-A. */ + GeocOpBoolBA=115 +}; +/******************************************************************************/ +/******************************************************************************/ +/** \struct _vertPoliClip +\brief Estructura de definición de un vértice de un polígono usado en + operaciones de recorte. El polígono se almacena en memoria como una lista + doblemente enlazada de vértices. +\date 14 de mayo de 2011: Creación de la estructura. +*/ +typedef struct _vertPoliClip +{ + /** \brief Coordenada X del vértice. */ + double x; + /** \brief Coordenada Y del vértice. */ + double y; + /** \brief Coordenada X perturbada del vértice. */ + double xP; + /** \brief Coordenada Y perturbada del vértice. */ + double yP; + /** \brief Vértice anterior. */ + struct _vertPoliClip* anterior; + /** \brief Vértice siguiente. */ + struct _vertPoliClip* siguiente; + /** + \brief Enlace al mismo nodo, perteneciente a otro polígono. + + Los puntos de intersección pertenecen tanto al polígono de recorte + como al recortado. + */ + struct _vertPoliClip* vecino; + /** + \brief Indicador de primer punto de polígono. + + Dos posibilidades: + - 0: No es el primer punto del polígono. + - Distinto de 0: Sí es el primer punto del polígono. + */ + char ini; + /** + \brief Indicador de punto de intersección. + + Dos posibilidades: + - 0: No es un punto de intersección. + - Distinto de 0: Sí es un punto de intersección. + */ + char interseccion; + /** + \brief Indicador de punto de entrada al interior del otro polígono. + + Dos posibilidades: + - 0: No es un punto de entrada, es de salida. + - Distinto de 0: Sí es un punto de entrada. + */ + char entrada; + /** + \brief Indicador de punto visitado. + + Dos posibilidades: + - 0: No ha sido visitado. + - Distinto de 0: Sí ha sido visitado. + */ + char visitado; + /** \brief Distancia, en tanto por uno, de un nodo de intersección con + respecto al primer vértice del segmento que lo contiene. */ + double alfa; +}vertPoliClip; +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Crea un vértice de tipo \ref _vertPoliClip y lo inserta entre otros dos. +\param[in] x Coordenada X del vértice. +\param[in] y Coordenada Y del vértice. +\param[in] anterior Vértice anterior (puede ser \p NULL). +\param[in] siguiente Vértice siguiente (puede ser \p NULL). +\param[in] vecino Campo _vertPoliClip::vecino (puede ser \p NULL). +\param[in] ini Campo _vertPoliClip::ini. +\param[in] interseccion Campo _vertPoliClip::interseccion. +\param[in] entrada Campo _vertPoliClip::entrada. +\param[in] visitado Campo _vertPoliClip::visitado. +\param[in] alfa Campo _vertPoliClip::alfa. +\return Puntero al nuevo vértice creado. Si se devuelve \p NULL, ha ocurrido un + error de asignación de memoria. +\date 18 de mayo de 2011: Creación de la función. +\date 21 de mayo de 2011: Eliminación del algumento \em siguientePoli y adición + del argumento \em ini. +\todo Esta función todavía no está probada. +*/ +vertPoliClip* CreaVertPoliClip(const double x, + const double y, + vertPoliClip* anterior, + vertPoliClip* siguiente, + vertPoliClip* vecino, + const char ini, + const char interseccion, + const char entrada, + const char visitado, + const double alfa); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Crea un polígono, como una lista doblemente enlazada de elementos + \ref _vertPoliClip. +\param[in] x Vector de coordenadas X de los nodos del polígono. +\param[in] y Vector de coordenadas Y de los nodos del polígono. +\param[in] nCoor 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. +\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 En la lista de salida que representa al polígono, el primer vértice + 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 \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. +\todo Esta función todavía no está probada. +*/ +vertPoliClip* CreaPoliClip(const double* x, + const double* y, + const size_t nCoor, + const size_t incX, + const size_t incY); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Libera la memoria asignada a un polígono almacenado como una lista + doblemente enlazada de elementos \ref _vertPoliClip. +\param[in] poli Puntero al primer elemento del polígono. +\note Esta función no comprueba si hay vértices del polígono anteriores al + vértice de entrada, por lo que si se quiere liberar toda la memoria + asignada a un polígono, el vértice pasado ha de ser el primero de la + lista. +\note Esta función \b *NO* trabaja con listas circulares. +\date 18 de mayo de 2011: Creación de la función. +\todo Esta función todavía no está probada. +*/ +void LibMemPoliClip(vertPoliClip* poli); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Elimina los vértices no originales de un polígono almacenado como una + lista doblemente enlazada de elementos \ref _vertPoliClip. +\param[in] poli Puntero al primer elemento del polígono. +\return Puntero al primer elemento del polígono original. Si se devuelve + \p NULL, ninguno de los vértices pertenecía al polígono original. +\note Esta función asume que el primero y el último vértices originales del + polígono pasado tienen las mismas coordenadas. +\note Los vértices eliminados por esta función son todos aquéllos cuyo campo + _vertPoliClip::interseccion sea distinto de 0. +\note Aunque se supone que el primer vértice de un polígono siempre es un + vértice original, si no lo es, la variable de entrada queda modificada. + Por tanto, siempre es recomendable capturar la variable de salida, que + garantiza la posición del primer elemento. +\note Las coordenadas de todos los vértices originales vuelven a ser la de + inicio, es decir, los campos _vertPoliClip::xP e _vertPoliClip::yP se + sobreescriben con los valores almacenados en _vertPoliClip::x e + _vertPoliClip::y. +\note Esta función \b *NO* trabaja con listas circulares. +\date 18 de mayo de 2011: Creación de la función. +\todo Esta función todavía no está probada. +*/ +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. +\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 + \p NULL, quiere decir qie el argumento de entrada valía \p NULL. +\note Esta función \b *NO* trabaja con listas circulares. +\date 30 de mayo de 2011: Creación de la función. +\todo Esta función todavía no está probada. +*/ +vertPoliClip* ReiniciaVerticesPoliClip(vertPoliClip* poli); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Busca el siguiente vértice original en un polígono. +\param[in] vert Puntero al vértice a partir del cual se ha de buscar. +\return Puntero al siguiente vértice original en el polígono. Si se devuelve + \p NULL, se ha llegado al final. +\note Esta función asume que el primero y el último vértices originales del + polígono pasado tienen las mismas coordenadas. +\note Los vértices no originales son todos aquéllos cuyo campo + _vertPoliClip::interseccion es distinto de 0. +\note Esta función \b *NO* trabaja con listas circulares. +\date 19 de mayo de 2011: Creación de la función. +\todo Esta función todavía no está probada. +*/ +vertPoliClip* SiguienteVertOrigPoliClip(vertPoliClip* vert); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Busca el siguiente vértice que sea una intersección no visitada en un + polígono. +\param[in] vert Puntero al vértice a partir del cual se ha de buscar. +\return Puntero al siguiente vértice que sea una intersección no visitada en el + polígono. Si se devuelve \p NULL, se ha llegado al final. +\note Esta función asume que el primero y el último vértices originales del + polígono pasado tienen las mismas coordenadas. +\note Los vértices intersección no visitados son todos aquéllos cuyo campo + _vertPoliClip::visitado es 0. +\note Esta función asume que el vértice inicial del polígono, aquél cuyo campo + _vertPoliClip::ini vale 1, es un vértice original. +\note Esta función puede trabajar con listas circulares y no circulares. +\date 21 de mayo de 2011: Creación de la función. +\todo Esta función todavía no está probada. +*/ +vertPoliClip* SiguienteIntersecNoVisitadaPoliClip(vertPoliClip* vert); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Busca el último vértice de un polígono almacenado como una lista + doblemente enlazada de vértives \ref _vertPoliClip. +\param[in] poli Puntero al primer elemento del polígono. +\return Puntero al último vértice del polígono, que es aquél cuyo campo + _vertPoliClip::siguiente apunta a \p NULL. Si se devuelve \p NULL, + significa que el argumento pasado en \em poli vale \p NULL. +\note Esta función \b *NO* trabaja con listas circulares. +\date 21 de mayo de 2011: Creación de la función. +\todo Esta función todavía no está probada. +*/ +vertPoliClip* UltimoVertPoliClip(vertPoliClip* poli); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Inserta un vértice de tipo \ref _vertPoliClip entre otros dos, atendiendo + al campo _vertPoliClip::alfa. +\param[in] ins Vértice a insertar. +\param[in] extremoIni Extremo inicial del segmento donde se insertará \em ins. +\param[in] extremoFin Extremo final del segmento donde se insertará \em ins. +\note Esta función asume que todos los elementos pasados tienen memoria + asignada. +\note Si entre \em extremoIni y \em extremoFin hay más vértices, \em ins se + insertará de tal modo que los campos _vertPoliClip::alfa queden ordenados + de menor a mayor. +\note Si el campo _vertPoliClip::alfa de \em ins tiene el mismo valor que el + de \em extremoIni, \em ins se insertará justo a continuación de + \em extremoIni. +\note Si el campo _vertPoliClip::alfa de \em ins tiene el mismo valor que el + de \em extremoFin, \em ins se insertará justo antes de \em extremoIni. +\note Esta función \b *NO* trabaja con listas circulares. +\date 19 de mayo de 2011: Creación de la función. +\todo Esta función todavía no está probada. +*/ +void InsertaVertPoliClip(vertPoliClip* ins, + vertPoliClip* extremoIni, + vertPoliClip* extremoFin); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Convierte una lista doblemente enlazada de elementos \ref _vertPoliClip + en una lista doblemente enlazada circular. +\param[in,out] poli Vértice inicial del polígono, almacenado como lista + doblemente enlazada, pero no cerrada. Al término de la ejecución + de la función la lista se ha cerrado, por medio de un enlace del + penúltimo elemento (el último es el primero repetido) con el + primero. +\return Puntero al último elemento del polígono original que, al ser el primer + elemento repetido, queda almacenado en memoria pero no neferenciado por + el polígono. Si el valor devuelto es \p NULL quiere decir que el + argumento de entrada era \p NULL. +\note Esta función \b *NO* trabaja con listas circulares. +\date 21 de mayo de 2011: Creación de la función. +\todo Esta función todavía no está probada. +*/ +vertPoliClip* CierraPoliClip(vertPoliClip* poli); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Convierte una lista doblemente enlazada circular de elementos + \ref _vertPoliClip en una lista doblemente enlazada simple. +\param[in,out] poli Vértice inicial del polígono, almacenado como lista + doblemente enlazada circular. Al término de la ejecución de la + función la lista ha recuperado su condición de doblemente + enlazada sin cerrar. +\param[in] ultimo Puntero al último elemento de la lista doblemente enlazada + original. Este argumento ha de ser el valor devuelto por la + función \ref CierraPoliClip. +\note Esta función asume que los elementos pasados tienen memoria asignada. +\note Esta función sólo trabaja con listas circulares. +\date 21 de mayo de 2011: Creación de la función. +\todo Esta función todavía no está probada. +*/ +void AbrePoliClip(vertPoliClip* poli, + vertPoliClip* ultimo); +/******************************************************************************/ +/******************************************************************************/ +/** +\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. +\param[in] x Coordenada X del punto de trabajo. +\param[in] y Coordenada Y del punto de trabajo. +\param[in] poli Polígono, almacenado como una lista doblemente enlazada de + elementos \ref _vertPoliClip. Sólo se tienen en cuenta los vértices + originales del polígono, que son todos aquéllos cuyo campo + _vertPoliClip::interseccion es distinto de 0. +\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. +\note El código de esta función ha sido adaptado de la función + \ref PtoEnPoligono. +\note Esta función no comprueba si la variable \em poli es un polígono + correctamente almacenado. +\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 + punto dentro o fuera, indistintamente (el chequeo del mismo punto con el + mismo polígono siempre dará el mismo resultado). +\note Esta función \b *NO* trabaja con listas circulares. +\date 19 de mayo de 2011: Creación de la función. +\todo Esta función no está probada. +*/ +int PtoEnPoliClip(const double x, + const double y, + vertPoliClip* poli); +/******************************************************************************/ +/******************************************************************************/ +/** +\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 del polígono. +\param[in] x Coordenada X del punto de trabajo. +\param[in] y Coordenada Y del punto de trabajo. +\param[in] poli Polígono, almacenado como una lista doblemente enlazada de + elementos \ref _vertPoliClip. Sólo se tienen en cuenta los vértices + originales del polígono, que son todos aquéllos cuyo campo + _vertPoliClip::interseccion es distinto de 0. +\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. +\note El código de esta función ha sido adaptado de la función + \ref PtoEnPoligonoVertice. +\note Esta función no comprueba si la variable \em poli es un polígono + correctamente almacenado. +\note Esta función utiliza en uno de sus pasos la función \ref PtoEnPoliClip y + se comporta igual que ella en el caso de puntos en el borde. +\note Esta función \b *NO* trabaja con listas circulares. +\date 19 de mayo de 2011: Creación de la función. +\todo Esta función no está probada. +*/ +int PtoEnPoliClipVertice(const double x, + const double y, + vertPoliClip* poli); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Cuenta el número de vértices originales que hay en un polígono almacenado + como una lista doblemente enlazada de elementos \ref _vertPoliClip. +\param[in] poli Polígono, almacenado como una lista doblemente enlazada de + elementos \ref _vertPoliClip. Sólo se tienen en cuenta los vértices + originales del polígono, que son todos aquéllos cuyo campo + _vertPoliClip::interseccion es distinto de 0. +\return Número de vértices originales almacenados. El último vértice, que es + igual al primero, también se cuenta. +\note Esta función no comprueba si la variable \em poli es un polígono + correctamente almacenado. +\note Esta función \b *NO* trabaja con listas circulares. +\date 19 de mayo de 2011: Creación de la función. +\todo Esta función no está probada. +*/ +size_t NumeroVertOrigPoliClip(vertPoliClip* poli); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Cuenta el número total de vértices que hay en un polígono almacenado como + una lista doblemente enlazada de elementos \ref _vertPoliClip. +\param[in] poli Polígono, almacenado como una lista doblemente enlazada de + elementos \ref _vertPoliClip. Se tienen en cuenta todos los vértices. +\return Número total de vértices almacenados. El último vértice, que debe ser + igual al primero, también se cuenta. +\note Esta función no comprueba si la variable \em poli es un polígono + correctamente almacenado. +\note Esta función \b *NO* trabaja con listas circulares. +\date 19 de mayo de 2011: Creación de la función. +\todo Esta función no está probada. +*/ +size_t NumeroVertPoliClip(vertPoliClip* poli); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Calcula la cantidad mínima a añadir a un número para que el valor de la + suma sea distinto del número original. +\param[in] x Número a perturbar. +\param[in] factor Factor para ir multiplicando el valor a añadir a \em x + mientras no sea suficiente para producir una perturbación detectable. + Un buen valor para este argumento es #GEOC_GREINER_FAC_EPS_PERTURB. +\return Cantidad mínima a añadir a \em x para que el valor de la suma sea + distinto de \em x. +\note Esta función no comprueba internamente si \em factor es menor o igual que + 1, lo que daría lugar a que la función entrase en un bucle infinito. +\note Como valor inicial de la cantidad a añadir se toma el producto de + \em factor por la constante \p DBL_EPSILON, perteneciente al fichero + \p float.h de C estándar. +\date 22 de mayo de 2011: Creación de la función. +\todo Esta función no está probada. +*/ +double CantPerturbMin(const double x, + const double factor); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Modifica un número la cantidad mínima para que sea distinto del número + original. +\param[in] x Número a perturbar. +\param[in] factor Factor para el cálculo de la cantidad perturbadora mínima. Ver + la documentación de la función \ref CantPerturbMin para obtener más + detalles. Un buen valor para este argumento es + #GEOC_GREINER_FAC_EPS_PERTURB. +\return Número perturbado. +\note La perturbación de \em x se realiza de la siguiente manera: + - Se calcula la cantidad mínima perturbadora \p perturb con la función + \ref CantPerturbMin. + - Se calcula un número seudoaleatorio con la función de C estándar + rand() (el generador de números seudoaleatorios se inicializa + con la orden srand((unsigned int)time(NULL));). + - Se comprueba la paridad del número seudoaleatorio generado para obtener + la variable \p signo, de tal forma que: + - Si el número seudoaleatorio es par: \p signo vale 1.0. + - Si el número seudoaleatorio es impar: \p signo vale -1.0. + - Se perturba \em x como xPerturb=x+signo*perturb. +\date 22 de mayo de 2011: Creación de la función. +\todo Esta función no está probada. +*/ +double PerturbaPuntoMin(const double x, + const double factor); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Realiza el paso número 1 del algoritmo de Greiner-Hormann, que consiste + en el cálculo de los puntos de intersección entre los dos polígonos de + trabajo. +\param[in,out] poliBas Polígono base, representado como una lista doblemente + enlazada de elementos \ref _vertPoliClip. Al término de la + ejecución de la función se le han añadido los puntos de + intersección. +\param[in,out] poliRec Polígono de recorte, representado como una lista + doblemente enlazada de elementos \ref _vertPoliClip. Al término + de la ejecución de la función se le han añadido los puntos de + intersección. +\param[in] facPer Factor para el posible cálculo de la perturbación de las + coordenadas de algunos vértices. Este valor es usado internamente por + la función \ref PerturbaPuntoMin (ver su documentación). Un buen + valor para este argumento es #GEOC_GREINER_FAC_EPS_PERTURB. +\param[out] nIntersec Número de intersecciones calculadas. +\param[out] nPerturb Número de puntos perturbados en el proceso. +\return Variable de estado. 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 no comprueba si las variables \em poliBas y \em poliRec son + polígonos correctamente almacenados. +\note En el caso de tener que perturbar algún vértice, sólo se modifican los de + \em poliRec, dejando las coordenadas del polígono base inalteradas. +\date 22 de mayo de 2011: Creación de la función. +\todo Esta función no está probada. +*/ +int Paso1Greiner(vertPoliClip* poliBas, + vertPoliClip* poliRec, + const double facPer, + size_t* nIntersec, + size_t* nPerturb); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Realiza el paso número 2 del algoritmo de Greiner-Hormann, que consiste + en la asignación de los puntos de intersección como entrada o salida. +\param[in,out] poliBas Polígono base, representado como una lista doblemente + enlazada de elementos \ref _vertPoliClip. Al término de la + ejecución de la función los puntos de intersección han sido + marcados como entrada o salida. +\param[in,out] poliRec Polígono de recorte, representado como una lista + doblemente enlazada de elementos \ref _vertPoliClip. Al término + de la ejecución de la función los puntos de intersección han sido + marcados como entrada o salida. +\param[in] op Identificador de la operación a realizar. Ha de ser un elemento + del tipo enumerado #GEOC_OP_BOOL_POLIG, excepto la unión exclusiva + \p xor. En el caso de indicar la operación de unión exclusiva \p xor, + se realiza una intersección y \b *NO* se avisa del argumento + incorrecto. +\note Esta función no comprueba si las variables \em poliBas y \em poliRec son + polígonos correctamente almacenados. +\date 22 de mayo de 2011: Creación de la función. +\todo Esta función no está probada. +*/ +void Paso2Greiner(vertPoliClip* poliBas, + vertPoliClip* poliRec, + const enum GEOC_OP_BOOL_POLIG op); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Realiza el paso número 3 del algoritmo de Greiner-Hormann, que consiste + en la generación de los polígonos resultado. +\param[in,out] poliBas Polígono base, representado como una lista doblemente + enlazada de elementos \ref _vertPoliClip, tal y como sale de la + función \ref Paso2Greiner. Al término de la ejecución de la + función los puntos visitados han sido marcados en el campo + _vertPoliClip::visitado. +\param[in,out] poliRec Polígono de recorte, representado como una lista + doblemente enlazada de elementos \ref _vertPoliClip, tal y como + sale de la función \ref Paso2Greiner. Al término de la ejecución + de la función los puntos visitados han sido marcados en el campo + _vertPoliClip::visitado. +\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. +\note Esta función no comprueba si las variables \em poliBas y \em poliRec son + polígonos correctamente almacenados. +\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. +\todo Esta función no está probada. +*/ +polig* Paso3Greiner(vertPoliClip* poliBas, + vertPoliClip* poliRec); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Realiza una operación booleana entre dos polígonos mediante el algoritmo + de Greiner-Hormann. +\param[in,out] poliBas Polígono base, representado como una lista doblemente + enlazada de elementos \ref _vertPoliClip. Al término de la + ejecución de la función se han añadido los puntos de intersección + con \em poliRec. +\param[in,out] poliRec Polígono de recorte, representado como una lista + doblemente enlazada de elementos \ref _vertPoliClip. Al término + de la ejecución de la función se han añadido los puntos de + intersección con \em poliRec. +\param[in] op Identificador de la operación a realizar. Ha de ser un elemento + del tipo enumerado #GEOC_OP_BOOL_POLIG. Varias posibilidades: + - #GeocOpBoolInter: Realiza la intersección entre \em poliBas y + \em poliRec. + - #GeocOpBoolUnion: Realiza la unión entre \em poliBas y \em poliRec. + - #GeocOpBoolXor: Realiza la unión exclusiva entre \em poliBas y + \em poliRec. + - #GeocOpBoolAB: Realiza la sustracción \em poliBas-poliRec. + - #GeocOpBoolBA: Realiza la sustracción \em poliRec-poliBas. +\param[in] facPer Factor para el posible cálculo de la perturbación de las + 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. 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 + enumerado #GEOC_OP_BOOL_POLIG. Si se introduce un valor no perteneciente + al tipo, se realiza la operación #GeocOpBoolInter. +\note En el caso de tener que perturbar algún vértice, sólo se modifican los de + \em poliRec, dejando las coordenadas de \em poliBase inalteradas. +\note Si \em facPer es menor o igual que 1, se sustituye internamente su valor + por #GEOC_GREINER_FAC_EPS_PERTURB (ver documentación de la función + \ref CantPerturbMin). +\note Esta función realiza la unión exclusiva #GeocOpBoolXor mediante la unión + de las operaciones individuales #GeocOpBoolAB y #GeocOpBoolBA. Esta última + unión simplemente es el almacenamiento en la estructura de salida de los + 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); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Realiza una operación booleana entre múltiples polígonos mediante el + algoritmo de Greiner-Hormann. +\param[in] poliBas Estructura \ref polig que almacena los polígonos base. +\param[in] poliRec Estructura \ref polig que almacena los polígonos de recorte. +\param[in] op Identificador de la operación a realizar. Ha de ser un elemento + del tipo enumerado #GEOC_OP_BOOL_POLIG. Varias posibilidades: + - #GeocOpBoolInter: Realiza la intersección entre los polígonos + almacenados en \em poliBas y los almacenados en \em poliRec. + - #GeocOpBoolUnion: Realiza la unión entre los polígonos almacenados + en \em poliBas y los almacenados en \em poliRec. + - #GeocOpBoolXor: Realiza la unión exclusiva entre los polígonoa + almacenados en \em poliBas y los almacenados en \em poliRec. + - #GeocOpBoolAB: Realiza la sustracción entre todos los polígonos + \em poliBas-poliRec. + - #GeocOpBoolBA: Realiza la sustracción entre todos los polígonos + \em poliRec-poliBas. +\param[in] facPer Factor para el posible cálculo de la perturbación de las + 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. +\return Estructura \ref polig con los polígonos resultado de las operaciones. Si + se devuelve \p NULL ha ocurrido un error de asignación de memoria. +\note Esta función realiza la operación \em op con todas las combinaciones + posibles de polígonos. Es decir, se recorren todos los polígonos + almacenados en \em poliBas y con cada uno de ellos se realiza la operación + \em op con cada polígono almacenado en \em poliRec. +\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 + enumerado #GEOC_OP_BOOL_POLIG. Si se introduce un valor no perteneciente + al tipo, se realiza la operación #GeocOpBoolInter. +\note En el caso de tener que perturbar algún vértice, sólo se modifican los + correspondientes a \em poliRec, dejando las coordenadas de los polígonos + de \em poliBase inalteradas. +\note Si \em facPer es menor o igual que 1, se sustituye internamente su valor + por #GEOC_GREINER_FAC_EPS_PERTURB (ver documentación de la función + \ref CantPerturbMin). +\note Esta función realiza la unión exclusiva #GeocOpBoolXor mediante la unión + de las operaciones individuales #GeocOpBoolAB y #GeocOpBoolBA. Esta última + unión simplemente es el almacenamiento en la estructura de salida de los + 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); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Crea una estructura \ref polig a partir de todos los vértices de un + polígono almacenado como una lista doblemente enlazada de elementos + \ref _vertPoliClip. +\param[in] poli Polígono de trabajo, representado como una lista doblemente + enlazada de elementos \ref _vertPoliClip. El puntero pasado ha + de apuntar al primer elemento del polígono (no se controla + internamente). +\param[in] coorOrig Identificador para copiar las coordenadas originales o + perturbadas. Dos posibilidades: + - 0: Se copiarán las coordenadas perturbadas _vertPoliClip::xP e + _vertPoliClip::yP. + - Distinto de 0: Se copiarán las coordenadas originales + _vertPoliClip::x e _vertPoliClip::y. +\return Estructura \ref polig que representa el polígono. Si se devuelve \p NULL + ha ocurrido un error de asignación de memoria. +\note Esta función no comprueba si la variable \em poli es un polígono + correctamente almacenado. +\note Esta función \b *NO* trabaja con listas circulares. +\note Esta función realiza una copia en memoria de las coordenadas de los + vértices de la estructura \em poli a la estructura de salida. +\date 29 de mayo de 2011: Creación de la función. +\todo Esta función no está probada. +*/ +polig* CreaPoligPoliClip(vertPoliClip* poli, + const int coorOrig); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Añade los vértices de un polígono almacenado como una lista doblemente + enlazada de elementos \ref _vertPoliClip a una estructura \ref polig + previamente creada. +\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 los + polígonos de la estructura \em anyade. +\param[in] anyade Polígono a añadir, representado como una lista doblemente + enlazada de elementos \ref _vertPoliClip. El puntero pasado ha + de apuntar al primer elemento del polígono (no se controla + internamente). +\param[in] coorOrig Identificador para copiar las coordenadas originales o + perturbadas. Dos posibilidades: + - 0: Se copiarán las coordenadas perturbadas _vertPoliClip::xP e + _vertPoliClip::yP. + - Distinto de 0: Se copiarán las coordenadas originales + _vertPoliClip::x e _vertPoliClip::y. +\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 no comprueba si la variable \em poli es un polígono + correctamente almacenado. +\note Esta función no comprueba si la variable \em anyade es un polígono + correctamente almacenado. +\note Esta función \b *NO* trabaja con listas circulares. +\note Esta función realiza una copia en memoria de las coordenadas de los + vértices de la estructura \em poli a la estructura de salida. +\note Esta función crea internamente una estructura \ref polig para luego + añadirla a \em poli con la función \ref AnyadePoligPolig. +\date 29 de mayo de 2011: Creación de la función. +\todo Esta función no está probada. +*/ +int AnyadePoligClipPolig(polig* poli, + vertPoliClip* anyade, + const int coorOrig); +/******************************************************************************/ +/******************************************************************************/ +#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/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 +#include +#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 new file mode 100644 index 0000000..50f8812 --- /dev/null +++ b/src/libgeoc/polig.h @@ -0,0 +1,1215 @@ +/* -*- coding: utf-8 -*- */ +/** +\ingroup geom gshhs +@{ +\file polig.h +\brief Definición de estructuras y declaración de funciones para el trabajo con + polígonos. +\author José Luis García Pallero, jgpallero@gmail.com +\note Este fichero contiene funciones paralelizadas con OpenMP. +\date 20 de abril 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. +*/ +/******************************************************************************/ +/******************************************************************************/ +#ifndef _POLIG_H_ +#define _POLIG_H_ +/******************************************************************************/ +/******************************************************************************/ +#include +#include +#include +#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 +extern "C" { +#endif +/******************************************************************************/ +/******************************************************************************/ +/** \struct polig +\brief Estructura contenedora de los vértices que definen el contorno de uno o + varios polígono. +\date 20 de abril de 2011: Creación de la estructura. +\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 +{ + /** \brief Número de elementos de los vectores de coordenadas. */ + size_t nElem; + /** + \brief Vector de polig::nElem elementos, que almacena las coordenadas X de + los vértices del polígono (o los polígonos), así como los separadores + entre polígonos. La primera coordenada de cada polígono se repite al + final. + */ + double* x; + /** + \brief Vector de polig::nElem elementos, que almacena las coordenadas Y de + los vértices del polígono (o los polígonos), así como los separadores + entre polígonos. La primera coordenada de cada polígono se repite al + final. + */ + double* y; + /** \brief Número de polígonos almacenados. */ + size_t nPolig; + /** + \brief Vector de polig::nPolig elementos, que almacena las posiciones en los + vectores \em x e \em y de inicio de cada polígono almacenado. + */ + size_t* posIni; + /** + \brief Vector de polig::nPolig elementos, que almacena el número de vértices + de cada polígono almacenado. El último vértice de cada polígono, que + es el primero repetido, también entra en la cuenta. + */ + size_t* nVert; + /** + \brief Identificador de si la estructura contiene información acerca de los + límites del rectángulo que encierra a cada polígono almacenado. + + Dos posibilidades: + - 0: La estructura no contiene información de los límites. + - Distinto de 0: La estructura sí contiene información de los + límites. + */ + int hayLim; + /** + \brief Vector de polig::nPolig elementos, que almacena la coordenada X + mínima de cada polígono almacenado. Este campo sólo contiene + información si el campo polig::hayLim es distinto de 0; si no, es + igual a \p NULL. + */ + double* xMin; + /** + \brief Vector de polig::nPolig elementos, que almacena la coordenada X + máxima de cada polígono almacenado. Este campo sólo contiene + información si el campo polig::hayLim es distinto de 0; si no, es + igual a \p NULL. + */ + double* xMax; + /** + \brief Vector de polig::nPolig elementos, que almacena la coordenada Y + mínima de cada polígono almacenado. Este campo sólo contiene + información si el campo polig::hayLim es distinto de 0; si no, es + igual a \p NULL. + */ + double* yMin; + /** + \brief Vector de polig::nPolig elementos, que almacena la coordenada Y + máxima de cada polígono almacenado. Este campo sólo contiene + información si el campo polig::hayLim es distinto de 0; si no, es + igual a \p NULL. + */ + double* yMax; + /** + \brief Identificador de si la estructura contiene información acerca de la + superficie de los polígonos almacenados. + + Dos posibilidades: + - 0: La estructura no contiene información de superficie. + - Distinto de 0: La estructura sí contiene información de superficie. + */ + int hayArea; + /** + \brief Vector de polig::nPolig elementos, que almacena la superficie de cada + polígono almacenado. Este campo sólo contiene información si el campo + polig::hayArea es distinto de 0; si no, es igual a \p NULL. La + superficie almacenada sólo es correcta si el polígono es simple, esto + es, si sus lados no se cortan entre ellos mismos. + + El área de los polígono puede ser negativa o positiva, de tal forma + que: + - Si es negativa: Los vértices de polígono están ordenados en el + sentido de las agujas del reloj. + - Si es positiva: Los vértices de polígono están ordenados en sentido + 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; +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Indica si hay alguna función compilada en paralelo con OpenMP en el + fichero \ref polig.c. +\param[out] version Cadena identificadora de la versión de OpenMP utilizada. + Este argumento sólo se utiliza si su valor de entrada es distinto de + \p NULL y si hay alguna función compilada con OpenMP. +\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 27 de mayo de 2011: Creación de la función. +\date 25 de agosto de 2011: Adición del argumento de entrada \em version. +*/ +int GeocParOmpPolig(char version[]); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Crea una estructura \ref polig vacía. +\return Estructura \ref polig vacía. Los campos escalares se inicializan con el + valor 0 y los vectoriales con \p NULL. Si se devuelve \p NULL ha + ocurrido un error de asignación de memoria. +\date 26 de mayo de 2011: Creación de la función. +\note Esta función todavía no está probada. +*/ +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. +\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. +\param[in] posNanX Vector que almacena las posiciones de los elementos #GEOC_NAN + en el vector \em x de coordenadas originales. +\param[in] posNanY Vector que almacena las posiciones de los elementos #GEOC_NAN + en el vector \em y de coordenadas originales. +\param[in] nNanX Número de elementos del vector \em posNanX. +\param[in] nNanY Número de elementos del vector \em posNanY. +\param[out] nElemMax Número máximo de elementos que contendrán los vectores de + coordenadas de los elementos de la estructura. +\param[out] nPolig Número de polígonos almacenados en los vectores \em x e + \em y de coordenadas originales. +\return Variable de error. Tres posibilidades: + - #GEOC_ERR_NO_ERROR: Si todo ha ido bien. + - #GEOC_ERR_POLIG_VEC_DISTINTO_NUM_POLIG: Si los vectores \em x e \em y + de coordenadas originales almacenan un número distinto de polígonos, + es decir, \em nNanX es distinto que \em nNanY. + - #GEOC_ERR_POLIG_VEC_DISTINTOS_POLIG: Si algunos polígonos almacenados + en \em x e \em y son distintos, es decir, las posiciones almacenadas + en \em posNanX son distintas de las almacenadas en \em posNanY. +\note Esta función no comprueba si el número de elementos de los vectores + \em posNanX y \em posNanY es congruente con los valores pasados en + \em nNanX y \em nNanY. +\date 26 de mayo de 2011: Creación de la función. +\note Esta función todavía no está probada. +*/ +int AuxCreaPolig1(const size_t nElem, + const size_t* posNanX, + const size_t* posNanY, + const size_t nNanX, + const size_t nNanY, + size_t* nElemMax, + size_t* nPolig); +/******************************************************************************/ +/******************************************************************************/ +/** +\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. +\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. +\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[out] xSal Vector para almacenar los elementos copiados del vector \em x. + Ha de tener la suficiente memoria asignada para copiar \em nElem + elementos más un posible elemento adicional, que es el primer + elemento de \em x, si éste no se repite al final. +\param[out] ySal Vector para almacenar los elementos copiados del vector \em y. + Ha de tener la suficiente memoria asignada para copiar \em nElem + elementos más un posible elemento adicional, que es el primer + elemento de \em y, si éste no se repite al final. +\param[out] nCopias Número de elementos copiados en los vectores \em xSal e + \em ySal, incluido el primer punto repetido al final, si se copia. +\note Esta función no comprueba si el número de elementos de los vectores \em x, + \em y, \em xSal e \em ySal es congruente con los valores pasados en + \em nElem, \em incX e \em incY. +\date 26 de mayo de 2011: Creación de la función. +\note Esta función todavía no está probada. +*/ +void AuxCreaPolig2(const double* x, + const double* y, + const size_t nElem, + const size_t incX, + const size_t incY, + double* xSal, + double* ySal, + size_t* nCopias); +/******************************************************************************/ +/******************************************************************************/ +/** +\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. +\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. +\param[in] nElem 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] posNan Vector que almacena las posiciones de los elementos #GEOC_NAN + en los vectores \em x e \em y. +\param[in] nNan Número de elementos del vector \em posNan. +\param[out] xSal Vector para almacenar las coordenadas X de los vértices de los + polígonos creados. +\param[out] ySal Vector para almacenar las coordenadas Y de los vértices de los + polígonos creados. +\param[out] posIni Vector para almacenar las posiciones de inicio de los + polígonos creados. +\param[out] nVert Vector para almacenar el número de vértices de los polígonos + creados. +\param[out] nPtos Número de posiciones con información almacenada en los + vectores \em xSal e \em ySal. +\param[out] nPolig Número de posiciones con información almacenada en los + vectores \em posIni y \em nVert. +\note Esta función no comprueba si el número de elementos de los vectores \em x, + \em y y \em posNan es congruente con los valores pasados en \em nElem, + \em incX, \em incY y \em nNan. +\note Esta función asume que los vectores \em xSal, \em ySal, \em posIni y + \em nVert tienen asignada suficiente memoria. +\date 29 de mayo de 2011: Creación de la función. +\note Esta función todavía no está probada. +*/ +void AuxCreaPolig3(const double* x, + const double* y, + const size_t nElem, + const size_t incX, + const size_t incY, + const size_t* posNan, + const size_t nNan, + double* xSal, + double* ySal, + size_t* posIni, + size_t* nVert, + size_t* nPtos, + size_t* nPolig); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Crea una estructura \ref polig a partir de dos vectores que contienen las + coordenadas de los vértices de uno o varios polígonos. +\param[in] x Vector que contiene las coordenadas X de los vértices del polígono + o polígonos de trabajo. Si hay varios polígonos, han de estar + separados por un valor #GEOC_NAN. +\param[in] y Vector que contiene las coordenadas Y de los vértices del polígono + o polígonos de trabajo. Si hay varios polígonos, han de estar + separados por un valor #GEOC_NAN. +\param[in] nElem 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[out] idError Identificador de error. Varias posibilidades: + - #GEOC_ERR_NO_ERROR: Todo ha ido bien. + - #GEOC_ERR_ASIG_MEMORIA: Ha ocurrido un error de asignación de + memoria. + - #GEOC_ERR_POLIG_VEC_DISTINTO_NUM_POLIG: Los vectores \em x e \em y + contienen un número distinto de polígonos. No contienen el mismo + número de identificadores #GEOC_NAN. + - #GEOC_ERR_POLIG_VEC_DISTINTOS_POLIG: Los vectores \em x e \em y + contienen distintos polígonos. Los marcadores #GEOC_NAN no están + colocados en las mismas posiciones. +\return Estructura \ref polig con los polígonos pasados. Si ocurre algún error, + se devuelve \p NULL y el motivo del fallo se codifica en la variable + \em idError. +\note Esta función está paralelizada con OpenMP. +\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 de \em nElem, \em incX e + \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, 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 + al final del listado del resto de vértices. +\note Esta función no calcula los límites de los polígonos ni su área, por lo + que los campos polig::hayLim y polig::hayArea se inicializan a 0 y los + campos polig::xMin, polig::xMax, polig::yMin, polig::yMax y polig::area se + inicializan a \p NULL. +\date 26 de mayo de 2011: Creación de la función. +\note Esta función todavía no está probada. +*/ +polig* CreaPolig(const double* x, + const double* y, + const size_t nElem, + const size_t incX, + const size_t incY, + int* idError); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Enlaza el contenido de una estructura \ref polig a otra. +\param[in] poliEnt Estructura \ref polig de entrada, que almacena los datos a + enlazar. +\param[out] poliSal Estructura \ref polig, cuyos campos serán enlazados a los de + la estructura \em poliEnt. Esta estructura ha de estar, como mínimo, + inicializada. Al término de la ejecución de la función, las + estructuras \em poliEnt y \em poliSal comparten el mismo espacio de + memoria en sus argumentos vectoriales. +\note Esta función asume que la estructura de entrada \em poligEnt tiene memoria + asignada. +\note Esta función asume que la estructura de salida \em poligSal está, como + mínimo, inicializada. +\note Esta función libera la posible memoria asignada a los campos de + \em poliSal antes de realizar el enlace. +\date 19 de junio de 2011: Creación de la función. +\note Esta función todavía no está probada. +*/ +void EnlazaCamposPolig(polig* poliEnt, + polig* poliSal); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Copia el contenido de una estructura \ref polig en otra. +\param[in] poli Estructura \ref polig de entrada, que almacena los datos a + copiar. +\param[out] idError Identificador de error. Varias posibilidades: + - #GEOC_ERR_NO_ERROR: Todo ha ido bien. + - #GEOC_ERR_ASIG_MEMORIA: Ha ocurrido un error de asignación de + memoria. + - #GEOC_ERR_POLIG_VEC_DISTINTO_NUM_POLIG: Los campos polig::x e + polig::y del polígono de entrada contienen un número distinto de + polígonos. No contienen el mismo número de identificadores + #GEOC_NAN. + - #GEOC_ERR_POLIG_VEC_DISTINTOS_POLIG: Los campos polig::x e + polig::y del polígono de entrada contienen distintos polígonos. + Los marcadores #GEOC_NAN no están colocados en las mismas + posiciones. +\return Polígono con los datos contenidos en \em poli copiados. Si ocurre algún + error se devuelve \p NULL y la causa se almacena en el argumento + \em idError. +\note Esta función asume que la estructura de entrada \em poli tiene memoria + asignada. +\date 09 de julio de 2011: Creación de la función. +\note Esta función todavía no está probada. +*/ +polig* CopiaPolig(const polig* poli, + int* idError); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Añade el contenido de una estructura \ref polig a otra. +\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 los + polígonos de la estructura \em anyade. +\param[in] anyade Estructura cuyo contenido será añadido a \em poli. +\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 En caso de error de asignación de memoria, la memoria de las estructuras + de entrada no se libera. +\note Si la estructura \em poli guarda información de superficie y límites de + los polígonos almacenados, esta información se calcula también para los + nuevos datos (en realidad, si la estructura \em anyade ya los tiene + calculados, simplemente se copian). +\date 29 de mayo de 2011: Creación de la función. +\note Esta función todavía no está probada. +*/ +int AnyadePoligPolig(polig* poli, + const polig* anyade); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Añade al contenido de una estructura \ref polig un conjunto de polígonos + definidos a partir de un listado con las coordenadas de sus vértices, de + la misma forma que el utilizado en la función \ref CreaPolig. +\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 los + polígonos pasados en \em x e \em y. +\param[in] x Vector que contiene las coordenadas X de los vértices del polígono + o polígonos a añadir. Si hay varios polígonos, han de estar separados + por un valor #GEOC_NAN. +\param[in] y Vector que contiene las coordenadas Y de los vértices del polígono + o polígonos a añadir. Si hay varios polígonos, han de estar separados + por un valor #GEOC_NAN. +\param[in] nElem 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. +\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. + - #GEOC_ERR_POLIG_VEC_DISTINTO_NUM_POLIG: Los vectores \em x e \em y + contienen un número distinto de polígonos. No contienen el mismo + número de identificadores #GEOC_NAN. + - #GEOC_ERR_POLIG_VEC_DISTINTOS_POLIG: Los vectores \em x e \em y + contienen distintos polígonos. Los marcadores #GEOC_NAN no están + colocados en las mismas posiciones. +\note Esta función asume que la estructura de entrada \em poli tiene memoria + asignada. +\note En caso de error de asignación de memoria, la memoria de la estructura y + los vectores de entrada no se libera. +\note Si la estructura \em poli guarda información de superficie y límites de + los polígonos almacenados, esta información se calcula también para los + nuevos datos. +\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 de \em nElem, \em incX e + \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. +\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 + al final del listado del resto de vértices. +\note Esta función crea internamente una estructura \ref polig para luego + añadirla a \em poli con la función \ref AnyadePoligPolig. +\date 29 de mayo de 2011: Creación de la función. +\note Esta función todavía no está probada. +*/ +int AnyadeDatosPolig(polig* poli, + const double* x, + const double* y, + const size_t nElem, + const size_t incX, + const size_t incY); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Libera la memoria asignada a una estructura \ref polig. +\param[in] datos Estructura \ref polig. +\date 20 de abril de 2011: Creación de la estructura. +\date 26 de mayo de 2011: Reescritura de la función para el trabajo con la nueva + versión de la estructura. +\note Esta función todavía no está probada. +*/ +void LibMemPolig(polig* datos); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Calcula los límites de todos los polígonos almacenados en una estructura + \ref polig. +\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 los + límites de los polígonos almacenados. +\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 está paralelizada con OpenMP. +\note Esta función asume que la estructura de entrada \ref polig tiene memoria + asignada. +\note En caso de error de asignación de memoria, la memoria de la estructura de + entrada no se libera. +\date 29 de mayo de 2011: Creación de la función. +\note Esta función todavía no está probada. +*/ +int CalcLimitesPolig(polig* poli); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Calcula los límites de un polígono a partir de las coordenadas de sus + vértices. +\param[in] x Vector que contiene las coordenadas X de los vértices del polígono + de trabajo. +\param[in] y Vector que contiene las coordenadas Y de los vértices del polígono + de trabajo. +\param[in] nElem 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[out] xMin Coordenada X mímina del polígono. +\param[out] xMax Coordenada X máxima del polígono. +\param[out] yMin Coordenada Y mímina del polígono. +\param[out] yMax Coordenada Y máxima del polígono. +\note Esta función está paralelizada con OpenMP. +\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 de \em nElem, \em incX e + \em incY. +\date 29 de mayo de 2011: Creación de la función. +\note Esta función todavía no está probada. +*/ +void LimitesPoligono(const double* x, + const double* y, + const size_t nElem, + const size_t incX, + const size_t incY, + double* xMin, + double* xMax, + double* yMin, + double* yMax); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Calcula los límites de una serie de polígonos a partir de las coordenadas + de sus vértices, almacenadas en vectores en el formato de la estructura + \ref polig. +\param[in] x Vector que contiene las coordenadas X de los vértices del polígono + de trabajo, tal y como se almacenan en una estructura \ref polig. +\param[in] y Vector que contiene las coordenadas Y de los vértices del polígono + de trabajo, tal y como se almacenan en una estructura \ref polig. +\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 Vector de \em nPolig elementos, que almacena las posiciones de + inicio de los polígonos de trabajo. +\param[in] nVert Vector de \em nPolig elementos, que almacena el número de + vértices de los polígonos de trabajo. +\param[in] nPolig Número de polígonos de trabajo. +\param[in] restaPosIni Número de posiciones a restar a los valores almacenados + en \em posIni, de tal forma que los índices de los vértices se + refieran al inicio pasado mediante los punteros \em x e \em y. +\param[out] xMin Vector de \em nPolig elementos para almacenar las coordenadas + X mínimas calculadas de los polígonos. +\param[out] xMax Vector de \em nPolig elementos para almacenar las coordenadas + X máximas calculadas de los polígonos. +\param[out] yMin Vector de \em nPolig elementos para almacenar las coordenadas + Y mínimas calculadas de los polígonos. +\param[out] yMax Vector de \em nPolig elementos para almacenar las coordenadas + Y máximas calculadas de los polígonos. +\note Esta función está paralelizada con OpenMP. +\note Esta función no comprueba si el número de elementos de los vectores \em x, + \em y, \em posIni, \em nVert, \em xMin, \em xMax, \em yMin e \em yMax es + congruente con los valores pasados de \em incX, \em incY, \em nPolig y + \em restaPoliIni. +\note Esta función no comprueba si las coordenadas almacenadas en los vectores + \em x e \em y están en el formato de la estructura \ref polig. +\date 29 de mayo de 2011: Creación de la función. +\note Esta función todavía no está probada. +*/ +void LimitesPoligonosPolig(const double* x, + const double* y, + const size_t incX, + const size_t incY, + const size_t* posIni, + const size_t* nVert, + const size_t nPolig, + const size_t restaPosIni, + double* xMin, + double* xMax, + double* yMin, + double* yMax); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Calcula el área de todos los polígonos almacenados en una estructura + \ref polig. +\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, + const double facCoor, + const int geo, + const double a, + const double f); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Calcula el área de un polígono simple (sin intersecciones consigo mismo) + a partir de las coordenadas de sus vértices. +\param[in] x Vector que contiene las coordenadas X de los vértices del polígono + de trabajo. Las coordenadas del primer punto pueden repetirse o no al + final, indistintamente. +\param[in] y Vector que contiene las coordenadas Y de los vértices del polígono + de trabajo. Las coordenadas del primer punto pueden repetirse o no al + final, indistintamente. +\param[in] nElem 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. +\return Superficie del polígono de trabajo. Dos posibilidades: + - Número negativo: Los vértices del polígono están ordenados en el + sentido de las agujas del reloj. + - Número positivo: Los vértices del polígono están ordenados en el + sentido contrario al de las agujas del reloj. +\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 de \em nElem, \em incX e + \em incY. +\note El algoritmo implementado es el correspondiente a la ecuación 21.4.20 del + Numerical Recipes, tercera edición, página 1127. Este algoritmo trabaja + con vectores de coordenadas en los que el primer punto no se repite al + final. Esta función comprueba internamente si el primer punto se repite al + final de los vectores pasados y actua en consecuencia para proporcionar un + resultado correcto. +\date 29 de mayo de 2011: Creación de la función. +\date 23 de junio de 2011: Adición de la capacidad de trabajar con vectores de + coordenadas en los que se repite el primer punto al final. +\note Esta función todavía no está probada. +*/ +double AreaPoligonoSimple(const double* x, + const double* y, + const size_t nElem, + const size_t incX, + const size_t incY); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Calcula el área de una serie de polígonos simples (sin intersecciones + consigo mismo) a partir de las coordenadas de sus vértices, almacenadas + en vectores en el formato de la estructura \ref polig. +\param[in] x Vector que contiene las coordenadas X de los vértices del polígono + de trabajo, tal y como se almacenan en una estructura \ref polig. +\param[in] y Vector que contiene las coordenadas Y de los vértices del polígono + de trabajo, tal y como se almacenan en una estructura \ref polig. +\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 Vector de \em nPolig elementos, que almacena las posiciones de + inicio de los polígonos de trabajo. +\param[in] nVert Vector de \em nPolig elementos, que almacena el número de + vértices de los polígonos de trabajo. +\param[in] nPolig Número de polígonos de trabajo. +\param[in] restaPosIni Número de posiciones a restar a los valores almacenados + en \em posIni, de tal forma que los índices de los vértices se + refieran al inicio pasado mediante los punteros \em x e \em y. +\param[out] area Vector de \em nPolig elementos para almacenar las superficies + calculadas de los polígonos. Los valores pueden ser positivos o + negativos: + - Número negativo: Los vértices del polígono están ordenados en el + sentido de las agujas del reloj. + - Número positivo: Los vértices del polígono están ordenados en el + sentido contrario al de las agujas del reloj. +\note Esta función está paralelizada con OpenMP. +\note Esta función no comprueba si el número de elementos de los vectores \em x, + \em y, \em posIni, \em nVert y \em area es congruente con los valores + pasados de \em incX, \em incY, \em nPolig y \em restaPoliIni. +\note Esta función no comprueba si las coordenadas almacenadas en los vectores + \em x e \em y están en el formato de la estructura \ref polig. +\date 29 de mayo de 2011: Creación de la función. +\note Esta función todavía no está probada. +*/ +void AreaPoligonosSimplesPolig(const double* x, + const double* y, + const size_t incX, + const size_t incY, + const size_t* posIni, + const size_t* nVert, + const size_t nPolig, + const size_t restaPosIni, + double* area); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Aplica un factor de escala y una traslación (en este orden) a las + coordenadas de todos los polígonos almacenados en una estructura + \ref polig. +\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 ha aplicado un + factor de escala y una traslación (en este orden) a las + coordenadas de todos los polígonos almacenados y, si se indica, a + los límites y las superficies. +\param[in] escalaX Factor de escala a aplicar a las coordenadas X. +\param[in] escalaY Factor de escala a aplicar a las coordenadas Y. +\param[in] trasladaX Traslación a aplicar a las coordenadas X. +\param[in] trasladaY Traslación a aplicar a las coordenadas Y. +\param[in] aplicaLim Identificador para aplicar o no los factores de escala y + las traslaciones a los límites de los polígonos (sólo si están + previemente calculados). Dos posibilidades: + - 0: No se aplican los factores de escala ni las traslaciones a los + límites. + - Distinto de 0: Sí se aplican los factores de escala y las + traslaciones a los límites, si estos están calculados en la + estructura de entrada. +\param[in] aplicaArea Identificador para aplicar o no los factores de escala + (que se aplican como un único factor \em escalaX*escalaY) a las áreas + de los polígonos (sólo si están previemente calculadas). Dos + posibilidades: + - 0: No se aplican los factores a las áreas. + - Distinto de 0: Sí se aplican los factores a las áreas, si estas + están calculadas en la estructura de entrada. +\note Esta función está paralelizada con OpenMP. +\note Primero se aplican los factores de escala y luego las traslaciones. +\note Esta función asume que la estructura de entrada \em poli tiene memoria + asignada. +\note A las áreas sólo se aplican los factores de escala, ya que son invariantes + ante traslaciones. +\note A las áreas, los factores de escala se aplican como uno solo, igual a + \em escalaX*escalaY, para que éstas queden correctamente expresadas en las + nuevas unidades a las que da lugar el escalado. +\date 02 de junio de 2011: Creación de la función. +\date 18 de junio de 2011: Distinción entre factores de escala y traslaciones + para las coordenadas X e Y. +\note Esta función todavía no está probada. +*/ +void EscalaYTrasladaPolig(polig* poli, + const double escalaX, + const double escalaY, + const double trasladaX, + const double trasladaY, + const int aplicaLim, + const int aplicaArea); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Aplica una traslación y un factor de escala (en este orden) a las + coordenadas de todos los polígonos almacenados en una estructura + \ref polig. +\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 ha aplicado una + traslación y un factor de escala (en este orden) a las + coordenadas de todos los polígonos almacenados y, si se indica, a + los límites y las superficies. +\param[in] escalaX Factor de escala a aplicar a las coordenadas X. +\param[in] escalaY Factor de escala a aplicar a las coordenadas Y. +\param[in] trasladaX Traslación a aplicar a las coordenadas X. +\param[in] trasladaY Traslación a aplicar a las coordenadas Y. +\param[in] aplicaLim Identificador para aplicar o no las traslaciones y los + factores de escala a los límites de los polígonos (sólo si están + previemente calculados). Dos posibilidades: + - 0: No se aplican las traslaciones ni los factores de escala a los + límites. + - Distinto de 0: Sí se aplican las traslaciones y los factores de + escala a los límites, si estos están calculados en la estructura de + entrada. +\param[in] aplicaArea Identificador para aplicar o no los factores de escala + (que se aplican como un único factor \em escalaX*escalaY) a las áreas + de los polígonos (sólo si están previemente calculadas). Dos + posibilidades: + - 0: No se aplican los factores a las áreas. + - Distinto de 0: Sí se aplican los factores a las áreas, si estas + están calculadas en la estructura de entrada. +\note Esta función está paralelizada con OpenMP. +\note Primero se aplican las traslaciones y luego los factores de escala. +\note Esta función asume que la estructura de entrada \em poli tiene memoria + asignada. +\note A las áreas sólo se aplican los factores de escala, ya que son invariantes + ante traslaciones. +\note A las áreas, los factores de escala se aplican como uno solo, igual a + \em escalaX*escalaY, para que éstas queden correctamente expresadas en las + nuevas unidades a las que da lugar el escalado. +\date 02 de junio de 2011: Creación de la función. +\date 18 de junio de 2011: Distinción entre factores de escala y traslaciones + para las coordenadas X e Y. +\note Esta función todavía no está probada. +*/ +void TrasladaYEscalaPolig(polig* poli, + const double escalaX, + const double escalaY, + const double trasladaX, + const double trasladaY, + const int aplicaLim, + const int aplicaArea); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Aplica un factor de escala y una traslación (el orden de aplicación se ha + de seleccionar) a las coordenadas de todos los polígonos almacenados en + una estructura \ref polig. +\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 ha aplicado un + factor de escala y una traslación (orden a seleccionar) a las + coordenadas de todos los polígonos almacenados y, si se indica, a + los límites y las superficies. +\param[in] escalaX Factor de escala a aplicar a las coordenadas X. +\param[in] escalaY Factor de escala a aplicar a las coordenadas Y. +\param[in] trasladaX Traslación a aplicar a las coordenadas X. +\param[in] trasladaY Traslación a aplicar a las coordenadas Y. +\param[in] orden Orden de aplicación de los factores de escala y traslación. Dos + posibilidades: + - 0: Primero se aplican los factores de escala y luego las + traslaciones \f$x'=f\cdot x+t\f$. + - Distinto de 0: Primero se aplican las traslaciones y luego los + factores de escala \f$x'=(x+t)\cdot f\f$. +\param[in] aplicaLim Identificador para aplicar o no los factores de escala y + las traslaciones a los límites de los polígonos (sólo si están + previemente calculados). Dos posibilidades: + - 0: No se aplican los factores de escala ni las traslaciones a los + límites. + - Distinto de 0: Sí se aplican los factores de escala y las + traslaciones a los límites, si estos están calculados en la + estructura de entrada. +\param[in] aplicaArea Identificador para aplicar o no los factores de escala + (que se aplican como un único factor \em escalaX*escalaY) a las áreas + de los polígonos (sólo si están previemente calculadas). Dos + posibilidades: + - 0: No se aplican los factores a las áreas. + - Distinto de 0: Sí se aplican los factores a las áreas, si estas + están calculadas en la estructura de entrada. +\note Esta función asume que la estructura de entrada \em poli tiene memoria + asignada. +\note A las áreas sólo se aplican los factores de escala, ya que son invariantes + ante traslaciones. +\note A las áreas, los factores de escala se aplican como uno solo, igual a + \em escalaX*escalaY, para que éstas queden correctamente expresadas en las + nuevas unidades a las que da lugar el escalado. +\date 02 de junio de 2011: Creación de la función. +\date 18 de junio de 2011: Distinción entre factores de escala y traslaciones + para las coordenadas X e Y. +\note Esta función todavía no está probada. +*/ +void MuevePolig(polig* poli, + const double escalaX, + const double escalaY, + const double trasladaX, + const double trasladaY, + const int orden, + const int aplicaLim, + const int aplicaArea); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Elimina vértices de los polígonos almacenados en una estructura + \ref polig mediante un algoritmo inspirado en el de Douglas-Peucker. Se + usa internamente la función \ref AligeraPolilinea. +\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, 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] 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: + - #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. + - #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/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 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 nSegRobOrig, + const size_t nSegRobAuto, + const double a, + const double f); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Imprime una línea de cabecera para un polígono almacenado en una + estructura \ref polig. +\param[in] poli Estructura \ref polig. +\param[in] indice Índice del polígono de trabajo en la estructura. +\param[in] iniCab Cadena de texto con la que comenzará la cabecera. +\param[in] impLim Identificador para imprimir o no los límites de coordenadas + del polígono de trabajo. Dos posibles valores: + - 0: No se imprimen. + - Distinto de 0: Sí se imprimen. +\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 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 + antes de imprimirlas. +\param[in] repitePrimerPunto Identificador para tener o no en cuenta el primer + vértice del polígono repetido al final del listado de coordenadas + para el cálculo del número de vértices del polígono. Dos posibles + valores: + - 0: No se repite, luego no se tiene en cuenta. + - Distinto de 0: Sí se repite, luego sí se tiene en cuenta. +\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: + iniCab númVert área xMín xMáx yMín yMáx atributo. +\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. +\note Esta función no comprueba internamente la validez de los argumentos de + formato. +\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, + const size_t indice, + const char iniCab[], + const int impLim, + const char formCoor[], + const int impArea, + const char formArea[], + const int impAtr, + const char formAtr[], + const double factorX, + const double factorY, + const int repitePrimerPunto, + FILE* idFich); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Imprime una estructura \ref polig en un fichero. +\param[in] poli Estructura \ref polig. +\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 + antes de imprimirlas. +\param[in] repitePrimerPunto Identificador para repetir o no el primer vértice + del polígono al final del listado de coordenadas. Dos posibles + valores: + - 0: No se repite. + - Distinto de 0: Sí se repite. +\param[in] iniNan Identificador para imprimir o no la marca de separación de + polígonos (\p NaN) delante del primer polígono. Dos posibles valores: + - 0: No se imprime. + - Distinto de 0: Sí se imprime. +\param[in] finNan Identificador para imprimir o no la marca de separación de + 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 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: + - 0: No se imprime. + - Distinto de 0: Sí se imprime. +\param[in] iniCab Cadena de texto con la que comenzará la cabecera. +\param[in] impLim Identificador para imprimir o no en la cabecera los límites de + coordenadas de los polígonos de trabajo. Dos posibles valores: + - 0: No se imprimen. + - Distinto de 0: Sí se imprimen. +\param[in] impArea Identificador para imprimir o no en la cabecera la superficie + de los polígonos de trabajo. Dos posibles valores: + - 0: No se imprime. + - Distinto de 0: Sí se imprime. +\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: + iniCab númVert área xMín xMáx yMín yMáx atributo. +\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. +\note Esta función no comprueba internamente la validez de los argumentos de + formato. +\note Esta función no comprueba internamente si el identificador pasado + corresponde a un fichero abierto para escribir. +\date 26 de mayo de 2011: Creación de la función. +\date 30 de mayo de 2011: Adición del argumento de entrada \em factor. +\date 18 de junio de 2011: Adición de la capacidad de escritura de una cabecera + y del uso de factores de escala independientes para las coordenadas X e Y. +\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, + const double factorX, + const double factorY, + const int repitePrimerPunto, + const int iniNan, + const int finNan, + const char formCoor[], + const int impCabecera, + const char iniCab[], + const int impLim, + const int impArea, + const char formArea[], + const int impAtr, + const char formAtr[], + FILE* idFich); +/******************************************************************************/ +/******************************************************************************/ +#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/polil.h b/src/libgeoc/polil.h new file mode 100644 index 0000000..8c9a73d --- /dev/null +++ b/src/libgeoc/polil.h @@ -0,0 +1,836 @@ +/* -*- coding: utf-8 -*- */ +/** +\ingroup geom gshhs +@{ +\file polil.h +\brief Definición de estructuras y declaración de funciones para el trabajo con + polilíneas. +\author José Luis García Pallero, jgpallero@gmail.com +\note Este fichero contiene funciones paralelizadas con OpenMP. +\date 03 de junio de 2011 +\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 + 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 _POLIL_H_ +#define _POLIL_H_ +/******************************************************************************/ +/******************************************************************************/ +#include +#include +#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/polig.h" +/******************************************************************************/ +/******************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif +/******************************************************************************/ +/******************************************************************************/ +/** \struct polil +\brief Estructura contenedora de los vértices que definen el contorno de una o + varias polilíneas. +\date 03 de junio de 2011: Creación de la estructura. +*/ +typedef struct +{ + /** \brief Número de elementos de los vectores de coordenadas. */ + size_t nElem; + /** + \brief Vector de polil::nElem elementos, que almacena las coordenadas X de + los vértices de la polilínea (o las polilíneas), así como los + separadores entre polilíneas. La primera coordenada de cada polilínea + se repite al final. + */ + double* x; + /** + \brief Vector de polil::nElem elementos, que almacena las coordenadas Y de + los vértices de la polilínea (o las polilíneas), así como los + separadores entre polilíneas. La primera coordenada de cada polilínea + se repite al final. + */ + double* y; + /** \brief Número de polilíneas almacenadas. */ + size_t nPolil; + /** + \brief Vector de polil::nPolig elementos, que almacena las posiciones en los + vectores \em x e \em y de inicio de cada polilínea almacenada. + */ + size_t* posIni; + /** + \brief Vector de polil::nPolig elementos, que almacena el número de vértices + de cada polilínea almacenada. + */ + size_t* nVert; + /** + \brief Identificador de si la estructura contiene información acerca de los + límites del rectángulo que encierra a cada polilínea almacenada. + + Dos posibilidades: + - 0: La estructura no contiene información de los límites. + - Distinto de 0: La estructura sí contiene información de los + límites. + */ + int hayLim; + /** + \brief Vector de polil::nPolig elementos, que almacena la coordenada X + mínima de cada polilínea almacenada. Este campo sólo contiene + información si el campo polil::hayLim es distinto de 0; si no, es + igual a \p NULL. + */ + double* xMin; + /** + \brief Vector de polil::nPolig elementos, que almacena la coordenada X + máxima de cada polilínea almacenada. Este campo sólo contiene + información si el campo polil::hayLim es distinto de 0; si no, es + igual a \p NULL. + */ + double* xMax; + /** + \brief Vector de polil::nPolig elementos, que almacena la coordenada Y + mínima de cada polilínea almacenada. Este campo sólo contiene + información si el campo polil::hayLim es distinto de 0; si no, es + igual a \p NULL. + */ + double* yMin; + /** + \brief Vector de polil::nPolig elementos, que almacena la coordenada Y + máxima de cada polilínea almacenada. Este campo sólo contiene + información si el campo polil::hayLim es distinto de 0; si no, es + igual a \p NULL. + */ + double* yMax; +}polil; +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Indica si hay alguna función compilada en paralelo con OpenMP en el + fichero \ref polil.c. +\param[out] version Cadena identificadora de la versión de OpenMP utilizada. + Este argumento sólo se utiliza si su valor de entrada es distinto de + \p NULL y si hay alguna función compilada con OpenMP. +\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 03 de junio de 2011: Creación de la función. +\date 25 de agosto de 2011: Adición del argumento de entrada \em version. +*/ +int GeocParOmpPolil(char version[]); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Crea una estructura \ref polil vacía. +\return Estructura \ref polil vacía. Los campos escalares se inicializan con el + valor 0 y los vectoriales con \p NULL. Si se devuelve \p NULL ha + ocurrido un error de asignación de memoria. +\date 26 de mayo de 2011: Creación de la función. +\note Esta función todavía no está probada. +*/ +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. +\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. +\param[in] posNanX Vector que almacena las posiciones de los elementos #GEOC_NAN + en el vector \em x de coordenadas originales. +\param[in] posNanY Vector que almacena las posiciones de los elementos #GEOC_NAN + en el vector \em y de coordenadas originales. +\param[in] nNanX Número de elementos del vector \em posNanX. +\param[in] nNanY Número de elementos del vector \em posNanY. +\param[out] nElemMax Número máximo de elementos que contendrán los vectores de + coordenadas de los elementos de la estructura. +\param[out] nPolil Número de polilíneas almacenadas en los vectores \em x e + \em y de coordenadas originales. +\return Variable de error. Tres posibilidades: + - #GEOC_ERR_NO_ERROR: Si todo ha ido bien. + - #GEOC_ERR_POLIL_VEC_DISTINTO_NUM_POLIL: Si los vectores \em x e \em y + de coordenadas originales almacenan un número distinto de polilíneas, + es decir, \em nNanX es distinto que \em nNanY. + - #GEOC_ERR_POLIL_VEC_DISTINTAS_POLIL: Si algunas polilíneas almacenadas + en \em x e \em y son distintas, es decir, las posiciones almacenadas + en \em posNanX son distintas de las almacenadas en \em posNanY. +\note Esta función no comprueba si el número de elementos de los vectores + \em posNanX y \em posNanY es congruente con los valores pasados en + \em nNanX y \em nNanY. +\date 03 de junio de 2011: Creación de la función. +\date 13 de junio de 2011: Corrección de error que hacía que el argumento + \em nElemMax que calculase mal si los argumentos \em nNanX y/o \em nNanY + valían 0. +\note Esta función todavía no está probada. +*/ +int AuxCreaPolil1(const size_t nElem, + const size_t* posNanX, + const size_t* posNanY, + const size_t nNanX, + const size_t nNanY, + size_t* nElemMax, + size_t* nPolil); +/******************************************************************************/ +/******************************************************************************/ +/** +\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. +\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. +\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[out] xSal Vector de \em nElem elementos para almacenar los elementos + copiados del vector \em x. +\param[out] ySal Vector de \em nElem elementos para almacenar los elementos + copiados del vector \em y. +\note Esta función no comprueba si el número de elementos de los vectores \em x, + \em y, \em xSal e \em ySal es congruente con los valores pasados en + \em nElem, \em incX e \em incY. +\date 03 de junio de 2011: Creación de la función. +\note Esta función todavía no está probada. +*/ +void AuxCreaPolil2(const double* x, + const double* y, + const size_t nElem, + const size_t incX, + const size_t incY, + double* xSal, + double* ySal); +/******************************************************************************/ +/******************************************************************************/ +/** +\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. +\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. +\param[in] nElem 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] posNan Vector que almacena las posiciones de los elementos #GEOC_NAN + en los vectores \em x e \em y. +\param[in] nNan Número de elementos del vector \em posNan. +\param[out] xSal Vector para almacenar las coordenadas X de los vértices de las + polilíneas creadas. +\param[out] ySal Vector para almacenar las coordenadas Y de los vértices de las + polilíneas creadas. +\param[out] posIni Vector para almacenar las posiciones de inicio de las + polilíneas creadas. +\param[out] nVert Vector para almacenar el número de vértices de las polilíneas + creadas. +\param[out] nPtos Número de posiciones con información almacenada en los + vectores \em xSal e \em ySal. +\param[out] nPolil Número de posiciones con información almacenada en los + vectores \em posIni y \em nVert. +\note Esta función no comprueba si el número de elementos de los vectores \em x, + \em y y \em posNan es congruente con los valores pasados en \em nElem, + \em incX, \em incY y \em nNan. +\note Esta función asume que los vectores \em xSal, \em ySal, \em posIni y + \em nVert tienen asignada suficiente memoria. +\date 03 de junio de 2011: Creación de la función. +\note Esta función todavía no está probada. +*/ +void AuxCreaPolil3(const double* x, + const double* y, + const size_t nElem, + const size_t incX, + const size_t incY, + const size_t* posNan, + const size_t nNan, + double* xSal, + double* ySal, + size_t* posIni, + size_t* nVert, + size_t* nPtos, + size_t* nPolil); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Crea una estructura \ref polil a partir de dos vectores que contienen las + coordenadas de los vértices de una o varias polilíneas. +\param[in] x Vector que contiene las coordenadas X de los vértices de la + polilínea o polilíneas de trabajo. Si hay varias polilíneas, han de + estar separados por un valor #GEOC_NAN. +\param[in] y Vector que contiene las coordenadas Y de los vértices de la + polilínea o polilíneas de trabajo. Si hay varias polilíneas, han de + estar separados por un valor #GEOC_NAN. +\param[in] nElem 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[out] idError Identificador de error. Varias posibilidades: + - #GEOC_ERR_NO_ERROR: Todo ha ido bien. + - #GEOC_ERR_ASIG_MEMORIA: Ha ocurrido un error de asignación de + memoria. + - #GEOC_ERR_POLIL_VEC_DISTINTO_NUM_POLIL: Los vectores \em x e \em y + contienen un número distinto de polilíneas. No contienen el mismo + número de identificadores #GEOC_NAN. + - #GEOC_ERR_POLIL_VEC_DISTINTAS_POLIL: Los vectores \em x e \em y + contienen distintas polilíneas. Los marcadores #GEOC_NAN no están + colocados en las mismas posiciones. +\return Estructura \ref polil con las polilíneas pasadas. Si ocurre algún error, + se devuelve \p NULL y el motivo del fallo se codifica en la variable + \em idError. +\note Esta función está paralelizada con OpenMP. +\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 de \em nElem, \em incX e + \em incY. +\note Si los vectores \em x e \em y almacenan varias polilíneas, éstas se + separan mediante valores #GEOC_NAN. Poner #GEOC_NAN en la primera posición + y/o la última es opcional. +\note Los posibles valores #GEOC_NAN han de estar en las mismas posiciones en + \em x e \em y. +\note Esta función no calcula los límites de las polilíneas, por lo que el + campo polil::hayLim se inicializa a 0 y los campos polil::xMin, + polil::xMax, polil::yMin y polil::yMax se inicializan a \p NULL. +\date 03 de junio de 2011: Creación de la función. +\note Esta función todavía no está probada. +*/ +polil* CreaPolil(const double* x, + const double* y, + const size_t nElem, + const size_t incX, + const size_t incY, + int* idError); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Enlaza el contenido de una estructura \ref polil a otra. +\param[in] poliEnt Estructura \ref polil de entrada, que almacena los datos a + enlazar. +\param[out] poliSal Estructura \ref polil, cuyos campos serán enlazados a los de + la estructura \em poliEnt. Esta estructura ha de estar, como mínimo, + inicializada. Al término de la ejecución de la función, las + estructuras \em poliEnt y \em poliSal comparten el mismo espacio de + memoria en sus argumentos vectoriales. +\note Esta función asume que la estructura de entrada \em poligEnt tiene memoria + asignada. +\note Esta función asume que la estructura de salida \em poligSal está, como + mínimo, inicializada. +\note Esta función libera la posible memoria asignada a los campos de + \em poliSal antes de realizar el enlace. +\date 19 de junio de 2011: Creación de la función. +\note Esta función todavía no está probada. +*/ +void EnlazaCamposPolil(polil* poliEnt, + polil* poliSal); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Copia el contenido de una estructura \ref polil en otra. +\param[in] poli Estructura \ref polil de entrada, que almacena los datos a + copiar. +\param[out] idError Identificador de error. Varias posibilidades: + - #GEOC_ERR_NO_ERROR: Todo ha ido bien. + - #GEOC_ERR_ASIG_MEMORIA: Ha ocurrido un error de asignación de + memoria. + - #GEOC_ERR_POLIL_VEC_DISTINTO_NUM_POLIL: Los campos polil::x e + polil::y de la polilínea de entrada contienenun número distinto de + polilíneas. No contienen el mismo número de identificadores + #GEOC_NAN. + - #GEOC_ERR_POLIL_VEC_DISTINTAS_POLIL: Los campos polig::x e + polig::y de la polilínea de entrada contienen distintas + polilíneas. Los marcadores #GEOC_NAN no están colocados en las + mismas posiciones. +\return Polilínea con los datos contenidos en \em poli copiados. Si ocurre algún + error se devuelve \p NULL y la causa se almacena en el argumento + \em idError. +\note Esta función asume que la estructura de entrada \em poli tiene memoria + asignada. +\date 09 de julio de 2011: Creación de la función. +\note Esta función todavía no está probada. +*/ +polil* CopiaPolil(const polil* poli, + int* idError); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Añade el contenido de una estructura \ref polil a otra. +\param[in,out] poli Estructura \ref polil, que almacena una serie de polilíneas. + Al término de la ejecución de la función, se han añadido las + polilíneas de la estructura \em anyade. +\param[in] anyade Estructura cuyo contenido será añadido a \em poli. +\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 polil tiene memoria + asignada. +\note En caso de error de asignación de memoria, la memoria de las estructuras + de entrada no se libera. +\note Si la estructura \em poli guarda información de límites de las polilíneas + almacenadas, esta información se calcula también para los nuevos datos (en + realidad, si la estructura \em anyade ya los tiene calculados, simplemente + se copian). +\date 03 de junio de 2011: Creación de la función. +\note Esta función todavía no está probada. +*/ +int AnyadePolilPolil(polil* poli, + const polil* anyade); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Añade al contenido de una estructura \ref polil un conjunto de polilíneas + definidas a partir de un listado con las coordenadas de sus vértices, de + la misma forma que el utilizado en la función \ref CreaPolil. +\param[in,out] poli Estructura \ref polil, que almacena una serie de polilíneas. + Al término de la ejecución de la función, se han añadido las + polilíneas pasados en \em x e \em y. +\param[in] x Vector que contiene las coordenadas X de los vértices de la + polilínea o polilíneas a añadir. Si hay varias polilíneas, han de + estar separadas por un valor #GEOC_NAN. +\param[in] y Vector que contiene las coordenadas Y de los vértices de la + polilínea o polilíneas a añadir. Si hay varias polilíneas, han de + estar separadas por un valor #GEOC_NAN. +\param[in] nElem 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. +\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. + - #GEOC_ERR_POLIL_VEC_DISTINTO_NUM_POLIL: Los vectores \em x e \em y + contienen un número distinto de polilíneas. No contienen el mismo + número de identificadores #GEOC_NAN. + - #GEOC_ERR_POLIL_VEC_DISTINTAS_POLIL: Los vectores \em x e \em y + contienen distintas polilíneas. Los marcadores #GEOC_NAN no están + colocados en las mismas posiciones. +\note Esta función asume que la estructura de entrada \em poli tiene memoria + asignada. +\note En caso de error de asignación de memoria, la memoria de la estructura y + los vectores de entrada no se libera. +\note Si la estructura \em poli guarda información de límites de las polilíneas + almacenadas, esta información se calcula también para los nuevos datos. +\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 de \em nElem, \em incX e + \em incY. +\note Si los vectores \em x e \em y almacenan varias polilíneas, éstas se + separan mediante valores #GEOC_NAN. Poner #GEOC_NAN en la primera posición + y/o la última es opcional. +\note Los posibles valores #GEOC_NAN han de estar en las mismas posiciones en + \em x e \em y. +\note Esta función crea internamente una estructura \ref polil para luego + añadirla a \em poli con la función \ref AnyadePolilPolil. +\date 03 de junio de 2011: Creación de la función. +\note Esta función todavía no está probada. +*/ +int AnyadeDatosPolil(polil* poli, + const double* x, + const double* y, + const size_t nElem, + const size_t incX, + const size_t incY); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Libera la memoria asignada a una estructura \ref polil. +\param[in] datos Estructura \ref polil. +\date 03 de junio de 2011: Creación de la función. +\note Esta función todavía no está probada. +*/ +void LibMemPolil(polil* datos); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Calcula los límites de todas las polilíneas almacenados en una estructura + \ref polil. +\param[in,out] poli Estructura \ref polil, que almacena una serie de polilíneas. + Al término de la ejecución de la función, se han añadido los + límites de las polilíneas almacenadas. +\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 está paralelizada con OpenMP. +\note Esta función asume que la estructura de entrada \ref polil tiene memoria + asignada. +\note En caso de error de asignación de memoria, la memoria de la estructura de + entrada no se libera. +\date 03 de junio de 2011: Creación de la función. +\note Esta función todavía no está probada. +*/ +int CalcLimitesPolil(polil* poli); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Aplica un factor de escala y una traslación (en este orden) a las + coordenadas de todas las polilíneas almacenadas en una estructura + \ref polil. +\param[in,out] poli Estructura \ref polil, que almacena una serie de polilíneas. + Al término de la ejecución de la función, se ha aplicado un + factor de escala y una traslación (en este orden) a las + coordenadas de todas las polilíneas almacenadas y, si se indica, + a los límites. +\param[in] escalaX Factor de escala a aplicar a las coordenadas X. +\param[in] escalaY Factor de escala a aplicar a las coordenadas Y. +\param[in] trasladaX Traslación a aplicar a las coordenadas X. +\param[in] trasladaY Traslación a aplicar a las coordenadas Y. +\param[in] aplicaLim Identificador para aplicar o no los factores de escala y + las traslaciones a los límites de las polilíneas (sólo si están + previemente calculados). Dos posibilidades: + - 0: No se aplican los factores de escala ni las traslaciones a los + límites. + - Distinto de 0: Sí se aplican los factores de escala y las + traslaciones a los límites, si estos están calculados en la + estructura de entrada. +\note Esta función está paralelizada con OpenMP. +\note Primero se aplican los factores de escala y luego las traslaciones. +\note Esta función asume que la estructura de entrada \em poli tiene memoria + asignada. +\date 03 de junio de 2011: Creación de la función. +\date 18 de junio de 2011: Distinción entre factores de escala y traslaciones + para las coordenadas X e Y. +\note Esta función todavía no está probada. +*/ +void EscalaYTrasladaPolil(polil* poli, + const double escalaX, + const double escalaY, + const double trasladaX, + const double trasladaY, + const int aplicaLim); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Aplica una traslación y un factor de escala (en este orden) a las + coordenadas de todas las polilíneas almacenadss en una estructura + \ref polil. +\param[in,out] poli Estructura \ref polil, que almacena una serie de polilíneas. + Al término de la ejecución de la función, se ha aplicado una + traslación y un factor de escala (en este orden) a las + coordenadas de todas las polilíneas almacenadas y, si se indica, + a los límites. +\param[in] escalaX Factor de escala a aplicar a las coordenadas X. +\param[in] escalaY Factor de escala a aplicar a las coordenadas Y. +\param[in] trasladaX Traslación a aplicar a las coordenadas X. +\param[in] trasladaY Traslación a aplicar a las coordenadas Y. +\param[in] aplicaLim Identificador para aplicar o no las traslaciones y los + factores de escala a los límites de las polilíneas (sólo si están + previemente calculados). Dos posibilidades: + - 0: No se aplican las traslaciones ni los factores de escala a los + límites. + - Distinto de 0: Sí se aplican las traslaciones y los factores de + escala a los límites, si estos están calculados en la estructura de + entrada. +\note Esta función está paralelizada con OpenMP. +\note Primero se aplican las traslaciones y luego los factores de escala. +\note Esta función asume que la estructura de entrada \em poli tiene memoria + asignada. +\date 03 de junio de 2011: Creación de la función. +\date 18 de junio de 2011: Distinción entre factores de escala y traslaciones + para las coordenadas X e Y. +\note Esta función todavía no está probada. +*/ +void TrasladaYEscalaPolil(polil* poli, + const double escalaX, + const double escalaY, + const double trasladaX, + const double trasladaY, + const int aplicaLim); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Aplica un factor de escala y una traslación (el orden de aplicación se ha + de seleccionar) a las coordenadas de todas las polilíneas almacenadas en + una estructura \ref polil. +\param[in,out] poli Estructura \ref polil, que almacena una serie de polilíneas. + Al término de la ejecución de la función, se ha aplicado un + factor de escala y una traslación (orden a seleccionar) a las + coordenadas de todas las polilíneas almacenadas y, si se indica, + a los límites. +\param[in] escalaX Factor de escala a aplicar a las coordenadas X. +\param[in] escalaY Factor de escala a aplicar a las coordenadas Y. +\param[in] trasladaX Traslación a aplicar a las coordenadas X. +\param[in] trasladaY Traslación a aplicar a las coordenadas Y. +\param[in] orden Orden de aplicación de los factores de escala y traslación. Dos + posibilidades: + - 0: Primero se aplican los factores de escala y luego las + traslaciones \f$x'=f\cdot x+t\f$. + - Distinto de 0: Primero se aplican las traslaciones y luego los + factores de escala \f$x'=(x+t)\cdot f\f$. +\param[in] aplicaLim Identificador para aplicar o no los factores de escala y + las traslaciones a los límites de las polilíneas (sólo si están + previemente calculados). Dos posibilidades: + - 0: No se aplican los factores de escala ni las traslaciones a los + límites. + - Distinto de 0: Sí se aplican los factores de escala y las + traslaciones a los límites, si estos están calculados en la + estructura de entrada. +\note Esta función asume que la estructura de entrada \em poli tiene memoria + asignada. +\date 03 de junio de 2011: Creación de la función. +\date 18 de junio de 2011: Distinción entre factores de escala y traslaciones + para las coordenadas X e Y. +\note Esta función todavía no está probada. +*/ +void MuevePolil(polil* poli, + const double escalaX, + const double escalaY, + const double trasladaX, + const double trasladaY, + const int orden, + const int aplicaLim); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Elimina vértices de las polilíneas almacenadas en una estructura + \ref polil mediante un algoritmo inspirado en el de Douglas-Peucker. Se + usa internamente la función \ref AligeraPolilinea. +\param[in,out] poli Estructura \ref polil, que almacena una serie de polilíneas. + 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] 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: + - #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. + - #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/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. +\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, 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. 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 nSegRobOrig, + const size_t nSegRobAuto); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Imprime una línea de cabecera para una polilínea almacenada en una + estructura \ref polil. +\param[in] poli Estructura \ref polil. +\param[in] indice Índice de la polilínea de trabajo en la estructura. +\param[in] iniCab Cadena de texto con la que comenzará la cabecera. +\param[in] impLim Identificador para imprimir o no los límites de coordenadas + de la polilínea de trabajo. Dos posibles valores: + - 0: No se imprimen. + - Distinto de 0: Sí se imprimen. +\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 + antes de imprimirlas. +\param[in] factorY Factor para multiplicar las coordenadas Y de los vértices + antes de imprimirlas. +\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: + iniCab númVert xMín xMáx yMín yMáx. +\note Si la estructura no tiene información de límites y se indica que se + impriman, los valores se calculan internamente. +\note Esta función asume que \em poli es una estructura \ref polil correctamente + almacenada. +\note Esta función no comprueba si la estructura pasada tiene memoria asignada. +\note Esta función no comprueba internamente la validez de los argumentos de + formato. +\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. +\note Esta función todavía no está probada. +*/ +void ImprimeCabeceraPolilFichero(const polil* poli, + const size_t indice, + const char iniCab[], + const int impLim, + const char formCoor[], + const double factorX, + const double factorY, + FILE* idFich); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Imprime una estructura \ref polil en un fichero. +\param[in] poli Estructura \ref polil. +\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 + antes de imprimirlas. +\param[in] iniNan Identificador para imprimir o no la marca de separación de + polilíneas (\p NaN) delante de la primera polilínea. Dos posibles + valores: + - 0: No se imprime. + - Distinto de 0: Sí se imprime. +\param[in] finNan Identificador para imprimir o no la marca de separación de + polilíneas (\p NaN) delante de la última polilínea. Dos posibles + valores: + - 0: No se imprime. + - Distinto de 0: Sí se imprime. +\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: + - 0: No se imprime. + - Distinto de 0: Sí se imprime. +\param[in] iniCab Cadena de texto con la que comenzará la cabecera. +\param[in] impLim Identificador para imprimir o no en la cabecera los límites de + coordenadas de las polilíneas de trabajo. Dos posibles valores: + - 0: No se imprimen. + - Distinto de 0: Sí se imprimen. +\param[in] idFich Identificador de fichero abierto para escribir. +\note La cabecera completa tiene el siguiente formato: + iniCab númVert xMín xMáx yMín yMáx. +\note Si la estructura no tiene información de límites y se indica que se + impriman, los valores se calculan internamente. +\note Esta función asume que \em poli es una estructura \ref polil correctamente + almacenada. +\note Esta función no comprueba si la estructura pasada tiene memoria asignada. +\note Esta función no comprueba internamente la validez de los argumentos de + formato. +\note Esta función no comprueba internamente si el identificador pasado + corresponde a un fichero abierto para escribir. +\date 03 de junio de 2011: Creación de la función. +\date 18 de junio de 2011: Adición de la capacidad de escritura de una cabecera + y del uso de factores de escala independientes para las coordenadas X e Y. +\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. +\note Esta función todavía no está probada. +*/ +void ImprimePolilFichero(const polil* poli, + const double factorX, + const double factorY, + const int iniNan, + const int finNan, + const char formCoor[], + const int impCabecera, + const char iniCab[], + const int impLim, + FILE* idFich); +/******************************************************************************/ +/******************************************************************************/ +#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/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 +#include +/******************************************************************************/ +/******************************************************************************/ +#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 +/******************************************************************************/ +/******************************************************************************/ +#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 new file mode 100644 index 0000000..a884db0 --- /dev/null +++ b/src/libgeoc/ptopol.h @@ -0,0 +1,1377 @@ +/* -*- coding: utf-8 -*- */ +/** +\ingroup geom gshhs +@{ +\file ptopol.h +\brief Declaración de funciones para la realización de chequeos de inclusión de + puntos en polígonos. + +En el momento de la compilación ha de seleccionarse el tipo de dato que se +utilizará en los cálculos intermedios de las funciones +\ref PtoEnPoligonoVerticeBorde y \ref PtoEnPoligonoVerticeBordeDouble. Si los +puntos de trabajo están muy alejados de los polígonos pueden darse casos de +resultados erróneos. Sería conveniente que los cálculos internedios se hiciesen +en variables de 64 bits, pero el tipo long int suele ser de 4 bytes en +procesadores de 32 bits. Para seleccionar este tipo como long long int, +lo que en procesadores de 32 bits equivale a una variable de 64 bits, es +necesario definir la variable para el preprocesador \em PTOPOL_BORDE_LONG_64. En +procesadores de 64 bits no es necesario (aunque puede utilizarse), ya que el +tipo long int tiene una longitud de 64 bits. Si no se define la +variable, se usará un tipo long int para los cálculos intermedios. En +\p gcc, las variables para el preprocesador se pasan como \em -DXXX, donde +\em XXX es la variable a introducir. El uso del tipo long long int en +procesadores de 32 bits puede hacer que las funciones se ejecuten hasta 10 veces +más lentamente que si se utiliza el tipo long int. 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. +\author José Luis García Pallero, jgpallero@gmail.com +\note Este fichero contiene funciones paralelizadas con OpenMP. +\date 05 de abril de 2010 +\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 + 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 _PTOPOL_H_ +#define _PTOPOL_H_ +/******************************************************************************/ +/******************************************************************************/ +#include +#include +#include"libgeoc/errores.h" +#include"libgeoc/geocnan.h" +#include"libgeoc/geocomp.h" +/******************************************************************************/ +/******************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_PTO_FUERA_POLIG +\brief Identificador de punto fuera de un polígono. +\date 12 de abril de 2011: Creación de la constante. +*/ +#define GEOC_PTO_FUERA_POLIG 0 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_PTO_DENTRO_POLIG +\brief Identificador de punto dentro de un polígono. +\date 12 de abril de 2011: Creación de la constante. +*/ +#define GEOC_PTO_DENTRO_POLIG 1 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_PTO_VERTICE_POLIG +\brief Identificador de punto que es un vértice de un polígono. +\date 12 de abril de 2011: Creación de la constante. +*/ +#define GEOC_PTO_VERTICE_POLIG 2 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_PTO_BORDE_POLIG +\brief Identificador de punto que está en el borde de un polígono. +\date 12 de abril de 2011: Creación de la constante. +*/ +#define GEOC_PTO_BORDE_POLIG 3 +/******************************************************************************/ +/******************************************************************************/ +/** +\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=(xMin2))&& \ +((yMin1)<=(yMax2))&&((yMax1)>=(yMin2)))) +/******************************************************************************/ +/******************************************************************************/ +/** +\typedef ptopol_long +\brief Nombre del tipo long int o long long int para utilizar + en los cálculos intermedios de las funciones + \ref PtoEnPoligonoVerticeBorde y \ref PtoEnPoligonoVerticeBordeDouble. Si + los puntos de trabajo están muy alejados de los polígonos pueden darse + casos de resultados erróneos. Sería conveniente que los cálculos + internedios se hiciesen en variables de 64 bits, pero el tipo + long int suele ser de 4 bytes en procesadores de 32 bits. + Mediante la variable del preprocesador PTOPOL_BORDE_LONG_64 indicamos que + este tipo sea long long int, lo que en procesadores de 32 bits + equivale a una variable de 64 bits. +\note Este tipo de dato sólo es para uso interno en el fichero \ref ptopol.c. No + se recomienda su uso fuera de él, ya que habría que tener el cuenta la + variable del preprocesador cada vez que se incluyera este fichero + (\ref ptopol.h) en un programa u otro fichero. +\date 19 de abril de 2011: Creación del tipo. +*/ +#if defined(PTOPOL_BORDE_LONG_64) +typedef long long int ptopol_long; +#else +typedef long int ptopol_long; +#endif +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Indica si hay alguna función compilada en paralelo con OpenMP en el + fichero \ref ptopol.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 13 de abril de 2011: Creación de la función. +\date 25 de agosto de 2011: Adición del argumento de entrada \em version. +*/ +int GeocParOmpPtopol(char version[]); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Indica si se está utilizando el tipo log long int para la + realización de cálculos intermedios en las funciones de chequeo de puntos + en polígonos que son capaces de detectar si un punto está en el borde. +\return Dos posibles valores: + - 0: No se está utilizando log long int. + - Distinto de 0: Sí se está utilizando log long int. +\date 19 de abril de 2011: Creación de la función. +*/ +int GeocLongLongIntPtopol(void); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Comprueba si un punto está contenido en un rectángulo. +\param[in] x Coordenada X del punto de trabajo. +\param[in] y Coordenada Y del punto de trabajo. +\param[in] xMin Coordenada X mínima del rectángulo. +\param[in] xMax Coordenada X máxima del rectángulo. +\param[in] yMin Coordenada Y mínima del rectángulo. +\param[in] yMax Coordenada Y máxima del rectángulo. +\return Varias posibilidades: + - #GEOC_PTO_FUERA_POLIG: El punto está fuera del rectángulo. + - #GEOC_PTO_DENTRO_POLIG: El punto está dentro del rectángulo. + - #GEOC_PTO_VERTICE_POLIG: El punto es un vértice del rectángulo. + - #GEOC_PTO_BORDE_POLIG: El punto pertenece a la frontera del + rectángulo, pero no es un vértice. +\note Esta función asume que \em xMinEsta 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. +\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 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. +\date 12 de abril de 2011: Las variables de salida son ahora constantes + simbólicas. +\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. +\todo Esta función no está probada. +*/ +int PtoEnPoligonoVerticeBorde(const long x, + const long y, + const long* coorX, + const long* coorY, + const size_t N, + const size_t incX, + const size_t incY); +/******************************************************************************/ +/******************************************************************************/ +/** +\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. 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] 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 El polígono de trabajo ha de ser único, sin huecos. Es opcional repetir + las coordenadas del primer punto al final del listado. +\note Los vértices del polígono pueden listarse en sentido dextrógiro o + levógiro. +\note 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. +\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 + real, que convierte a enteros (por redondeo o truncamiento) intermamente, + mediante la aplicación de un factor de escala. +\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. +\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 para aplicar a las coordenadas del + 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. 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. +\return Varias 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. + - #GEOC_PTO_BORDE_POLIG: El punto pertenece a la frontera del polígono, + pero no es un vértice. +\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 El polígono ha de ser único, sin huecos. Es opcional repetir las + coordenadas del primer punto al final del listado. +\note Los vértices del polígono pueden listarse en sentido dextrógiro o + levógiro. +\note El código de esta función es el mismo que el de la función + \ref PtoEnPoligonoVerticeBorde, salvo que convierte internamente varias + variables intermedias de tipo \p double a tipo \p long \p int, que es el + tipo de datos necesario para detectar correctamente si un punto pertenece + al borde de un polígono. +\note Las variables se redondean internamente con la orden + (long)(round(factor*variable)), y se truncan con la orden + (long)(factor*variable). +\note 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. +\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 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 + simbólicas. +\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, + const double y, + const double* coorX, + const double* coorY, + const size_t N, + const size_t incX, + const size_t incY, + const double factor, + const int redondeo); +/******************************************************************************/ +/******************************************************************************/ +/** +\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. 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] 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 El polígono de trabajo ha de ser único, sin huecos. Es opcional repetir + las coordenadas del primer punto al final del listado. +\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 + (long)(round(factor*variable)), y se truncan con la orden + (long)(factor*variable). +\note 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. +\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. +\param[in] x Vector que contiene las coordenadas X de los vértices de una serie + de polígonos, tal y como entraría en la definición de múltiples + elementos (pero sin huecos) para la función \ref PtoEnPoligono. La + marca de separación entre polígonos ha de ser #GEOC_NAN. +\param[in] y Vector que contiene las coordenadas Y de los vértices de una serie + de polígonos, tal y como entraría en la definición de múltiples + elementos (pero sin huecos) para la función \ref PtoEnPoligono. La + marca de separación entre polígonos ha de ser #GEOC_NAN. Este + argumento puede valer NULL, en cuyo caso sólo se trabajará con el + vector \em x. +\param[in] N 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[out] nNan Número de valores #GEOC_NAN encontrados, que es el número de + elementos del vector de salida. +\return Varias posibilidades: + - Si todo ha ido bien, vector que contiene las posiciones en el vector o + vectores originales donde se almacena el valor #GEOC_NAN. Si se + trabaja con los vectores \em x e \em y, la posición sólo se extrae si + ambos vectores contienen #GEOC_NAN para una misma posición. + - NULL: Pueden haber ocurrido dos cosas: + - Si \em nNan vale 0, en los datos de entrada no hay ningún valor + #GEOC_NAN. + - Si \em nNan es mayor que 0, ha ocurrido un error interno de + asignación de memoria. +\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 N, \em incX e + \em incY. +\note Las posiciones de los elementos #GEOC_NAN encontradas se refieren al + número de elementos \em N de los vectores de trabajo. Para encontrar la + posición real en memoria es necesario tener en cuenta las variables + \em incX e \em incY. +\date 13 de abril de 2011: Creación de la función. +\todo Esta función no está probada. +*/ +size_t* BuscaGeocNanEnVectores(const double* x, + const double* y, + const size_t N, + const size_t incX, + const size_t incY, + size_t* nNan); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Extrae los parámetros de inicio y número de elementos de un polígono en + una lista de polígonos separados por un indicador. Esta función está + pensada para el chequeo en paralelo de la inclusión de puntos en + polígonos. +\param[in] posInd Vector que contiene las posiciones de los indicadores en el + vector original. Este argumento es el vector que devuelve la función + \ref BuscaGeocNanEnVectores. +\param[in] indPosInd Índice en el vector de posiciones de indicadores del + indicador que da comienzo al polígono de trabajo. +\param[in] incX Posiciones de separación entre los elementos del vector original + que almacena las coordenadas X del listado de polígonos. Este + argumento siempre ha de ser un número positivo. +\param[in] incY Posiciones de separación entre los elementos del vector original + que almacena las coordenadas Y del listado de polígonos. Este + argumento siempre ha de ser un número positivo. +\param[out] iniX Posición de inicio de la coordenada X del polígono de trabajo + en el vector original que almacena las coordenadas X del listado de + polígonos. Para encontrar la posición real en memoria es necesario + tener en cuenta la variable \em incX. +\param[out] iniY Posición de inicio de la coordenada Y del polígono de trabajo + en el vector original que almacena las coordenadas Y del listado de + polígonos. Para encontrar la posición real en memoria es necesario + tener en cuenta la variable \em incY. +\param[out] nElem Número de elementos que conforman el polígono de trabajo. +\note Esta función no comprueba si el vector \em posInd contiene datos. +\note Esta función asume que el vector \em posInd contiene un número \b *PAR* de + datos. +\note Esta función asume que el argumento \em indPosInd no es la última posición + del vector \em posInd. +\date 13 de abril de 2011: Creación de la función. +\todo Esta función no está probada. +*/ +void DatosPoliIndividualEnVecInd(const size_t* posInd, + const size_t indPosInd, + const size_t incX, + const size_t incY, + size_t* iniX, + size_t* iniY, + size_t* nElem); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Comprueba si un punto está contenido en una serie de polígonos + individuales 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. +\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 de los + elementos. Puede contener varios polígonos, pero no huecos (si los + hay, serán tratados como otros polígonos). +\param[in] coorY Vector que contiene las coordenadas Y de los vértices de los + elementos. Puede contener varios polígonos, pero no huecos (si los + hay, serán tratados como otros polígonos). +\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] posNan Vector que almacena las posiciones en los vectores \em coorX y + \em coorY de los elementos #GEOC_NAN, que separan los polígonos + individuales. Este vector es la salida de la función + \ref BuscaGeocNanEnVectores. +\param[in] nNan Número de elementos del vector \em posNan. +\param[out] poli Número del polígono en que está incluido el punto de trabajo. + Si hay varios polígonos que contienen al punto de trabajo no se + puede asegurar cuál de ellos será el indicado en este argumento. + Este argumento sólo tiene sentido si el valor retornado por la + función es distinto de #GEOC_PTO_FUERA_POLIG. +\return Dos posibilidades: + - #GEOC_PTO_FUERA_POLIG: El punto está fuera de todos los polígonos + listados. + - #GEOC_PTO_DENTRO_POLIG: El punto está dentro de, al menos, un polígono + de entre los listados. +\note Esta función se puede ejecutar en paralelo con OpenMP. +\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 no comprueba si el número de elementos del vector \em posNan + es congruente con el valor pasado en \em nNan. +\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 + 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 es la misma que la de la + función \ref PtoEnPoligono. Las marcas de comienzo y final de los + listados, así como las de separación entre polígonos han de ser valores + #GEOC_NAN. +\note Aunque los vectores \em coorX y \em coorY sólo contengan un polígono, los + elementos primero y último han de ser #GEOC_NAN. +\note Los huecos en los polígonos no serán tenidos en cuenta, serán tratados + como polígonos individuales. +\date 14 de abril de 2011: Creación de la función. +\todo Esta función no está probada. +*/ +int PtoEnPoligonoInd(const double x, + const double y, + const double* coorX, + const double* coorY, + const size_t N, + const size_t incX, + const size_t incY, + const size_t* posNan, + const size_t nNan, + size_t* poli); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Comprueba si un punto está contenido en una serie de polígonos + individuales 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 de los + elementos. Puede contener varios polígonos, pero no huecos (si los + hay, serán tratados como otros polígonos). +\param[in] coorY Vector que contiene las coordenadas Y de los vértices de los + elementos. Puede contener varios polígonos, pero no huecos (si los + hay, serán tratados como otros polígonos). +\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] posNan Vector que almacena las posiciones en los vectores \em coorX y + \em coorY de los elementos #GEOC_NAN, que separan los polígonos + individuales. Este vector es la salida de la función + \ref BuscaGeocNanEnVectores. +\param[in] nNan Número de elementos del vector \em posNan. +\param[out] poli Número del polígono en que está incluido el punto de trabajo. + Si hay varios polígonos que contienen al punto de trabajo no se + puede asegurar cuál de ellos será el indicado en este argumento. + Este argumento sólo tiene sentido si el valor retornado por la + función es distinto de #GEOC_PTO_FUERA_POLIG. +\return Dos posibilidades: + - #GEOC_PTO_FUERA_POLIG: El punto está fuera de todos los polígonos + listados. + - #GEOC_PTO_DENTRO_POLIG: El punto está dentro de, al menos, un polígono + de entre los listados. + - #GEOC_PTO_VERTICE_POLIG: El punto es un vértice de, al menos, un + polígono de entre los listados. +\note Esta función se puede ejecutar en paralelo con OpenMP. +\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 no comprueba si el número de elementos del vector \em posNan + es congruente con el valor pasado en \em nNan. +\note Esta función no detecta el caso de que el punto de trabajo esté en el + borde del polígono. 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 es la misma que la de la + función \ref PtoEnPoligono. Las marcas de comienzo y final de los + listados, así como las de separación entre polígonos han de ser valores + #GEOC_NAN. +\note Aunque los vectores \em coorX y \em coorY sólo contengan un polígono, los + elementos primero y último han de ser #GEOC_NAN. +\note Los huecos en los polígonos no serán tenidos en cuenta, serán tratados + como polígonos individuales. +\date 14 de abril de 2011: Creación de la función. +\todo Esta función no está probada. +*/ +int PtoEnPoligonoVerticeInd(const double x, + const double y, + const double* coorX, + const double* coorY, + const size_t N, + const size_t incX, + const size_t incY, + const size_t* posNan, + const size_t nNan, + size_t* poli); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Comprueba si un punto está contenido en una serie de polígonos + individuales 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 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 de los + elementos. Puede contener varios polígonos, pero no huecos (si los + hay, serán tratados como otros polígonos). +\param[in] coorY Vector que contiene las coordenadas Y de los vértices de los + elementos. Puede contener varios polígonos, pero no huecos (si los + hay, serán tratados como otros polígonos). +\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] posNan Vector que almacena las posiciones en los vectores \em coorX y + \em coorY de los elementos #GEOC_NAN, que separan los polígonos + individuales. Este vector es la salida de la función + \ref BuscaGeocNanEnVectores. +\param[in] nNan Número de elementos del vector \em posNan. +\param[out] poli Número del polígono en que está incluido el punto de trabajo. + Si hay varios polígonos que contienen al punto de trabajo no se + puede asegurar cuál de ellos será el indicado en este argumento. + Este argumento sólo tiene sentido si el valor retornado por la + función es distinto de #GEOC_PTO_FUERA_POLIG. +\return Dos posibilidades: + - #GEOC_PTO_FUERA_POLIG: El punto está fuera de todos los polígonos + listados. + - #GEOC_PTO_DENTRO_POLIG: El punto está dentro de, al menos, un polígono + de entre los listados. + - #GEOC_PTO_VERTICE_POLIG: El punto es un vértice de, al menos, un + polígono de entre los listados. + - #GEOC_PTO_BORDE_POLIG: El punto pertenece a la frontera de, al menos, + un polígono de entre los listados, pero no es un vértice. +\note Esta función se puede ejecutar en paralelo con OpenMP. +\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 no comprueba si el número de elementos del vector \em posNan + es congruente con el valor pasado en \em nNan. +\note La estructura de los vectores de coordenadas es la misma que la de la + función \ref PtoEnPoligono. Las marcas de comienzo y final de los + listados, así como las de separación entre polígonos han de ser valores + #GEOC_NAN. +\note Aunque los vectores \em coorX y \em coorY sólo contengan un polígono, los + elementos primero y último han de ser #GEOC_NAN. +\note Los huecos en los polígonos no serán tenidos en cuenta, serán tratados + como polígonos individuales. +\note 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. +\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 14 de abril de 2011: Creación de la función. +\todo Esta función no está probada. +*/ +int PtoEnPoligonoVerticeBordeInd(const long x, + const long y, + const long* coorX, + const long* coorY, + const size_t N, + const size_t incX, + const size_t incY, + const size_t* posNan, + const size_t nNan, + size_t* poli); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Comprueba si un punto está contenido en una serie de polígonos + individuales 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 a aplicación de un factor + de escala. +\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 de los + elementos. Puede contener varios polígonos, pero no huecos (si los + hay, serán tratados como otros polígonos). +\param[in] coorY Vector que contiene las coordenadas Y de los vértices de los + elementos. Puede contener varios polígonos, pero no huecos (si los + hay, serán tratados como otros polígonos). +\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 para aplicar a las coordenadas del + punto de trabajo y de los vértices de los polígonos, 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[in] posNan Vector que almacena las posiciones en los vectores \em coorX y + \em coorY de los elementos #GEOC_NAN, que separan los polígonos + individuales. Este vector es la salida de la función + \ref BuscaGeocNanEnVectores. +\param[in] nNan Número de elementos del vector \em posNan. +\param[out] poli Número del polígono en que está incluido el punto de trabajo. + Si hay varios polígonos que contienen al punto de trabajo no se + puede asegurar cuál de ellos será el indicado en este argumento. + Este argumento sólo tiene sentido si el valor retornado por la + función es distinto de #GEOC_PTO_FUERA_POLIG. +\return Dos posibilidades: + - #GEOC_PTO_FUERA_POLIG: El punto está fuera de todos los polígonos + listados. + - #GEOC_PTO_DENTRO_POLIG: El punto está dentro de, al menos, un polígono + de entre los listados. + - #GEOC_PTO_VERTICE_POLIG: El punto es un vértice de, al menos, un + polígono de entre los listados. + - #GEOC_PTO_BORDE_POLIG: El punto pertenece a la frontera de, al menos, + un polígono de entre los listados, pero no es un vértice. +\note Esta función se puede ejecutar en paralelo con OpenMP. +\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 no comprueba si el número de elementos del vector \em posNan + es congruente con el valor pasado en \em nNan. +\note Las variables se redondean internamente con la orden + (long)(round(factor*variable)), y se truncan con la orden + (long)(factor*variable). +\note La estructura de los vectores de coordenadas es la misma que la de la + función \ref PtoEnPoligono. Las marcas de comienzo y final de los + listados, así como las de separación entre polígonos han de ser valores + #GEOC_NAN. +\note Aunque los vectores \em coorX y \em coorY sólo contengan un polígono, los + elementos primero y último han de ser #GEOC_NAN. +\note Los huecos en los polígonos no serán tenidos en cuenta, serán tratados + como polígonos individuales. +\note 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. +\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 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, + const double y, + const double* coorX, + const double* coorY, + const size_t N, + const size_t incX, + const size_t incY, + const double factor, + const int redondeo, + const size_t* posNan, + const size_t nNan, + 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 +/******************************************************************************/ +/******************************************************************************/ +#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/recpolil.h b/src/libgeoc/recpolil.h new file mode 100644 index 0000000..188f934 --- /dev/null +++ b/src/libgeoc/recpolil.h @@ -0,0 +1,440 @@ +/* -*- coding: utf-8 -*- */ +/** +\ingroup geom gshhs +@{ +\file recpolil.h +\brief Definición de estructuras y declaración de funciones para el recorte de + polilíneas por medio de polígonos. +\author José Luis García Pallero, jgpallero@gmail.com +\date 04 de junio 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. +*/ +/******************************************************************************/ +/******************************************************************************/ +#ifndef _RECPOLIL_H_ +#define _RECPOLIL_H_ +/******************************************************************************/ +/******************************************************************************/ +#include +#include +#include"libgeoc/errores.h" +#include"libgeoc/eucli.h" +#include"libgeoc/geocnan.h" +#include"libgeoc/greiner.h" +#include"libgeoc/polig.h" +#include"libgeoc/polil.h" +#include"libgeoc/ptopol.h" +#include"libgeoc/segmento.h" +/******************************************************************************/ +/******************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_RECPOLIL_BUFFER_PTOS +\brief Número de puntos para ir asignando memoria en bloques para las polilíneas + de salida en la funcion \ref Paso2Recpolil. Ha de ser un número mayor o + igual a 2. +\date 04 de junio de 2011: Creación de la constante. +*/ +#define GEOC_RECPOLIL_BUFFER_PTOS 100 +/******************************************************************************/ +/******************************************************************************/ +/** \enum GEOC_OP_BOOL_POLIL +\brief Operación booleana entre polilínea y polígono. +\date 04 de junio de 2011: Creación del tipo. +*/ +enum GEOC_OP_BOOL_POLIL +{ + /** \brief Polilínea interior al polígono. */ + GeocOpBoolDentro=111, + /** \brief Polilínea exterior al polígono. */ + GeocOpBoolFuera=112 +}; +/******************************************************************************/ +/******************************************************************************/ +/** \struct _vertPolilClip +\brief Estructura de definición de un vértice de una polilínea usada en + operaciones de recorte. La polilínea se almacena en memoria como una + lista doblemente enlazada de vértices. +\date 04 de junio de 2011: Creación de la estructura. +*/ +typedef struct _vertPolilClip +{ + /** \brief Coordenada X del vértice. */ + double x; + /** \brief Coordenada Y del vértice. */ + double y; + /** \brief Vértice anterior. */ + struct _vertPolilClip* anterior; + /** \brief Vértice siguiente. */ + struct _vertPolilClip* siguiente; + /** + \brief Indicador de punto de la polilínea original. + + Dos posibilidades: + - 0: No es un punto de la polilínea original. + - Distinto de 0: Sí es un punto de la polilínea original. + */ + char orig; + /** + \brief Posición del vértice con respecto al polígono de recorte. + + Tres posibilidades: + - #GEOC_PTO_FUERA_POLIG: El punto está fuera del polígono. + - #GEOC_PTO_BORDE_POLIG: El punto está en el borde o en un vértice + del polígono. + - #GEOC_PTO_DENTRO_POLIG: El punto está dentro del polígono. + */ + char pos; + /** \brief Distancia, en tanto por uno, de un nodo de intersección con + respecto al primer vértice del segmento que lo contiene. */ + double alfa; +}vertPolilClip; +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Crea un vértice de tipo \ref _vertPolilClip y lo inserta entre otros dos. +\param[in] x Coordenada X del vértice. +\param[in] y Coordenada Y del vértice. +\param[in] anterior Vértice anterior (puede ser \p NULL). +\param[in] siguiente Vértice siguiente (puede ser \p NULL). +\param[in] orig Campo _vertPolilClip::orig. +\param[in] pos Campo _vertPolilClip::pos. +\param[in] alfa Campo _vertPolilClip::alfa. +\return Puntero al nuevo vértice creado. Si se devuelve \p NULL, ha ocurrido un + error de asignación de memoria. +\date 04 de junio de 2011: Creación de la función. +\todo Esta función todavía no está probada. +*/ +vertPolilClip* CreaVertPolilClip(const double x, + const double y, + vertPolilClip* anterior, + vertPolilClip* siguiente, + const char orig, + const char pos, + const double alfa); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Crea una polilínea, como una lista doblemente enlazada de elementos + \ref _vertPolilClip. +\param[in] x Vector de coordenadas X de los nodos de la polilínea. +\param[in] y Vector de coordenadas Y de los nodos de la polilínea. +\param[in] nCoor 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. +\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 \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. +\todo Esta función todavía no está probada. +*/ +vertPolilClip* CreaPolilClip(const double* x, + const double* y, + const size_t nCoor, + const size_t incX, + const size_t incY); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Libera la memoria asignada a una polilínea almacenada como una lista + doblemente enlazada de elementos \ref _vertPolilClip. +\param[in] poli Puntero al primer elemento de la polilínea. +\note Esta función no comprueba si hay vértices de la polilínea anteriores al + vértice de entrada, por lo que si se quiere liberar toda la memoria + asignada a una polilínea, el vértice pasado ha de ser el primero de la + lista. +\date 04 de junio de 2011: Creación de la función. +\todo Esta función todavía no está probada. +*/ +void LibMemPolilClip(vertPolilClip* poli); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Elimina los vértices no originales de una polilínea almacenada como una + lista doblemente enlazada de elementos \ref _vertPolilClip. +\param[in] poli Puntero al primer elemento de la polilínea. +\return Puntero al primer elemento de la polilínea original. Si se devuelve + \p NULL, ninguno de los vértices pertenecía a la polilínea original. +\note Los vértices eliminados por esta función son todos aquéllos cuyo campo + _vertPolilClip::orig sea igual a 0. +\note Aunque se supone que el primer vértice de una polilínea siempre es un + vértice original, si no lo es, la variable de entrada queda modificada. + Por tanto, siempre es recomendable capturar la variable de salida, que + garantiza la posición del primer elemento. +\date 04 de junio de 2011: Creación de la función. +\todo Esta función todavía no está probada. +*/ +vertPolilClip* ReiniciaPolilClip(vertPolilClip* poli); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Busca el siguiente vértice original en una polilínea. +\param[in] vert Puntero al vértice a partir del cual se ha de buscar. +\return Puntero al siguiente vértice original en la polilínea. Si se devuelve + \p NULL, se ha llegado al final. +\note Los vértices no originales son todos aquéllos cuyo campo + _vertPolilClip::orig es distinto de 0. +\date 04 de junio de 2011: Creación de la función. +\todo Esta función todavía no está probada. +*/ +vertPolilClip* SiguienteVertOrigPolilClip(vertPolilClip* vert); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Inserta un vértice de tipo \ref _vertPolilClip entre otros dos, + atendiendo al campo _vertPolilClip::alfa. +\param[in] ins Vértice a insertar. +\param[in] extremoIni Extremo inicial del segmento donde se insertará \em ins. +\param[in] extremoFin Extremo final del segmento donde se insertará \em ins. +\note Esta función asume que todos los elementos pasados tienen memoria + asignada. +\note Si entre \em extremoIni y \em extremoFin hay más vértices, \em ins se + insertará de tal modo que los campos _vertPolilClip::alfa queden ordenados + de menor a mayor. +\note Si el campo _vertPolilClip::alfa de \em ins tiene el mismo valor que el + de \em extremoIni, \em ins se insertará justo a continuación de + \em extremoIni. +\note Si el campo _vertPolilClip::alfa de \em ins tiene el mismo valor que el + de \em extremoFin, \em ins se insertará justo antes de \em extremoIni. +\date 04 de junio de 2011: Creación de la función. +\todo Esta función todavía no está probada. +*/ +void InsertaVertPolilClip(vertPolilClip* ins, + vertPolilClip* extremoIni, + vertPolilClip* extremoFin); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Cuenta el número de vértices originales que hay en una polilínea + almacenada como una lista doblemente enlazada de elementos + \ref _vertPolilClip. +\param[in] poli Polilínea, almacenado como una lista doblemente enlazada de + elementos \ref _vertPolilClip. Sólo se tienen en cuenta los vértices + originales de la polilínea, que son todos aquéllos cuyo campo + _vertPolilClip::orig es distinto de 0. +\return Número de vértices originales almacenados. +\note Esta función no comprueba si la variable \em poli es una polilínea + correctamente almacenada. +\date 04 de junio de 2011: Creación de la función. +\todo Esta función no está probada. +*/ +size_t NumeroVertOrigPolilClip(vertPolilClip* poli); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Cuenta el número total de vértices que hay en una polilínea almacenada + como una lista doblemente enlazada de elementos \ref _vertPolilClip. +\param[in] poli Polilínea, almacenado como una lista doblemente enlazada de + elementos \ref _vertPolilClip. Se tienen en cuenta todos los + vértices. +\return Número total de vértices almacenados. +\note Esta función no comprueba si la variable \em poli es una polilínea + correctamente almacenada. +\date 04 de junio de 2011: Creación de la función. +\todo Esta función no está probada. +*/ +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. +\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 + ejecución de la función se le han añadido los puntos de + intersección con el polígono de recorte y se han asignado los + valores correctos al campo _vertPolilClip::pos de cada vértice. +\param[in] poliRec Polígono de recorte, representado como una lista doblemente + enlazada de elementos \ref _vertPoliClip. +\param[out] nIntersec Número de intersecciones (intersecciones propiamente + dichas y puntos en el borde del polígono) calculadas. +\return Variable de estado. 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 no comprueba si las variables \em polil y \em poliRec son + estructuras correctamente almacenadas. +\note El polígono \em poliRec puede provenir de una operación booleana previa + entre polígonos, ya que sólo se recorrerán sus vértices originales, que + serán aquéllos cuyo campo _vertPoliClip::interseccion valga 0. +\date 06 de junio de 2011: Creación de la función. +\todo Esta función no está probada. +*/ +int Paso1Recpolil(vertPolilClip* poli, + vertPoliClip* poliRec, + size_t* nIntersec); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Realiza el paso número 2 del algoritmo de recorte de polilíneas, que + consiste en la generación de lss polilíneas resultado. +\param[in] poli Polilínea a recortar, representada como una lista doblemente + enlazada de elementos \ref _vertPolilClip, tal y como sale de la + función \ref Paso1Recpolil. +\param[in] op Identificador de la operación a realizar. Ha de ser un elemento + del tipo enumerado #GEOC_OP_BOOL_POLIL. +\return Estructura \ref polil con las polilíneas resultado de la operación. Si + se devuelve \p NULL ha ocurrido un error de asignación de memoria. +\note Esta función no comprueba si la variable \em polil es una polilínea + correctamente almacenada. +\date 06 de junio de 2011: Creación de la función. +\todo Esta función no está probada. +*/ +polil* Paso2Recpolil(vertPolilClip* poli, + const enum GEOC_OP_BOOL_POLIL op); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Recorta una polilínea según un polígono de recorte. +\param[in,out] poli Polilínea de trabajo, representada como una lista doblemente + enlazada de elementos \ref _vertPolilClip. Al término de la + ejecución de la función se le han añadido los puntos de + intersección con el polígono de recorte y se han asignado los + valores correctos al campo _vertPolilClip::pos de cada vértice. +\param[in] poliRec Polígono de recorte, representado como una lista doblemente + enlazada de elementos \ref _vertPoliClip. +\param[in] op Identificador de la operación a realizar. Ha de ser un elemento + del tipo enumerado #GEOC_OP_BOOL_POLIL. Varias posibilidades: + - #GeocOpBoolDentro: Calcula la porción de \em poli que está dentro + \em poliRec. + - #GeocOpBoolFuera: Calcula la porción de \em poli que está fuera + \em poliRec. +\param[out] nIntersec Número de intersecciones calculadas. +\return Estructura \ref polil con las polilíneas resultado de la operación. Si + se devuelve \p NULL ha ocurrido un error de asignación de memoria. +\note Esta función no comprueba si las variables \em poli y \em poliRec son + estructuras correctamente almacenadas. +\note Esta función no comprueba internamente si \em op pertenece al tipo + enumerado #GEOC_OP_BOOL_POLIL. Si se introduce un valor no perteneciente + al tipo, se realiza la operación #GeocOpBoolDentro. +\note Esta función asume que los puntos de borde pertenecen al interior del + 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. +*/ +polil* RecortaPolil(vertPolilClip* poli, + vertPoliClip* poliRec, + const enum GEOC_OP_BOOL_POLIL op, + size_t* nIntersec); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Recorta múltiples polilíneas según múltiples polígonos de recorte. +\param[in] poli Estructura \ref polil que almacena las polilíneas de trabajo. +\param[in] poliRec Estructura \ref polig que almacena los polígonos de recorte. +\param[in] op Identificador de la operación a realizar. Ha de ser un elemento + del tipo enumerado #GEOC_OP_BOOL_POLIL. Varias posibilidades: + - #GeocOpBoolDentro: Calcula la porción de las polilíneas almacenadas + en \em poli que están dentro de los polígonos almacenados en + \em poliRec. + - #GeocOpBoolFuera: Calcula la porción de las polilíneas almacenadas + en \em poli que están fuera de los polígonos almacenados en + \em poliRec. +\param[out] nIntersec Número total de intersecciones calculadas entre todas las + polilíneas con todos los polígonos. +\return Estructura \ref polil con las polilíneas resultado de las operaciones. + Si se devuelve \p NULL ha ocurrido un error de asignación de memoria. +\note Esta función realiza la operación \em op con todas las combinaciones + posibles de polilíneas y polígonos. Es decir, se recorren todas las + polilíneas y con cada una de ellas se realiza la operación \em op con cada + polígono almacenado en \em poliRec. +\note Esta función no comprueba si las variables \em poli y \em poliRec son + estructuras correctamente almacenadas. +\note Esta función no comprueba internamente si \em op pertenece al tipo + enumerado #GEOC_OP_BOOL_POLIL. Si se introduce un valor no perteneciente + al tipo, se realiza la operación #GeocOpBoolDentro. +\note Esta función asume que los puntos de borde pertenecen al interior de los + polígonos de recorte. +\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. +*/ +polil* RecortaPolilMult(const polil* poli, + const polig* poliRec, + const enum GEOC_OP_BOOL_POLIL op, + size_t* nIntersec); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Crea una estructura \ref polil a partir de todos los vértices de una + polilínea almacenada como una lista doblemente enlazada de elementos + \ref _vertPolilClip. +\param[in] poli Polilínea de trabajo, representada como una lista doblemente + enlazada de elementos \ref _vertPolilClip. El puntero pasado ha + de apuntar al primer elemento de la polilínea (no se controla + internamente). +\return Estructura \ref polil que representa la polilínea. Si se devuelve + \p NULL ha ocurrido un error de asignación de memoria. +\note Esta función no comprueba si la variable \em poli es una polilínea + correctamente almacenada. +\note Esta función realiza una copia en memoria de las coordenadas de los + vértices de la estructura \em poli a la estructura de salida. +\date 06 de junio de 2011: Creación de la función. +\todo Esta función no está probada. +*/ +polil* CreaPolilPolilClip(vertPolilClip* poli); +/******************************************************************************/ +/******************************************************************************/ +#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/segmento.h b/src/libgeoc/segmento.h new file mode 100644 index 0000000..7ec3dab --- /dev/null +++ b/src/libgeoc/segmento.h @@ -0,0 +1,377 @@ +/* -*- coding: utf-8 -*- */ +/** +\ingroup geom +@{ +\file segmento.h +\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 +\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 + 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 _SEGMENTO_H_ +#define _SEGMENTO_H_ +/******************************************************************************/ +/******************************************************************************/ +#include"libgeoc/fgeneral.h" +#include"libgeoc/ptopol.h" +/******************************************************************************/ +/******************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_SEG_NO_INTERSEC +\brief Identificador de que dos segmentos no se cortan. +\date 14 de mayo de 2011: Creación de la constante. +*/ +#define GEOC_SEG_NO_INTERSEC 0 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_SEG_INTERSEC +\brief Identificador de que dos segmentos se cortan en un punto, pero no son + colineales. +\date 14 de mayo de 2011: Creación de la constante. +*/ +#define GEOC_SEG_INTERSEC 1 +/******************************************************************************/ +/******************************************************************************/ +/** +\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 (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_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_EXTREMOS_COLIN 4 +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_SEG_INTERSEC_MISMO_SEG +\brief Identificador de que dos segmentos tienen todos sus puntos extremos en + común. +\date 21 de mayo de 2011: Creación de la constante. +*/ +#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, 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 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. +\param[in] y Coordenada Y del punto de trabajo. +\param[in] xIni Coordenada X del punto inicial del segmento que define la recta. +\param[in] yIni Coordenada Y del punto inicial del segmento que define la recta. +\param[in] xFin Coordenada X del punto final del segmento que define la recta. +\param[in] yFin Coordenada Y del punto final del segmento que define la recta. +\return Varias posibilidades: + - Menor que 0: El punto está a la derecha de la recta. + - 0: El punto pertenece a la recta. + - Mayor que 0: El punto está a la izquierda de la recta. +\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 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 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. +*/ +#define POS_PTO_RECTA_2D(x,y,xIni,yIni,xFin,yFin) \ +(((xIni)-(x))*((yFin)-(y))-((xFin)-(x))*((yIni)-(y))) +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Comprueba si tres puntos (A, B, C) del plano son colineales. +\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. +\return Dos posibilidades: + - 0: Los puntos no son colineales. + - Distinto de 0: Los puntos son colineales. +\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. +*/ +int TresPuntosColineales2D(const double xA, + const double yA, + const double xB, + const double yB, + const double xC, + const double yC); +/******************************************************************************/ +/******************************************************************************/ +/** +\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 son + colineales. +\param[in] x Coordenada X del punto a comprobar. +\param[in] y Coordenada Y del punto a comprobar. +\param[in] xA Coordenada X del primer punto del segmento. +\param[in] yA Coordenada Y del primer punto del segmento. +\param[in] xB Coordenada X del segundo punto del segmento. +\param[in] yB Coordenada Y del segundo punto del segmento. +\return Dos posibilidades: + - 0: El punto de trabajo no está situado entre los dos puntos dato o es + igual a alguno de ellos. + - Distinto de 0: El punto de trabajo sí está situado entre los dos + puntos dato. +\note Esta función sirve de apoyo para \ref PtoComunSegmParalelos2D. +\date 14 de mayo de 2011: Creación de la función. +\todo Esta función no está probada. +*/ +int PuntoEntreDosPuntos2DColin(const double x, + const double y, + const double xA, + const double yA, + const double xB, + const double yB); +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Calcula un punto común entre dos segmentos paralelos AB y CD. +\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[out] x Coordenada X del punto común. +\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_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 + común. +\note Esta función sirve de apoyo para \ref IntersecSegmentos2D. +\note Esta función utiliza internamente la función \ref TresPuntosColineales2D, + que no es robusta. En consecuencia, los resultados de esta función tampoco + lo son. +\note Si los segmentos se tocan en los dos extremos (son el mismo segmento), las + coordenadas devueltas son siempre las del vértice A. +\note Si los segmentos tienen más de un punto en común, pero no son el mismo + segmento, las coordenadas de salida siempre son las de un punto extremo de + 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_EXTREMOS_COLIN y #GEOC_SEG_INTERSEC_MISMO_SEG. +\todo Esta función no está probada. +*/ +int PtoComunSegmParalelos2D(const double xA, + const double yA, + const double xB, + const double yB, + const double xC, + const double yC, + const double xD, + const double yD, + double* x, + double* y); +/******************************************************************************/ +/******************************************************************************/ +/** +\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[out] x Coordenada X del punto común. +\param[out] y Coordenada Y del punto común. +\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 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 + común. +\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 Si los segmentos se tocan en los dos extremos (son el mismo segmento), las + coordenadas devueltas son siempre las del vértice A. +\note Si los segmentos tienen más de un punto en común, pero no son el mismo + segmento, las coordenadas de salida siempre son las de un punto extremo de + 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, + const double xB, + const double yB, + const double xC, + const double yC, + const double xD, + const double yD, + double* x, + 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 +/******************************************************************************/ +/******************************************************************************/ +#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/ventorno.h b/src/libgeoc/ventorno.h new file mode 100644 index 0000000..d330d35 --- /dev/null +++ b/src/libgeoc/ventorno.h @@ -0,0 +1,100 @@ +/* -*- coding: utf-8 -*- */ +/** +\ingroup anespec general +@{ +\file ventorno.h +\brief Definición de variables de entorno y declaración de funciones para su + control. +\author José Luis García Pallero, jgpallero@gmail.com +\date 31 de marzo de 2011 +\section Licencia Licencia +Copyright (c) 2011, 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 _VENTORNO_H_ +#define _VENTORNO_H_ +/******************************************************************************/ +/******************************************************************************/ +#include +#include +/******************************************************************************/ +/******************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ENV_NOM_VAR_PILOMBS +\brief Nombre de la variable de entorno para imprimir o no pasos intermedios en + la ejecución de la función \ref AnalisisLombSig. +\date 31 de marzo de 2011: Creación de la constante. +*/ +#define GEOC_ENV_NOM_VAR_PILOMBS "GEOC_ENV_PILOMBS" +/******************************************************************************/ +/******************************************************************************/ +/** +\def GEOC_ENV_VAL_REF_PILOMBS +\brief Valor de referencia de la variable de entorno #GEOC_ENV_NOM_VAR_PILOMBS. +\date 31 de marzo de 2011: Creación de la constante. +*/ +#define GEOC_ENV_VAL_REF_PILOMBS "0" +/******************************************************************************/ +/******************************************************************************/ +/** +\brief Comprueba si una variable de entorno está definida y es igual a un valor. +\param[in] var Nombre de la variable de entorno a comprobar. +\param[in] valRef Valor de referencia de la variable de entorno. +\return Tres posibilidades: + - Menor que 0: La variable de entorno no está definida. + - 0: La variable de entorno existe, pero tiene un valor distinto a + \em valRef. + - Mayor que 0: La variable de entorno existe y tiene el mismo valor que + \em valRef. +\date 31 de marzo de 2011: Creación de la función. +\todo Esta función todavía no está probada. +*/ +int VarEnvValRef(const char* var, + const char* valRef); +/******************************************************************************/ +/******************************************************************************/ +#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/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;i0 ? 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;i0 ? 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;i0 ? 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 + * + * This file is part of OctCLIP. + * + * OctCLIP is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, see + * . + */ +/******************************************************************************/ +/******************************************************************************/ +#ifndef _OCTCLIP_H_ +#define _OCTCLIP_H_ +/******************************************************************************/ +/******************************************************************************/ +#include"libgeoc/geom.h" +/******************************************************************************/ +/******************************************************************************/ +#endif +/******************************************************************************/ +/******************************************************************************/ diff --git a/src/polig.c b/src/polig.c new file mode 100644 index 0000000..1252999 --- /dev/null +++ b/src/polig.c @@ -0,0 +1,2048 @@ +/* -*- coding: utf-8 -*- */ +/** +\ingroup geom gshhs +@{ +\file polig.c +\brief Definición de funciones para el trabajo con polígonos. +\author José Luis García Pallero, jgpallero@gmail.com +\note Este fichero contiene funciones paralelizadas con OpenMP. +\date 20 de abril 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/polig.h" +/******************************************************************************/ +/******************************************************************************/ +int GeocParOmpPolig(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 +} +/******************************************************************************/ +/******************************************************************************/ +polig* IniciaPoligVacio(void) +{ + //estructura de salida + polig* sal=NULL; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //asignamos memoria para la estructura + sal = (polig*)malloc(sizeof(polig)); + //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; + } + //inicializamos los campos escalares a 0 + sal->nElem = 0; + sal->nPolig = 0; + sal->hayLim = 0; + sal->hayArea = 0; + //inicializamos los campos vectoriales a NULL + sal->x = NULL; + sal->y = NULL; + sal->posIni = NULL; + sal->nVert = NULL; + sal->xMin = NULL; + sal->xMax = NULL; + sal->yMin = NULL; + sal->yMax = NULL; + sal->area = NULL; + sal->atr = NULL; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return sal; +} +/******************************************************************************/ +/******************************************************************************/ +int AuxCreaPolig1(const size_t nElem, + const size_t* posNanX, + const size_t* posNanY, + const size_t nNanX, + const size_t nNanY, + size_t* nElemMax, + size_t* nPolig) +{ + //índice para recorrer bucles + size_t i=0; + //variable de salida + int estado=GEOC_ERR_NO_ERROR; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //comprobamos si hay el mismo número de NaN en los dos vectores + if(nNanX!=nNanY) + { + //salimos de la función + return GEOC_ERR_POLIG_VEC_DISTINTO_NUM_POLIG; + } + //comprobamos si hay NaN en las mismas posiciones de los vectores + for(i=0;i fin del #pragma omp parallel sections + //comprobamos los posibles errores de asignación de memoria + if(((posNanX==NULL)&&(nNanX!=0))||((posNanY==NULL)&&(nNanY!=0))) + { + //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; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //comprobamos si los vectores tienen bien colocados los NaN y calculamos + //el número máximo de elementos de los vectores de la estructura y el + //número de polígonos + *idError = AuxCreaPolig1(nElem,posNanX,posNanY,nNanX,nNanY,&nElemMax, + &nPolig); + //comprobamos los posibles errores + if(*idError!=GEOC_ERR_NO_ERROR) + { + //liberamos la memoria asignada + LibMemPolig(sal); + free(posNanX); + free(posNanY); + //escribimos el mensaje de error + if(*idError==GEOC_ERR_POLIG_VEC_DISTINTO_NUM_POLIG) + { + GEOC_ERROR("Error: Los vectores de trabajo no contienen el mismo " + "número de polígonos"); + } + else if(*idError==GEOC_ERR_POLIG_VEC_DISTINTOS_POLIG) + { + GEOC_ERROR("Error: Los vectores de trabajo no contienen los mismos " + "polígonos"); + } + //salimos de la función + return NULL; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //asignamos el número de polígonos + sal->nPolig = nPolig; + //paralelización con OpenMP +#if defined(_OPENMP) +#pragma omp parallel sections default(none) \ + shared(sal,nElemMax,nPolig) +#endif +{ + //asignamos memoria para los vectores de la estructura +#if defined(_OPENMP) +#pragma omp section +#endif + sal->x = (double*)malloc(nElemMax*sizeof(double)); +#if defined(_OPENMP) +#pragma omp section +#endif + sal->y = (double*)malloc(nElemMax*sizeof(double)); +#if defined(_OPENMP) +#pragma omp section +#endif + sal->posIni = (size_t*)malloc(nPolig*sizeof(double)); +#if defined(_OPENMP) +#pragma omp section +#endif + sal->nVert = (size_t*)malloc(nPolig*sizeof(double)); +} // --> fin del #pragma omp parallel sections + //comprobamos los posibles errores + if((sal->x==NULL)||(sal->y==NULL)||(sal->posIni==NULL)||(sal->nVert==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; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //copiamos los polígonos a la estructura + //como ya sabemos que el número de NaN y sus posiciones son los mismos para + //los vectores x e y, trabajamos con los valores para el vector x + AuxCreaPolig3(x,y,nElem,incX,incY,posNanX,nNanX,sal->x,sal->y,sal->posIni, + sal->nVert,&ptos,&nPolig); + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //comprobamos si hay de verdad algún polígono + if(nPolig==0) + { + //liberamos la memoria asignada + LibMemPolig(sal); + free(posNanX); + free(posNanY); + //creamos la estructura vacía + sal = IniciaPoligVacio(); + //comprobamos los posibles errores + if(sal==NULL) + { + //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; + } + //salimos de la función + return sal; + } + //asignamos el número de elementos a la estructura + sal->nElem = ptos; + //comprobamos si hay que reajustar el tamaño de los vectores de coordenadas + if(ptos!=nElemMax) + { + //asignamos el nuevo tamaño de los vectores + sal->nElem = ptos; + //reajustamos los tamaños + sal->x = (double*)realloc(sal->x,ptos*sizeof(double)); + sal->y = (double*)realloc(sal->y,ptos*sizeof(double)); + } + //comprobamos si el número de polígonos es el estimado + if(nPolig!=sal->nPolig) + { + //asignamos de nuevo la variable de número de polígonos + sal->nPolig = nPolig; + //reajustamos los tamaños + sal->posIni = (size_t*)realloc(sal->posIni,nPolig*sizeof(size_t)); + sal->nVert = (size_t*)realloc(sal->nVert,nPolig*sizeof(size_t)); + } + //comprobamos los posibles errores + if((sal->x==NULL)||(sal->y==NULL)||(sal->posIni==NULL)||(sal->nVert==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 + 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;inPolig;i++) + { + sal->atr[i] = 0; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //liberamos la memoria asignada + free(posNanX); + free(posNanY); + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return sal; +} +/******************************************************************************/ +/******************************************************************************/ +void EnlazaCamposPolig(polig* poliEnt, + polig* poliSal) +{ + //LIBERAMOS LA POSIBLE MEMORIA ASIGNADA A LOS CAMPOS VECTORIALES DE LA + //ESTRUCTURA DE SALIDA + //comprobamos si hay algún elemento en los vectores de coordenadas + if(poliSal->nElem) + { + free(poliSal->x); + free(poliSal->y); + } + //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) + { + free(poliSal->xMin); + free(poliSal->xMax); + free(poliSal->yMin); + free(poliSal->yMax); + } + //comprobamos si hay superficies calculadas + if(poliSal->hayArea) + { + free(poliSal->area); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //enlazamos todos los campos de la estructura de entrada en la de salida + poliSal->nElem = poliEnt->nElem; + poliSal->x = poliEnt->x; + poliSal->y = poliEnt->y; + poliSal->nPolig = poliEnt->nPolig; + poliSal->posIni = poliEnt->posIni; + poliSal->nVert = poliEnt->nVert; + poliSal->hayLim = poliEnt->hayLim; + poliSal->xMin = poliEnt->xMin; + poliSal->xMax = poliEnt->xMax; + poliSal->yMin = poliEnt->yMin; + poliSal->yMax = poliEnt->yMax; + poliSal->hayArea = poliEnt->hayArea; + poliSal->area = poliEnt->area; + poliSal->atr = poliEnt->atr; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return; +} +/******************************************************************************/ +/******************************************************************************/ +polig* CopiaPolig(const polig* poli, + int* idError) +{ + //polígono de salida + polig* sal=NULL; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //inicializamos la variable de error + *idError = GEOC_ERR_NO_ERROR; + //inicializamos el polígono de salida + sal = IniciaPoligVacio(); + //comprobamos los posibles errores + if(sal==NULL) + { + //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; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //sólo continuamos si el polígono de entrada contiene datos + if(poli->nElem) + { + //copiamos las coordenadas de los vértices + *idError = AnyadeDatosPolig(sal,poli->x,poli->y,poli->nElem,1,1); + //comprobamos si ha ocurrido algún error + if((*idError)!=GEOC_ERR_NO_ERROR) + { + //liberamos la memoria asignada + LibMemPolig(sal); + //escribimos el mensaje de error + if((*idError)==GEOC_ERR_ASIG_MEMORIA) + { + GEOC_ERROR("Error de asignación de memoria"); + } + else if((*idError)==GEOC_ERR_POLIG_VEC_DISTINTO_NUM_POLIG) + { + GEOC_ERROR("Error: Los vectores de coordenadas del polígono\n" + "de entrada no contienen el mismo número de " + "polígonos"); + } + else if((*idError)==GEOC_ERR_POLIG_VEC_DISTINTOS_POLIG) + { + GEOC_ERROR("Error: Los vectores de coordenadas del polígono\n" + "de entrada no contienen los mismos polígonos"); + } + //salimos de la función + return NULL; + } + //comprobamos si hay que calcular límites + if(poli->hayLim) + { + //calculamos los límites + *idError = CalcLimitesPolig(sal); + //comprobamos los posibles errores + if((*idError)!=GEOC_ERR_NO_ERROR) + { + //liberamos la memoria asignada + LibMemPolig(sal); + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return NULL; + } + } + //comprobamos si hay que calcular superficies + if(poli->hayArea) + { + //calculamos las áreas + *idError = CalcAreaPolig(sal,1.0,0,0.0,0.0); + //comprobamos los posibles errores + if((*idError)!=GEOC_ERR_NO_ERROR) + { + //liberamos la memoria asignada + LibMemPolig(sal); + //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 AnyadePoligPolig(polig* poli, + const polig* anyade) +{ + //índice para recorrer bucles + size_t i=0; + //variable de posición + size_t pos=0; + //número total de elementos + size_t nElem=0,nPolig=0; + //variable de estado (salida) + int estado=GEOC_ERR_NO_ERROR; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //si el polígono a añadir está vacío, salimos de la función + if((anyade!=NULL)&&(anyade->nPolig==0)) + { + //salimos de la función sin hacer nada + return estado; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //calculamos el número total de elementos del polígono conjunto + nElem = poli->nElem+anyade->nElem; + //si el polígono original contenía datos, al número total de elementos hay + //que restarle 1 por el NaN común que sobra al juntar las dos estructuras + if(poli->nPolig) + { + nElem--; + } + //calculamos el número total de polígonos + nPolig = poli->nPolig+anyade->nPolig; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //reasignamos memoria para cubrir los nuevos datos + poli->x = (double*)realloc(poli->x,nElem*sizeof(double)); + 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) + { + poli->xMin = (double*)realloc(poli->xMin,nPolig*sizeof(double)); + poli->xMax = (double*)realloc(poli->xMax,nPolig*sizeof(double)); + poli->yMin = (double*)realloc(poli->yMin,nPolig*sizeof(double)); + poli->yMax = (double*)realloc(poli->yMax,nPolig*sizeof(double)); + } + if(poli->hayArea) + { + poli->area = (double*)realloc(poli->area,nPolig*sizeof(double)); + } + //comprobamos los posibles errores en las asignaciones obligatorias + if((poli->x==NULL)||(poli->y==NULL)||(poli->posIni==NULL)|| + (poli->nVert==NULL)||(poli->atr==NULL)) + { + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return GEOC_ERR_ASIG_MEMORIA; + } + //comprobamos los posibles errores en las asignaciones de límites + if(poli->hayLim) + { + if((poli->xMin==NULL)||(poli->xMax==NULL)||(poli->yMin==NULL)|| + (poli->yMax==NULL)) + { + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return GEOC_ERR_ASIG_MEMORIA; + } + } + //comprobamos los posibles errores en las asignaciones de áreas + if(poli->hayArea) + { + 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; + } + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //calculamos la posición de inicio para copiar en la estructura de salida + //si la estructura de salida está vacía, se comienza en la primera posición + //si tiene datos, se comienza a continuación en la última (dentro del bucle, + //la suma de posIni hace que se comience a continuación de la última) + pos = (poli->nPolig==0) ? 0 : poli->nElem-1; + //recorremos el número de nuevos elementos + for(i=0;inElem;i++) + { + //copiamos las coordenadas + poli->x[pos+i] = anyade->x[i]; + poli->y[pos+i] = anyade->y[i]; + } + //calculamos las posiciones a sumar para ajustar las posiciones de inicio de + //los polígonos añadidos + //si la estructura de salida está vacía, se copian las posiciones tal cual + //si tiene datos, se suman las posiciones ya ocupadas + pos = (poli->nPolig==0) ? 0 : poli->nElem-1; + //recorremos el número de polígonos + for(i=0;inPolig;i++) + { + //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]; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //comprobamos si hay que calcular límites + if(poli->hayLim) + { + //comprobamos si ya están calculados + if(anyade->hayLim) + { + //recorremos el número de polígonos y copiamos los límites + for(i=0;inPolig;i++) + { + //copiamos los límites + poli->xMin[poli->nPolig+i] = anyade->xMin[i]; + poli->xMax[poli->nPolig+i] = anyade->xMax[i]; + poli->yMin[poli->nPolig+i] = anyade->yMin[i]; + poli->yMax[poli->nPolig+i] = anyade->yMax[i]; + } + } + else + { + //calculamos los límites y los copiamos + LimitesPoligonosPolig(&(anyade->x[1]),&(anyade->y[1]),1,1, + anyade->posIni,anyade->nVert,anyade->nPolig, + anyade->posIni[0],&(poli->xMin[poli->nPolig]), + &(poli->xMax[poli->nPolig]), + &(poli->yMin[poli->nPolig]), + &(poli->yMax[poli->nPolig])); + } + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //comprobamos si hay que calcular áreas + if(poli->hayArea) + { + //comprobamos si ya están calculadas + if(anyade->hayArea) + { + //recorremos el número de polígonos y copiamos las superficies + for(i=0;inPolig;i++) + { + //copiamos los límites + poli->area[poli->nPolig+i] = anyade->area[i]; + } + } + else + { + //calculamos las superficies y las copiamos + AreaPoligonosSimplesPolig(&(anyade->x[1]),&(anyade->y[1]),1,1, + anyade->posIni,anyade->nVert, + anyade->nPolig,anyade->posIni[0], + &(poli->area[poli->nPolig])); + } + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //ajustamos los tamaños antes de salir + poli->nElem = nElem; + poli->nPolig = nPolig; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return estado; +} +/******************************************************************************/ +/******************************************************************************/ +int AnyadeDatosPolig(polig* poli, + const double* x, + const double* y, + const size_t nElem, + const size_t incX, + const size_t incY) +{ + //polígono auxiliar + polig* aux=NULL; + //variable de estado (salida) + int estado=GEOC_ERR_NO_ERROR; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //contemplamos una posible salida rápida + if(nElem==0) + { + //salimos de la función + return estado; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //creamos un nuevo polígono con los datos a añadir + aux = CreaPolig(x,y,nElem,incX,incY,&estado); + //comprobamos los posibles errores + if(estado!=GEOC_ERR_NO_ERROR) + { + //liberamos la memoria asignada + LibMemPolig(aux); + //escribimos el mensaje de error + if(estado==GEOC_ERR_ASIG_MEMORIA) + { + GEOC_ERROR("Error de asignación de memoria"); + } + else if(estado==GEOC_ERR_POLIG_VEC_DISTINTO_NUM_POLIG) + { + GEOC_ERROR("Error: Los vectores de trabajo no contienen el mismo " + "número de polígonos"); + } + else if(estado==GEOC_ERR_POLIG_VEC_DISTINTOS_POLIG) + { + GEOC_ERROR("Error: Los vectores de trabajo no contienen los mismos " + "polígonos"); + } + //salimos de la función + return estado; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //añadimos la nueva estructura + estado = AnyadePoligPolig(poli,aux); + //comprobamos los posibles errores + if(estado!=GEOC_ERR_NO_ERROR) + { + //liberamos la memoria asignada + LibMemPolig(aux); + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return estado; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //liberamos la memoria utilizada + LibMemPolig(aux); + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return estado; +} +/******************************************************************************/ +/******************************************************************************/ +void LibMemPolig(polig* datos) +{ + //comprobamos si hay memoria que liberar + if(datos!=NULL) + { + //liberamos la memoria asignada al vector de coordenadas X + if(datos->x!=NULL) + { + free(datos->x); + } + //liberamos la memoria asignada al vector de coordenadas Y + if(datos->y!=NULL) + { + free(datos->y); + } + //liberamos la memoria asignada al vector de posiciones + if(datos->posIni!=NULL) + { + free(datos->posIni); + } + //liberamos la memoria asignada al vector de número de vértices + if(datos->nVert!=NULL) + { + free(datos->nVert); + } + //liberamos la memoria asignada a los vector de coordenadas X mínimas + if(datos->xMin!=NULL) + { + free(datos->xMin); + } + //liberamos la memoria asignada a los vector de coordenadas X máximas + if(datos->xMax!=NULL) + { + free(datos->xMax); + } + //liberamos la memoria asignada a los vector de coordenadas Y mínimas + if(datos->yMin!=NULL) + { + free(datos->yMin); + } + //liberamos la memoria asignada a los vector de coordenadas Y máximas + if(datos->yMax!=NULL) + { + free(datos->yMax); + } + //liberamos la memoria asignada al vector de áreas + if(datos->area!=NULL) + { + 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); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return; +} +/******************************************************************************/ +/******************************************************************************/ +int CalcLimitesPolig(polig* poli) +{ + //variable de estado (salida) + int estado=GEOC_ERR_NO_ERROR; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //comprobamos salida rápida + if((poli->nPolig==0)||(poli->hayLim)) + { + //salimos de la función si la estructura no contiene polígonos o si + //éstos ya tienen calculados sus límites + return estado; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //paralelización con OpenMP +#if defined(_OPENMP) +#pragma omp parallel sections default(none) \ + shared(poli) +#endif +{ + //asignamos memoria para los vectores de límites +#if defined(_OPENMP) +#pragma omp section +#endif + poli->xMin = (double*)malloc((poli->nPolig)*sizeof(double)); +#if defined(_OPENMP) +#pragma omp section +#endif + poli->xMax = (double*)malloc((poli->nPolig)*sizeof(double)); +#if defined(_OPENMP) +#pragma omp section +#endif + poli->yMin = (double*)malloc((poli->nPolig)*sizeof(double)); +#if defined(_OPENMP) +#pragma omp section +#endif + poli->yMax = (double*)malloc((poli->nPolig)*sizeof(double)); +} // --> fin del #pragma omp parallel sections + //comprobamos los posibles errores + if((poli->xMin==NULL)||(poli->xMax==NULL)||(poli->yMin==NULL)|| + (poli->yMax==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 límites + poli->hayLim = 1; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //calculamos los límites de todos los polígonos + LimitesPoligonosPolig(poli->x,poli->y,1,1,poli->posIni,poli->nVert, + poli->nPolig,0,poli->xMin,poli->xMax,poli->yMin, + poli->yMax); + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return estado; +} +/******************************************************************************/ +/******************************************************************************/ +void LimitesPoligono(const double* x, + const double* y, + const size_t nElem, + const size_t incX, + const size_t incY, + double* xMin, + double* xMax, + double* yMin, + double* yMax) +{ + //posiciones de los elementos máximo y mínimo + size_t posXMin=0,posXMax=0,posYMin=0,posYMax=0; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //buscamos las posiciones de los elementos máximo y mínimo + //paralelización con OpenMP +#if defined(_OPENMP) +#pragma omp parallel sections default(none) \ + shared(incX,x,nElem,posXMin,posXMax,incY,y,posYMin,posYMax) +#endif +{ + //posiciones en el vector X +#if defined(_OPENMP) +#pragma omp section +#endif + MinMax(x,nElem,incX,&posXMin,&posXMax); + //posiciones en el vector Y +#if defined(_OPENMP) +#pragma omp section +#endif + MinMax(y,nElem,incY,&posYMin,&posYMax); +} // --> fin del #pragma omp parallel sections + //extraemos los valores de las posiciones calculadas + *xMin = x[posXMin*incX]; + *xMax = x[posXMax*incX]; + *yMin = y[posYMin*incY]; + *yMax = y[posYMax*incY]; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return; +} +/******************************************************************************/ +/******************************************************************************/ +void LimitesPoligonosPolig(const double* x, + const double* y, + const size_t incX, + const size_t incY, + const size_t* posIni, + const size_t* nVert, + const size_t nPolig, + const size_t restaPosIni, + double* xMin, + double* xMax, + double* yMin, + double* yMax) +{ + //índice para recorrer bucles + size_t i=0; + //posición inicial del polígono de trabajo + size_t pI=0; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //paralelización con OpenMP +#if defined(_OPENMP) +#pragma omp parallel for default(none) schedule(dynamic) \ + shared(nPolig,posIni,restaPosIni,incX,x,incY,y,nVert,xMin,xMax,yMin,yMax) \ + private(i,pI) +#endif + //recorremos el número de polígonos + for(i=0;i fin del #pragma omp parallel for + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return; +} +/******************************************************************************/ +/******************************************************************************/ +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) + { + //salimos de la función si la estructura + return estado; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //comprobamos si la estructura no contiene área calculada + if(!(poli->hayArea)) + { + //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;inElem;i++) + { + x[i] = poli->x[i]*facCoor; + y[i] = poli->y[i]*facCoor; + } + } + else + { + //recorremos los polígonos + for(i=0;inPolig;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;jnVert[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; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //calculamos las superficies de todos los polígonos + 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 + return estado; +} +/******************************************************************************/ +/******************************************************************************/ +double AreaPoligonoSimple(const double* x, + const double* y, + const size_t nElem, + const size_t incX, + const size_t incY) +{ + //índice para recorrer bucles + size_t i=0; + //número de elementos de trabajo, que inicializamos con el valor pasado + size_t nElemTrab=nElem; + //variable de salida + double area=0.0; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //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])) + { + //el número de elementos de trabajo es uno menos que el pasado + nElemTrab = nElem-1; + } + //el algoritmo utilizado es la segunda expresión de la ecuación 21.4.20 del + //Numerical Recipes, tercera edición, página 1127 + //recorremos los puntos hasta el penúltimo + for(i=0;i<(nElemTrab-1);i++) + { + //vamos sumando + area += (x[(i+1)*incX]+x[i*incX])*(y[(i+1)*incY]-y[i*incY]); + } + //sumamos la contribución del último lado, es decir, el lado que contiene + //como vértice final al primer punto + area += (x[0]+x[(nElemTrab-1)*incX])*(y[0]-y[(nElemTrab-1)*incY]); + //dividimos entre dos para calcular el área real + area /= 2.0; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return area; +} +/******************************************************************************/ +/******************************************************************************/ +void AreaPoligonosSimplesPolig(const double* x, + const double* y, + const size_t incX, + const size_t incY, + const size_t* posIni, + const size_t* nVert, + const size_t nPolig, + const size_t restaPosIni, + double* area) +{ + //índice para recorrer bucles + size_t i=0; + //posición inicial del polígono de trabajo + size_t pI=0; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //paralelización con OpenMP +#if defined(_OPENMP) +#pragma omp parallel for default(none) schedule(dynamic) \ + shared(nPolig,posIni,restaPosIni,area,incX,x,incY,y,nVert) \ + private(i,pI) +#endif + //recorremos el número de polígonos + for(i=0;i fin del #pragma omp parallel for + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return; +} +/******************************************************************************/ +/******************************************************************************/ +void EscalaYTrasladaPolig(polig* poli, + const double escalaX, + const double escalaY, + const double trasladaX, + const double trasladaY, + const int aplicaLim, + const int aplicaArea) +{ + //paralelización con OpenMP +#if defined(_OPENMP) +#pragma omp parallel sections default(none) \ + shared(poli,escalaX,trasladaX,escalaY,trasladaY) +#endif +{ +#if defined(_OPENMP) +#pragma omp section +#endif + //aplicamos los factores de escala y las traslaciones a las coordenadas X + EscalaYTrasladaVector(poli->x,poli->nElem,1,escalaX,trasladaX); +#if defined(_OPENMP) +#pragma omp section +#endif + //aplicamos los factores de escala y las traslaciones a las coordenadas Y + EscalaYTrasladaVector(poli->y,poli->nElem,1,escalaY,trasladaY); +} // --> fin del #pragma omp parallel sections + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //ESTA PARTE NO LA PARALELIZAMOS, YA QUE SUPONEMOS QUE EL NÚMERO DE + //POLÍGONOS EN UNA ESTRUCTURA SIEMPRE SERÁ MUCHÍSIMO MENOR QUE EL NÚMERO + //TOTAL DE VÉRTICES + //comprobamos si hay que aplicar el factor a los límites + if(aplicaLim&&poli->hayLim) + { + //aplicamos los factores de escala y las traslaciones a los límites + EscalaYTrasladaVector(poli->xMin,poli->nPolig,1,escalaX,trasladaX); + EscalaYTrasladaVector(poli->xMax,poli->nPolig,1,escalaX,trasladaX); + EscalaYTrasladaVector(poli->yMin,poli->nPolig,1,escalaY,trasladaY); + EscalaYTrasladaVector(poli->yMax,poli->nPolig,1,escalaY,trasladaY); + } + //comprobamos si hay que aplicar el factor a las superficies + if(aplicaArea&&poli->hayArea) + { + //aplicamos el factor de escala a las áreas + EscalaYTrasladaVector(poli->area,poli->nPolig,1,fabs(escalaX*escalaY), + 0.0); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return; +} +/******************************************************************************/ +/******************************************************************************/ +void TrasladaYEscalaPolig(polig* poli, + const double escalaX, + const double escalaY, + const double trasladaX, + const double trasladaY, + const int aplicaLim, + const int aplicaArea) +{ + //paralelización con OpenMP +#if defined(_OPENMP) +#pragma omp parallel sections default(none) \ + shared(poli,escalaX,trasladaX,escalaY,trasladaY) +#endif +{ +#if defined(_OPENMP) +#pragma omp section +#endif + //aplicamos las traslaciones y los factores de escala a las coordenadas X + TrasladaYEscalaVector(poli->x,poli->nElem,1,escalaX,trasladaX); +#if defined(_OPENMP) +#pragma omp section +#endif + //aplicamos las traslaciones y los factores de escala a las coordenadas Y + TrasladaYEscalaVector(poli->y,poli->nElem,1,escalaY,trasladaY); +} // --> fin del #pragma omp parallel sections + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //ESTA PARTE NO LA PARALELIZAMOS, YA QUE SUPONEMOS QUE EL NÚMERO DE + //POLÍGONOS EN UNA ESTRUCTURA SIEMPRE SERÁ MUCHÍSIMO MENOR QUE EL NÚMERO + //TOTAL DE VÉRTICES + //comprobamos si hay que aplicar el factor a los límites + if(aplicaLim&&poli->hayLim) + { + //aplicamos las traslaciones y los factores de escala a los límites + TrasladaYEscalaVector(poli->xMin,poli->nPolig,1,escalaX,trasladaX); + TrasladaYEscalaVector(poli->xMax,poli->nPolig,1,escalaX,trasladaX); + TrasladaYEscalaVector(poli->yMin,poli->nPolig,1,escalaY,trasladaY); + TrasladaYEscalaVector(poli->yMax,poli->nPolig,1,escalaY,trasladaY); + } + //comprobamos si hay que aplicar el factor a las superficies + if(aplicaArea&&poli->hayArea) + { + //aplicamos el factor de escala a las áreas + TrasladaYEscalaVector(poli->area,poli->nPolig,1,fabs(escalaX*escalaY), + 0.0); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return; +} +/******************************************************************************/ +/******************************************************************************/ +void MuevePolig(polig* poli, + const double escalaX, + const double escalaY, + const double trasladaX, + const double trasladaY, + const int orden, + const int aplicaLim, + const int aplicaArea) +{ + //comprobamos el orden de aplicación de los factores + if(orden==0) + { + //primero los factores de escala y luego las traslaciones + EscalaYTrasladaPolig(poli,escalaX,escalaY,trasladaX,trasladaY,aplicaLim, + aplicaArea); + } + else + { + //primero las traslaciones y luego los factores de escala + TrasladaYEscalaPolig(poli,escalaX,escalaY,trasladaX,trasladaY,aplicaLim, + aplicaArea); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return; +} +/******************************************************************************/ +/******************************************************************************/ +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 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,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 + size_t* pos=NULL; + //variable de salida + int estado=GEOC_ERR_NO_ERROR; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //comprobamos una posible salida rápida + if(poli->nPolig==0) + { + //salimos de la función + return estado; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //inicializamos la estructura auxiliar vacía + aux = IniciaPoligVacio(); + //comprobamos los posibles errores + if(aux==NULL) + { + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return GEOC_ERR_ASIG_MEMORIA; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //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;inPolig;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;jx[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(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 + return GEOC_ERR_ASIG_MEMORIA; + } + //comprobamos si el polígono se ha quedado en tres puntos + if(nPtos==3) + { + //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))) + { + //asignamos memoria para los vectores de coordenadas del polígono + //aligerado + x = (double*)malloc(nPtos*sizeof(double)); + y = (double*)malloc(nPtos*sizeof(double)); + //comprobamos posibles errores + if((x==NULL)||(y==NULL)) + { + //liberamos la memoria asignada + LibMemPolig(aux); + 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 + return GEOC_ERR_ASIG_MEMORIA; + } + //recorremos el número de puntos del polígono aligerado + for(j=0;jx[posIni+pos[j]]; + y[j] = poli->y[posIni+pos[j]]; + } + //añadimos las coordenadas al polígono aligerado + estado = AnyadeDatosPolig(aux,x,y,nPtos,1,1); + //sólo puede haber ocurrido un error de asignación de memoria, ya + //que suponemos que el polígono de entrada es correcto + if(estado!=GEOC_ERR_NO_ERROR) + { + //liberamos la memoria asignada + LibMemPolig(aux); + 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 + return GEOC_ERR_ASIG_MEMORIA; + } + //liberamos la memoria asignada a los vectores de coordenadas + free(x); + free(y); + } + //liberamos la memoria asignada al vector de posiciones del aligerado + free(pos); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //comprobamos si hay que calcular límites + if(poli->hayLim) + { + //calculamos los límites + estado = CalcLimitesPolig(aux); + //comprobamos los posibles errores + if(estado!=GEOC_ERR_NO_ERROR) + { + //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 + return GEOC_ERR_ASIG_MEMORIA; + } + } + //comprobamos si hay que calcular superficies + if(poli->hayArea) + { + //calculamos las áreas + estado = CalcAreaPolig(aux,facCoor,esf,a,f); + //comprobamos los posibles errores + if(estado!=GEOC_ERR_NO_ERROR) + { + //liberamos la memoria asignada + LibMemPolig(aux); + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return GEOC_ERR_ASIG_MEMORIA; + } + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //enlazamos los campos de la estructura auxiliar a los de la estructura de + //salida + EnlazaCamposPolig(aux,poli); + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //liberamos la memoria asignada + free(aux); + if(facCoor!=1.0) + { + free(xF); + free(yF); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return estado; +} +/******************************************************************************/ +/******************************************************************************/ +void ImprimeCabeceraPoligFichero(const polig* poli, + const size_t indice, + const char iniCab[], + const int impLim, + const char formCoor[], + const int impArea, + const char formArea[], + const int impAtr, + const char formAtr[], + const double factorX, + const double factorY, + const int repitePrimerPunto, + FILE* idFich) +{ + //número de vértices del polígono de trabajo + size_t nVert=0; + //superficie de los polígonos + double area=0.0; + //límites + double xMin=0.0,xMax=0.0,yMin=0.0,yMax=0.0,limAux=0.0; + //variables de posición + size_t pos=0,posXMin=0,posXMax=0,posYMin=0,posYMax=0; + //variable auxiliar + size_t aux=0; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //ajustamos la variable auxiliar como el posible número a restar si no hay + //que repetir el primer vértice del polígono + aux = (repitePrimerPunto) ? 0 : 1; + //número de vértices a imprimir del polígono + nVert = poli->nVert[indice]-aux; + //posición de inicio del polígono + pos = poli->posIni[indice]; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //imprimimos la marca de inicio y el número de vértices + fprintf(idFich,"%s %8zu",iniCab,nVert); + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //comprobamos si hay que imprimir la superficie + if(impArea) + { + //comprobamos si ya está calculada la superficie o no + if(poli->hayArea) + { + //aplicamos los factores de escala y extraemos la superficie + area = poli->area[indice]*fabs(factorX)*fabs(factorY); + } + else + { + //calculamos la superficie + area = AreaPoligonoSimple(&(poli->x[pos]),&(poli->y[pos]), + poli->nVert[indice],1,1); + //aplicamos los factores de escala + area *= fabs(factorX)*fabs(factorY); + } + //imprimimos el valor de la superficie + fprintf(idFich," "); + fprintf(idFich,formArea,area); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //comprobamos si hay que imprimir los límites + if(impLim) + { + //comprobamos si ya están calculados los límites + if(poli->hayLim) + { + //extraemos los límites + xMin = poli->xMin[indice]; + xMax = poli->xMax[indice]; + yMin = poli->yMin[indice]; + yMax = poli->yMax[indice]; + } + else + { + //buscamos las posiciones de los elementos máximo y mínimo + //paralelización con OpenMP +#if defined(_OPENMP) +#pragma omp parallel sections default(none) \ +shared(poli,pos,nVert,posXMin,posXMax,posYMin,posYMax) +#endif +{ + //posiciones en el vector X +#if defined(_OPENMP) +#pragma omp section +#endif + MinMax(&(poli->x[pos]),nVert,1,&posXMin,&posXMax); + //posiciones en el vector Y +#if defined(_OPENMP) +#pragma omp section +#endif + MinMax(&(poli->y[pos]),nVert,1,&posYMin,&posYMax); +} // --> fin del #pragma omp parallel sections + //extraemos los valores extremos + xMin = poli->x[pos+posXMin]; + xMax = poli->x[pos+posXMax]; + yMin = poli->y[pos+posYMin]; + yMax = poli->y[pos+posYMax]; + } + //comprobamos si el factor de escala para X es negativo + if(factorX<0.0) + { + //los límites cambian + limAux = xMin; + xMin = xMax; + xMax = limAux; + //aplicamos el factor de escala + xMin *= factorX; + xMax *= factorX; + } + //comprobamos si el factor de escala para Y es negativo + if(factorY<0.0) + { + //los límites cambian + limAux = yMin; + yMin = yMax; + yMax = limAux; + //aplicamos el factor de escala + yMin *= factorY; + yMax *= factorY; + } + //imprimimos los límites + fprintf(idFich," "); + fprintf(idFich,formCoor,xMin); + fprintf(idFich," "); + fprintf(idFich,formCoor,xMax); + fprintf(idFich," "); + fprintf(idFich,formCoor,yMin); + fprintf(idFich," "); + fprintf(idFich,formCoor,yMax); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //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"); + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return; +} +/******************************************************************************/ +/******************************************************************************/ +void ImprimePoligFichero(const polig* poli, + const double factorX, + const double factorY, + const int repitePrimerPunto, + const int iniNan, + const int finNan, + const char formCoor[], + const int impCabecera, + const char iniCab[], + const int impLim, + const int impArea, + const char formArea[], + const int impAtr, + const char formAtr[], + FILE* idFich) +{ + //índices para recorrer bucles + size_t i=0,j=0; + //cadena de formato para imprimir los posibles valores NaN + char formNan[GEOC_NAN_LON_FORM_NUM_SIMPLE+1]; + //variable de posición + size_t pos=0; + //variable auxiliar + size_t aux=0; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //comprobamos si la estructura contiene algún polígono + if(poli->nPolig==0) + { + //salimos sin imprimir nada + return; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //creamos la cadena de formato para imprimir los polibles NaN + FormatoNumFormatoTexto(formCoor,formNan); + //ajustamos la variable auxiliar como el posible número a restar si no hay + //que repetir el primer vértice de los polígonos + aux = (repitePrimerPunto) ? 0 : 1; + //comprobamos si hay que imprimir la marca separadora al principio + if(iniNan) + { + //la imprimimos + ImprimeGeocNanTexto(idFich,2,formNan,1); + } + //recorremos el número de polígonos + for(i=0;inPolig;i++) + { + //comprobamos si hay que imprimir la cabecera + if(impCabecera) + { + //imprimos la cabecera + ImprimeCabeceraPoligFichero(poli,i,iniCab,impLim,formCoor,impArea, + formArea,impAtr,formAtr,factorX,factorY, + repitePrimerPunto,idFich); + } + //posición del punto inicial del polígono + pos = poli->posIni[i]; + //recorremos el número de vértices del polígono de trabajo + for(j=0;j<(poli->nVert[i]-aux);j++) + { + //imprimimos las coordenadas, multiplicadas por los factores + fprintf(idFich,formCoor,factorX*poli->x[pos+j]); + fprintf(idFich,formCoor,factorY*poli->y[pos+j]); + fprintf(idFich,"\n"); + } + //imprimimos la marca separadora al final (menos para el último) + if(i!=(poli->nPolig-1)) + { + ImprimeGeocNanTexto(idFich,2,formNan,1); + } + } + //comprobamos si hay que imprimir la marca separadora al final + if(finNan) + { + //la imprimimos + ImprimeGeocNanTexto(idFich,2,formNan,1); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //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/polil.c b/src/polil.c new file mode 100644 index 0000000..b819dc3 --- /dev/null +++ b/src/polil.c @@ -0,0 +1,1535 @@ +/* -*- coding: utf-8 -*- */ +/** +\ingroup geom gshhs +@{ +\file polil.c +\brief Definición de funciones para el trabajo con polilíneas. +\author José Luis García Pallero, jgpallero@gmail.com +\note Este fichero contiene funciones paralelizadas con OpenMP. +\date 03 de junio 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/polil.h" +/******************************************************************************/ +/******************************************************************************/ +int GeocParOmpPolil(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 +} +/******************************************************************************/ +/******************************************************************************/ +polil* IniciaPolilVacia(void) +{ + //estructura de salida + polil* sal=NULL; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //asignamos memoria para la estructura + sal = (polil*)malloc(sizeof(polil)); + //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; + } + //inicializamos los campos escalares a 0 + sal->nElem = 0; + sal->nPolil = 0; + sal->hayLim = 0; + //inicializamos los campos vectoriales a NULL + sal->x = NULL; + sal->y = NULL; + sal->posIni = NULL; + sal->nVert = NULL; + sal->xMin = NULL; + sal->xMax = NULL; + sal->yMin = NULL; + sal->yMax = NULL; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return sal; +} +/******************************************************************************/ +/******************************************************************************/ +int AuxCreaPolil1(const size_t nElem, + const size_t* posNanX, + const size_t* posNanY, + const size_t nNanX, + const size_t nNanY, + size_t* nElemMax, + size_t* nPolil) +{ + //índice para recorrer bucles + size_t i=0; + //variable de salida + int estado=GEOC_ERR_NO_ERROR; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //comprobamos si hay el mismo número de NaN en los dos vectores + if(nNanX!=nNanY) + { + //salimos de la función + return GEOC_ERR_POLIL_VEC_DISTINTO_NUM_POLIL; + } + //comprobamos si hay NaN en las mismas posiciones de los vectores + for(i=0;i fin del #pragma omp parallel sections + //comprobamos los posibles errores de asignación de memoria + if(((posNanX==NULL)&&(nNanX!=0))||((posNanY==NULL)&&(nNanY!=0))) + { + //liberamos la memoria asignada + LibMemPolil(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; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //comprobamos si los vectores tienen bien colocados los NaN y calculamos + //el número máximo de elementos de los vectores de la estructura y el + //número de polilíneas + *idError = AuxCreaPolil1(nElem,posNanX,posNanY,nNanX,nNanY,&nElemMax, + &nPolil); + //comprobamos los posibles errores + if(*idError!=GEOC_ERR_NO_ERROR) + { + //liberamos la memoria asignada + LibMemPolil(sal); + free(posNanX); + free(posNanY); + //escribimos el mensaje de error + if(*idError==GEOC_ERR_POLIL_VEC_DISTINTO_NUM_POLIL) + { + GEOC_ERROR("Error: Los vectores de trabajo no contienen el mismo " + "número de polilíneas"); + } + else if(*idError==GEOC_ERR_POLIL_VEC_DISTINTAS_POLIL) + { + GEOC_ERROR("Error: Los vectores de trabajo no contienen las mismas " + "polilíneas"); + } + //salimos de la función + return NULL; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //asignamos el número de polilíneas + sal->nPolil = nPolil; + //paralelización con OpenMP +#if defined(_OPENMP) +#pragma omp parallel sections default(none) \ + shared(sal,nElemMax,nPolil) +#endif +{ + //asignamos memoria para los vectores de la estructura +#if defined(_OPENMP) +#pragma omp section +#endif + sal->x = (double*)malloc(nElemMax*sizeof(double)); +#if defined(_OPENMP) +#pragma omp section +#endif + sal->y = (double*)malloc(nElemMax*sizeof(double)); +#if defined(_OPENMP) +#pragma omp section +#endif + sal->posIni = (size_t*)malloc(nPolil*sizeof(double)); +#if defined(_OPENMP) +#pragma omp section +#endif + sal->nVert = (size_t*)malloc(nPolil*sizeof(double)); +} // --> fin del #pragma omp parallel sections + //comprobamos los posibles errores + if((sal->x==NULL)||(sal->y==NULL)||(sal->posIni==NULL)||(sal->nVert==NULL)) + { + //liberamos la memoria asignada + LibMemPolil(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; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //copiamos las polilíneas a la estructura + //como ya sabemos que el número de NaN y sus posiciones son los mismos para + //los vectores x e y, trabajamos con los valores para el vector x + AuxCreaPolil3(x,y,nElem,incX,incY,posNanX,nNanX,sal->x,sal->y,sal->posIni, + sal->nVert,&ptos,&nPolil); + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //comprobamos si hay de verdad alguna polilínea + if(nPolil==0) + { + //liberamos la memoria asignada + LibMemPolil(sal); + free(posNanX); + free(posNanY); + //creamos la estructura vacía + sal = IniciaPolilVacia(); + //comprobamos los posibles errores + if(sal==NULL) + { + //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; + } + //salimos de la función + return sal; + } + //asignamos el número de elementos a la estructura + sal->nElem = ptos; + //comprobamos si hay que reajustar el tamaño de los vectores de coordenadas + if(ptos!=nElemMax) + { + //asignamos el nuevo tamaño de los vectores + sal->nElem = ptos; + //reajustamos los tamaños + sal->x = (double*)realloc(sal->x,ptos*sizeof(double)); + sal->y = (double*)realloc(sal->y,ptos*sizeof(double)); + } + //comprobamos si el número de polilíneas es el estimado + if(nPolil!=sal->nPolil) + { + //asignamos de nuevo la variable de número de polilíneas + sal->nPolil = nPolil; + //reajustamos los tamaños + sal->posIni = (size_t*)realloc(sal->posIni,nPolil*sizeof(size_t)); + sal->nVert = (size_t*)realloc(sal->nVert,nPolil*sizeof(size_t)); + } + //comprobamos los posibles errores + if((sal->x==NULL)||(sal->y==NULL)||(sal->posIni==NULL)||(sal->nVert==NULL)) + { + //liberamos la memoria asignada + LibMemPolil(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; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //liberamos la memoria asignada + free(posNanX); + free(posNanY); + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return sal; +} +/******************************************************************************/ +/******************************************************************************/ +void EnlazaCamposPolil(polil* poliEnt, + polil* poliSal) +{ + //LIBERAMOS LA POSIBLE MEMORIA ASIGNADA A LOS CAMPOS VECTORIALES DE LA + //ESTRUCTURA DE SALIDA + //comprobamos si hay algún elemento en los vectores de coordenadas + if(poliSal->nElem) + { + free(poliSal->x); + free(poliSal->y); + } + //comprobamos si hay alguna polilínea en los vectores de posiciones + if(poliSal->nPolil) + { + free(poliSal->posIni); + free(poliSal->nVert); + } + //comprobamos si hay límites calculados + if(poliSal->hayLim) + { + free(poliSal->xMin); + free(poliSal->xMax); + free(poliSal->yMin); + free(poliSal->yMax); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //enlazamos todos los campos de la estructura de entrada en la de salida + poliSal->nElem = poliEnt->nElem; + poliSal->x = poliEnt->x; + poliSal->y = poliEnt->y; + poliSal->nPolil = poliEnt->nPolil; + poliSal->posIni = poliEnt->posIni; + poliSal->nVert = poliEnt->nVert; + poliSal->hayLim = poliEnt->hayLim; + poliSal->xMin = poliEnt->xMin; + poliSal->xMax = poliEnt->xMax; + poliSal->yMin = poliEnt->yMin; + poliSal->yMax = poliEnt->yMax; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return; +} +/******************************************************************************/ +/******************************************************************************/ +polil* CopiaPolil(const polil* poli, + int* idError) +{ + //polilínea de salida + polil* sal=NULL; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //inicializamos la variable de error + *idError = GEOC_ERR_NO_ERROR; + //inicializamos la polilínea de salida + sal = IniciaPolilVacia(); + //comprobamos los posibles errores + if(sal==NULL) + { + //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; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //sólo continuamos si la polilínea de entrada contiene datos + if(poli->nElem) + { + //copiamos las coordenadas de los vértices + *idError = AnyadeDatosPolil(sal,poli->x,poli->y,poli->nElem,1,1); + //comprobamos si ha ocurrido algún error + if((*idError)!=GEOC_ERR_NO_ERROR) + { + //liberamos la memoria asignada + LibMemPolil(sal); + //escribimos el mensaje de error + if((*idError)==GEOC_ERR_ASIG_MEMORIA) + { + GEOC_ERROR("Error de asignación de memoria"); + } + else if((*idError)==GEOC_ERR_POLIL_VEC_DISTINTO_NUM_POLIL) + { + GEOC_ERROR("Error: Los vectores de coordenadas de la\n" + "polilínea de entrada no contienen el mismo número " + "de polilíneas"); + } + else if((*idError)==GEOC_ERR_POLIL_VEC_DISTINTAS_POLIL) + { + GEOC_ERROR("Error: Los vectores de coordenadas de la\n" + "polilínea de entrada no contienen las mismas " + "polilíneas"); + } + //salimos de la función + return NULL; + } + //comprobamos si hay que calcular límites + if(poli->hayLim) + { + //calculamos los límites + *idError = CalcLimitesPolil(sal); + //comprobamos los posibles errores + if((*idError)!=GEOC_ERR_NO_ERROR) + { + //liberamos la memoria asignada + LibMemPolil(sal); + //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 AnyadePolilPolil(polil* poli, + const polil* anyade) +{ + //índice para recorrer bucles + size_t i=0; + //variable de posición + size_t pos=0; + //número total de elementos + size_t nElem=0,nPolil=0; + //variable de estado (salida) + int estado=GEOC_ERR_NO_ERROR; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //si la polilínea a añadir está vacía, salimos de la función + if((anyade!=NULL)&&(anyade->nPolil==0)) + { + //salimos de la función sin hacer nada + return estado; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //calculamos el número total de elementos de la polilínea conjunta + nElem = poli->nElem+anyade->nElem; + //si la polilínea original contenía datos, al número total de elementos hay + //que restarle 1 por el NaN común que sobra al juntar las dos estructuras + if(poli->nPolil) + { + nElem--; + } + //calculamos el número total de polilíneas + nPolil = poli->nPolil+anyade->nPolil; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //reasignamos memoria para cubrir los nuevos datos + poli->x = (double*)realloc(poli->x,nElem*sizeof(double)); + poli->y = (double*)realloc(poli->y,nElem*sizeof(double)); + poli->posIni = (size_t*)realloc(poli->posIni,nPolil*sizeof(size_t)); + poli->nVert = (size_t*)realloc(poli->nVert,nPolil*sizeof(size_t)); + //reasignamos también para los posibles vectores de límites + if(poli->hayLim) + { + poli->xMin = (double*)realloc(poli->xMin,nPolil*sizeof(double)); + poli->xMax = (double*)realloc(poli->xMax,nPolil*sizeof(double)); + poli->yMin = (double*)realloc(poli->yMin,nPolil*sizeof(double)); + poli->yMax = (double*)realloc(poli->yMax,nPolil*sizeof(double)); + } + //comprobamos los posibles errores en las asignaciones obligatorias + if((poli->x==NULL)||(poli->y==NULL)||(poli->posIni==NULL)|| + (poli->nVert==NULL)) + { + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return GEOC_ERR_ASIG_MEMORIA; + } + //comprobamos los posibles errores en las asignaciones de límites + if(poli->hayLim) + { + if((poli->xMin==NULL)||(poli->xMax==NULL)||(poli->yMin==NULL)|| + (poli->yMax==NULL)) + { + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return GEOC_ERR_ASIG_MEMORIA; + } + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //calculamos la posición de inicio para copiar en la estructura de salida + //si la estructura de salida está vacía, se comienza en la primera posición + //si tiene datos, se comienza a continuación en la última (dentro del bucle, + //la suma de posIni hace que se comience a continuación de la última) + pos = (poli->nPolil==0) ? 0 : poli->nElem-1; + //recorremos el número de nuevos elementos + for(i=0;inElem;i++) + { + //copiamos las coordenadas + poli->x[pos+i] = anyade->x[i]; + poli->y[pos+i] = anyade->y[i]; + } + //calculamos las posiciones a sumar para ajustar las posiciones de inicio de + //las polilíneas añadidas + //si la estructura de salida está vacía, se copian las posiciones tal cual + //si tiene datos, se suman las posiciones ya ocupadas + pos = (poli->nPolil==0) ? 0 : poli->nElem-1; + //recorremos el número de polilíneas + for(i=0;inPolil;i++) + { + //copiamos las posiciones de inicio actualizadas y el número de vértices + poli->posIni[poli->nPolil+i] = anyade->posIni[i]+pos; + poli->nVert[poli->nPolil+i] = anyade->nVert[i]; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //comprobamos si hay que calcular límites + if(poli->hayLim) + { + //comprobamos si ya están calculados + if(anyade->hayLim) + { + //recorremos el número de polilíneas y copiamos los límites + for(i=0;inPolil;i++) + { + //copiamos los límites + poli->xMin[poli->nPolil+i] = anyade->xMin[i]; + poli->xMax[poli->nPolil+i] = anyade->xMax[i]; + poli->yMin[poli->nPolil+i] = anyade->yMin[i]; + poli->yMax[poli->nPolil+i] = anyade->yMax[i]; + } + } + else + { + //calculamos los límites y los copiamos + LimitesPoligonosPolig(&(anyade->x[1]),&(anyade->y[1]),1,1, + anyade->posIni,anyade->nVert,anyade->nPolil, + anyade->posIni[0],&(poli->xMin[poli->nPolil]), + &(poli->xMax[poli->nPolil]), + &(poli->yMin[poli->nPolil]), + &(poli->yMax[poli->nPolil])); + } + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //ajustamos los tamaños antes de salir + poli->nElem = nElem; + poli->nPolil = nPolil; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return estado; +} +/******************************************************************************/ +/******************************************************************************/ +int AnyadeDatosPolil(polil* poli, + const double* x, + const double* y, + const size_t nElem, + const size_t incX, + const size_t incY) +{ + //polilínea auxiliar + polil* aux=NULL; + //variable de estado (salida) + int estado=GEOC_ERR_NO_ERROR; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //contemplamos una posible salida rápida + if(nElem==0) + { + //salimos de la función + return estado; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //creamos una nueva polilínea con los datos a añadir + aux = CreaPolil(x,y,nElem,incX,incY,&estado); + //comprobamos los posibles errores + if(estado!=GEOC_ERR_NO_ERROR) + { + //liberamos la memoria asignada + LibMemPolil(aux); + //escribimos el mensaje de error + if(estado==GEOC_ERR_ASIG_MEMORIA) + { + GEOC_ERROR("Error de asignación de memoria"); + } + else if(estado==GEOC_ERR_POLIL_VEC_DISTINTO_NUM_POLIL) + { + GEOC_ERROR("Error: Los vectores de trabajo no contienen el mismo " + "número de polilíneas"); + } + else if(estado==GEOC_ERR_POLIL_VEC_DISTINTAS_POLIL) + { + GEOC_ERROR("Error: Los vectores de trabajo no contienen las mismas " + "polilíneas"); + } + //salimos de la función + return estado; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //añadimos la nueva estructura + estado = AnyadePolilPolil(poli,aux); + //comprobamos los posibles errores + if(estado!=GEOC_ERR_NO_ERROR) + { + //liberamos la memoria asignada + LibMemPolil(aux); + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return estado; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //liberamos la memoria utilizada + LibMemPolil(aux); + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return estado; +} +/******************************************************************************/ +/******************************************************************************/ +void LibMemPolil(polil* datos) +{ + //comprobamos si hay memoria que liberar + if(datos!=NULL) + { + //liberamos la memoria asignada al vector de coordenadas X + if(datos->x!=NULL) + { + free(datos->x); + } + //liberamos la memoria asignada al vector de coordenadas Y + if(datos->y!=NULL) + { + free(datos->y); + } + //liberamos la memoria asignada al vector de posiciones + if(datos->posIni!=NULL) + { + free(datos->posIni); + } + //liberamos la memoria asignada al vector de número de vértices + if(datos->nVert!=NULL) + { + free(datos->nVert); + } + //liberamos la memoria asignada a los vector de coordenadas X mínimas + if(datos->xMin!=NULL) + { + free(datos->xMin); + } + //liberamos la memoria asignada a los vector de coordenadas X máximas + if(datos->xMax!=NULL) + { + free(datos->xMax); + } + //liberamos la memoria asignada a los vector de coordenadas Y mínimas + if(datos->yMin!=NULL) + { + free(datos->yMin); + } + //liberamos la memoria asignada a los vector de coordenadas Y máximas + if(datos->yMax!=NULL) + { + free(datos->yMax); + } + //liberamos la memoria asignada a la estructura + free(datos); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return; +} +/******************************************************************************/ +/******************************************************************************/ +int CalcLimitesPolil(polil* poli) +{ + //variable de estado (salida) + int estado=GEOC_ERR_NO_ERROR; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //comprobamos salida rápida + if((poli->nPolil==0)||(poli->hayLim)) + { + //salimos de la función si la estructura no contiene polilíneas o si + //éstas ya tienen calculados sus límites + return estado; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //paralelización con OpenMP +#if defined(_OPENMP) +#pragma omp parallel sections default(none) \ + shared(poli) +#endif +{ + //asignamos memoria para los vectores de límites +#if defined(_OPENMP) +#pragma omp section +#endif + poli->xMin = (double*)malloc((poli->nPolil)*sizeof(double)); +#if defined(_OPENMP) +#pragma omp section +#endif + poli->xMax = (double*)malloc((poli->nPolil)*sizeof(double)); +#if defined(_OPENMP) +#pragma omp section +#endif + poli->yMin = (double*)malloc((poli->nPolil)*sizeof(double)); +#if defined(_OPENMP) +#pragma omp section +#endif + poli->yMax = (double*)malloc((poli->nPolil)*sizeof(double)); +} // --> fin del #pragma omp parallel sections + //comprobamos los posibles errores + if((poli->xMin==NULL)||(poli->xMax==NULL)||(poli->yMin==NULL)|| + (poli->yMax==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 límites + poli->hayLim = 1; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //calculamos los límites de todas las polilíneas + LimitesPoligonosPolig(poli->x,poli->y,1,1,poli->posIni,poli->nVert, + poli->nPolil,0,poli->xMin,poli->xMax,poli->yMin, + poli->yMax); + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return estado; +} +/******************************************************************************/ +/******************************************************************************/ +void EscalaYTrasladaPolil(polil* poli, + const double escalaX, + const double escalaY, + const double trasladaX, + const double trasladaY, + const int aplicaLim) +{ + //paralelización con OpenMP +#if defined(_OPENMP) +#pragma omp parallel sections default(none) \ + shared(poli,escalaX,trasladaX,escalaY,trasladaY) +#endif +{ +#if defined(_OPENMP) +#pragma omp section +#endif + //aplicamos los factores de escala y las traslaciones a las coordenadas X + EscalaYTrasladaVector(poli->x,poli->nElem,1,escalaX,trasladaX); +#if defined(_OPENMP) +#pragma omp section +#endif + //aplicamos los factores de escala y las traslaciones a las coordenadas Y + EscalaYTrasladaVector(poli->y,poli->nElem,1,escalaY,trasladaY); +} // --> fin del #pragma omp parallel sections + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //ESTA PARTE NO LA PARALELIZAMOS, YA QUE SUPONEMOS QUE EL NÚMERO DE + //POLÍGONOS EN UNA ESTRUCTURA SIEMPRE SERÁ MUCHÍSIMO MENOR QUE EL NÚMERO + //TOTAL DE VÉRTICES + //comprobamos si hay que aplicar el factor a los límites + if(aplicaLim&&poli->hayLim) + { + //aplicamos los factores de escala y las traslaciones a los límites + EscalaYTrasladaVector(poli->xMin,poli->nPolil,1,escalaX,trasladaX); + EscalaYTrasladaVector(poli->xMax,poli->nPolil,1,escalaX,trasladaX); + EscalaYTrasladaVector(poli->yMin,poli->nPolil,1,escalaY,trasladaY); + EscalaYTrasladaVector(poli->yMax,poli->nPolil,1,escalaY,trasladaY); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return; +} +/******************************************************************************/ +/******************************************************************************/ +void TrasladaYEscalaPolil(polil* poli, + const double escalaX, + const double escalaY, + const double trasladaX, + const double trasladaY, + const int aplicaLim) +{ + //paralelización con OpenMP +#if defined(_OPENMP) +#pragma omp parallel sections default(none) \ + shared(poli,escalaX,trasladaX,escalaY,trasladaY) +#endif +{ +#if defined(_OPENMP) +#pragma omp section +#endif + //aplicamos las traslaciones y los factores de escala a las coordenadas X + TrasladaYEscalaVector(poli->x,poli->nElem,1,escalaX,trasladaX); +#if defined(_OPENMP) +#pragma omp section +#endif + //aplicamos las traslaciones y los factores de escala a las coordenadas Y + TrasladaYEscalaVector(poli->y,poli->nElem,1,escalaY,trasladaY); +} // --> fin del #pragma omp parallel sections + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //ESTA PARTE NO LA PARALELIZAMOS, YA QUE SUPONEMOS QUE EL NÚMERO DE + //POLÍGONOS EN UNA ESTRUCTURA SIEMPRE SERÁ MUCHÍSIMO MENOR QUE EL NÚMERO + //TOTAL DE VÉRTICES + //comprobamos si hay que aplicar el factor a los límites + if(aplicaLim&&poli->hayLim) + { + //aplicamos las traslaciones y los factores de escala a los límites + TrasladaYEscalaVector(poli->xMin,poli->nPolil,1,escalaX,trasladaX); + TrasladaYEscalaVector(poli->xMax,poli->nPolil,1,escalaX,trasladaX); + TrasladaYEscalaVector(poli->yMin,poli->nPolil,1,escalaY,trasladaY); + TrasladaYEscalaVector(poli->yMax,poli->nPolil,1,escalaY,trasladaY); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return; +} +/******************************************************************************/ +/******************************************************************************/ +void MuevePolil(polil* poli, + const double escalaX, + const double escalaY, + const double trasladaX, + const double trasladaY, + const int orden, + const int aplicaLim) +{ + //comprobamos el orden de aplicación de los factores + if(orden==0) + { + //primero los factores de escala y luego las traslaciones + EscalaYTrasladaPolil(poli,escalaX,escalaY,trasladaX,trasladaY, + aplicaLim); + } + else + { + //primero las traslaciones y luego los factores de escala + TrasladaYEscalaPolil(poli,escalaX,escalaY,trasladaX,trasladaY, + aplicaLim); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return; +} +/******************************************************************************/ +/******************************************************************************/ +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 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,nVert=0,nPtos=0; + //polilínea que es un mismo punto + int pmp=0; + //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 + size_t* pos=NULL; + //variable de salida + int estado=GEOC_ERR_NO_ERROR; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //comprobamos una posible salida rápida + if(poli->nPolil==0) + { + //salimos de la función + return estado; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //inicializamos la estructura auxiliar vacía + aux = IniciaPolilVacia(); + //comprobamos los posibles errores + if(aux==NULL) + { + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return GEOC_ERR_ASIG_MEMORIA; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //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;inPolil;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;jx[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(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 + return GEOC_ERR_ASIG_MEMORIA; + } + //comprobamos si la polilínea se ha quedado en dos puntos + if(nPtos==2) + { + //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]])); + } + //comprobamos si después del aligerado todavía queda una polilínea que + //no sea un único punto + if((nPtos>2)||((nPtos==2)&&(!pmp))) + { + //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 + if((x==NULL)||(y==NULL)) + { + //liberamos la memoria asignada + LibMemPolil(aux); + 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 + return GEOC_ERR_ASIG_MEMORIA; + } + //recorremos el número de puntos de la polilínea aligerada + for(j=0;jx[posIni+pos[j]]; + y[j] = poli->y[posIni+pos[j]]; + } + //añadimos las coordenadas a la polilínea aligerada + estado = AnyadeDatosPolil(aux,x,y,nPtos,1,1); + //sólo puede haber ocurrido un error de asignación de memoria, ya + //que suponemos que la polilínea de entrada es correcta + if(estado!=GEOC_ERR_NO_ERROR) + { + //liberamos la memoria asignada + LibMemPolil(aux); + 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 + return GEOC_ERR_ASIG_MEMORIA; + } + //liberamos la memoria asignada a los vectores de coordenadas + free(x); + free(y); + } + //liberamos la memoria asignada al vector de posiciones del aligerado + free(pos); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //comprobamos si hay que calcular límites + if(poli->hayLim) + { + //calculamos los límites + estado = CalcLimitesPolil(aux); + //comprobamos los posibles errores + if(estado!=GEOC_ERR_NO_ERROR) + { + //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 + return GEOC_ERR_ASIG_MEMORIA; + } + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //enlazamos los campos de la estructura auxiliar a los de la estructura de + //salida + EnlazaCamposPolil(aux,poli); + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //liberamos la memoria asignada + free(aux); + if(facCoor!=1.0) + { + free(xF); + free(yF); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return estado; +} +/******************************************************************************/ +/******************************************************************************/ +void ImprimeCabeceraPolilFichero(const polil* poli, + const size_t indice, + const char iniCab[], + const int impLim, + const char formCoor[], + const double factorX, + const double factorY, + FILE* idFich) +{ + //número de vértices de la polilínea de trabajo + size_t nVert=0; + //límites + double xMin=0.0,xMax=0.0,yMin=0.0,yMax=0.0,limAux=0.0; + //variables de posición + size_t pos=0,posXMin=0,posXMax=0,posYMin=0,posYMax=0; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //número de vértices a imprimir de la polilínea + nVert = poli->nVert[indice]; + //posición de inicio de la polilínea + pos = poli->posIni[indice]; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //imprimimos la marca de inicio y el número de vértices + fprintf(idFich,"%s %8zu",iniCab,nVert); + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //comprobamos si hay que imprimir los límites + if(impLim) + { + //comprobamos si ya están calculados los límites + if(poli->hayLim) + { + //extraemos los límites + xMin = poli->xMin[indice]; + xMax = poli->xMax[indice]; + yMin = poli->yMin[indice]; + yMax = poli->yMax[indice]; + } + else + { + //buscamos las posiciones de los elementos máximo y mínimo + //paralelización con OpenMP +#if defined(_OPENMP) +#pragma omp parallel sections default(none) \ +shared(poli,pos,nVert,posXMin,posXMax,posYMin,posYMax) +#endif +{ + //posiciones en el vector X +#if defined(_OPENMP) +#pragma omp section +#endif + MinMax(&(poli->x[pos]),nVert,1,&posXMin,&posXMax); + //posiciones en el vector Y +#if defined(_OPENMP) +#pragma omp section +#endif + MinMax(&(poli->y[pos]),nVert,1,&posYMin,&posYMax); +} // --> fin del #pragma omp parallel sections + //extraemos los valores extremos + xMin = poli->x[pos+posXMin]; + xMax = poli->x[pos+posXMax]; + yMin = poli->y[pos+posYMin]; + yMax = poli->y[pos+posYMax]; + } + //comprobamos si el factor de escala para X es negativo + if(factorX<0.0) + { + //los límites cambian + limAux = xMin; + xMin = xMax; + xMax = limAux; + //aplicamos el factor de escala + xMin *= factorX; + xMax *= factorX; + } + //comprobamos si el factor de escala para Y es negativo + if(factorY<0.0) + { + //los límites cambian + limAux = yMin; + yMin = yMax; + yMax = limAux; + //aplicamos el factor de escala + yMin *= factorY; + yMax *= factorY; + } + //imprimimos los límites + fprintf(idFich," "); + fprintf(idFich,formCoor,xMin); + fprintf(idFich," "); + fprintf(idFich,formCoor,xMax); + fprintf(idFich," "); + fprintf(idFich,formCoor,yMin); + fprintf(idFich," "); + fprintf(idFich,formCoor,yMax); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salto de línea final + fprintf(idFich,"\n"); + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return; +} +/******************************************************************************/ +/******************************************************************************/ +void ImprimePolilFichero(const polil* poli, + const double factorX, + const double factorY, + const int iniNan, + const int finNan, + const char formCoor[], + const int impCabecera, + const char iniCab[], + const int impLim, + FILE* idFich) +{ + //índices para recorrer bucles + size_t i=0,j=0; + //cadena de formato para imprimir los posibles valores NaN + char formNan[GEOC_NAN_LON_FORM_NUM_SIMPLE+1]; + //variable de posición + size_t pos=0; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //comprobamos si la estructura contiene alguna polilínea + if(poli->nPolil==0) + { + //salimos sin imprimir nada + return; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //creamos la cadena de formato para imprimir los polibles NaN + FormatoNumFormatoTexto(formCoor,formNan); + //comprobamos si hay que imprimir la marca separadora al principio + if(iniNan) + { + //la imprimimos + ImprimeGeocNanTexto(idFich,2,formNan,1); + } + //recorremos el número de polilíneas + for(i=0;inPolil;i++) + { + //comprobamos si hay que imprimir la cabecera + if(impCabecera) + { + //imprimos la cabecera + ImprimeCabeceraPolilFichero(poli,i,iniCab,impLim,formCoor,factorX, + factorY,idFich); + } + //posición del punto inicial de la polilínea + pos = poli->posIni[i]; + //recorremos el número de vértices de la polilínea de trabajo + for(j=0;jnVert[i];j++) + { + //imprimimos las coordenadas, multiplicadas por factor + fprintf(idFich,formCoor,factorX*poli->x[pos+j]); + fprintf(idFich,formCoor,factorY*poli->y[pos+j]); + fprintf(idFich,"\n"); + } + //imprimimos la marca separadora al final (menos para el último) + if(i!=(poli->nPolil-1)) + { + ImprimeGeocNanTexto(idFich,2,formNan,1); + } + } + //comprobamos si hay que imprimir la marca separadora al final + if(finNan) + { + //la imprimimos + ImprimeGeocNanTexto(idFich,2,formNan,1); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //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/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 new file mode 100644 index 0000000..035ac4b --- /dev/null +++ b/src/ptopol.c @@ -0,0 +1,1332 @@ +/* -*- coding: utf-8 -*- */ +/** +\ingroup geom gshhs +@{ +\file ptopol.c +\brief Declaración de funciones para la realización de chequeos de inclusión de + puntos en polígonos. + +En el momento de la compilación ha de seleccionarse el tipo de dato que se +utilizará en los cálculos intermedios de las funciones +\ref PtoEnPoligonoVerticeBorde y \ref PtoEnPoligonoVerticeBordeDouble. Si los +puntos de trabajo están muy alejados de los polígonos pueden darse casos de +resultados erróneos. Sería conveniente que los cálculos internedios se hiciesen +en variables de 64 bits, pero el tipo long int suele ser de 4 bytes en +procesadores de 32 bits. Para seleccionar este tipo como long long int, +lo que en procesadores de 32 bits equivale a una variable de 64 bits, es +necesario definir la variable para el preprocesador \em PTOPOL_BORDE_LONG_64. En +procesadores de 64 bits no es necesario (aunque puede utilizarse), ya que el +tipo long int tiene una longitud de 64 bits. Si no se define la +variable, se usará un tipo long int para los cálculos intermedios. En +\p gcc, las variables para el preprocesador se pasan como \em -DXXX, donde +\em XXX es la variable a introducir. El uso del tipo long long int en +procesadores de 32 bits puede hacer que las funciones se ejecuten hasta 10 veces +más lentamente que si se utiliza el tipo long int. 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. +\author José Luis García Pallero, jgpallero@gmail.com +\note Este fichero contiene funciones paralelizadas con OpenMP. +\date 05 de abril de 2010 +\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 + 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/ptopol.h" +/******************************************************************************/ +/******************************************************************************/ +int GeocParOmpPtopol(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 +} +/******************************************************************************/ +/******************************************************************************/ +int GeocLongLongIntPtopol(void) +{ + //comprobamos si se ha pasado la variable del preprocesador +#if defined(PTOPOL_BORDE_LONG_64) + return 1; +#else + return 0; +#endif +} +/******************************************************************************/ +/******************************************************************************/ +int PtoEnRectangulo(const double x, + const double y, + const double xMin, + const double xMax, + const double yMin, + const double yMax) +{ + //posibles posiciones del punto + if((xxMax)||(yyMax)) + { + //punto fuera + return GEOC_PTO_FUERA_POLIG; + } + else if((x>xMin)&&(xyMin)&&(y=xMin2)&&(xMax1<=xMax2)&&(yMin1>=yMin2)&&(yMax1<=yMax2)) + { + //el rectángulo está contenido + sal = 1; + } + } + else + { + //el borde no se tiene en cuenta + if((xMin1>xMin2)&&(xMax1yMin2)&&(yMax1y)!=(coorY[posJY]>y))&& + (x<(coorX[posJX]-coorX[posIX])*(y-coorY[posIY])/ + (coorY[posJY]-coorY[posIY])+coorX[posIX])) + { + c = !c; + } + } + //asignamos el elemento de salida + if(c) + { + //el punto está dentro del polígono + c = GEOC_PTO_DENTRO_POLIG; + } + else + { + //el punto está fuera del polígono + c = GEOC_PTO_FUERA_POLIG; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return c; +} +/******************************************************************************/ +/******************************************************************************/ +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;i0)!=(cy1>0); + Lstrad = (cy<0)!=(cy1<0); + //straddle computation + if(Rstrad||Lstrad) + { + //compute intersection of e with x axis + X = ((double)(cx*cy1-cx1*cy))/((double)(cy1-cy)); + //crosses ray if strictly positive intersection + if(Rstrad&&(X>0.0)) + { + Rcross++; + } + //crosses ray if strictly negative intersection + if(Lstrad&&(X<0.0)) + { + Lcross++; + } + } + } + //q on the edge if left and right cross are not the same parity + if((Rcross%2)!=(Lcross%2)) + { + //el punto está en un borde + return GEOC_PTO_BORDE_POLIG; + } + //q inside if an odd number of crossings + if((Rcross%2)==1) + { + //el punto es interior + return GEOC_PTO_DENTRO_POLIG; + } + else + { + //el punto es exterior + return GEOC_PTO_FUERA_POLIG; + } +} +/******************************************************************************/ +/******************************************************************************/ +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;idmax) + { + 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(fmult*x)); + fY = (ptopol_long)(round(fmult*y)); + } + else + { + //truncamiento + fX = (ptopol_long)(fmult*x); + fY = (ptopol_long)(fmult*y); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //for each edge e=(i-1,i), see if crosses ray + for(i=0;i0)!=(cy1>0); + Lstrad = (cy<0)!=(cy1<0); + //straddle computation + if(Rstrad||Lstrad) + { + //compute intersection of e with x axis + X = ((double)(cx*cy1-cx1*cy))/((double)(cy1-cy)); + //crosses ray if strictly positive intersection + if(Rstrad&&(X>0.0)) + { + Rcross++; + } + //crosses ray if strictly negative intersection + if(Lstrad&&(X<0.0)) + { + Lcross++; + } + } + } + //q on the edge if left and right cross are not the same parity + if((Rcross%2)!=(Lcross%2)) + { + //el punto está en un borde + return GEOC_PTO_BORDE_POLIG; + } + //q inside if an odd number of crossings + if((Rcross%2)==1) + { + //el punto es interior + return GEOC_PTO_DENTRO_POLIG; + } + else + { + //el punto es exterior + return GEOC_PTO_FUERA_POLIG; + } +} +/******************************************************************************/ +/******************************************************************************/ +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 cierro el if(continuar) si compilamos para OpenMP +#endif + } // --> fin del #pragma omp parallel for + } + else + { + //hacemos una comprobación normal + pos = PtoEnPoligono(x,y,coorX,coorY,N,incX,incY); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return pos; +} +/******************************************************************************/ +/******************************************************************************/ +int PtoEnPoligonoVerticeInd(const double x, + const double y, + const double* coorX, + const double* coorY, + const size_t N, + const size_t incX, + const size_t incY, + const size_t* posNan, + const size_t nNan, + size_t* poli) +{ + //índice para recorrer bucles + size_t i=0; + //posiciones de inicio de los vértices X e Y + size_t iniX=0,iniY=0; + //número de elementos del polígono a chequear + size_t nElem=0; + //variable auxiliar de situación de punto + int posAux=0; + //variable indicadora de continuación de chequeos + size_t continuar=1; + //variable de salida + int pos=GEOC_PTO_FUERA_POLIG; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //inicializamos el polígono que contiene al punto + *poli = 0; + //comprobamos si hay valores NaN + if(nNan) + { + //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 + //libres + //hago esto porque es muy probable que los polígonos vengan listados de + //mayor a menor número de vértices y así se podrá trabajar con varios + //polígonos pequeños mientras se testea uno grande +#if defined(_OPENMP) +#pragma omp parallel for default(none) schedule(dynamic) \ + 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 +#if defined(_OPENMP) +#pragma omp flush(continuar) +#endif + //comprobamos si hay que continuar chequeando polígonos + if(continuar) + { + //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 = PtoEnPoligonoVertice(x,y,&coorX[iniX],&coorY[iniY], + nElem,incX,incY); + //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(paraSiPuntoDentro) +#endif +{ + //si el punto no está fuera, no se han de hacer más operaciones + //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&&(posAux!=GEOC_PTO_FUERA_POLIG)) + { + //asignamos la variable de salida + pos = posAux; + //asignamos el polígono que contiene al punto + *poli = i; + //indicamos que no hay que continuar haciendo pruebas + //esta variable se usa para el caso de ejecución en paralelo + continuar = 0; + //hacemos que todos los hilos vean la variable continuar + //actualizada +#if defined(_OPENMP) +#pragma omp flush(continuar) +#endif + } +} + } + } // --> fin del #pragma omp parallel for + } + else + { + //hacemos una comprobación normal + pos = PtoEnPoligonoVertice(x,y,coorX,coorY,N,incX,incY); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return pos; +} +/******************************************************************************/ +/******************************************************************************/ +int PtoEnPoligonoVerticeBordeInd(const long x, + const long y, + const long* coorX, + const long* coorY, + const size_t N, + const size_t incX, + const size_t incY, + const size_t* posNan, + const size_t nNan, + size_t* poli) +{ + //índice para recorrer bucles + size_t i=0; + //posiciones de inicio de los vértices X e Y + size_t iniX=0,iniY=0; + //número de elementos del polígono a chequear + size_t nElem=0; + //variable auxiliar de situación de punto + int posAux=0; + //variable indicadora de continuación de chequeos + size_t continuar=1; + //variable de salida + int pos=GEOC_PTO_FUERA_POLIG; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //inicializamos el polígono que contiene al punto + *poli = 0; + //comprobamos si hay valores NaN + if(nNan) + { + //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 + //libres + //hago esto porque es muy probable que los polígonos vengan listados de + //mayor a menor número de vértices y así se podrá trabajar con varios + //polígonos pequeños mientras se testea uno grande +#if defined(_OPENMP) +#pragma omp parallel for default(none) schedule(dynamic) \ + 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 +#if defined(_OPENMP) +#pragma omp flush(continuar) +#endif + //comprobamos si hay que continuar chequeando polígonos + if(continuar) + { + //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 = PtoEnPoligonoVerticeBorde(x,y,&coorX[iniX], + &coorY[iniY],nElem,incX, + incY); + //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(paraSiPuntoDentro) +#endif +{ + //si el punto no está fuera, no se han de hacer más operaciones + //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&&(posAux!=GEOC_PTO_FUERA_POLIG)) + { + //asignamos la variable de salida + pos = posAux; + //asignamos el polígono que contiene al punto + *poli = i; + //indicamos que no hay que continuar haciendo pruebas + //esta variable se usa para el caso de ejecución en paralelo + continuar = 0; + //hacemos que todos los hilos vean la variable continuar + //actualizada +#if defined(_OPENMP) +#pragma omp flush(continuar) +#endif + } +} + } + } // --> fin del #pragma omp parallel for + } + else + { + //hacemos una comprobación normal + pos = PtoEnPoligonoVerticeBorde(x,y,coorX,coorY,N,incX,incY); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return pos; +} +/******************************************************************************/ +/******************************************************************************/ +int PtoEnPoligonoVerticeBordeDoubleInd(const double x, + const double y, + const double* coorX, + const double* coorY, + const size_t N, + const size_t incX, + const size_t incY, + const double factor, + const int redondeo, + const size_t* posNan, + const size_t nNan, + size_t* poli) +{ + //índice para recorrer bucles + size_t i=0; + //posiciones de inicio de los vértices X e Y + size_t iniX=0,iniY=0; + //número de elementos del polígono a chequear + size_t nElem=0; + //variable auxiliar de situación de punto + int posAux=0; + //variable indicadora de continuación de chequeos + size_t continuar=1; + //variable de salida + int pos=GEOC_PTO_FUERA_POLIG; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //inicializamos el polígono que contiene al punto + *poli = 0; + //comprobamos si hay valores NaN + if(nNan) + { + //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 + //libres + //hago esto porque es muy probable que los polígonos vengan listados de + //mayor a menor número de vértices y así se podrá trabajar con varios + //polígonos pequeños mientras se testea uno grande +#if defined(_OPENMP) +#pragma omp parallel for default(none) schedule(dynamic) \ + 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 + for(i=0;i<(nNan-1);i++) + { + //hacemos que todos los hilos vean la variable continuar actualizada +#if defined(_OPENMP) +#pragma omp flush(continuar) +#endif + //comprobamos si hay que continuar chequeando polígonos + if(continuar) + { + //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 = PtoEnPoligonoVerticeBordeDouble(x,y,&coorX[iniX], + &coorY[iniY],nElem, + incX,incY,factor, + redondeo); + //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(paraSiPuntoDentro) +#endif +{ + //si el punto no está fuera, no se han de hacer más operaciones + //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&&(posAux!=GEOC_PTO_FUERA_POLIG)) + { + //asignamos la variable de salida + pos = posAux; + //asignamos el polígono que contiene al punto + *poli = i; + //indicamos que no hay que continuar haciendo pruebas + //esta variable se usa para el caso de ejecución en paralelo + continuar = 0; + //hacemos que todos los hilos vean la variable continuar + //actualizada +#if defined(_OPENMP) +#pragma omp flush(continuar) +#endif + } +} + } + } // --> fin del #pragma omp parallel for + } + else + { + //hacemos una comprobación normal + pos = PtoEnPoligonoVerticeBordeDouble(x,y,coorX,coorY,N,incX,incY, + factor,redondeo); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return pos; +} +/******************************************************************************/ +/******************************************************************************/ +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; +} +/******************************************************************************/ +/******************************************************************************/ +/** @} */ +/******************************************************************************/ +/******************************************************************************/ +/* 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/recpolil.c b/src/recpolil.c new file mode 100644 index 0000000..c6cbe40 --- /dev/null +++ b/src/recpolil.c @@ -0,0 +1,1403 @@ +/* -*- coding: utf-8 -*- */ +/** +\ingroup geom gshhs +@{ +\file recpolil.c +\brief Definición funciones para el recorte de polilíneas por medio de + polígonos. +\author José Luis García Pallero, jgpallero@gmail.com +\date 05 de junio de 2011 +\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 + 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/recpolil.h" +/******************************************************************************/ +/******************************************************************************/ +vertPolilClip* CreaVertPolilClip(const double x, + const double y, + vertPolilClip* anterior, + vertPolilClip* siguiente, + const char orig, + const char pos, + const double alfa) +{ + //variable de salida (nuevo vértice) + vertPolilClip* nuevoVert=NULL; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //asignamos memoria para el nuevo vértice + nuevoVert = (vertPolilClip*)malloc(sizeof(vertPolilClip)); + //comprobamos los posibles errores + if(nuevoVert==NULL) + { + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return NULL; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //asignamos los vértices anterior y posterior + nuevoVert->anterior = anterior; + nuevoVert->siguiente = siguiente; + //si anterior es un vértice bueno + if(anterior!=NULL) + { + //lo apuntamos al vértice creado + nuevoVert->anterior->siguiente = nuevoVert; + } + //si siguiente es un vértice bueno + if(siguiente!=NULL) + { + //indicamos que el vértice creado es el anterior + nuevoVert->siguiente->anterior = nuevoVert; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //asignamos el resto de campos + nuevoVert->x = x; + nuevoVert->y = y; + nuevoVert->orig = orig; + nuevoVert->pos = pos; + nuevoVert->alfa = alfa; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return nuevoVert; +} +/******************************************************************************/ +/******************************************************************************/ +vertPolilClip* CreaPolilClip(const double* x, + const double* y, + const size_t nCoor, + const size_t incX, + const size_t incY) +{ + //índice para recorrer bucles + size_t i=0; + //variable auxiliar de posición + size_t posIni=0; + //otra variable auxiliar + int hayVert=0; + //estructura auxiliar + vertPolilClip* aux=NULL; + //variable de salida + vertPolilClip* poli=NULL; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //buscamos el primer punto que sea distinto de NaN + for(i=0;isiguiente; + //liberamos la memoria + free(aux); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return; +} +/******************************************************************************/ +/******************************************************************************/ +vertPolilClip* ReiniciaPolilClip(vertPolilClip* poli) +{ + //estructura que apunta al espacio en memoria a liberar + vertPolilClip* borra=NULL; + //estructura auxiliar + vertPolilClip* aux=NULL; + //estructura de salida + vertPolilClip* sal=NULL; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //inicializamos la estructura auxiliar + aux = poli; + //comprobamos una posible salida rápida + if(aux==NULL) + { + //salimos de la función + return NULL; + } + //buscamos para la estructura de salida el primer vértice original + while(aux!=NULL) + { + //comprobamos si estamos ante un vértice bueno + if(aux->orig) + { + //asignamos la variable de salida + sal = aux; + //salimos del bucle + break; + } + //siguiente vértice + aux = aux->siguiente; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //volvemos a inicializar la variable auxiliar + aux = poli; + //mientras la variable de trabajo no apunte a NULL + while(aux!=NULL) + { + //comprobamos si estamos ante un vértice a borrar + if(aux->orig==0) + { + //lo almacenamos en la estructura de borrado + borra = aux; + //actualizamos el puntero de vértice siguiente + if(aux->anterior!=NULL) + { + //cuando el vértice a borrar no es el primero de la lista + aux->anterior->siguiente = aux->siguiente; + } + else if(aux->siguiente!=NULL) + { + //cuando el vértice a borrar es el primero de la lista + aux->siguiente->anterior = NULL; + } + //actualizamos el puntero de vértice anterior + if(aux->siguiente!=NULL) + { + //cuando el vértice a borrar no es el último de la lista + aux->siguiente->anterior = aux->anterior; + } + else if(aux->anterior!=NULL) + { + //cuando el vértice a borrar es el último de la lista + aux->anterior->siguiente = NULL; + } + //apuntamos al siguiente elemento + aux = aux->siguiente; + //liberamos la memoria + free(borra); + } + else + { + //reinicializamos el resto de miembros, menos las coordenadas + //originales y el identificador de vértice original + aux->pos = GEOC_PTO_FUERA_POLIG; + aux->alfa = 0.0; + //siguiente elemento + aux = aux->siguiente; + } + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return sal; +} +/******************************************************************************/ +/******************************************************************************/ +vertPolilClip* SiguienteVertOrigPolilClip(vertPolilClip* vert) +{ + //variable de salida, que inicializamos con la dirección de entrada + vertPolilClip* sal=vert; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //si estamos ante un vértice original, pasamos al siguiente + if((sal!=NULL)&&sal->orig) + { + //apuntamos al siguiente vértice + sal = sal->siguiente; + } + //vamos rechazando vérties no originales (el bucle se para cuando llegamos + //al final o a un vértice que no es original) + while((sal!=NULL)&&(sal->orig==0)) + { + //pasamos al siguiente vértice + sal = sal->siguiente; + } + //si hemos llegado a un vértice que no es original, apuntamos a NULL + if((sal!=NULL)&&(sal->orig==0)) + { + //asignamos NULL + sal = NULL; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return sal; +} +/******************************************************************************/ +/******************************************************************************/ +/******************************************************************************/ +void InsertaVertPolilClip(vertPolilClip* ins, + vertPolilClip* extremoIni, + vertPolilClip* extremoFin) +{ + //estructura auxiliar + vertPolilClip* aux=NULL; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //inicializamos el vértice auxiliar como el extremo inicial pasado + aux = extremoIni; + //mientras no lleguemos al extremo final y el punto a insertar esté más + //lejos del origen que el punto de trabajo + while((aux!=extremoFin)&&((aux->alfa)<=(ins->alfa))) + { + //avanzamos al siguiente vértice + aux = aux->siguiente; + } + //insertamos el punto y ordenamos los punteros de vértices anterior y + //posterior + ins->siguiente = aux; + ins->anterior = aux->anterior; + ins->anterior->siguiente = ins; + ins->siguiente->anterior = ins; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return; +} +/******************************************************************************/ +/******************************************************************************/ +size_t NumeroVertOrigPolilClip(vertPolilClip* poli) +{ + //estructura auxiliar + vertPolilClip* aux=NULL; + //variable de salida + size_t num=0; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //inicializamos la estructura auxiliar con la dirección de entrada + aux = poli; + //comprobamos si estamos ante un vértice original + if(aux->orig) + { + //si no es un vértice original, nos posicionamos en el siguiente que sí + //lo sea + aux = SiguienteVertOrigPolilClip(aux); + } + //mientras no lleguemos al final + while(aux!=NULL) + { + //aumentamos el contador de vértices originales + num++; + //nos posicionamos en el siguiente vértice original + aux = SiguienteVertOrigPolilClip(aux); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return num; +} +/******************************************************************************/ +/******************************************************************************/ +size_t NumeroVertPolilClip(vertPolilClip* poli) +{ + //estructura auxiliar + vertPolilClip* aux=NULL; + //variable de salida + size_t num=0; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //inicializamos la estructura auxiliar con la dirección de entrada + aux = poli; + //mientras no lleguemos al final + while(aux!=NULL) + { + //aumentamos el contador de vértices + num++; + //nos posicionamos en el siguiente vértice + aux = aux->siguiente; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return num; +} +/******************************************************************************/ +/******************************************************************************/ +int Paso1Recpolil(vertPolilClip* poli, + vertPoliClip* poliRec, + size_t* nIntersec) +{ + //estructuras auxiliares que apuntan a los elementos pasados + vertPolilClip* auxA=NULL; + vertPoliClip* auxC=NULL; + //estructuras auxiliares para trabajar con el siguiente vértice + vertPolilClip* auxB=NULL; + vertPoliClip* auxD=NULL; + //vértices de intersección a insertar + vertPolilClip* insPolil=NULL; + //coordenadas de la intersección de dos segmentos + double xI=0.0,yI=0.0; + //longitud de segmento y parámetro alfa + double lon=0.0,alfa=0.0; + //código de intersección de segmentos + int intersec=0; + //variable auxiliar + int nuevoPunto=0; + //variable de salida + int salida=GEOC_ERR_NO_ERROR; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //inicializamos el número de intersecciones a 0 + *nIntersec = 0; + //EL PRIMER PASO DEL ALGORITMO DE RECORTE DE POLILÍNEAS ES EL CÁLCULO DE + //TODOS LOS PUNTOS DE INTERSECCIÓN ENTRE LOS POLÍGONOS + //recorremos los vértices de la polilínea + for(auxA=poli;auxA->siguiente!=NULL;auxA=auxA->siguiente) + { + //sólo trabajamos si el vértice es original + if(auxA->orig) + { + //recorremos los vértices del polígono de recorte + for(auxC=poliRec;auxC->siguiente!=NULL;auxC=auxC->siguiente) + { + //sólo trabajamos si el vértice es original (esto hace que + //podamos trabajar con un polígono proveniente de una operación + //booleana previa entre polígonos + if(auxC->interseccion==0) + { + //siguiente vértice de los segmentos + auxB = SiguienteVertOrigPolilClip(auxA); + auxD = SiguienteVertOrigPoliClip(auxC); + //calculamos la intersección de los segmentos + intersec = IntersecSegmentos2D(auxA->x,auxA->y,auxB->x, + auxB->y,auxC->x,auxC->y, + auxD->x,auxD->y,&xI,&yI); + //comprobamos la posición relativa del primer punto del + //segmento de la polilínea con respecto al polígono + //esta función sólo marca dentro o fuera + auxA->pos = (char)PtoEnPoliClip(auxA->x,auxA->y,poliRec); + //comprobamos si el segmento de la polilínea contiene al + //último punto de ésta, por lo que el bucle se acabará aquí + if(auxB->siguiente==NULL) + { + //comprobamos la posición relativa del último punto + auxB->pos = (char)PtoEnPoliClip(auxB->x,auxB->y, + poliRec); + } + //comprobamos si hay que aumentar el contador de + //intersecciones + if(intersec!=GEOC_SEG_NO_INTERSEC) + { + //aumentamos el contador de intersecciones + (*nIntersec)++; + } + //comprobamos el tipo de intersección + if(intersec==GEOC_SEG_INTERSEC) + { + //INTERSECCIÓN LIMPIA + //calculamos la longitud del segmento de la polilínea + lon = Dist2D(auxA->x,auxA->y,auxB->x,auxB->y); + //calculamos los parámetros alfa + alfa = Dist2D(auxA->x,auxA->y,xI,yI)/lon; + //creamos el nuevo vértice a insertar + insPolil = CreaVertPolilClip(xI,yI,NULL,NULL,0, + (char)GEOC_PTO_BORDE_POLIG, + alfa); + //comprobamos los posibles errores + if(insPolil==NULL) + { + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return GEOC_ERR_ASIG_MEMORIA; + } + //añadimos el punto de intersección + InsertaVertPolilClip(insPolil,auxA,auxB); + } + 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 + //comprobamos si el extremo que toca es el inicial del + //segmento de la polilínea + if((xI==auxA->x)&&(yI==auxA->y)) + { + //el primer punto del segmento está en el borde + auxA->pos = (char)GEOC_PTO_BORDE_POLIG; + } + else if((xI!=auxB->x)||(yI!=auxB->y)) + { + //el extremo que toca es del segmento del polígono y + //no toca al punto final del segmento de la + //polilínea + //calculamos la longitud del segmento de la + //polilínea + lon = Dist2D(auxA->x,auxA->y,auxB->x,auxB->y); + //calculamos los parámetros alfa + alfa = Dist2D(auxA->x,auxA->y,xI,yI)/lon; + //creamos el nuevo vértice a insertar + insPolil = CreaVertPolilClip(xI,yI,NULL,NULL,0, + (char)GEOC_PTO_BORDE_POLIG, + alfa); + //comprobamos los posibles errores + if(insPolil==NULL) + { + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return GEOC_ERR_ASIG_MEMORIA; + } + //añadimos el punto de intersección + InsertaVertPolilClip(insPolil,auxA,auxB); + } + else + { + //comprobamos si estamos ante el segmento que + //contiene al último punto de la polilínea + if(auxB->siguiente==NULL) + { + //el último punto del segmento está en el borde + auxB->pos = (char)GEOC_PTO_BORDE_POLIG; + } + else + { + //disminuimos el contador de intersecciones, ya + //que esta se detectará en la siguiente vuelta + //del bucle + (*nIntersec)--; + } + } + } + else if(intersec==GEOC_SEG_INTERSEC_EXTREMOS_COLIN) + { + //LOS SEGMENTOS SON COLINEALES PERO SÓLO SE TOCAN EN EL + //EXTREMO + //comprobamos si el extremo que toca es el primero + if((xI==auxA->x)&&(yI==auxA->y)) + { + //el primer punto del segmento está en el borde + auxA->pos = (char)GEOC_PTO_BORDE_POLIG; + } + else + { + //comprobamos si estamos ante el segmento que + //contiene al último punto de la polilínea + if(auxB->siguiente==NULL) + { + //el último punto del segmento está en el borde + auxB->pos = (char)GEOC_PTO_BORDE_POLIG; + } + else + { + //disminuimos el contador de intersecciones, ya + //que esta se detectará en la siguiente vuelta + //del bucle + (*nIntersec)--; + } + } + } + else if(intersec==GEOC_SEG_INTERSEC_MISMO_SEG) + { + //AMBOS SEGMENTOS SON EL MISMO + //el primer punto del segmento está en el borde + auxA->pos = (char)GEOC_PTO_BORDE_POLIG; + //comprobamos si estamos ante el segmento que contiene + //al último punto de la polilínea + if(auxB->siguiente==NULL) + { + //aumentamos el contador de intersecciones + (*nIntersec)++; + //el último punto del segmento está en el borde + auxB->pos = (char)GEOC_PTO_BORDE_POLIG; + } + } + else if(intersec==GEOC_SEG_INTERSEC_COLIN) + { + //LOS SEGMENTOS TIENEN MÁS DE UN PUNTO EN COMÚN, PERO NO + //SON EL MISMO + //comprobamos si el extremo inicial está tocando el + //polígono o no + if((xI==auxA->x)&&(yI==auxA->y)) + { + //el primer punto del segmento está en el borde + auxA->pos = (char)GEOC_PTO_BORDE_POLIG; + //identificador de nuevo punto + nuevoPunto = 0; + //comprobamos si alguno de los extremos del segmento + //del polígono está dentro del segmento de la + //polilínea + if(PuntoEntreDosPuntos2DColin(auxC->x,auxC->y, + auxA->x,auxA->y, + auxB->x,auxB->y)) + { + //nuevo punto + nuevoPunto = 1; + //coordenadas del punto intersección + xI = auxC->x; + yI = auxC->y; + } + else if(PuntoEntreDosPuntos2DColin(auxD->x,auxD->y, + auxA->x,auxA->y, + auxB->x,auxB->y)) + { + //nuevo punto + nuevoPunto = 1; + //coordenadas del punto intersección + xI = auxD->x; + yI = auxD->y; + } + //comprobamos si hay que añadir el nuevo punto + if(nuevoPunto) + { + //aumentamos el contador de intersecciones + (*nIntersec)++; + //calculamos la longitud del segmento de la + //polilínea + lon = Dist2D(auxA->x,auxA->y,auxB->x,auxB->y); + //calculamos los parámetros alfa + alfa = Dist2D(auxA->x,auxA->y,xI,yI)/lon; + //creamos el nuevo vértice a insertar + insPolil = CreaVertPolilClip(xI,yI,NULL,NULL,0, + (char)GEOC_PTO_BORDE_POLIG, + alfa); + //comprobamos los posibles errores + if(insPolil==NULL) + { + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return GEOC_ERR_ASIG_MEMORIA; + } + //añadimos el punto de intersección + InsertaVertPolilClip(insPolil,auxA,auxB); + } + //comprobamos si estamos ante el segmento que + //contiene al último punto de la polilínea + if(auxB->siguiente==NULL) + { + //comprobamos si el último punto del segmento + //de la polilínea está contenido en el segmento + //del polígono + if(PuntoEntreDosPuntos2DColin(auxB->x,auxB->y, + auxC->x,auxC->y, + auxD->x,auxD->y)) + { + //aumentamos el contador de intersecciones + (*nIntersec)++; + //indicamos que el último punto del segmento + //de la polilínea está en el borde + auxB->pos = (char)GEOC_PTO_BORDE_POLIG; + } + } + } + else + { + //comprobamos si el vértice a añadir es el extremo + //final del segmento del polígono (la función + //devuelve las coordenadas del extremo final del + //segmento de la polilínea + if((xI==auxB->x)&&(yI==auxB->y)) + { + //asignamos las coordenadas de salida correctas + xI = auxD->x; + yI = auxD->y; + } + //calculamos la longitud del segmento de la + //polilínea + lon = Dist2D(auxA->x,auxA->y,auxB->x,auxB->y); + //calculamos los parámetros alfa + alfa = Dist2D(auxA->x,auxA->y,xI,yI)/lon; + //creamos el nuevo vértice a insertar + insPolil = CreaVertPolilClip(xI,yI,NULL,NULL,0, + (char)GEOC_PTO_BORDE_POLIG, + alfa); + //comprobamos los posibles errores + if(insPolil==NULL) + { + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return GEOC_ERR_ASIG_MEMORIA; + } + //añadimos el punto de intersección + InsertaVertPolilClip(insPolil,auxA,auxB); + //comprobamos si estamos ante el segmento que + //contiene al último punto de la polilínea + if(auxB->siguiente==NULL) + { + //aumentamos el contador de intersecciones + (*nIntersec)++; + //indicamos que el último punto del segmento de + //la polilínea está en el borde + auxB->pos = (char)GEOC_PTO_BORDE_POLIG; + } + } + } + } + } + } + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return salida; +} +/******************************************************************************/ +/******************************************************************************/ +polil* Paso2Recpolil(vertPolilClip* poli, + const enum GEOC_OP_BOOL_POLIL op) +{ + //estructura auxiliar + vertPolilClip* aux=NULL; + //vectores de coordenadas de los vértices del resultado + double* x=NULL; + double* y=NULL; + //número de elementos de los vectores x e y + size_t nPtos=0; + //número de elementos para los que ha sido asignada memoria + size_t nElem=0; + //variable de estado + int estado=GEOC_ERR_NO_ERROR; + //polilínea de salida + polil* resultado=NULL; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //chequeamos una posible salida rápida porque la polilínea sea NULL + if(poli==NULL) + { + //creamos la estructura vacía + resultado = IniciaPolilVacia(); + //comprobamos los posibles errores + if(resultado==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 resultado; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //inicializamos la estructura auxiliar con la dirección de entrada + aux = poli; + //distinguimos entre las dos operaciones + //por defecto, recorte + if(op!=GeocOpBoolFuera) + { + //vamos recorriendo vértices de la polilínea + do + { + //comprobamos si el vértice es del borde o de dentro del polígono + if(aux->pos==GEOC_PTO_DENTRO_POLIG) + { + //un punto de dentro del polígono siempre pertenece a la + //polilínea recortada + //no hace falta asignar los elementos NaN de separación de + //polilíneas, que ya se añaden cuando de trabaja con un punto de + //borde + //aumentamos el número de elementos almacenados en los vectores + //de coordenadas + nPtos++; + //comprobamos si hay que reasignar memoria + if(nPtos>nElem) + { + //aumentamos el número de elementos + nElem += GEOC_RECPOLIL_BUFFER_PTOS; + //reasignamos memoria + x = (double*)realloc(x,nElem*sizeof(double)); + y = (double*)realloc(y,nElem*sizeof(double)); + //comprobamos los posibles errores + if((x==NULL)||(y==NULL)) + { + //liberamos la posible memoria asignada + free(x); + free(y); + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return NULL; + } + } + //asignamos las coordenadas del vértice + x[nPtos-1] = aux->x; + y[nPtos-1] = aux->y; + } + else if(aux->pos==GEOC_PTO_BORDE_POLIG) + { + //comprobamos la situación de los vértices anterior y siguiente + //para la posible reasignación de memoria + if((aux->anterior==NULL)||(aux->siguiente==NULL)|| + (aux->anterior->pos==GEOC_PTO_FUERA_POLIG)|| + (aux->siguiente->pos==GEOC_PTO_FUERA_POLIG)) + { + //este es un vértice de comienzo o fin de una polilínea, por + //lo que necesitamos memoria para las coordenadas y el + //marcador NaN + nPtos += 2; + } + else + { + //este vértice pertenece al interior del polígono + nPtos++; + } + //comprobamos si hay que reasignar memoria + if(nPtos>nElem) + { + //aumentamos el número de elementos + nElem += GEOC_RECPOLIL_BUFFER_PTOS; + //reasignamos memoria + x = (double*)realloc(x,nElem*sizeof(double)); + y = (double*)realloc(y,nElem*sizeof(double)); + //comprobamos los posibles errores + if((x==NULL)||(y==NULL)) + { + //liberamos la posible memoria asignada + free(x); + free(y); + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return NULL; + } + } + //comprobamos de nuevo la situación de los vértices anterior y + //posterior + if((aux->anterior==NULL)|| + (aux->anterior->pos==GEOC_PTO_FUERA_POLIG)) + { + //el vértice es inicio de polilínea + //asignamos los valores NaN de separación + x[nPtos-2] = GeocNan(); + y[nPtos-2] = GeocNan(); + //asignamos las coordenadas del vértice + x[nPtos-1] = aux->x; + y[nPtos-1] = aux->y; + } + else if((aux->siguiente==NULL)|| + (aux->siguiente->pos==GEOC_PTO_FUERA_POLIG)) + { + //el vértice es final de polilínea + //asignamos las coordenadas del vértice + x[nPtos-2] = aux->x; + y[nPtos-2] = aux->y; + //asignamos los valores NaN de separación + x[nPtos-1] = GeocNan(); + y[nPtos-1] = GeocNan(); + } + else + { + //el vértice pertenece a la polilínea recortada + x[nPtos-1] = aux->x; + y[nPtos-1] = aux->y; + } + } + //avanzamos al siguiente vértice + aux = aux->siguiente; + }while(aux!=NULL); + } + else + { + //vamos recorriendo vértices de la polilínea + do + { + //comprobamos si el vértice es del borde o de fuera del polígono + if(aux->pos==GEOC_PTO_FUERA_POLIG) + { + //un punto de fuera del polígono siempre pertenece a la + //polilínea exterior + //no hace falta asignar los elementos NaN de separación de + //polilíneas, que ya se añaden cuando de trabaja con un punto de + //borde + //aumentamos el número de elementos almacenados en los vectores + //de coordenadas + nPtos++; + //comprobamos si hay que reasignar memoria + if(nPtos>nElem) + { + //aumentamos el número de elementos + nElem += GEOC_RECPOLIL_BUFFER_PTOS; + //reasignamos memoria + x = (double*)realloc(x,nElem*sizeof(double)); + y = (double*)realloc(y,nElem*sizeof(double)); + //comprobamos los posibles errores + if((x==NULL)||(y==NULL)) + { + //liberamos la posible memoria asignada + free(x); + free(y); + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return NULL; + } + } + //asignamos las coordenadas del vértice + x[nPtos-1] = aux->x; + y[nPtos-1] = aux->y; + } + else if(aux->pos==GEOC_PTO_BORDE_POLIG) + { + //comprobamos la situación de los vértices anterior y siguiente + //para la posible reasignación de memoria + if((aux->anterior!=NULL)&&(aux->siguiente!=NULL)&& + (aux->anterior->pos==GEOC_PTO_FUERA_POLIG)&& + (aux->siguiente->pos==GEOC_PTO_FUERA_POLIG)) + { + //este vértice pertenece al exterior del polígono + nPtos++; + } + else if(((aux->anterior==NULL)|| + (aux->anterior->pos!=GEOC_PTO_FUERA_POLIG))&& + (aux->siguiente!=NULL)&& + (aux->siguiente->pos==GEOC_PTO_FUERA_POLIG)) + { + //este es un vértice de comienzo de una polilínea, por lo + //que necesitamos memoria para las coordenadas y el marcador + //NaN + nPtos += 2; + } + else if(((aux->siguiente==NULL)|| + (aux->siguiente->pos!=GEOC_PTO_FUERA_POLIG))&& + (aux->anterior!=NULL)&& + (aux->anterior->pos==GEOC_PTO_FUERA_POLIG)) + { + //este es un vértice de fin de una polilínea, por lo que + //necesitamos memoria para las coordenadas y el marcador NaN + nPtos += 2; + } + //comprobamos si hay que reasignar memoria + if(nPtos>nElem) + { + //aumentamos el número de elementos + nElem += GEOC_RECPOLIL_BUFFER_PTOS; + //reasignamos memoria + x = (double*)realloc(x,nElem*sizeof(double)); + y = (double*)realloc(y,nElem*sizeof(double)); + //comprobamos los posibles errores + if((x==NULL)||(y==NULL)) + { + //liberamos la posible memoria asignada + free(x); + free(y); + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return NULL; + } + } + //comprobamos de nuevo la situación de los vértices anterior y + //posterior + if((aux->anterior!=NULL)&&(aux->siguiente!=NULL)&& + (aux->anterior->pos==GEOC_PTO_FUERA_POLIG)&& + (aux->siguiente->pos==GEOC_PTO_FUERA_POLIG)) + { + //el vértice pertenece a la polilínea recortada + x[nPtos-1] = aux->x; + y[nPtos-1] = aux->y; + } + else if(((aux->anterior==NULL)|| + (aux->anterior->pos!=GEOC_PTO_FUERA_POLIG))&& + (aux->siguiente!=NULL)&& + (aux->siguiente->pos==GEOC_PTO_FUERA_POLIG)) + { + //el vértice es inicio de polilínea + //asignamos los valores NaN de separación + x[nPtos-2] = GeocNan(); + y[nPtos-2] = GeocNan(); + //asignamos las coordenadas del vértice + x[nPtos-1] = aux->x; + y[nPtos-1] = aux->y; + } + else if(((aux->siguiente==NULL)|| + (aux->siguiente->pos!=GEOC_PTO_FUERA_POLIG))&& + (aux->anterior!=NULL)&& + (aux->anterior->pos==GEOC_PTO_FUERA_POLIG)) + { + //el vértice es final de polilínea + //asignamos las coordenadas del vértice + x[nPtos-2] = aux->x; + y[nPtos-2] = aux->y; + //asignamos los valores NaN de separación + x[nPtos-1] = GeocNan(); + y[nPtos-1] = GeocNan(); + } + } + //avanzamos al siguiente vértice + aux = aux->siguiente; + }while(aux!=NULL); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //creamos la estructura de salida + resultado = CreaPolil(x,y,nPtos,1,1,&estado); + //comprobamos los posibles errores + if(resultado==NULL) + { + //liberamos la memoria asignada + free(x); + free(y); + //comprobamos el error + if(estado==GEOC_ERR_ASIG_MEMORIA) + { + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + } + else + { + //mensaje de error + GEOC_ERROR("Error en la llamada a 'CreaPolil()'\nEste error no " + "puede producirse aquí porque los NaN deben estar " + "bien puestos"); + } + //salimos de la función + return NULL; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //liberamos la memoria utilizada + free(x); + free(y); + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return resultado; +} +/******************************************************************************/ +/******************************************************************************/ +polil* RecortaPolil(vertPolilClip* poli, + vertPoliClip* poliRec, + const enum GEOC_OP_BOOL_POLIL op, + size_t* nIntersec) +{ + //identificador de error + int idError=GEOC_ERR_NO_ERROR; + //polilínea de salida de salida + polil* resultado=NULL; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //PRIMER PASO DEL ALGORITMO: CÁLCULO DE TODOS LOS PUNTOS DE INTERSECCIÓN + //ENTRE LA POLILÍNEA Y EL POLÍGONO + //calculamos los puntos de intersección + idError = Paso1Recpolil(poli,poliRec,nIntersec); + //comprobamos los posibles errores + if(idError==GEOC_ERR_ASIG_MEMORIA) + { + //mensaje de error + GEOC_ERROR("Error de asignación de memoria en la llamada a " + "'Paso1Recpolil'"); + //salimos de la función + return NULL; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //comprobamos si no hay intersecciones + if(!(*nIntersec)) + { + //comprobamos las posibles situaciones relativas entre la polilínea y el + //polígono que pueden producir cero intersecciones + if(PtoEnPoliClip(poli->x,poli->y,poliRec)==GEOC_PTO_FUERA_POLIG) + { + //LA POLILÍNEA ESTÁ FUERA DEL POLÍGONO DE RECORTE + //distinguimos las operaciones (por defecto, dentro) + if(op!=GeocOpBoolFuera) + { + //el resultado es una polilínea vacía + resultado = CreaPolilPolilClip(NULL); + } + else + { + //el resultado es la polilínea original + resultado = CreaPolilPolilClip(poli); + } + } + else + { + //LA POLILÍNEA ESTÁ DENTRO DEL POLÍGONO DE RECORTE + //distinguimos las operaciones (por defecto, dentro) + if(op!=GeocOpBoolFuera) + { + //el resultado es la polilínea original + resultado = CreaPolilPolilClip(poli); + } + else + { + //el resultado es una polilínea vacía + resultado = CreaPolilPolilClip(NULL); + } + } + //comprobamos los posibles errores + if(resultado==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 resultado; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //realizamos la operación si hay alguna intersección + resultado = Paso2Recpolil(poli,op); + //comprobamos los posibles errores + if(resultado==NULL) + { + //mensaje de error + GEOC_ERROR("Error de asignación de memoria en la llamada a " + "'Paso2Recpolil'"); + //salimos de la función + return NULL; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return resultado; +} +/******************************************************************************/ +/******************************************************************************/ +polil* RecortaPolilMult(const polil* poli, + const polig* poliRec, + const enum GEOC_OP_BOOL_POLIL op, + size_t* nIntersec) +{ + //índices para recorrer bucles + size_t i=0,j=0; + //variable de posición + size_t pos=0; + //posición de un rectángulo con respecto a otro + int pr=0; + //número de intersecciones auxiliar + size_t nInt=0; + //variable de error + int estado=GEOC_ERR_NO_ERROR; + //listas de trabajo + vertPolilClip* polilClip=NULL; + vertPoliClip* poligClip=NULL; + //polilínea auxiliar + polil* polilAux=NULL; + //variable de salida + polil* resultado=NULL; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //inicializamos el número total de intersecciones + *nIntersec = 0; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //inicializamos la variable de salida + resultado = IniciaPolilVacia(); + //comprobamos los posibles errores + if(resultado==NULL) + { + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return NULL; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //recorremos las polilíneas a recortar + for(i=0;inPolil;i++) + { + //dirección de inicio de los vértices de la polilínea + pos = poli->posIni[i]; + //creamos la polilínea a recortar de trabajo + polilClip = CreaPolilClip(&(poli->x[pos]),&(poli->y[pos]), + poli->nVert[i],1,1); + //comprobamos los posibles errores + if(polilClip==NULL) + { + //liberamos la memoria asignada hasta ahora + LibMemPolil(resultado); + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return NULL; + } + //recorremos los polígonos de recorte + for(j=0;jnPolig;j++) + { + //comprobamos si la polilínea y el polígono tienen definidos sus + //límites + if((poli->hayLim)&&(poliRec->hayLim)) + { + //comprobamos si los restángulos que encierran a la polilínea y + //al polígono son disjuntos o no + 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)) + { + //si buscamos la parte de la polilínea que cae dentro del + //polígono, no se añade nada + //vamos a la siguiente vuelta del bucle + continue; + } + else if(pr&&(op==GeocOpBoolFuera)) + { + //si buscamos la parte de la polilínea que cae fuera del + //polígono, se añade la polilínea entera + estado = AnyadeDatosPolil(resultado,&(poli->x[pos]), + &(poli->y[pos]),poli->nVert[i],1, + 1); + //comprobamos los posibles errores, que sólo pueden ser de + //asignación de memoria + if(estado!=GEOC_ERR_NO_ERROR) + { + //liberamos la posible memoria asignada hasta ahora + LibMemPolilClip(polilClip); + LibMemPolil(resultado); + //lanzamos el mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return NULL; + } + //vamos a la siguiente vuelta del bucle + continue; + } + } + //dirección de inicio de los vértices del polígono de recorte + pos = poliRec->posIni[j]; + //creamos el polígono de recorte de trabajo + poligClip = CreaPoliClip(&(poliRec->x[pos]),&(poliRec->y[pos]), + poliRec->nVert[j],1,1); + //comprobamos los posibles errores + if(poligClip==NULL) + { + //liberamos la memoria asignada hasta ahora + LibMemPolilClip(polilClip); + LibMemPolil(resultado); + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return NULL; + } + //recortamos + polilAux = RecortaPolil(polilClip,poligClip,op,&nInt); + //comprobamos los posibles errores + if(polilAux==NULL) + { + //liberamos la posible memoria asignada hasta ahora + LibMemPolilClip(polilClip); + LibMemPoliClip(poligClip); + LibMemPolil(resultado); + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return NULL; + } + //sumamos el número de intersecciones + (*nIntersec) += nInt; + //añadimos la polilínea recortada a la variable de salida + if(AnyadePolilPolil(resultado,polilAux)==GEOC_ERR_ASIG_MEMORIA) + { + //liberamos la posible memoria asignada hasta ahora + LibMemPolilClip(polilClip); + LibMemPoliClip(poligClip); + LibMemPolil(polilAux); + LibMemPolil(resultado); + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return NULL; + } + //liberamos la memoria asignada al polígono de esta vuelta del bucle + LibMemPoliClip(poligClip); + //liberamos la memoria asignada a la polilínea auxiliar + LibMemPolil(polilAux); + //reinicializamos la polilínea a recortar + polilClip = ReiniciaPolilClip(polilClip); + } + //liberamos la memoria asignada a la polilínea de esta vuelta del bucle + LibMemPolilClip(polilClip); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return resultado; +} +/******************************************************************************/ +/******************************************************************************/ +polil* CreaPolilPolilClip(vertPolilClip* poli) +{ + //índice para recorrer bucles + size_t i=0; + //número de elementos + size_t nVert=0,nElem=0; + //estructura auxiliar + vertPolilClip* aux=poli; + //variable de salida + polil* result=NULL; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //creamos la estructura vacía + result = IniciaPolilVacia(); + //comprobamos los posibles errores + if(result==NULL) + { + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return NULL; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //contamos todos los vértices de la polilínea + nVert = NumeroVertPolilClip(poli); + //contemplamos una posible salida rápida + if(nVert==0) + { + //devolvemos la estructura vacía + return result; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //número de elementos de los vectores de coordenadas + nElem = nVert+2; + //asignamos memoria para los vectores de coordenadas de la estructura + result->x = (double*)malloc(nElem*sizeof(double)); + result->y = (double*)malloc(nElem*sizeof(double)); + //asignamos memoria para los vectores de posición + result->posIni = (size_t*)malloc(sizeof(size_t)); + result->nVert = (size_t*)malloc(sizeof(size_t)); + //comprobamos los posibles errores de asignación de memoria + if((result->x==NULL)||(result->y==NULL)||(result->posIni==NULL)|| + (result->nVert==NULL)) + { + //liberamos la posible memoria asignada + LibMemPolil(result); + //mensaje de error + GEOC_ERROR("Error de asignación de memoria"); + //salimos de la función + return NULL; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //asignamos el número de elementos de los vectores de coordenadas y de + //polilíneas + result->nElem = nElem; + result->nPolil = 1; + //asignamos la posición de inicio y el número de vértices + result->posIni[0] = 1; + result->nVert[0] = nVert; + //asignamos los separadores de polilínea al principio y al final + result->x[0] = GeocNan(); + result->y[0] = GeocNan(); + result->x[nElem-1] = GeocNan(); + result->y[nElem-1] = GeocNan(); + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //recorremos los vértices de la polilínea + for(i=1;i<=nVert;i++) + { + //copio las coordenadas del vértice + result->x[i] = aux->x; + result->y[i] = aux->y; + //siguiente vértice + aux = aux->siguiente; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return result; +} +/******************************************************************************/ +/******************************************************************************/ +/** @} */ +/******************************************************************************/ +/******************************************************************************/ +/* 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/segmento.c b/src/segmento.c new file mode 100644 index 0000000..836b5cc --- /dev/null +++ b/src/segmento.c @@ -0,0 +1,476 @@ +/* -*- coding: utf-8 -*- */ +/** +\ingroup geom +@{ +\file segmento.c +\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 +\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 + 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/segmento.h" +/******************************************************************************/ +/******************************************************************************/ +int TresPuntosColineales2D(const double xA, + const double yA, + const double xB, + const double yB, + const double xC, + const double yC) +{ + //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 + //calculamos y salimos de la función + return (POS_PTO_RECTA_2D(xA,yA,xB,yB,xC,yC)==0.0); +} +/******************************************************************************/ +/******************************************************************************/ +int PuntoEntreDosPuntos2DColin(const double x, + const double y, + const double xA, + const double yA, + const double xB, + const double yB) +{ + //código de salida + int cod=0; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //distinguimos entre segmento vertical y no vertical + if(xA!=xB) + { + //segmento no vertical, utilizamos las coordenadas X + cod = ((xAx)&&(x>xB)); + } + else + { + //segmento vertical, utilizamos las coordenadas Y + cod = ((yAy)&&(y>yB)); + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return cod; +} +/******************************************************************************/ +/******************************************************************************/ +int PtoComunSegmParalelos2D(const double xA, + const double yA, + const double xB, + const double yB, + const double xC, + const double yC, + const double xD, + const double yD, + double* x, + double* y) +{ + //variable de salida + int cod=GEOC_SEG_NO_INTERSEC; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //comprobamos si los puntos son colineales + if(!TresPuntosColineales2D(xA,yA,xB,yB,xC,yC)) + { + //los segmentos son paralelos, pero no se cortan + return GEOC_SEG_NO_INTERSEC; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //comprobamos si los segmentos son el mismo + if(((xA==xC)&&(yA==yC)&&(xB==xD)&&(yB==yD))|| + ((xA==xD)&&(yA==yD)&&(xB==xC)&&(yB==yC))) + { + //coordenadas de salida + *x = xA; + *y = yA; + //los segmentos son el mismo + return GEOC_SEG_INTERSEC_MISMO_SEG; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //comprobamos si algún punto está entre medias del otro segmento + if(PuntoEntreDosPuntos2DColin(xA,yA,xC,yC,xD,yD)) + { + //el punto A está en el segmento CD + *x = xA; + *y = yA; + //salimos + return GEOC_SEG_INTERSEC_COLIN; + } + else if(PuntoEntreDosPuntos2DColin(xC,yC,xA,yA,xB,yB)) + { + //el punto C está en el segmento AB + *x = xC; + *y = yC; + //salimos + return GEOC_SEG_INTERSEC_COLIN; + } + else if(PuntoEntreDosPuntos2DColin(xB,yB,xC,yC,xD,yD)) + { + //el punto B está en el segmento CD + *x = xB; + *y = yB; + //salimos + return GEOC_SEG_INTERSEC_COLIN; + } + else if(PuntoEntreDosPuntos2DColin(xD,yD,xA,yA,xB,yB)) + { + //el punto D está en el segmento AB + *x = xD; + *y = yD; + //salimos + return GEOC_SEG_INTERSEC_COLIN; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //comprobamos si sólo comparten el extremo A + if(((xA==xC)&&(yA==yC))||((xA==xD)&&(yA==yD))) + { + //coordenadas de salida + *x = xA; + *y = yA; + //los segmentos comparten un extremo + return GEOC_SEG_INTERSEC_EXTREMOS_COLIN; + } + //comprobamos si sólo comparten el extremo B + if(((xB==xC)&&(yB==yC))||((xB==xD)&&(yB==yD))) + { + //coordenadas de salida + *x = xB; + *y = yB; + //los segmentos comparten un extremo + return GEOC_SEG_INTERSEC_EXTREMOS_COLIN; + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //salimos de la función + return cod; +} +/******************************************************************************/ +/******************************************************************************/ +int IntersecSegmentos2D(const double xA, + const double yA, + const double xB, + const double yB, + const double xC, + const double yC, + const double xD, + const double yD, + 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=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))) + { + //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 = 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(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 = 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)) + { + //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 = -(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)) + { + //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; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //comprobamos si estamos ante una intersección pura y dura o los segmentos + //no se cortan + if((s>0.0)&&(s<1.0)&&(t>0.0)&&(t<1.0)) + { + //asignamos la variable de salida + cod = GEOC_SEG_INTERSEC; + } + else if((s<0.0)||(s>1.0)||(t<0.0)||(t>1.0)) + { + //asignamos la variable de salida + cod = GEOC_SEG_NO_INTERSEC; + } + //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 + return cod; +} +/******************************************************************************/ +/******************************************************************************/ +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; +} +/******************************************************************************/ +/******************************************************************************/ +/** @} */ +/******************************************************************************/ +/******************************************************************************/ +/* 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/ventorno.c b/src/ventorno.c new file mode 100644 index 0000000..d5ca57f --- /dev/null +++ b/src/ventorno.c @@ -0,0 +1,86 @@ +/* -*- coding: utf-8 -*- */ +/** +\ingroup anespec general +@{ +\file ventorno.c +\brief Definición de funciones para el control de variables de entorno. +\author José Luis García Pallero, jgpallero@gmail.com +\date 31 de marzo de 2011 +\version 1.0 +\section Licencia Licencia +Copyright (c) 2011, 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/ventorno.h" +/******************************************************************************/ +/******************************************************************************/ +int VarEnvValRef(const char* var, + const char* valRef) +{ + //posible valor de la variable de entorno + char* valEnv=NULL; + //variable de salida + int salida=0; + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //extraemos el valor de la variable de entorno + valEnv = getenv(var); + //comprobamos si la variable está definida + if(valEnv==NULL) + { + //se devuelve menor que 0 + salida = -1; + } + else + { + //comprobamos su valor + if(strcmp(valEnv,valRef)) + { + //su valor es distinto al de referencia + salida = 0; + } + else + { + //si es igual al de referencia + salida = 1; + } + } + //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////// + //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; */ -- cgit v1.2.3 From 6612f08f61d3181d3a810463d12b954b288791d6 Mon Sep 17 00:00:00 2001 From: Rafael Laboissiere Date: Tue, 26 May 2020 05:46:48 -0300 Subject: Do not strip the debugging symbols from _oc_polybool.oct Forwarded: https://savannah.gnu.org/bugs/index.php?55343 Last-Update: 2020-05-26 Also, include the -g option to enable debugging option for all compilers. Gbp-Pq: Name do-not-strip-debugging-symbols.patch --- src/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile b/src/Makefile index e15c37a..6e5f736 100644 --- a/src/Makefile +++ b/src/Makefile @@ -40,7 +40,7 @@ compile: $(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 + $(MKOCTFILE) -g -I. _oc_polybool.cc *.o .PHONY: clean clean: -- cgit v1.2.3 From c05b90afa9f36563981dc34da6574dd2280629a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Laboissi=C3=A8re?= Date: Tue, 26 May 2020 05:46:48 -0300 Subject: Fix documentation in doc string of function _oc_polybool Forwarded: https://savannah.gnu.org/bugs/index.php?58446 Last-Update: 2020-05-26 Gbp-Pq: Name spelling-doc-oc-polybool.patch --- src/_oc_polybool.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/_oc_polybool.cc b/src/_oc_polybool.cc index 058bdf8..1a51527 100644 --- a/src/_oc_polybool.cc +++ b/src/_oc_polybool.cc @@ -72,7 +72,7 @@ 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\ +@var{p} where the polygon end, and the third column 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\ -- cgit v1.2.3 From edebec8d9a313a781415599613c0df3c6c5cc595 Mon Sep 17 00:00:00 2001 From: Rafael Laboissiere Date: Sun, 14 Nov 2021 14:03:11 -0300 Subject: Do not strip the debugging symbols from _oc_polybool.oct Forwarded: https://savannah.gnu.org/bugs/index.php?55343 Last-Update: 2020-05-26 Also, include the -g option to enable debugging option for all compilers. Gbp-Pq: Name do-not-strip-debugging-symbols.patch --- src/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile b/src/Makefile index e15c37a..6e5f736 100644 --- a/src/Makefile +++ b/src/Makefile @@ -40,7 +40,7 @@ compile: $(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 + $(MKOCTFILE) -g -I. _oc_polybool.cc *.o .PHONY: clean clean: -- cgit v1.2.3 From fbcac7922bbc7410b3495f3ca43c290043910ec5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Laboissi=C3=A8re?= Date: Sun, 14 Nov 2021 14:03:11 -0300 Subject: Fix documentation in doc string of function _oc_polybool Forwarded: https://savannah.gnu.org/bugs/index.php?58446 Last-Update: 2020-05-26 Gbp-Pq: Name spelling-doc-oc-polybool.patch --- src/_oc_polybool.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/_oc_polybool.cc b/src/_oc_polybool.cc index 058bdf8..1a51527 100644 --- a/src/_oc_polybool.cc +++ b/src/_oc_polybool.cc @@ -72,7 +72,7 @@ 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\ +@var{p} where the polygon end, and the third column 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\ -- cgit v1.2.3 From 22d474141a1f1672137497da77965ae364dd21c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Laboissi=C3=A8re?= Date: Sun, 14 Nov 2021 14:03:11 -0300 Subject: Honor the environment variable CFLAGS and CXXFLAGS Forwarded: https://savannah.gnu.org/bugs/index.php?61483 Last-Update: 2021-11-14 This is required in Debian, such that hardening flags like -fstack-protector-strong, -Wformat, and -Werror=format-security are used in the compilation of C++ files. Gbp-Pq: Name honor-cflags-cxxflags.patch --- src/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Makefile b/src/Makefile index 6e5f736..a368bc2 100644 --- a/src/Makefile +++ b/src/Makefile @@ -6,10 +6,10 @@ FLAGSCOMW=-Wall -Wextra -Wshadow -Wcast-qual -Wcast-align -Wwrite-strings #Common optimization flags for C and C++ FLAGSCOMO=-O2 -funroll-loops -fno-common -fshort-enums #Flags for C -CFLAGS=-std=c99 -pedantic $(FLAGSCOMW) -Wconversion -Wmissing-prototypes +CFLAGS+=-std=c99 -pedantic $(FLAGSCOMW) -Wconversion -Wmissing-prototypes CFLAGS+=-Wstrict-prototypes -Wnested-externs $(FLAGSCOMO) #Flags for C++ -CXXFLAGS=$(FLAGSCOMW) $(FLAGSCOMO) +CXXFLAGS+=$(FLAGSCOMW) $(FLAGSCOMO) #Export flags for compilers and linker export CFLAGS CXXFLAGS -- cgit v1.2.3 From a729b9e52c2abae729ad5e30e809c1eb15003ed2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Laboissi=C3=A8re?= Date: Sun, 14 Nov 2021 14:03:11 -0300 Subject: Use string literal in call to error() function Forwarded: https://savannah.gnu.org/bugs/index.php?61484 Last-Update: 2021-11-14 Compilation errors are triggered when option -Werror=format-security is used. Gbp-Pq: Name format-security-error.patch --- src/_oc_polybool.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/_oc_polybool.cc b/src/_oc_polybool.cc index 1a51527..af95cb0 100644 --- a/src/_oc_polybool.cc +++ b/src/_oc_polybool.cc @@ -113,7 +113,7 @@ DEFUN_DLD(_oc_polybool,args,,HELPTEXT) "Incorrect number of input arguments\n\t" "See help _oc_polybool"); //error message - error(errorText); + error("%s", errorText); } else { @@ -161,7 +161,7 @@ DEFUN_DLD(_oc_polybool,args,,HELPTEXT) //error text sprintf(&errorText[strlen(errorText)],"Error in memory allocation"); //error message - error(errorText); + error("%s", errorText); //exit return outputList; } @@ -199,7 +199,7 @@ DEFUN_DLD(_oc_polybool,args,,HELPTEXT) "The third input argument (op=%s) is not correct", opchar.c_str()); //error message - error(errorText); + error("%s", errorText); //exit return outputList; } @@ -217,7 +217,7 @@ DEFUN_DLD(_oc_polybool,args,,HELPTEXT) //error text sprintf(&errorText[strlen(errorText)],"Error in memory allocation"); //error message - error(errorText); + error("%s", errorText); //exit return outputList; } -- cgit v1.2.3