octclip-2.0.1/0000755000175000017500000000000013657741226011610 5ustar olafolafoctclip-2.0.1/INDEX0000644000175000017500000000014213655033577012400 0ustar olafolaftoolbox >> OctCLIP Category Kernel functions _oc_polybool Category Driver functions oc_polybool octclip-2.0.1/inst/0000755000175000017500000000000013656317046012563 5ustar olafolafoctclip-2.0.1/inst/oc_polybool.m0000644000175000017500000003200113656316704015255 0ustar olafolaf## 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 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 octclip-2.0.1/COPYING0000644000175000017500000010451313655034206012636 0ustar olafolaf 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 . octclip-2.0.1/NEWS0000644000175000017500000000310713657740157012312 0ustar olafolafSummary 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 octclip-2.0.1/src/0000755000175000017500000000000013657740731012377 5ustar olafolafoctclip-2.0.1/src/posmatvec.c0000644000175000017500000003022212175463336014540 0ustar olafolaf/* -*- 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; */ octclip-2.0.1/src/dpeuckera.c0000644000175000017500000002004212463476247014506 0ustar olafolaf/* -*- coding: utf-8 -*- */ /** \ingroup geom @{ \file dpeuckera.c \brief Declaración de funciones auxiliares para el uso de la familia de algoritmos de Douglas-Peucker. \author José Luis García Pallero, jgpallero@gmail.com \date 01 de abril de 2014 \copyright Copyright (c) 2014, José Luis García Pallero. All rights reserved. \par Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: \par - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - Neither the name of the copyright holders nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. \par THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /******************************************************************************/ /******************************************************************************/ #include"libgeoc/dpeuckera.h" /******************************************************************************/ /******************************************************************************/ size_t* CasosEspecialesAligeraPolilinea(const double* x, const double* y, const size_t nPtos, const size_t incX, const size_t incY, const double tol, size_t* nPtosSal, int* hayCasoEspecial) { //índice para recorrer bucles size_t i=0; //valor absoluto de la tolerancia double atol=fabs(tol); //vector de salida size_t* salida=NULL; //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //en principio, el número de puntos de salida es el mismo que el de entrada *nPtosSal = nPtos; //inicializamos la variable indicadora de caso especial a 0 *hayCasoEspecial = 0; //vamos comprobando casos especiales if(nPtos==0) { //indicamos que estamos anteun caso especial *hayCasoEspecial = 1; //actualizamos la variable de número de puntos de salida *nPtosSal = 0; //salimos de la función return NULL; } else if(nPtos==1) { //indicamos que estamos anteun caso especial *hayCasoEspecial = 1; //asignamos memoria para el vector de salida salida = (size_t*)malloc(sizeof(size_t)); //comprobamos si ha ocurrido algún error if(salida==NULL) { //mensaje de error GEOC_ERROR("Error de asignación de memoria"); //salimos de la función return NULL; } //la entrada sólo es un punto *nPtosSal = 1; salida[0] = 0; } else if(nPtos==2) { //indicamos que estamos ante un caso especial *hayCasoEspecial = 1; //en principio, los dos puntos son válidos *nPtosSal = 2; //comprobamos si los puntos son o no el mismo if((x[0]==x[incX])&&(y[0]==y[incY])) { //sólo vale el primer punto *nPtosSal = 1; } //asignamos memoria para el vector de salida salida = (size_t*)malloc((*nPtosSal)*sizeof(size_t)); //comprobamos si ha ocurrido algún error if(salida==NULL) { //mensaje de error GEOC_ERROR("Error de asignación de memoria"); //salimos de la función return NULL; } //copiamos los puntos válidos for(i=0;i<(*nPtosSal);i++) { salida[i] = i; } } else if((nPtos==3)&&(x[0]==x[2*incX])&&(y[0]==y[2*incY])) { //indicamos que estamos ante un caso especial *hayCasoEspecial = 1; //en principio, hay dos puntos válidos *nPtosSal = 2; //comprobamos también si el segundo punto es el mismo que el primero if((x[0]==x[incX])&&(y[0]==y[incY])) { //sólo vale el primer punto *nPtosSal = 1; } //asignamos memoria para el vector de salida salida = (size_t*)malloc((*nPtosSal)*sizeof(size_t)); //comprobamos si ha ocurrido algún error if(salida==NULL) { //mensaje de error GEOC_ERROR("Error de asignación de memoria"); //salimos de la función return NULL; } //copiamos los puntos válidos for(i=0;i<(*nPtosSal);i++) { salida[i] = i; } } else if(atol==0.0) { //indicamos que estamos anteun caso especial *hayCasoEspecial = 1; //asignamos memoria para el vector de salida salida = (size_t*)malloc(nPtos*sizeof(size_t)); //comprobamos si ha ocurrido algún error if(salida==NULL) { //mensaje de error GEOC_ERROR("Error de asignación de memoria"); //salimos de la función return NULL; } //inicializamos el número de puntos de salida y la posición del primero *nPtosSal = 1; salida[0] = 0; //recorremos el resto de puntos for(i=1;i * * 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; } octclip-2.0.1/src/dpeucker.c0000644000175000017500000003075312463476241014351 0ustar olafolaf/* -*- 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;i=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;i #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; */ octclip-2.0.1/src/libgeoc/errores.h0000644000175000017500000013637513655033577015655 0ustar olafolaf/* -*- 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; */ octclip-2.0.1/src/libgeoc/mate.h0000644000175000017500000005736512463477120015113 0ustar olafolaf/* -*- 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; */ octclip-2.0.1/src/libgeoc/dpeuckere.h0000644000175000017500000017041412463476262016131 0ustar olafolaf/* -*- coding: utf-8 -*- */ /** \ingroup geom @{ \file dpeuckere.h \brief Declaración de funciones auxiliares para el aligerado de polilíneas sobre la superficie de la esfera, basadas en el algoritmo de Douglas-Peucker. \author José Luis García Pallero, jgpallero@gmail.com \note Este fichero contiene funciones paralelizadas con OpenMP. \date 15 de agosto de 2013 \copyright Copyright (c) 2013-2014, José Luis García Pallero. All rights reserved. \par Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: \par - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - Neither the name of the copyright holders nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. \par THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /******************************************************************************/ /******************************************************************************/ #ifndef _DPEUCKERE_H_ #define _DPEUCKERE_H_ /******************************************************************************/ /******************************************************************************/ #if defined(_OPENMP) #include #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; */ octclip-2.0.1/src/libgeoc/compilador.h0000644000175000017500000001226113655033577016310 0ustar olafolaf/* -*- 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; */ octclip-2.0.1/src/libgeoc/arco.h0000644000175000017500000010452412463476227015106 0ustar olafolaf/* -*- 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; */ octclip-2.0.1/src/libgeoc/ptopol.h0000644000175000017500000024264713656245544015511 0ustar olafolaf/* -*- 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; */ octclip-2.0.1/src/libgeoc/dpeuckera.h0000644000175000017500000002666512463476253016135 0ustar olafolaf/* -*- 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 #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; */ octclip-2.0.1/src/libgeoc/proyecaux.h0000644000175000017500000001106712463477176016204 0ustar olafolaf/* -*- 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; */ octclip-2.0.1/src/libgeoc/geocomp.h0000644000175000017500000002311413655033577015607 0ustar olafolaf/* -*- 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; */ octclip-2.0.1/src/libgeoc/posmatvec.h0000644000175000017500000006444012175464533016162 0ustar olafolaf/* -*- 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; */ octclip-2.0.1/src/libgeoc/geom.h0000644000175000017500000000640513655033577015111 0ustar olafolaf/* -*- 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; */ octclip-2.0.1/src/libgeoc/eucli.h0000644000175000017500000002642113655033577015263 0ustar olafolaf/* -*- 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; */ octclip-2.0.1/src/libgeoc/polil.h0000644000175000017500000013235712463476332015303 0ustar olafolaf/* -*- 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; */ octclip-2.0.1/src/libgeoc/general.h0000644000175000017500000000624313655033577015577 0ustar olafolaf/* -*- 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; */ octclip-2.0.1/src/libgeoc/greiner.h0000644000175000017500000013375313656244065015621 0ustar olafolaf/* -*- 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; */ octclip-2.0.1/src/libgeoc/recpolil.h0000644000175000017500000005627413656226554016004 0ustar olafolaf/* -*- 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; */ octclip-2.0.1/src/libgeoc/polig.h0000644000175000017500000020612513656066424015273 0ustar olafolaf/* -*- 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; */ octclip-2.0.1/src/libgeoc/dpeuckerp.h0000644000175000017500000013145112463476271016142 0ustar olafolaf/* -*- 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; */ octclip-2.0.1/src/libgeoc/fgeneral.h0000644000175000017500000011267413242775336015751 0ustar olafolaf/* -*- 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; */ octclip-2.0.1/src/libgeoc/ventorno.h0000644000175000017500000001174613655033577016040 0ustar olafolaf/* -*- 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; */ octclip-2.0.1/src/libgeoc/geocnan.h0000644000175000017500000002746413655033577015604 0ustar olafolaf/* -*- 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; */ octclip-2.0.1/src/libgeoc/segmento.h0000644000175000017500000004602212463476354016002 0ustar olafolaf/* -*- 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; */ octclip-2.0.1/src/eucli.c0000644000175000017500000002443313655033577013653 0ustar olafolaf/* -*- 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; */ octclip-2.0.1/src/Makefile0000644000175000017500000000330013657740722014033 0ustar olafolaf# -*- coding: utf-8 -*- #Compiler MKOCTFILE?=mkoctfile #Common warning flags for C and C++ FLAGSCOMW=-Wall -Wextra -Wshadow -Wcast-qual -Wcast-align -Wwrite-strings #Common optimization flags for C and C++ FLAGSCOMO=-O2 -funroll-loops -fno-common -fshort-enums #Flags for C CFLAGS=-std=c99 -pedantic $(FLAGSCOMW) -Wconversion -Wmissing-prototypes CFLAGS+=-Wstrict-prototypes -Wnested-externs $(FLAGSCOMO) #Flags for C++ CXXFLAGS=$(FLAGSCOMW) $(FLAGSCOMO) #Export flags for compilers and linker export CFLAGS CXXFLAGS .PHONY: all all: compile .PHONY: compile compile: $(MKOCTFILE) -c -I. calctopo.c -o calctopo.o $(MKOCTFILE) -c -I. compilador.c -o compilador.o $(MKOCTFILE) -c -I. dpeuckera.c -o dpeuckera.o $(MKOCTFILE) -c -I. dpeuckere.c -o dpeuckere.o $(MKOCTFILE) -c -I. dpeuckerp.c -o dpeuckerp.o $(MKOCTFILE) -c -I. dpeucker.c -o dpeucker.o $(MKOCTFILE) -c -I. errores.c -o errores.o $(MKOCTFILE) -c -I. eucli.c -o eucli.o $(MKOCTFILE) -c -I. fgeneral.c -o fgeneral.o $(MKOCTFILE) -c -I. geocnan.c -o geocnan.o $(MKOCTFILE) -c -I. geocomp.c -o geocomp.o $(MKOCTFILE) -c -I. -DCOLUMN_MAJOR_ORDER_MATVEC posmatvec.c -o posmatvec.o $(MKOCTFILE) -c -I. -DCALCULO_PRODUCTO_MULT mate.c -o mate.o $(MKOCTFILE) -c -I. arco.c -o arco.o $(MKOCTFILE) -c -I. greiner.c -o greiner.o $(MKOCTFILE) -c -I. polig.c -o polig.o $(MKOCTFILE) -c -I. polil.c -o polil.o $(MKOCTFILE) -c -I. ptopol.c -o ptopol.o $(MKOCTFILE) -c -I. recpolil.c -o recpolil.o $(MKOCTFILE) -c -I. segmento.c -o segmento.o $(MKOCTFILE) -c -I. ventorno.c -o ventorno.o $(MKOCTFILE) -c -I. proyecaux.c -o proyecaux.o $(MKOCTFILE) -s -I. _oc_polybool.cc *.o .PHONY: clean clean: rm -rf *.o *~ .PHONY: cleanall cleanall: rm -rf *~ *.o *.oct octclip-2.0.1/src/polil.c0000644000175000017500000016550313655514100013657 0ustar olafolaf/* -*- 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; */ octclip-2.0.1/src/recpolil.c0000644000175000017500000017252512463476337014372 0ustar olafolaf/* -*- 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; */ octclip-2.0.1/src/geocnan.c0000644000175000017500000002045213655033577014161 0ustar olafolaf/* -*- coding: utf-8 -*- */ /** \ingroup geocnan geom matriz gshhs @{ \file geocnan.c \brief Definición de funciones para el trabajo con constantes 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. */ /******************************************************************************/ /******************************************************************************/ #include"libgeoc/geocnan.h" /******************************************************************************/ /******************************************************************************/ double GeocNan(void) { //devolvemos el valor de NaN //le calculamos el valor absoluto porque, en algunos sistemas, al imprimir //un valor GEOC_NAN normal, éste sale con un signo negativo delante //aclaración a 22 de septiembre de 2011: parecía que con lo del fabs() //estaba solucionado el asunto del signo negativo, pero no es así //la impresión con signo negativo parece que depende de los flags de //optimización al compilar y de los propios compiladores //no obstante, se mantiene el fabs() return fabs(GEOC_NAN); } /******************************************************************************/ /******************************************************************************/ int EsGeocNan(const double valor) { //comparamos y salimos de la función return valor!=valor; } /******************************************************************************/ /******************************************************************************/ size_t* PosGeocNanEnVector(const double* datos, const size_t nDatos, const size_t incDatos, size_t* nNan) { //índice para recorrer bucles size_t i=0; //vector de salida size_t* salida=NULL; //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //inicializamos a 0 el número de NaN encontrados *nNan = 0; //comprobamos una posible salida rápida if(nDatos==0) { //salimos de la función return salida; } //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //recorremos los elementos de los vectores for(i=0;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 /******************************************************************************/ /******************************************************************************/ octclip-2.0.1/src/mate.c0000644000175000017500000010570213025312637013463 0ustar olafolaf/* -*- 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;iatol) { //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; */ octclip-2.0.1/src/polig.c0000644000175000017500000023536513656250412013662 0ustar olafolaf/* -*- 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; */ octclip-2.0.1/src/geocomp.c0000644000175000017500000001201613655033577014175 0ustar olafolaf/* -*- coding: utf-8 -*- */ /** \ingroup anespec general geocomp geodesia geom geopot gravim mmcc @{ \file geocomp.c \brief Definición de 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. */ /******************************************************************************/ /******************************************************************************/ #include"libgeoc/geocomp.h" /******************************************************************************/ /******************************************************************************/ void VersionOpenMP(const int macro_OPENMP, char version[]) { //vamos comprobando los valores de la macro if(macro_OPENMP==GEOC_OMP_F_1_0) { //versión 1.0 strcpy(version,GEOC_OMP_V_1_0); } else if(macro_OPENMP==GEOC_OMP_F_2_0) { //versión 2.0 strcpy(version,GEOC_OMP_V_2_0); } else if(macro_OPENMP==GEOC_OMP_F_2_5) { //versión 2.5 strcpy(version,GEOC_OMP_V_2_5); } else if(macro_OPENMP==GEOC_OMP_F_3_0) { //versión 3.0 strcpy(version,GEOC_OMP_V_3_0); } else if(macro_OPENMP==GEOC_OMP_F_3_1) { //versión 3.1 strcpy(version,GEOC_OMP_V_3_1); } else { //versión desconocida strcpy(version,GEOC_OMP_V_DESC); } //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //salimos de la función return; } /******************************************************************************/ /******************************************************************************/ int FechaVersionOpenMP(const char version[]) { //variable de salida int fecha=GEOC_OMP_F_DESC; //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //vamos comprobando los valores de la versión if(!strcmp(version,GEOC_OMP_V_1_0)) { //versión 1.0 fecha = GEOC_OMP_F_1_0; } else if(!strcmp(version,GEOC_OMP_V_2_0)) { //versión 2.0 fecha = GEOC_OMP_F_2_0; } else if(!strcmp(version,GEOC_OMP_V_2_5)) { //versión 2.5 fecha = GEOC_OMP_F_2_5; } else if(!strcmp(version,GEOC_OMP_V_3_0)) { //versión 3.0 fecha = GEOC_OMP_F_3_0; } else if(!strcmp(version,GEOC_OMP_V_3_1)) { //versión 3.1 fecha = GEOC_OMP_F_3_1; } //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //salimos de la función return fecha; } /******************************************************************************/ /******************************************************************************/ /** @} */ /******************************************************************************/ /******************************************************************************/ /* 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; */ octclip-2.0.1/src/ventorno.c0000644000175000017500000000742213655033577014423 0ustar olafolaf/* -*- 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; */ octclip-2.0.1/src/proyecaux.c0000644000175000017500000001035512463477174014570 0ustar olafolaf/* -*- 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; */ octclip-2.0.1/src/compilador.c0000644000175000017500000000744113655033577014703 0ustar olafolaf/* -*- 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; */ octclip-2.0.1/src/greiner.c0000644000175000017500000023670213656244246014207 0ustar olafolaf/* -*- coding: utf-8 -*- */ /** \ingroup geom gshhs @{ \file greiner.c \brief Definició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. */ /******************************************************************************/ /******************************************************************************/ #include"libgeoc/greiner.h" /******************************************************************************/ /******************************************************************************/ 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) { //variable de salida (nuevo vértice) vertPoliClip* nuevoVert=NULL; //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //asignamos memoria para el nuevo vértice nuevoVert = (vertPoliClip*)malloc(sizeof(vertPoliClip)); //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->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; */ octclip-2.0.1/src/arco.c0000644000175000017500000011110412463476223013461 0ustar olafolaf/* -*- 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; */ octclip-2.0.1/src/calctopo.c0000644000175000017500000000702713655033577014356 0ustar olafolaf/* -*- 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; */ octclip-2.0.1/src/segmento.c0000644000175000017500000004652312463476350014373 0ustar olafolaf/* -*- 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; */ octclip-2.0.1/src/errores.c0000644000175000017500000001353513655033577014234 0ustar olafolaf/* -*- 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; */ octclip-2.0.1/src/dpeuckere.c0000644000175000017500000017557613655510024014523 0ustar olafolaf/* -*- coding: utf-8 -*- */ /** \ingroup geom @{ \file dpeuckere.c \brief Definición de funciones auxiliares para el aligerado de polilíneas sobre la superficie de la esfera, basadas en el algoritmo de Douglas-Peucker. \author José Luis García Pallero, jgpallero@gmail.com \note Este fichero contiene funciones paralelizadas con OpenMP. \date 15 de agosto de 2013 \copyright Copyright (c) 2013-2020, José Luis García Pallero. All rights reserved. \par Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: \par - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - Neither the name of the copyright holders nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. \par THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /******************************************************************************/ /******************************************************************************/ #include"libgeoc/dpeuckere.h" /******************************************************************************/ /******************************************************************************/ int GeocParOmpDpeuckere(char version[]) { //comprobamos si hay paralelización #if defined(_OPENMP) //comprobamos si hay que extraer versión if(version!=NULL) { //calculamos la versión VersionOpenMP(_OPENMP,version); } //salimos de la función return 1; #else if(version!=NULL) { //utilizamos la variable version para que no dé warming al compilar strcpy(version,""); } //salimos de la función return 0; #endif } /******************************************************************************/ /******************************************************************************/ void DouglasPeuckerOriginalEsfera(const double* x, const double* y, const size_t nPtos, const size_t incX, const size_t incY, const double tol, const size_t posIni, const size_t posFin, char* usados) { //índice para recorrer bucles size_t i=0; //seno de la distancia angular de los puntos al segmento base double dist=0.0; //valor absoluto del seno de la tolerancia, excepto en el caso en que ésta //sea mayor que pi/2, que hacemos 1-cos(tol) para que quede un valor mayor //que 1 double stol=(tol<=(2.0*GEOC_CONST_PI)) ? fabs(sin(tol)) : 1.0-cos(tol); //posición de la distancia máxima size_t pos=0; //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //comprobamos casos especiales if((nPtos<=2)||(stol==0.0)) { //se usan todos los puntos for(i=0;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)&&(lonVRlong 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; */ octclip-2.0.1/doc/0000755000175000017500000000000013657741233012353 5ustar olafolafoctclip-2.0.1/doc/octclip.pdf0000644000175000017500000063617113657740352014522 0ustar olafolaf%PDF-1.5 % 47 0 obj << /Length 1960 /Filter /FlateDecode >> stream xڥXM{6WH&/ڦ7y6uOI4 H(RKRv}߾3P"n fGG7W۫kF"gR:aQi&MчUv;nV2ޭ]ځ\Kߛ_~ƯX@k%"!X7 6-(cR7$'\" g*DL׋톕\l(;)j%xA"lڲilL"‡@ji>J4+,J?%&CDvMʕ|)D)kIT2 BsJRJ%+d'RخqLdlꄣ>L3R.}oi\HiuB7͖: &4?*-Q2WFߗspN[ɏtG{SJkweaQ|Ajf8Sۦ 8Vtەnesn,[%Zʹ1^S.H^4p3j背"0/q>4:U;Mw4d|o}DwAp.72t)] G&ƿ񼔊R _S.yr5 S$`3n-^Y$Om5`mwp :Gx@㦷}ϮߖmKnkֶhxبtɁgn|" úr@1*mYcK.E`-.ۚnpsX,$t|?i瘭k@aI0YOhs͆8nvXP2U~z#Q)QAœ`BgS2!#+%MTvNE 1ńHpss1 W5s\u{dBci4PY褞ipphf;FH}.$!mLL%[?Sq>mg{V!}XaCk B]޷ :v43 tHI_S 2.R 20&oGxzzb|Yo m=' n*+W&,X>OY%9V-}o10`,q&"Qxmolx2>~JJb [ჩƚ/{dVeݻzy͆}2 ޯCgtZLc,_ Z0s  endstream endobj 72 0 obj << /Length 2345 /Filter /FlateDecode >> stream xڭY˒W3PzB#l~ѨPm5wάbf4sY{}U]s&N i`fi"eX4w=X-Y{+j*|.U1ԧkЅҶud05 \]>lB&Mo*PXN:9="ՆoN&7d2:xgSxZ/ :?'NΖ`י βu `c CW^ Vx>ʏ1F_ O%ۊ1ci4¢*/]OZ8S4.U>ڤ}̟Ҽ+OZ_&;-5aovLSPpJMˇa).oj ͯq6 gpEiNv4h) @|\vK_dNiOJŐw7Aa@id ɨln>$4&:wѽDp]4S􏛿m -Ffԩ69ST*s(ܝ>wڙzƘ;I0$NSUw}es'N|ᅬ]3If ,^R͖AJ/(p qԂT> W`n s |+Pf4 PPs-p&܉RFV[ k7--x(6ȤS4̅2 9ԟԠ鈮r].@ѥ8Oyď@647 ]j8 e]|-?Z2G']sThfDІPK7yy-ՄBQn扴|? +0v~G<h'Nu2YB0ޒ 7W{e|WB]*kVg-I~Խ,zC,;M",8Ѻ#a 4cԺ_N!  1#a70T_0w< gs˙'a83{H{i"C qja'ECG CGDESqc WS ˋ9_dRIrds B6@1~T,{#MݖG6c7!ZnXU3?ti~2 mɰ.`T"w$2MH܆'\.u3>ޠ*ֵ$[ GR ;T˔L?x%q7̱VNN堺FQ?h4Mz*%e)Șrh:\*=vT_Mq/r;Bc_)a׏a)NcY=}"~E)\D^AM!&%U-HzY /)Zݑw~ľ~sXqwX#Z "Bq(ƂF.a}&S` j, =p/UӃQ*Z˱t%1^dz.W0)],'Be6 M&iMs؜%',ĕ܋8b^q<'LS+y\u=3X-㷋yW/]Ie<#AIqMZ1?9d]!W|qe{E˸f B2`qW3@v_@FYBv+نu7zfjz}T3u!k?;KO!A=!uiZj#Rܪ-:@IV@g9>QH$hMY@ 3R|Ћ-}9F8ע? K%O*|m6? endstream endobj 85 0 obj << /Length 1159 /Filter /FlateDecode >> stream xڕVr6+g"$U:N4ɸjIHbML @[eݐ}?@UDo'I$ebQ(#)LF2BI< tbNѝhexƳKOELU]k6i] UZS&x?G˔fQof 9*[gX&Zv* }b *v?ma՝}5^fq#uͫnƘs 4_c9En;SQy&#K!LgICMX髶O߾ɌAMhSa>qYFGB7QuwMݪRR*0I!7bX$תSuM{g,L_]5 <޺KmtSzBA]ѯ̂-p"+~ pi$}v}^f]@@i2 5 'qzgJzWǔCO$rx moqD2z3X4pТ\>BiKR`H2сHٗBA\!"}" C~*~u?}*q ݳa.0͜aa!Wʅ G\.q5R聱_U5 OISq{~MhZT9. *ׅ퇎vR, =hJǾ2x5H9$77>{$Ȩwt ar@uUA!Sx6]A|+~ > stream xڍP-CpwBNM.hqww ![p@Gf̽WWTA׶s>]Qٛ89:\nv.T:: ?vT:-0 bo'/ r~Iv9'7O_!=T rrv`'T: {(>MlP)r>W4M!`gJ(l lL7%@ G(lƎJа8P7wvAg lbge`? XtEN#djjoY!6`3+dgq 6 gbd 88;;Al~$mmvN@r!vf0sqjA]qM,^~>v7.<y  8C]>^v7BAL&` ?ٟ`?C!=gq8~Yafv6b&_#wxrظx9~^QAXY;s{>ZvK-s)?+ `GϿ8Gg ;v'Bl?w0mmr>7-o8Wŝ#9%q;+d]w|n_b2uB?Yi`;uaT(ت67m4&6h-&r SUXgM)Ƌ7^-aImwF jm_ ' (^i~p o풣qtyw+^W}4tv[uOl-F3Z?x.$kəkn\ A wW͌rS7 -.1$^ќWIQ\hT9lhȑkAldb}QDdhNbܜ:N|T'BϨР·*\a_m^_0F K'bO|{0er831!cQ\ݡW!0%UG*'kQXҘI8yњU.O̧/JM^/ ܼA[sv 7+OfX !Ep}K7}=Zh\_]F16Y_PON07K-z-\|L#)y̙Uέ>KojB8MDq耺A4JHR8@1}#&SIת2o%Mѭ&}=m֗JZSJ;;9q0^a;*4]uz{v}1ppTeRq, _mQ2,!njDFb+dbrmQ綪 r%{${ka+2Rƌ@\a]H ^uX"fRz ۆ*ڥ'>D!'y0W@τ""(>,.fVvc 33,P1 ¸jLx )y4|ϨU:л0ՕqOpDbL.Z ¯{Sa)ހeB>ɶyu{v!YKR:*}Z{Q>ա(1WdVy &ISciUeLKt+>4#C$6]1;UPvC`ӥRtIn^:XW)lՃĝ"ז(/J!L0x`vsw4wNEZjJQ44mvW`8M9CktaQַU僰վ8+LD2lF,aH﹮m3 ;7Y0К҃>Qѕc6Ttamhl*%|d 7E"RF:JiȌŻDfy+:X*0(S̑NbsY+9*cn 6}ibpC (>6CNn GlupfXL hֶ6USWPafC駚c%wf!q1ߣ{ey"i{:(*uRtvCuz_j3d(99wN_NA3tj{LtuU4{1-hKٓ.f:,BXoTL+.ic0(UtFV=M0uCM|͕6Jl_v ZyG h+Zo+lL7]w.5.,6f[< ?=KM’5+\ICv_kG(]G)0b|RB)KO_Ì&cƨr06:\xwe"V$ӡ<{%30sn~`^XSznssE׃*!q$6x> S+nB X]8nACQYf%N7EejI'U۞ /w+M\UZ$ UJNSwX~tAѧiXDwHȿ_~5Q9h..galqlٍ&-)[c+1>v5$Opܲ"Nɪ{$}.^H+i1\fcе)鵱ھAqoC &:gdYݕ}okA~vPQXSQ2_1MA- GWq#j(Uj ^{(y AlqP?ȚQޣ:`6'fɤHCg}͍۽Ο Du)I3w62RHe LZ[U/76Yߜt2^ gkb_b-$oT 6)q8-v+ӬSDRC1o2Ao!?vb9 fÃo"0/ nZ ^O--ylod~DyS+؟kSqy):iv.ӞԹ_8* +lr@lIG%j}څ-Gϴ/\/[z}dW%&D=^g( "ǽH12l:1a 03՟Js[`fD)/Ζ4φuEKMZ_(eNG]Sݺ0qe|OOܢ9໙z -ĕ@&XNL4=j]#dJgר=#AQ7?{qXH -ʖdv*3+Me:d:fjLnGh}IXTK hg<ұiFh"^YRIsO@psnzrK!b~ڶitV47ͣ<,)/֤/rnKMhjxhs|C.o, iG|F^cCCɌVu>SrahN3[VD/JV|=3aԦ,i==ȭ ?&$R4dU^^V1.INЗQW`Kkφ5Jb'SG.%T H {.qcs?_}dz eN킖X\Sӝ_^gnz,ryͨ,-oЎ7mXWemJd(5*aVqBT%)Hf[ NUG_ xaNҺKXe۴@M:Suv*ӌ\|WKJX.FY?38)鏘J.7,O hhfD'4.(H}ԣq|@K rBL~jdQE}Ϙ ÷/dsO^{|_332/jX)+4U|y g#x[nڍϙŇ bATBMm#$(g-V3X}Z gr n:|W=~_yEH]IzJh ͆SA^^.IrΚab߃0x~U ͷ[d#*MGSp/m$UutK{͗\~)@c` 'ut|ɘ0_"+&ɢ&^@u׹Qy䳸m/Җ*6C?Ss8`(6?>OAPt=u|FE6,=o%wͧik/_`B_&2߅iJ[+5u3RrKuli:DJatS`pYEynE)0~9aQRFI ARMz˱pyݳ۵iqExXLO{D)gjüHzATOfap_ 8Cq[*dY}La|^ W023zSxourб`j3ɉ\h}%(b7|r06Ět/sH:{0}GUsWԣ T,Ց w][24!uʉ OdGW$`0g n4R _Wޅ.4hHQ SawrsmO]ߞe;vSthK#i. %_DЦ~l}t Q4=WL\1@&L3Io*ėpqayNƬBZkƦCK_mIoa3mZNdr|dDyZ#]6(!6vƸX.R:%/l Ȓ}nW|7} @۔]d9 %\ PgNX ',?uRիɮ)h4ryY!MW!TB:y#k6Z=Z(o}hhnϝȢLVr>wδiᄑśŤ`bhgC?E؉@C“RTa`.%N]by>08N-/ż5P2/qGF&9v!QE|4;B;񯍚`/#Pl= lԆv|_c}NQC~՝ty.9Oz{oi_A6_ d6 'EM"Yrيm:s>dn"s9ԣ&"<#W.Ny8*_bWǝLP0Gㄢ)}]UXm":ٜ_{SzO.T(n*I#rGG^s~o@>@NO14 a3ؖ9RFp\t&- ;]z2S dCo1m.ଈL[BbO+ ?K{>V})+F+1,V L蒕S7#l X4t!L/VI`#=x=Hjbl5<A/jCt>.-ګž0S"|䄞MhI!JvR]! :'!gV]{v~S4g61äõu%"\`T4ZvWixz-ӌ%gA{b;ӄڋQ[p%DFH=jۇE*>H/P#N) ?d {X8M];FS'%}\x"1CBqeҁLy}om R$?S91ӃPÿzkRޔ%'*.[DʶN~jJDjv.|3H:l#(v, ~876ƥ0X}=:R#ֲoatd}c&U "Th3i_&r+kIr -8FYgrtEg}Ũ6^c h{Kۜ,+}DoxH҆;qfv!;MI *O]; ҋ eʑC-3I` ᒃh[> r[ ޭ9-Ȅ>e=P}j9>3PU" a*+XFIM68 *rNM S721mA 57/\W-zIzE6^Åw|T-(hcӅ;3^R6rt0I%|-{Talrh#hʵ.TcmV6;G3- !EۛΧGK}jbUt?nv(qLbsɉըc049LY/bpuuc_e^AR8kO$2ŏfANY QZjȵ]ZԔ0J^] ^/1POOw2O2)-W44' f'j[ͶJKUlX@|HD>arOBm̀;=F ¾$iה _=+3sn$Uj7Ԝx ѱZ'fYVR]oGh4i;c]%ȢXOn?=@4;4Q}"AzO)K +3vN 4놉BŨB*8"1 nggnZ2jDq1gd[77oO8ǹWlItF~ҿI̕uFl5K,X$u0_ = Kdl0븸Z RIONp+H,ʮ?aWy9+{X&8]eLyTxM×WO*4we# 5e5܌:3(}4x;ޫFMwg쯹_,دI %Aȴ񢷀vUj fC],u6@Q)Qݷ ĭ!O~X2\!P.m'3c 7r;wJ-C[JemZ$lVnAv[_G3 %i I_tbx7 Xh?:ŲrU>>:7^^!N}yOS%EwS PlFEDSiwq9יϰ`"۪쭃AlqIf$q=oC.Rf~F(Bk)MC@7(64#q>YTG1dS>]rA~wyZ o66ܶ)_tv\Ud'&M(ƹH%ʖWΠS<3PDVHu6VRZh ʬnw,4?avKdPM(P/AN뜗묞Alvr~'3y^i r!?5K(gyJql"=zT=T{3R:YȤ0J*A#UC%\܇BbEeYL3Jou4B='Qo`F]-4{"Q(H-5=ZmbI"] ?a1_sG٨jW̲n4ǠnU9dn^NƄs2x >āV0^Su7Z~7V ]"XE}O^l2T;1}DN@ˤ슼ӛqIZWyfmfͳoZZLDM"I~V*`u9J (bftsPR$.~%N*V}U+2]vB^v=UR8_x7s#5x[D*:%EK$hP ԀP ql;T7,шQi̻ZGjb07 %W~Wf& H3ǒ{w #4>}ܾu9ُ!~6b|fT7^C1Y2<~ -^xt2ev7XęPE\mROn\h'-swM(YOQvF.$N11~o? :ՀpDąqA%)}^>@Y_ ztdTXJw:3DGׯJ{MAM~ D&;hQ|(IZoHB`1y>N\ hQƇqi |^T AHG8fJ̠ظw}{mM]K;6:JFEZK+Hg۽";l ?_Ô9E܏oE|Ve&;wjez/o|v|'B"wʘ2@M,{}[|E(hFdVxc .e0)uѻ.mphS!hI}\%_ Æ5`P}}=dk@o.?y(qRnz-K67h=#3r~ZK'aU"` ώ)0AH~ utu~4AxO ?Q<KOsޞ(c'ZÖ6qIeXνcQ媾mv Qy%(|UI(XI/!;؄Q\0YGK)?E0RnDWA*e'D5L{>kfʾ4W^Gf=*B=/V$i_2_~׽ƩtڐTgn:lh:Hԧ%'-qďu~=:_^LK.n%f4e,9`=e &h(~Þ{D!sS|sq4en8eBwbֺ6(6Ukqw˧+WB/02'>SƖ%ɇLdK_I.;l3Pzp-Nޝ: WѯC>69)&L5E\QC)eU6ӓxa$ƣb%uh<;.;>Bdi®Ҋ+#^;6JfkKk_մ=,ַn|O6Y~z6$)y8_i-ѳIuv!o<a}Ot\gay7Eg=2u}Q'CAUFfRX\7T/+4F*Wz٨^؎Zr$W{N׎?T՞H.׵J>q!!|!N_сbn^Bq7V @ :,Å#$c-vr-ɺ<VcAֽ\#@斐8Ss}]#;QR(dVGЂn%2mIXM>n6EohM:"DA>ւ m'4_ ,9BD<[ǧ߾V.D(gP?1 0p+:nJ|]-%ҮJ5MzK cU YMb*ڏUQWƊm4e<05@0}FCT_x?tL o.+O:Nz "_ȧ ?M^}8ch1;My"xVsgp9.N7n"!;|>#ʹTxdHx$^}2 0i%1k7$( b3Hy _ײF"닞1 ӈj%ZtuŅ yb)L̝U LQ`˛ԡͦCB=8SCw9FvQbA\F(CΧ퐬zcq-S;?H^ϫ$~:rT7k.||ckߘBӺoًd]/sw H*esCe({ТNg#J{r@UЏo>1/wYJz@<$ p1걭>Z8v99%>IihHnHʇ+쳋b|-xH`~U8#ƀ,D]BK,Ќ cK[#FªBf|tK UfIñ / )j:2G0UCۄȯp`&b솱չXXE[l!̣EM=uv8,;'t\",5cȡJж#*h^|3kB^3)+"#>v&!urҥ?njշw&)VS}QQW8ܶ\3 \7͞dAZa:(t8KNw{XY~ K)BC b!22JFR.&"gf8ȓG?UE`ԜMն> stream xڍw4]6тDFeFE] 3 w;E'z zD I>}^ksvgƬ#AZAW>^8@ASH  @ll0W8/1(D vEh;M$ DA ?$/C$JvA5$BtBl\k pv9BQ0k0 v:wzHk!8$\]ā@^ /e+ t.P;U0@ S/@Gq"\n@oS|` Bs{e{m|J54To<#$ Ą"?haWaݦe8N?ci!Ѭ8&Hd?Sῢo$jG v2@=H ghpT]1CD2 цZPm ץK,k&o=7R a0~!a{>|I@=SE ].tq~$y rDV#1߈ODDq( Bo6K}7@PkDgrt<_F&پr̡.^rVe<[BȽ|Mq,vs^xKN_Z fǨ?l1nt}Ռ١Ɩ&JG~ѫYW:?6EgJXt' ,x-*s>+dS'dn^p ,??^,we5a:&gFѧ(N-,ȆbQ,X1'Y{oOJuV}eӐԊO{OӾ;xOH"PռƁD{V L_nM, Z0U}>Gډ*J{WEP"rt8Ho5:!ֹ{DC%ڗ3Fzu9$3 goM:iEMΚvkM8@uРV45rS@k|U/S*:;# zr=/Ea,a&QP[ Q-z{'?_짷OvRe20){`ȶVRqU,G&?|ׅ2;΅(UG$'Ho ۷4Iy_SJi}WRE"}&:g{ѠQ(m߁Ҿl-~ҙ [#CqEǹ5,ɉ&簃#qA"iۤP5H"Ԓq*H{ lJ|,@H;QrѨ:pe=` ʐO鑔Ҹr[]`#F-vR-uNj%cOlZFYIore utl7aE݅܊4(rT'*OyF\MǍh{bUt*'SP$Ҫ âF sC-KEDQld>ߚq Ȕd=QӥoqQL^ E8uEpoઽYZD [F5:%3N LwB>lN/^5Y@>?(-+u ˜!ieaQ>(nadb&n~X\!Y66O,%Wχ^drz <_86X?ר뙨aB"?]-;}LD;Z41s93EZ2&(|M=MwkpBBum .ّc)F=U|!xsy2;oBr/Ec2R(]x0 ET#h"J, Fլ=wM`\'DsAƮ8 ^:r!J,<`b_ta Ӧ!S'Bn% ^3Z: 1kyrvIOVKtᶘC'ƷbӨ)5moalW'͎g[%I^ߍ"XYS];*lӁlMc{ yZte>>KRzJ%6Ke!1׋5C@noG%d cM)ڪzOxGmG^KS9E׸ne1#(>)M1aFclkqtGj>S?ۜc9}dJw8Čթslc8m2G,=ih<,k‰PMB5QFC=y qn=X lM&=am;pbō'Rzǥc8`p+e"a/SV}7Y'AlOgQf3}WN,gӥډOwlݡ{^w΄3w 5,#ɡ|docjT@ jwֶٌ_-{ЈQ {E͇@/,?^lUme7-ݳ.i<.R_R)*y3sK#&<4Cԩh=(ҌQ~w|n)6+ZeqgGvKN֫oK_}V=US;3ͯO9V x.Q< L\?!BuwJu9x"/8ڷҥG6 awpاzuq75x#>ty܍Է鬀1ZT.s{ƏuDd"9>8$NŨb4.f[c$f^|>ը>om햴C #.FJLod)p53áB xM9EqD'WO+*HɅ&U5aoW7UvX}I@YߊOVdG=U͵T1џ>58'՗mA_1j'+*%HTnGWcQitdx3g<|[za4Ve. &-ci%z[K0dqu7P(?_QQىq;-c!6ƥk%vt|PK-3~*oLHYvȏ.:e _^{NM' tDj|X.o庥p>6TMJ>=`h3]Bd 3l. _32<8,Nܽ"w1O%?],Ȼ%w8oIXaBzI$pdjMwOɛJ %}{Yz4(M0(&=Ϫ>:GXu'dzYeD]I~5qxFP,LS;k)<,E M4~QbC5YHHM+4Ť@{ޗy(E͍> ǯ SviQneU!EzCBS7. 8q$.H'l#[UV.(;tDpn,U*휟GI$JZ#>0kSCD9-{FG-g3o&z:GG dֺP?91p!eK|73x8TwٻSghtmF ri uVK'psw`p475U^/KuG1{D*cw-Bɤȳ_J#e}ɽ+9v6b3' &'OHEשUS=Qm~0 .qܺlk7"Q +$<0{22CM|fzԪ,KdT.BZa61ŶkŋȻvϘԩ*B*}sFWlJbZ01)'stil bxLQe 2⬰8LTEZ4If]Lx= '^1D,/>q*׈=ۇ> L1((|^<8uyZŴp+~Żi|':t"sl\>ZCX994 K9#H{q|[L9(*qgR8ÃNB<c=7]*Cv2+j2c=qs,uGv7ojpY8My/TXŀcq̈́OLGZyyl [Lr9 dJ{8%df4mqB>fUAbX]:_+OS6\8|o"+I]z57n-ca^[fcG(-pJ醥WGWECrҥ \ eGrHrp.^.4I 75/`9]0) .D,kU~9Ei19 nz}:/#~6nLnu`szMT~N(|ǮԘlOai_CYZApMƑ84@4D&z|,x40X3"ɾШ~^Py3] PhBuz}3!ٮ (}DBOG%5t-,^ Pft,C!11]+'2Wl4y!yƓl4p~-e){F+}=ۼՂo/:=:x1=5cV^s(T\Q3GKԳD;_(vH&s(QӓUQē(N>MS e08+g~Yb1.wDZa/PIFԁٶx)dM/o䲕P␁ ;;N:JP?c@3J$ eM5U/ʤI[% kL0ev8fƏ='ER2-j~V &qa.E`J+ɉmgisd\eA!o8Z,|f4rIgMEMx;l3 8QpMNNC* ۉ/\ HZ2ʜY!fM?4hK`ZqG]ʻ#K^F=['L#] W+7(}1s9E͓Wdw@.ysazNԤ:wI57\]vS19` Cr6K\~;O\Q!*|᷼U=;W3@Vm<`ȅL0$@a@V^t4u*/b<}y PĨy$=)wkz;cU""IX\3Zizi.~xNY6-,avFnGMdIqShÂ:٨Ht`خ?K{8fOc@@v&"Ɠ]tDӔR Rm\!_MOӍf쥍v^yF?,duФ+xnO56>(0=#k҅cb=J*[8% endstream endobj 118 0 obj << /Length1 1629 /Length2 9509 /Length3 0 /Length 10565 /Filter /FlateDecode >> stream xڍT}6NHwĂ ҝ..ҭttHtww7HHH>>}gϹf4Y%p3,.RҔ`ssbiAl!80t P8L_)& rzd*aEg[WO.7 @e6"qĤۻ;@-`c# aq`eDs-@n8W a+''{A Օ dwedBG  4@d76L:O&<lc3 q<TPC`$tEN 27ك`P%j *99@0o"rAmAf?jd%jj$w9Rp;;w}P݁߯ Z@a`ߍ0[g_Gl';?7;'q3>B oO{=7r!ޞv7N3%fşQP7!9? ٺ-uu崙$ `ap_;W UYsqP ZF'S?`؍yϒ#O鿳%:A`!젶Q Dž/U+CPg*8WBfi,P7X dnfk7[( wX9d6Ga9>nCwKrpc>#y㖂!nHdCz,om 2 >P?=$@A?Q@ȿ h/ Z ǂ >f >r|l_F? qq?>es3\(:R+θ0Q'xt>iXŲo;T$^eΟznPպs_R~2l%9gFlDIJB>5pN 1e&}uB+O|*흕ҔHtoj85 j=ܴߊ0 MRIy-~Z>0M!y<-ybDH(xGx׀M cQ+jytY)dC%2wtNYFL<S3sPL&ѽOS>y ?5zÄ{J TGbU͵~h?5r3gD h}m g[;ꖚ4rrG% ?T,yGW!A0iN"H#["%_~̙N yGƖfnQ]2MMSe4pΥ ;9wgRBЪk0݂^J5'w)U3epsCpSN tV~a|A@x>V NXߘy_bWt'V*O>syE,%k갑n\3LM$_08Mw#y2yI+!1U\[g eS)Ϡe9ԃ$rf:㍯n7sh?G)/_0IFG8t_-TY][OtV91I6)2i1K5^XNΈJE#9yvb^sie7l:_ ف")^gBK@{қi\8:[_B |(W&1|T c̳'Uu-u~^C0K;OZ 9mKbiM }`N ~mRu!#=Wg3kpq\k |z}Uݩ S^%4L\5AJ'ʝDbD3։؅-ȏ(gU6E)az gw~/' kblTGm2̪X:q4j XT%t^:vFD=Nky]Mۨ@AޫVg]ahL3OØCT%K-\Nl-xhmF^do#<:^ГqL'ko MGi.>'SGqabmgЮ^&M~ {mHZWS`_ϲ c/1Dr)La2Q)&{i5)"db/^b,hm>4{@%dI=s$⤠P_Tc~6Aqg27,_mձKW̛KdZQX'h&RR"n==DI~|a4#\`#%HI'zac<~o~<#o#]I& *l:$l+JY%Y 65Hfstǜ2yq=R``SJP^gI̾҂EB8Y֠:g``,g_+1]MFl74E)KZmX_Ck g%x zܫ#wH6[fte&R]a xh<0UّqV0*4--*]ZRA !4yFG A5 ,a\ y=^Z;rmjv6%ϐEǛ!}jV?4/DjѠDpu]‡:JIm{@2Kzn4{NgƢ-czd;7$􌥫9͐ߕ_KnѶ*vgeU0wR$ObHC*D%% ..BYRg!f\L],,q>sΞ]5A||QƗD_[ː'sxfpnMj$yy1v= zrɔ D-"M{X9>h$ϤU7Ӄh*Ee<6d>@¥aAM;uQe렣g , H GUlPӎ"Ovn w{m_In#qu{I '+ @)Q##`qlKA*X,j{TK} TwF.IE}sp [y'C]ʐtdθG8v|eEZA FWaI. wj(dmsjSd楕:R勿ّUY5J>,CJY B߉pǮ}2 ])ԞB՛}kfRpmK$ ulGɄX7V6ڈv(\"͖F_Rsoλj [~\e ]dz'l۰_nQRXa-ExnzNj}PPKcڻ"DAS;흙-R4}](lW;﮾+IUL:[j7g11:y3NT =ک9ٹId^WR,f=ݻ%0 s;MlKSݡ -N^ }Cmh!K/gv0Qwj7.*GJȼM@NE5؇n z?ɲx/ђx;ٻ8r/sbF}'TXhCGAd}@%IeQu(YxL#z=]fɘUׇ7 `  kxʬ!Pyk~sDGB؊y(-$0.x[0y?z2o[p_ TCyqhpxVo.RiM0B.q wȷл<ئbT'X#S F>:6N!Io{*#YS*C,6(T8K~%!,DmݚiXt{tf̸eLp%cYt "x̻~~Ք!7b(t$HI^@wŚ+1(* ^ 3T#-Vng/Lw zwn[3qAtoi!3,(bJҨbUf/Za--l%*qif\W^50lVZ?a&委*9~5ӿ'#=?i:/u$>t~n-&&*^zBfUȺeGL=ށP2^1-M#j"QudXV@]T(EH2^6$ÇCT7L8DPoqfIʆQǚ-ݍIE9yI+|z?[KF /ePd璣<Ȥٷ,լȾnw%n(-h.Z!v"`V&{ǵ>GɡͷuT SPLUaGؗqŻ ^;$o]MFIT="*|$YNH⻥oKWV BZ`xڼjk ύ/ hlsQ [V{"O ޘYZ.7덮o+?ͥr0*`S̳R+)t,չyˊ^bͧ>dY/\>>8k8Uvm RĽE䴝+(جJ!r? > stream xڌPj-wNCpwwwwƝ]݂Kw޳L-'$SQgp2J99YXj,v&6DJJ =bDJ-#? ] LStrȹX\||,,61trHzXrN@7DJq'goW+k8|ИXyyuژ:MA@pDsS{ _4 33'-d P]= (: am\i 6@G7PU(;6VۀXXCo￈lljnlmh@^ _nN`SS{S327HL<7sWg_%2EW~6@sp۽￁_EX;3k:ڸe%m!YANn^v2f^/%_bpNKp@K ruS`acl@˿1x6^}X'CzY89{1|Ued?:11'//# גq?7Ϳlm=4>Zs)9,,_ϫ/ ;!)w{iMlm^ZwgM"keACuOmܤl*6 s뿷o_WfoTqrY0Gt2?n )hd׉qrL]]MC#N/+-^Zb3trEk\fѿD#n`x̒Aܬf? ,e ')AxJ8 YS p@׿2ww7n@qiɜ?̶!NГqoBprO;wɵڬ [/ý;47"ˤ/}lORx{66ׁ8cb"F }?`;6ry.<*X^_*V"Tk䑞+f4c K(ͲÁ0Ͻnng1s'H>#DZm?Y`sƧ#;L{[VcѫM4!u-F-Ʊcln@5ݤlcWre,P=ZVm*27ߧFw-#;=ڥDVtѫ+|ĩqnm,6:ògXpߐ G"=>1S} 3;d;~thTd ;AW4ѯѭ뚞Ds?Cc0bu` Mʩrl}EI? ָ4cW tBRlHGjB;%8XIkSK9C0^?'z8,2\'#bG'5Pç 5,v|0Fz j)QT9Z&إq 9PU/7\W=`?e~&]0J-XyKq&P} vR8HEB6 h&ae)O8r8klyXZ>_ ۨ> oj7Nd<O+A 2 ?Wz[;S8Mn azd5`,Ƞ}CÃL?Nk3Ώ} KE\]O\x}(\ rv|;l]yUy_ô= G}M#ĤsIWhP#ؔYfRkdU((쟎Zowˏ-PQZ%|Ogpw PbYwOL8EAW2ЋR9}lCP>לotn*TM%\?۳+i"B@5hbYv~RX͋DžLbfw.s쐘H Kbn`eaϭ-6C @񋰬(aé{&VT !ouJY#'U9ٺi2_xCԉ4c/Jʘ4Vh86M%TCǿEZFTU;Q,=d~ןlyӗmE"ɖG%J./P{ʉU!#Zqm_;ڍD}QQ .>" "Wm)_=ͮ9k"1l6+.]7ʼz;SP)2|l fvo;h Sz/kUo>RprB5@E-ObDZ 0C+6 ggj]Rq]*L] 0A^0%x:ZUjQ4Tn8u?*YI*v0k?)9EU!Wji/wG΢`(3)l0tTΓE[ nKm>Kk=}oOcoUӓl6SFzX3˃)*@%ﶋVqkX1 ">sƒ"y"|x W₊P%o1ܼ 6TIV[\ސ>I)7] #V/RH \/:h[h^^ .` d0 ,͸## eDfj^WWd#;N2s/y&ӛ@EJ@x=(oʘ\x(p[uūYA"x >AvKzCZU.*x}:LFޠQeg+ ڭWIIQfp?%j҄TJW4Fh EEB4;{ ^GHjjce>!ٛR8P,#bp*6Or{}963ϵʼfo{%X#}tRk%&_z *Vm4p/ƅ&E_?ӫg> `;cu?<^#NHAjJ_ƞʇvDnhS@]QdurS}{γpF?ҥ[1m軠q Hgv4v-O"p7:XݤD+/մrndi+D~ŴH3m9cLac}#5"A vKG hsLl3Hd1ᙴHY;"m9[YP0NNeR)8lEBk l9|dOi.%2nq&1 fci!"ĔxVKdtE .sҫ揪HS=X[C6O%7L#C,U8dp~~n_&F"g\z޿ߒ1 ԇgMH?1Tpb{jrc>n.Qe@ l'I QraSE>:x4G{ j(8oA7Sfct,V|G5Za`mQR>Io *myU6 81lQu'BO%] EGJtc^xo; Q%XFǔTaXu\#+ĦLHN>s{VIk?" %WuAPY8KќT|N٨o#Wo+ ۫k$ D;Ί T|`uy:@ {0^A5I9Nye8Xx7fʇU\P/8 6^)<Şb8) [Y\7Ikp>w] &Mr lR~Nwl6_мX)SPliL֐0HjuL_5BBq/$@۔+]s&|.nLgP4 }g!Жa ۏ;n88!^)LBSv5T)3. ӻR>&--;"2T)o0@Gl" +jQ2oYzsBsؔI-fKߣ%;)ԖnHu5_oZZu⌐(md(˼Ǔ?4~l -ꑏlb] p0g@: qh]υHR5^6BiUc#vhytđ6d"'8W+& S+&~P5&Բy/d{7*#ǾpigΦFHֿM[N3wyܽW)\/S֮#Zsx~$>Fdʣݷᓹ޿BSc T>"2+T~(u)g@IcegosT,Λ2HIc]Fp\=.,{΂jBd]̛A&Lq^%{gR<$dݛyGMF͵ҙXK@̱sHqc爛QՎOBpVďe"g&F3mpE;`ve]]D-EC6t1lܫzv.ώg0u]я%nn>-[S+^$03V$0`nV [oOϕ'akȗPzZ '5+oCy zҤuڢs*Vv7YtS|ҜMЍz8;,b~d&4q":&ř_W1_F0cZxNH M&e&)k߇*=F;~[H=*0r23#3PqQDȖV@dW3Rm`-` y%!/]T5z!ѡC$Kd~hN5ZP ^撠 ~$ CPdT^ҨUه>Ɠ_UؚaP>cW~;"vZ2k>i2 ~t?%ŏΠDUFeSmP#{)37~=E-w"(u@ 靺NK@m<\peDůPFӌ$᎞/ HzJ8S׵wHHqj&޹sEɧRƙ^=qК9~1:MäE4ѹd HVo~ɲ6.k.vߕʲ[* Q(LA y,z9Šq۴PVie8 M$QZyG=ޥ_xaFub ˊgՑ?hYLz2XKRMtk~7 f:#S5{LΣA1|zBBbsjX꺀fL9-f=‰RǪ:'o}hWȸVGkFfp+4 tXOCZؤp#l%2>]b&̑H.QK,y`yF5b= i~_f$dT{גj36H cJ*~^0Υ0`Pm؇6"9; ,v_UE+nBF, "i$|P:RT'NĢ7x X.>8 B@.MMS@ʍЍn.&?s ќyːur0 %\y#1qpK9\Tb5 ܼxYٔK{F s($tcR6o4FTbR;gX$-lj?O~j.Oذc^&K HMh[YB}) sQn'N2Z\Sos ^FHrX?| wZoPvšK; ]g ;6 }\NeTW v@ V4/ސ\0TwqTSl}{N*ͿhEl ?ilt fn(Ha?*h՞q5ϝ[pўUp\80l0Fagkː4O[)%ҧ^3Fu1hr W[sWp`,ewm^&~j6$#l:4=O+y]~vHxK%?֬ҁňOO9ނ_r9q; {*i͈ozx'uT]}(E-.'(|;4kÇ_"@Wv|oHOp+\Q򡞷pjYa$ܛȈavO4(8\U&) PbW>rWoQ(J|Cʄ<+ĺX|vMX DS(Uc4,nɇh-Ѝf1'| k$kF}K)1N`ˠ[Aq s^'-ȆkTl4e!4h6w;8,~nU194K'l1MED$@m\H/lT/>6e'@L}N͎mmH~MvIeyWfҎhʑܐ<$4𹺚h\4 ;D{ˣ'G,ܫST(^IY`[@nJd5ު},DFbCeeg쫰,"zk'W"q.)iRkҐXF0C̣m>kzwJ% mD\I큝?61 ]Wz̡M_:6da"- CoɓOkЦڃ&xw&dcR6i Zy PF5OsG" h& x::xѽNfg\^Ail3;C`QEq~C=4*|L_lX0|rdd|>bou4HNު;=d6GVh+lnNʆn֕B!4 u^o\歌}+5tG$܋({@ϭ e.;KCf -yF#T`nѠiibǗjycRbn D?0,Ʒ_@d\|(`UnUt+UNmtlb~7[y04Oe1vM8)W$϶\qwW()I#s@{z`jgK/t"HL8еvUaZ-A^΃A*T[gkoN<Pꁰolp\MoM,Lov"94>-E#K&΅$/TBw#̞ liMݨ0iIG~aV -**ң0V .UdtXj6|KjAܧ)&2\ ]m-Rl BL[X-"[F|/cKknoy*Ǟ+0 Y}\0R-y.* }evTpUs}T@#oGeP$/y]1 z`jV(X ]Uf@`|e~ &";J M"089A+]#*U:fmqiSʴܼهPKBI#dhu@祉/oW)o((a VւH!Q"Z nK=XmqXʁo4dǍx^V'! EV؜zUUQl4cαsVM_Qq$.성\nյJJ$O/Bu;%;-jV}H7!da?DoO7s^f)|*9fGvp0|;xV"waS{b>1F1Ov'ҺuSQxM((+|{rJbz}V} j[ WnO־djzPR 6ǂ+m,bػxQk6Wj%^yӜ2ʼn2\ZyaFh%3)vw{[jum$)6eR# _&g[l2Y{{gPSo?:W1[5c(ٖӞhS5i]C!T"͓4y|>TX9ˍO1!arԇpOE|*t*e"Б# 4am9vr'ug6?w*̅N(݁Mvb5 )N1O Γm- ؤRK/X"_ܟWV e;} 8r+fr`eny6? Hz~j#' lc9Iu3vbc$[}7WFӲu)Ϟ!]l0PhP(r#@t4.Q.] Çv <ݦ1G﹠RbRbG3a2 !S31D1fV\N3"2yf'UCɊ7bIQּLRg*qf8@>^( 'o8[ObJʨB(WK#7fժXf FKOgwيg@%NlEnr]vr҇pPN~b!SԾKDEKB@:`0Y-Ԧ!k]$d @~1_abHٖ,< *SUh O0u^YAPc{A)[y†J*-^fl+F/$YXB;#P})&fXt"K2}./8[;GZ~x[XZ{{\(X4!CW A((uew.9/mRIOJ c—{K,^4,zRGC6ZYYXvJ{,B G7dlu3D{!?~JP1{6B.i =@kaUEx}ſM.MUM#>w {E R*[ j+* ^:Islm_ LSKȳ=e>yVn[aaNiέ=sc׿iPd,z:M%L` rfD5))n+|UiU~wlzk97ڦW!ӥ X!@uBfA׃, urɄXKPF1Ǧ:8]dzUO@ J)W4؍bTrsřZDUy۫u8"i7yCVt9Rf~)Bp GyA pSꮘ=AICTvWD[+iޮ6zZiGϻ?!mJjeyb6k(v*a6h=x]Y7XUދrX=hZL+?$cRQ^U%?%Q{e?kp.#T23&T5J*@x-"S&nޱ.]3j>QzԔwsKY_Ep7]{j zB8d_=ˠ؊n`q PDTִ6{jPѫdN!10,HY|ŞfNM݊-榭FN79Z=n۽y x$̜}&JHɑ?ЈG˛z8x-*=ц?|aƭ{(tRXg qRL[AIPAվ㷐mVd1TCFywR4<_i؉ vFշ1\Y)U œ$n"#Ժn7%;Wᬆd VPS׋e[]Zx$nhA_3JcVba/+4?jZ=_CN%L T U 5IŽbrY!&Im2cr9ڶLe#?E ;܈/p&tHDDS)Tґ川Xb{խGҽkϭ6U=ffW6nZ4r{A T~'?Ztl"!ےj.S &Z5j<@?%-T?. ;RHogg@PLط4舞|DAjoL_Or&U+`$>RRpFe+]}4N5/~D#g,N%1,vYɽt a.S3tZ,#`4֝]=Vfca7{FN.E$EV͋ Xf&%Nq3E'w Y.- <&To~4l%oVHB&VN)-)#;4XfR^3?>8<6<:ژKWѷk9sXV{:!46@t-Ht&׆Cҷ AAs&ݶ'{U-P`+Z==]Ue蓰1C1!ZrG`#D%VYeؓTf+ ʷ/0Ag!$,>7ˡÃx tg(2IӾƒ:Us1D~̳%D:FDD@5Lq;b.ʬVzx@6AU D`1"ؔ:䰗 3#E^*= bEk*6M'<*)x9oE8vʘT*_؛&H>d[JNCRՋE73,#T4ޕz>H&_a&"0 w&ZHݣe =ZS\W_S)M|@ tdՎYdh39.K) P@M|&~ x*nCVN,S& W '- nrRTM9y+X;|jʫ!߷JU j b5FPk#M3&ycb{ !0741@kir;MS~M%MWR* L&s5& BUc[1r$hKY )DUtp4!BoOp vxmB{?v\Q*ϙCj,ZKRʨG2{VGGG9w9<ߕ{"`Aӆ2Bxz!. [gaD럹@ܮT }I:cT-<$+aJ|;}lsJTD uא4C(乥a(^m$֨k<_a~G^+%ՅLCR?lF[&_ksC[穢E7x5Tш1Yk;nRWh"d{ E w agT͎z(o0QL-lUxsZ5&\[-QikQ}HYjҁ{^X!YIQMSoy7$BeHEc @P]'#äT)Ka"iqt "j8a9Fȸ~vIH w@;aT[x7rDy|N"yo>l^8to6)\#(qF (4:K:G.ֿ҃ɥ*|]TQ7e(jgi"bZJL>If%;L빤Y6_nAZ8dk%<"D5 2:¨v91-Cg =RULXJE`ߞa&^N ;vm dF8> nϫNIcw<ӮX%o(}s.Kf%RK:l;ꆞhBqi^u$w%ӎ[HlV. {e gQ, Af=0CF dNⰙ\t $4e۝#]@B('Sf!ؖbFPt٠BQ٘O+s n`=%!\&"lJr케ea #lzIcb8akg%lC9&92"єl3-oJeoBrؙf8\/q<iF fx~X=,k`=]S-:ml:뚟DIItG?3?e$:o' !C1j BΧK4 Sv쩭,MW"8reTJ9Ug \LA>\M|#`:Ja~t Ar(;FhNM??gZ.sg%R4%G^JUΣ0ZHQӯ~=-S&·=Vw<,} І&nǯ*)x*$OŻPFJ|n+ zRK{{!G***;;Ě}2}]r.?US{Y5%׬YqWgmsYmFgHTWXadڵ)Qf|h^uY;#;3 cAIN[n6M 6K> 8AEg&}-F3l[G9j t𩧓@* 6RC}4c&i@{r&O~_99ZMHӍ.8\7xjf7գk|8=u?W]I4{CuMQq)7nǘ#+4wb_5ZTn/XA`eЀ751 PkH`a~T}T8E/=uWZ44>WלIrbe͌~3 <F[q[U5nVn-4G2 5;#OC%w h&]OW/6T63(X? aq)ҒR؏Qilc*.v[B}6TwyۼkiUe1^`3 q@2a$ÑiyJc? uak؄EUAVA9#$DF.ӸuV! [L.7X$?ÅUAF,}0~q]ޮV>IZwc=-ge6' iaeMYPEds<ƴj:Yˇ<$"АQ`;m{^Og|)͸4ψ%a'7_-^e G7lyDjeOů!C۲?H#Ƙ&>*=;`:KS^ZI/3qLuOK[W~姀[:SPjRegZ s%q HKjl4 8A(P5"r9B)[(XąJaHJAءֈ#XGŘN)OiTWO;s U&y3";wgh [hXS?t+gbfQ`]=UFDKl! Z%Eg@NJ$=br#,A-23-Ld>:" ;@kfa$(X@/mWQ[~F)_E.*RHKή_s L|gzY 9ꩌՏ1GX6قYƐ3^"زtjJKn)Ӭf/ƅSQR5(+'Y#*֥G}w7*s#_4[OV|6䲴vI!7Q5u w|(=Z2;XiBWTI#"Ydo1mS;Z ag^wU"|n]rimyit_FWOmXUaNOqˁ%$,h[YCF( jN2msVWG0E0/ H0 kRu }sW4 ZFiI +F}XkjoJؒ:MKp'}zmzYEr^kI6.zmIdiZ҂EQ/3{m i =gT/U%s oc@ 0`!SzLnĆ#u1g\[10A+=4jWX0D#.0![Ee5%4Un1ּO3;j =BJŦ71HR;o>M~=WnfKʼn1-GN8#i!ɫr.4˚>/WůA%S уeLo.W܉USs ƛ102#ѹJ Ebnp- <ؤ?ܗYbDJ}][uM/q,27ή10F&P#GШ-[kE.6GK:s" sTa w.Chn s$,K#}@[m4ɳ dAIO8azHy [$-vöuRMI]G-F"a3i9g,>~ yn x$m$UvrLRSwfwLI]o&Lp1zY#lJBA|d4aӠuʎZQ5d2Шc {/{UjfŢ&RA>ViKUM (. #4݊<}l?lLVq9{ 'rULNϿ~f5tG] %y 1x Gn{XJח=,N˱ Re(5dLi!ITicfkC*i'0k9LFD$s,ul 6ކdqӮV.[`g"-'%PMRk+u e~ہ!I$E#%kV8SŃXS[mG"މznn=]F9yBw1[qUvq<}Udֆ(x+6c4z-Μϒz5jyP8$fဉJ0iO(FסScɈQ+vhavuj.lu3$v,f|Ji1Iiz|SEf .FǀAO B=/.!lm֊y Wtڷ6rXskV'}Rr+[+e+k:ߧ)Xb+_ueɳ#3l>[BOkX&\:IaXhEW=UT^_ocz=hSz|in<T‡$ 5ɉy:c!T/Ieq& Gm,3҂Z,N)+p9a>?ZlEJp\J{uW[Q S.*oGx*ul0L\g@$n*]Q|6{'Q1&M*𰻠d^[+UZ66gVv2νXH~aJ̴ԹYDڡQi)LdѡPQ>?98!rve ;uWl x}P. j/:v\? ;߃O+%cLmϽ6Sǃ:s2( Gt@Qz +R/w9 :qP+u=a4ajK۵,e:8άv+&\o M0)ႎ MB 8?kyD{#O$v:; >dw2\}z#U2_Kw>gNg4 TJ$dūȿ:!_P*1e:uASGW8+Mw R0lD TNQO՗17T.FgsvdZMe[>zj"!ۏ rMvHn &;RvOy·ߒ2`f{ԬUQkR"+4q'mVo6GQT%'|)Ҡ#|:& Btdl=a̒Xtbɚ٘47&df/PϫMyQ}sh[sQڏ h gX ym6N쌡RG ѨXrPiє*>\zO. kFypㅯT ݺvvvv~Teϊ9uėKgNuy[N9(^݁$O&{ZSjBU[ǣ#Gp/ēY2lfmXKgyhTْg$Dk2pS}TS<$<;?9%kjM 8\Vnez+lS}auo-m̂>)bq `]&VPlO90]Mbq(Շ R6\dzVWQϵ+q,9װL d}tcU}%K#i˱[&\g7j|ANyba7TܾEp*_ 핤>Ò젎BFhmd^clAMYOkW5D )(vNzanVAqf%DG:׹; pG.TgD9l3G9S Acщ:ɲ_d=j L4@G} p*îW6C}/Jg:.xP?5p(q]Z1e>t=ep~L!@.w51l0MQ5j畫%܃Er]X <ZǕ`2 1sDEPc 9MG4.>f~,Ʌ3,{U jЀ N7&sdh }o&,ie=Ou.LΉN"q9 ɎŌ;xB79z(j42gRh}~ui9gQ+dͦ؎\`hp %K.n%\K4NŢO2~p-Ϗ ^qu]"DVȍ3?/h{S/C,DN Y3רAasx<2)I21GV@ s^*v we"Xglj@\q2tH~T{E{ir`[!%HW*"qFk@k2nu?Y?WEz~IC&Th;Lqɴ_27Y_ $0:@.X:* I,}?C ;DX"ʤD~Ev[c~}BxnqqS2J1B7쎢G.)Qy@tgfkzPkuE߲tDx(7:\GRW֙2p6SgfZl gGe(E~wp\DFmc[]4*Fh2hZP/[EWĵN6"Zm,83\0ij9`3JC*kNKHVVo1^sf\CĕoPT?i|$m&%GKC-!ƈ{d=G$z %=J!8y6(6KN:o6eS961CP3,J,O ~p{k72e5h]}<[` &bX=nnÐ*ɶnnRb-ԪN|j٧=Ї݈,5u>魿;KӱXfUhBhF:~E}vYK'd; ~DSJqpFV$Q:ꚠNJRH.OUH܅K^ml7HH=}=U\Ϯ:,fEDD)xɭ=hqQ^kηx g1E:18ZIP"a= d6*x=e'KAql-+!?yDUa7iR6 endstream endobj 122 0 obj << /Length1 2002 /Length2 12564 /Length3 0 /Length 13802 /Filter /FlateDecode >> stream xڍP-< adpww'-@,-y'+`VڽzwoBMYhq1 $59ll,llHZ`7{f$j+"IۋM%NPpsyyll ttH{e#D-q{9?tv~~^? 9lfrx9h y+'+=f\<@@* Ql5<]@=q}pA.JU'`!&[Z::8CkPQbqrcCۻ:{-^ #0 k-]^E@ /%✣`mCXm8'mLzfEhi!.i}˛tWbK䏾M)ꝿL4; M?o$E$a{t iV.pvCS+¾j>1SˣP1k\6K]hލ5O/٫gr$F$8_5o>+UZ=o HaƧh|%}?g|8nG糭qnBC=)@GH #6vC.١"+ª9o+j2Y՞[>gA!R7I HUm=hr Ns?4iǠ -e3(M{9C;@B4ὺ|)dFxypDqTijæ ۇ9{HQ8|Z#'d H\W(Эtqj\&Ra)bmN5Qt0؄ILD)$ٷ?T1'ʹJs4G[6 'Z.0!ʨ ڕ[f4s².{N°@iϏ o`7pkWHw$!6ABSJhWsJd o7e1LW%qQE̽[NKLZ+YijQzw'O5v'jkPTFe"_Kv=EW$});-׉ / ^Tx(OKfe"|gN6vt#iS6|훶sla؉!k9 |iSn^ o)5`4_T j:^ :/S^V΂5Bp9H/S"z ]d.]`%*JO*b,IOE~(ϖ5E{hgSxmy 9W'yh_fowQ 9옯#2Gڭ»Tw 3%-oH΂\$)hz9C"#V!?2h$#'9S Y]2I0 `ݴ S&WDŽDqL9NL)R™Dv3 un YA zؙx6 R 3X*X}S)BA_rK%.;!;NZ a9֔V %9NO3As͸L2$~ ˡa0U1Nh*(_ )hI}q8iWz=N_LE׌Z]SӚ4I X߶lq%E{ʽg#Sr-5Ѡe0|9vR S㫟)Oͬf7b33۸pG*$Pގ7V'(h͆'Jx!C>㗇1¬▘[^Dh<~5uޥG^&~(JZť (r)kI<鄇_9PZjʍpk,0IW+Pp ċQ *F]Tb,V|A싚9Qi'N>oduGEI~re^L{ qvD`tbd7(p!q#N")QxMC,E)tL~v\)âJ|nDQpAP-28݃=IZ#`!>Nsf5HB`*ٖD.yu_k6VdTzyk`͙O%9(a>GÝvփg0o"a1#D?ߡ[w|B~p(yglTxAP+lH[Ww8Uja˦óvW84CzYd؏lVI׈1 WOsށ(478Sd %Bp8dm#oҲiߖ}$XU67*Iyf *0~Ҍcٓr.)edXl܅r{s)䝂&)*}{7zT9RmMceY8}53M }XziO5G$moʀrTt|h*UVy|2dk6e+"߅_2)qr'zcK-sAr9EY40%РVᶃ3,'T?0kir^N!$>6r34q%]D=We^Zzd$1c>6+7!B7q/GkiSG^y֊a8arfD(#W{ƒٳa[}!!"=D)U a^@wHQ ݒjA *  B<?qG(!zO+^ Y9#7L>i6'6'7 %1;i _Dm>_%{w|^^`5_^71]KE9C|]waV@+BIaZNb &C0ea`^JuFކN=x@]z g%Cp'Q# 6&XQG*rGP?ut+pc)xfAzyt٣?l.fF ߸E\ֹˢzGǗf$ƒƖ{ASaMp kڻ"n &Fȿ__8t 3hv]/Ι/}Zl"XfCE 4RC2Qqx~7Ӌ6'$6?2e+ g-BgC.&+j9]v)F+fCk_abr5I3WY) d o1#Y!ڡ9DzøEe`FFKʵ٦! 5iX#ŒO_IP nL3Pz|vX@VHgglV#5~/ GuIA2#8 zwݔa߶C|4ւ w[8?T렟#<-(%X3q_cLqOj!EʏE\d.H TJžY):p֫=_$IVVu'<Ú ,Lۡ&?}u.I!\ T[F>zsfl)A4!۸ E>q.[BB)O ( >U,~4.0ZNcM6PO7gbm6xx Mۘٮ= Æ9h_ TedVFF*9S_۩C%Wܝc6ڇ T͖H5eX_ڏE-m݂PXΒn`(c0!bt=L`zGf?Vl42hX JEJ%9dd8te\r}>B9"RԦAfN~r T=Gפ7f:eq*crMC-~u{(-d*!@ `C*}Z&R#Gk@R^m{+W"_8EQ[HLO~"B(wu{]#55-@X/lsnXuZ#ciUufy8)]֖%V%qz䜮[YfT3V 1f39_6z w{H#]L*-Eq"#K{#ҝFUB ! EDل9 b;wRO+waz*RXпn(JL8'0-M (?yg8Ae:|q:6=xim*-γ$‚׺]ʼneZY4B^IKd:& qjs6szNDmнrG$5ŽxҺrw4:ep7R\qkLK%wwkٻDэkD )>|O Mü2%Tl:DFY$bR9ݳ֩xB6NKkG~jԮ#䳙F"Eb\I M}syÏ9Z x8'MsХaI]mgD6?T}xZ;NCF2 O=߆"mR5s\U P ]t.6?R`pZu5sƙבUJ>HRhH#?%ôAш{MED,s)-sŕ]$'9/3ym|4Eyokz} %ʾ(}=Ea&9NecG-vGų3zQ}ƈ)BXC uY!鳈Օq(BE-gdMf'TB%\Y^T1]>%gnF-,lx;;)mΉ76̄|JI!jZi()/` 8Ue`?~ξbmu?IM0;)\|ĤzU~Nr'&:Á+hàdef&~;=@#󂼉~h#>˰K=kN)HJb2QY}bH_QqP~Ehh-4 IGʔR28RLl_;QHW TmJ, ,(jbg9@nqG!m"4$dAW:AA[faWGAsm"`Lg#*Nߕ2ˢ.ׁPmLEK:$L>1VFm3XcOq>M; W-9ORa:ZgcW =wC/BM% ~z/uI[͍XM] ڎFc.D#yq&W~sU)sA*I6 on.Cߕ4[V$ȳd[Te]ŗ o2ígckx>"-F8 GZB&q j9ǘY} q e l}ySѱe$ T{;\Bi,G;E"OxmbYk]\bjuMLxT Xh^R)/cx m6u._v"ݶxs2|ʅ1A=Ifg!No=SM%ֽo?fc MU⤅~o1 _ϡ?,K.N܊;?U)/z-WZ3U:1Og5kEtwA*MEuC2dT)P7)Qř-)ۓQNGn@ZX41:z< k4a0Ԭ)Q2Ra.~rTQҊTY ;py`/P٣ĉ/7č(ZuI1-NoNS0ٔM{'>E* N5Vgc{5~\&Ƨ*)4J2:&g-P/O@R\F`"i0p>e[Cc9zeh*AuGt"Vk5lZs$( n[6PSd0jf09Y,>~ )0[ V,:,YcR).;igDByꈀ"fC2&9c,!t-I NGڔ'h9KDdNhlT.t!#-߳vR2$ɖD^S1TU *CFbWV+9Attt;ѪnEO ;14ZʎWzpP{9$dN,N) V:ޔcOe ~V4Z'p>^amtYkgwsAlëCyQBӌn\u_6b=+O΀Rc /ViR޷9HE喙FXVtPCa䌙^[ɒkqrgԟ̤IXT#A!h:DWeNg9 ZB1h51:_8q$?wxNm!{ΊT=op>sxv%6U(!(nwn +E׷Us/MWVm.`C^((?43?hwwlx\>]l׼eډ77*6ho]G>*PN+Gəfe+@Uvd ZѨnp1)f'&#~ նw%Mf{2%`yqd u3եCGMl.f΄7^SDWpkmw~8KȘ_OR<#{cK6krQW{o  =]g:n 'mNSv^X/nHPM< h #KwMg-Ǥtx%  Uv&(%rt&>Hnf=)8V%Y*!@Z{GLݚ+!,ej>GI0(o fwqZ'>q{`FlQc[+L cW25ͯL LDy8 Omfˠ;sIzg =FcQLU;qkVM]zg@t67†7Eԫn"ށ=CP1u6Ƨ ONž8`fyŽXSd 洞Q留Q͑o6snj~T=d72W<50&0%vQf۴6/~Zֻ*-2Y$SZw@0c#2|c2Q 8c4Amk{aXVjl?鍳On!ox3:J\SRy91Ao Ae`Fi+DSUF/`R væ[֕Ǹ*pK yIMV l{$0|1D< - E`x!<ՐqEBPܮw¤aWUimĔFW!dzŪ{~|eC *D6"HBD\? ;?s *){OE#G |H\'8:M[JvrMhȾKݲiU_%VH_]V62}F33ik'_x$8\Li-BF}MVuaD9s'5"Ʀ6eXc q̀x;`}8DŽ o Qgjrt4H endstream endobj 124 0 obj << /Length1 1611 /Length2 9057 /Length3 0 /Length 10104 /Filter /FlateDecode >> stream xڍP\.Lp wwwwwmhww 48 Ipwww$CHfUթs%kojZJ mVIkH qgdHjq8888Piiu̨z W70"iWM9N (y88|BB.B]2`k*@ JC}\vdp NH:\@K@" A>E b,fucdxZ 7'`Pi:v`?Pw/KW nk+yq @3X_pqMW/"0w%ur!#.X tt>[zZ-~ ' |.܀`gw767݇ϓu@ ~0WHQ毐g?6[;_rvu|A9C6E6' *'' tXl؟ ?Ểpz2}5OeVVR7d}RRPo+77 7%]psaϿΟ`7Y ?7>p?+w4ptf->ϙUY=׫n<[ǿv{5@?]א9! ׭`dogEv翗ֿ&`j,$.^^(Zk? @]Q(?]7j AH7|f=GFϪe rmk:99g* __/z @W⟛A@ԕE(P8ܾ6Zċ`Rt@?oŵ 㧷[WoFzd.%V)#Ej?'k.O N| C!eՑKCSƫ_޻n|meYxyB"*DwV2d&3o˫9' dfԀw~F\o|7*uܺi.qg+.nf*zT5=A]Vd0;TA9ڎEv}@D>kGa(#I Mab]u,x+͔f19:7[b_tGe3+O `^.<-qh21<Ҙ#ZT߉9C"G{1n0SM޻2U#4xJj[\\# KGvIH[^=KWL޻v[>*=D<@7ukMUYZ;þ-PX ![l 0Xߑ*j H0/>d '֎Ogη\:J9se "۩zUk. 7ILf&k{cKha8'ۚOoOVe.hl$lZ ˘9-,o!0f=45`o>~!8M5`JQxl2.5/V~z4KsUlCw7P)e:ajhuG( je/Fe6ZO奬iT\lQ&2V='R,`$yL٠mt_^+z.KzH$aX=u1@rˇ37E9@$::K[S)q`GѦ4b`=#Z ϝ`/A*r?"CYɋ6\? KکJsjnIdKbᷦ{f фbEuE/J CHĘyBAGId8\5dsK+D %v7wѕv6Q9AƜ0~r*a5t&)A".vCoZt2ˑ> k /qu\nMWN`^;Iaf$&eA,;ފ 7;cM~{u﹨LN>M7` 0S|xm]9OxC]X+W w<|‡r*RGY#N>9_k.*T~5O:"]R 0 Pɪ@[ ;_Y;wA_g-|gMc [>( xR5ױRxZvm8][Q]W+2Y qLL+g=Nyծ/w Fu_whK{{p\Z̮d?{@o)tˌsv/I*v*^}jզw 769mX<6/DMOhR!sy2Y?)V^*zJ!j}k611V@抑r]7:] \hȀ6Ò!R3)hMLi=F$"14a@=Gh 7Gӆ@XUbA˷ =\1S6V.} 8ODuoQƳ:zk^4{Ƹ>)o;EZo|Dū,LYrb0)=(EQv; L F@ 3G.⻊ҽI4P^x#0lҶ܂ƅ`J$|egd1#zg jF3 Ԍ OOQ|f^ M]]X4uptx7`gKtqUv{ڋi'Oj6~(t'hwV)go}M-aP';I;g+"w̰כn)޳xezќ2캡UcunlmȢLjqo}1i9)ǃ VBrifj"Fs&,w|\tA4Km+'b0oj8(g`J{g.6VWP9z/Dyˍ[tˮ=o 2b#RLe-2k؞*jb2Q6!J#zqmtZUj zZ ^н[)T CtIy>4(ۜ:O# ^p]n烠f&n2|+)~Fg$-8X|LսR8ǬРc7FAT@n> QwIpb1n0n:aO4XyWz 9KQBBVhwq8Qh$^ 1 'rZ-Km Q$qخ84Gvl2.-'d[5z7JҔ!.^X!oL;!-LTXXpР95e1rSf"8.%/o_|uA$UזHWY?1KoƁ%{P/=+3 g23 !ߧIb{Wr RnZiTcU#dXBˢaHi6/᫘_3gD^ɫ[WY Ȑh{*w243 3al+jyk]_R_Ɵ//Agww" ;Eѡ,gFL{~Ġt6zLǀ7 ( ^c!$3u!&U}-*@c{B3x_1ޢД[uœ`AMa[?xι <4oTh{nw}D.; O5!Po(3(+#p.*KJmG0]]r >NXb/ۣM/^$J88f@JMp.3{_%]\hgiN$10Jȱ͜? r0f낸0;"!ozM/2rj z^)rJŝ6O!P1X1iyVOa͹bBs>MbĉS jSc4k (O% 2+r`sz`nN)6eip)%tڿ*E^%H%"PZiK\ lq#s)cץDk.~>.E " @e\v!>k)YaOf4ək@ﳷ1 4,U["Uӏtn/ӿ -Lk9Γэ|V390Sw G+v=v8u|ڽsw/D@"o{eVgf&g[YƲ*Vo5 oF$uU6}J>cR G-X5%{wQo|No~+qƌ<|9!jV=)Ddl5WMց̿dF}~9Ӕrf/u\rE !~\75I..eo|쌹-CCSx3 i ҰBܽɨuP9aܘU{$`XrFF4vxԾ8_j0{h, c`EA)0S!dt"+7v/6#BMjf[Gg.~*6V mj\܄zRmfv.I$gDT?t5F0Mԣ*:q1O| zSX}*fpB-~ܮTC:21h`:!U7:]dkŏsKAf */YSr#ճb3( _/c&R3gy5~L9‚pŦB6= cl+۬.d-/ EI}mx7% ^DΝŀ H`=h~Wq+ro+Ma&S^ո=6 rjh9хzs_Y]j\ XdY X̩g`3rgKՖc&Y4}x|̚9V%j/:Rcg* HnVbn6|z\=nWgr,[J#u e 0ǣpMjd@EjN_N\$%t? ֣"Sm4V!_gk;2N6rک;pC+7wTԺSUp(MV;)-6h`wq Z(ݮqdtate^-3} }H\e-B޻b3? Eᯅ_KDuϾZnծc)\Ƚ#OeS J] '>4R|WڝlTx鳰y5vzQ 3|Ta\2;g7c'`Ovp^h/,;|uQ55 2l4KZةsXma)Dнo55#,uu{/R^,q"wwUhˊRif)Q4ڷU#P=ڶギ8yHxhwqy( HEfՉ@+4TO2CN30fgT.+OG\@G9"dGSBϹf=潬P6ݯ|o(3t]3?DvU7m6ZBO5p-H7tfQ%3 .^_3E 1 {*${ d8$LhrlPgO.Sѿ~kSty!P%4vcNe6LcDAur-#Z2y۾P:BW 2jt A5!AFi>\#Fo{p;LhSka 1OT{[QYjs%26 ^OYMh1GwƒZn[8 uO{(O;f~97=Z.S\C C*#U}amժ#{S@EliS]A0y`P/nFdӥIbPoOK $ɞH@[DY"4>12*O9 9g+9FCI!bjxzo֖7d6*ҷ`Zva;]F9~~eςI܎|Xn\q\Ӆ-q8kZm!xangtu$lOsYo}Zcooa)dSJ?CHq{COdfp[:KTxq̽.9dQǪʡ&bZq] 8Hif֨Hl>Xfd?zM;~,Q?4efËq2Vj֔{@‚:NszDŽL?})*џtQS%wj+ V}FegLi9ۦru{Uym z۵ i:5EPP|uKMc<?EWwem((2lxkE*jwހR|+|0/#J(p:|N~/&5`ָÕN$WDC5'lz~M.d XCD$7."2E{xVu~H}/'ЫXw=6Pa}x)3+(cȗ-*Y&ݶHZ#bL68Z>Jo$T:Ɇ`-7Z@w]Kݳi7B+3pn9W2zaɨ$7"ʮ[βRgrt4F^##@gya!GQ AbUS8Iom2+DazDL.Դ{8%NE\-_af%_j^7^F=GZ{h#{mZ9m]t!2?m':f:[k҃L0hoX᯻ < 06$ +͉$| KV>lE}6-TӔw%`l(1?TBAEō%cdy~1Q+FKs.LAP.҂s(QwWҨI#d!3 sJY7\\~0/qbg\MmËb1瘛%zP-[E(jD;P!9 pnBr4iQO|O oXaspƁ& E^nfO vJވѦPO}:`ũaBʋ(CQ8j9Byb=7f,~4+?bptz|~&@֠x'KA%xlN *F8z=kAĬL}5{'.Ǘ3"RkjԄ̣K,ܨRgNR'۽ ^DY *zVT$w$],$@(Y$V;ȵ} q/ vOd8 #4߀K]*~3_hr|$.@\'ktF>RCG\೪ D[D424d!UbR endstream endobj 126 0 obj << /Length1 1373 /Length2 6096 /Length3 0 /Length 7038 /Filter /FlateDecode >> stream xڍwTl7ҍ #FnPBc6F74 !tJJ7H! !Ny~;;gw3 #E@5}I$&f0/- !ˮQ:qG:n1,d@>0G@z~H S_G "##%'E `8@rc*BnSE# !+,+vB y0 E@ݡ"\`^MN(_0 (`(  w"Sm=_Ww'!;`nP Ꮏn^L< s;`4h y`n'd  GyOB0[sp/<௳ {Goas8FE3@R2'Nnc8aF/BzCA08cPd#ah5<'[ p7\f:VIU @ sg#0.@Ն;!25ҿy&/ B< H|O ݿ?hz6V;o;( ]0ojD& u4 .A/oP#ˆahxaŐ%5ovJHH$؏sI #a!8 ` 8!$S\ y~+Ș:(_ H$f_NCh(dn|TvVrWpmDafW0`0:'|S%=W y֫ǭo^%%-VK|GLy=3"C-MnTHsQ ]]0=f^-KzY6!`oV X;NKG}ts:oU'$h'A8jU4|LԫɊ. 8WFLPi"n+64M,lgA-tejq uY<J |~ΌXz^Pij<@E{H6̒z*֪r6YwW͔%IOǘ=OC SAQ|`jo0(97!7q3TX ~(r'QDREE9/$6Z#Q QiqJ :uܮq=.gmnXN|\2~eZ/ SߴJ*K[ "`AOt>>{{\S*gȷ ^5Z踓݋|lQ_tzO`Qcvԥ{c5.qv]_$[7(4$ZyP,l#l}"kU[/-uinDdH>pG+fܚz`{AEWrkl>^yӏ&IqTt>V48˳mXmǿ`Uޒ|9]\Ti=&Fu^V—LkvCÍD9)'jgVߦYwqHARK=O՜4r$.4me] 91 ts]4)Vyv!9_"~ d|* GM5jH3l=xZʼnĨ; i8=GH=y[B~u:od-t$х>gv-VsOzmvJ/11r QqΎ!enIdRPY)/;<Ig^\]RKlu#5dFTڭ`B"#ֳ{ 9T#t,E/yi-i;Ǘ dZiiɒiRה"& NJA3(oSK˞01/|bCFCE@7{3ZlR}Qj5ʊA,Qx[4GG\8Yg3X^b%MƵ^8ٱڰ,X斞Ѽh,[gp0ߺj)yq_DnPOgYҷXaBs+n;'h=uo ﱵUtxZɷ,#&I0SZR=. Ӌ)Qw([r}FsVoȴ}0jg-@B!˓Tn]/Շ5)ۜZ,$Ģ'V6֪vt}v pgJztCXL Aw'*dw~in0>jBL[=lz+A`FR~>,%fC3f&n)K"ֺEyFM *VQg)&X*pǀ #Ȩa8@Gg_(*1lF V_Г 1ՎdT[E+bE蒋:y`=.Tfvt{ }LTzJg2U2f> <}՗'CoB19BųWFsXKUw'w)v zkjsȃZQBM;,/o#v6>,l "" XV?Ɉϑ7AEY ?0Lj3U5{ȜGͧW #M0z^#{1zD(źMU>)PY [5οДEG>>PۏOj:-%OԾ\И~\8 sXƭrH/} L^e}NO.( į{? qp3;|+q,Y|(G^Cq/&?gIU~Hgn›k-W 2K%#[j^%M#҅HDrin󓙿\K5r} я;9Y4TjP1c2>ܒ_hL[_^:cKMWf}pjgݚ7sD0T=[X鷴9I UK[yV$MyS8gIYܸ=̈́6*w) ]I t)Rut6Wp8W' /FUT\p+s?zm'JUDǮ9WvMhNw/zY -dp ќ{ONU)vf63V{dHDBt~A0u1WcΉ~f,Dǜ4/kn_vM (mF簪ŔK> 7k^?~\& !i"뭆l*Dە@NȚYRGEѮBȻ .Ⲩ+CTZm0W(dI?r>aV1|R43or/}Be$yى9ْ?N >#~H1*3j07}iON!zN$WX?;Av5njsϿS2PpMJ'OS_>k:qt3 NOߏo8|\n%T64*xƓ䫂g@S[28$7]oN1X.6=ߛ/$9 ţjcb!+Gfd$7t/y5:)vTp<^!cq! \8AM4 Xy'Fgؾpkט(=9O\rB['B3N#y &u{YfrHT'By^$."ו3O.`l8aIE@\z1~W<<iq9<ɧ>}X{ǹg'cԀL|}3usnB\"އ_ QI0,p@v珆ϵHkgiάphVoӉYJ9abV:Brc٪=]Ivo-b D'񎰇l,bɧ"صa{^6W*8{m;J&i>e -`G ? {+y^PZpvy*s%gSE| 3IG$^"汞JQ~e!72}{D5>Ju.Cϐ+%Ҭ<MHE_dq uh;߀TF J4U*7-"yXz(!B>u|.;֧H4]!:H;AJOqNJwOWXyRjYiiκriJ#nPQiYA5Vb w7cfwSY~8UQS!6s8:&*,p>G5K:"{ '2x+Ԏ1%_VthE1myZYDbAogogܾ3,楶`U._C@襼֣x VQrw7?φҤTo HW"I]:Xh@wɌ#83E*4<;;A x3Q=a×@ ~Q8 54~lFk+m{lv(V?mxnnNl:"Vtٽ /TnkΖM峣q)mF[6Ē)CFw?YIXȪl](72)-ORT,^| [nZ5Dlqq|M> stream xڍVT]$e$RPSj`f`r DBJIiEii) i %U@;{׺wk{Ύ}k*;hV"` 10XgzX|po~U ԠX|>B$i9 eՠ~gPT^ʿ@ "++#;c0( źaPO)c!p ŠH14UAPM>p] ݘhc6E`8oD(|/j ?zD] "7_ٿP (W 4`EP@"5z X=PhrvՂk7±@)0,# ½Yˌ?[ \_x;@ @g t"Pf˟=~D6O<-g43誙[* n.t'*.!qq ~O#(*j\@?o_5}!'X8Poۂ0M)z4|=={~Dx>ZUEW k@KDh F,U }>(@Q>`]phy: v.q)i #豈8^ Ph,>o/~ b0xY<kShͻUwV* ʏX>Ma}i_fEc:>- +Ms6^E77:$4&z\I!j|lA@ت×{(пK3l}ĊKi]ӲmË򜞎pbE9ɅvhFr.t!$ q6 GA}XyYmX8ޏ\ǩ0ĕJ|j# XHJڪV~fLt3;^DRk;t۸ 2*g2_^ &/ϟʵ?ǥ0ͥǚ^q- DeLA:./} Qڞ bT.8pNѱ/J";daZcff NF8ít&ŮuUŰb`WSPE1))9(xtƥ9n=yQ K4eLPL! &bnIN>g{WQԎ9l4EkK>bw$̈b{dR#}g|c[fMz |k.H>IƢPޝ/t/|՜&%2TXmL]}%ֳK:G nC&?,Y-z0jg6(𱟮LϬ=, ̫7xHZT!eh"c#{SiLͼ[΋iy7rt^\NX^tڽbHr8nx9ޕgrLexr"\h 7RuO$S dyYNj?=ڡ唶SX>p">.E9caIR<ŏ4vRUOjC^=PwiFn zx.,!feap7Hz(f9`ڡrZ.݊B`ǽzp"OT1c*I\{~̌kˁqzWfCp*OgY zP .DEE_#.3 nڴDD2;ܞG)HۈV_zO{M7^IR$c)SHuK(~^@*6ಲ+s4=2b6&LL `#2֜E[u8j b<}V,:d3=hk/V{\.ѦĢ>ڼMOkxkxJc[dz5żZ.~|p d1s ֋7dcVDM]?]snyxvVNr>HF3O{EiZ)&+ةm]f4>qK}`$JZl׵ߴ#r[KXS5LnJCۀ0 L[+Kn5<,bW?"8q ||mg|- \SnYuU޹99Rk [Kf3:z*ڡki~$bVy!,UB-FŃ ӼWIxWFijsgcB>q+m^WZ+5Hᴛ&^ZB݌RoS9R.xmC_ hwu =- DeID(Z9 gM_ AB79 GYȤې,Nn*款ү6cXuWn%d-eHQeN aZ,ׇ ߘr.v輁qiIzq:N9Oѹ,L LO'yn\m!^οQRB8v߈u[LjK0d|4/:ʗ- f]DOˆDi Xt'|k7m88gh6 *mgO .sʸ2T1$B @->&8s%"a2@o(gꧾ4]Q;m:r ~o{W 8I@d<(Ҥ+zVy%%wlљbɵSd~8Oԋ:S+MRiٓ;/,mi]•GTl4O{krMGKNݫ6RLl Gdw' x.72(Wo*w͑F+zr{ Ў}5't)"(t4h9E59@.t+INzq5$;6 4dj3QV[ic6`Wy_>?Tcu/h?0p'|MU\J LfKƮjt,ՇIϹ݃ -Cf5nwNbgJK"_f꒞tz.0X.#j3MHVFX{cЇ# WK`bUwm'c I sxQC2_k5E;+z"<_"'o(* BT,dlz;MfM߱eJdMTj. )nDhkm.樛E\2_`v]dG:HO%e0%$/K,Afvۯ'@]VhcRhUD.&R[7JՖ?=bŭR4y7tR2 kté95f~Q~ʿh9MK3eU/Ø.d$(i$pVayScD7N˛WPoJ Ak,FDWz[N`R-ݣjỎ/{E 0+V "'U>#%PuǢztC|FD-N^b_jvk!l00^FSSP跐V9䟃̢WD-%pw/Kk'Ć};LE9c!mÕs.%KZ5H26woo8N$oF7YBo ~N6X<\}/Qp}֫Aflg2#۸$y)Xb_c^D|'P9A3LخUԾmv;K{DcZpڋ:6SH60}y2Ԁ*{b>r`zӳ׼euHPrH҄MtbFI)p$W /B/S@zvUwj.SXC綾 Fe.yB4bB//L|x+v4!r}bnP?*ƨ|\f Jԃo9U C)ME/ 3T\ =iH$oG7H?G*y8M؀CJF;JORXFo?N.rk 4T>, 9 Hw-^c vk0q("*ML֋08}&~`pdr%[L-hXL.'2V3rHrኍAyτk<iU+ӳ[ hl%^]#'8@61fk\"w(.3ȅ9B"NTI[3á%[5eM\ VLgRy!|$alJKShyZ51R[$]kV#qBGˍAo~3)րSSm)7QYzBL厍 Ta¯ۿgdTwksw6HO͕ ]\Rjt KI-giB;dQpUMNF^0.8T* DTNQIsdL%zcfO:DiG =W6>!Q?JC/;OW'#]#i=Sl"ÌLچɰ^=H"'k2P(n(5Ἕ6_s"95QL;wҾ墄 os& F,aEri#׿{ӓ ||ě(xUKl `P +&J}VX^(U |R9AKKX/&Dƽ,aB\mn* 9<+&cQ?nr\BM&q5iOuƛ Gclw\na*.n0ݣ| }c4`7y/]jO}c b\Ky3/ *oԻQN .MgY<$a*fn 1U!ZtX%JA}fs:HjLUnGhY0tw[8BK6o!Nz-r A&{V|Zߒ\v )zq 䲗bJ']RCB?ib74gcvxBp^f~5 7Hx|ļ~GkJsdHñ2U2Rp9}s8 !-Y>;ijq1 bm vj[p1?#Xk}8A`OöỜ^Ϩ^Jd$*jIBk U7gσjAjȞ.~''Z3 ;h$;k)>$_ L\0n'@ k=?Si7ÐKt'H!y$X^eT-J3B +T54D f)b\*gS4I(@ endstream endobj 130 0 obj << /Length1 1958 /Length2 12622 /Length3 0 /Length 13825 /Filter /FlateDecode >> stream xڍPi.Cpn}pwKvvꜚjj "f&@I{  #3/@LÅ@Anb K@ trK/4vy)؃6 '/ /33 xnVfF=@!fdeaԦ4.?"v@'+Sc@hfojt..LLvΌN4w+K*4Q.@gauK+j.N@r~wpj2% /c 9 #G +ПƦv O+Pgtp04u7v356y71@RD`^s6urpqftB?¼LrqF=l ׳\4@V@XY]\<,#ajGpuO?}%}́?n@+ߊF,,3+S Ow1/y'+.>[f [l.'u ? [%*jf`0r0X\E?,x"~JC?ݧb; 37D #jkGklgeϾ'_4rZY}VΒV@3e+S˿F/ fk*;[qX}Lm/ yS|_N)27cX98NNƞ-~Go54z9&F˻ <_0! qA<&0IXLR 6?$zϠzϠ7~zb08L##wƦMG7}~Lfwfoggټ d0 S|a/Nߡ ӳ 9+O¿D߉8Sܻ]#eU[^vwN̝=\ɹ d}'5uuzg>|9@S{S`:w YO4 KN()4ٟ7nERHP/x4&=<&N!,>i''dPyq lwtFQ.ļwh\ ]SٯC|aш ,(0ə%qa Ÿ@ț|#MC=a+d}ZRgu#%=LY./pK߲Kf=STw:4eĒhN+Þs*!sbLhdՀbwe1ݘɷC9- 'ã[M6O,t>%“_79N|c LOo1j2T&mE~i0>])؊JkEnnE4vzIi-J' Q= RqUwvs].',P^+z)=>`ao4bp["X0n ܐwPj5Wޮ?vK੗z@=4krTXKvAKs_(\X?BuwHt?TL9Aja"jr8{\+ QBDrT-EضQ&ʯB4Mラu?rX*iW s@bhEbtޮp$k= XN<+E-f`h:;} ,j.DS]"zq!tv0dž*cqo?ѹ6!YHAтZ '$i;''=DWsÆLIdVH]CPPt ŕ]ۑ*.ף}-abNMϸ^EI!Ԙ@c^\8I0! l$C"[fҐ:Gu%p}yN,*>ؔ/$yQ3~AmX\4cpC?5XK<6a,r8ɇ:©_Y-}1Q: T:?HZD%&c`gh"y%Kf1 q T/q,W_eԊҠ14H άز%F4a22 n mʜMd3rāc:sՀGmrhTOD#B0V8%uƇ]oJ,%n1!iX}}$љ+_mw= zjX8 .><*y77ߐӊƵ2BJGWI0{YZ 8\ū v6_=7eHuԘ8pIK*?HEM\'HY .;p'V+.|0o? NKņ;";n$͇! *e7R ؏Ue6D*BqW4)$eXs+j(GXN%hiW2ic*m.1Ӽuk 7͠AD/r}ׅo .+q8Y&g(nڞ%9Nr[OD%w2 iTrQx;]$ }4p^2%~oGIG$bEOWsgFћ'K_+9ˆKU)ھ3 X~|ѣ|6̩lΗ=׹6C dtu,ҧ'&#佈A7{LHiTbAqh{.|zѷܼ /Aj[Vۈxzn dsX'YxAt7R)0m_>KʼKoI%fewT P2{˅ET{*>>vxrԯ{!,PmL S.u~oU5em_Gb@٭4d3Oɱ1#m(xf~ae~'r}Ԯ"YV"e$#+Pr`߯}/: nToGX֙1y3WEhA!o nC:%}%Ƿ <d7FWQq5.χ%FsCm#"o[W>ǭ_\Uv ;e͜<)\ҡ"ij!Q"z[uۉ׎BҌمYqϩ$SA5~v҅#|p=ǃ:oLY!# >Aihrx?KȎ3q!Yg4́!$Q2e(?н_h&í9jeXxAU*i&h؉lBq~] u9}qj\tO(Wnpܻak6[?u捜zt.}0rMSKO>.XURbh7;.ZID@bz$ؽL=!f }_YU;"٣b£XG{ u87LB "zj$sYbĬ&8Ȫ&Pvsm P i^x YYuC 5J|rì*'/ E-C$&҆ow7 18?oQ/nS[uU֍^@2f>Kl?~b3,4;jǀHlUc Pb?ʴ6u㑚ª7ÃXvO[bxrVNfFk1yL.ayi꣰ lۅ0SR$H[Vn˛ &+t-$tRug!] s0>L am!UX[l{"]{EKJ,`b" >yimZ^o%MP4[ n+}wom.D!Kxߴb.A 8ڌZf4 h)w]dvڷ,5\Au$x'xg9)k9"uDS%dy&5:L[uXd pf FN<˓S5i';!]+~G"m[̦,At•AF3 :Y,)gVg:'p!P3:=*/qcȴ3xǻK=a0ɒckP6>>/!pSNF`Jb+sJS \PFs7xz $/)#E b@nˎŽߕdA4Fge:j·KOoV>z8q]ogZ`7u|޷JG|ݜs}2 v W+#q3]`ъqbK&tEVmYt_A设9y5ֶX_ !s|#ZViY"لy*8f.j<(fWÛ%Z^R!2ʖ]6s]]rL1>~못knW zd[gR,4T9Fhm,…o ˛i!q0% ̿c[X}Evxk#6 '>$-(Uطtj<#:I!4S^5A>%чƀ:m8)-|#`e&%IV.]-&A+zdWAXfJ?\gIOfAJG!tԥ CvB7{m]I10x丗'['peoN4&h]'G.FQ79 voZ*dҍQ$N 5TJ߳1I,'_Ü6!I "e%Z v q@LF@ Kxňz ZpL UEDUTlkևЙϳ|eF$SxV?%3ť2E] 9o( vx1|y͌⓭(N~dL-Lp(V_{O;gsNr c9JDOљ5܀^M!K{U` fWasn;t]ab^ܙGpmFp~xM.|Auq7'=]tr+Yq.!^}L߽Tmsm{y~P6!"}y|lC(kr+r:l=qc}G9˻ƷHt'vSi/'UU>*Ssd+?8b1וܩAI2o!\N+i_qj=2ſO'2!z-Ef/Goa}-vZ(ːQ㵧pfdGeEAtk;L%tZWG2BCx6$Na.h B~\Ro ţEu/&?}z 1S0E.: 9$M&CIjw9(9ny6jf_o71vj4j5x*r2)%.4&5;z4.e#Zch׹]`D&[17Fف+$>x[bTJ&/W_yY}흱>8_K؎[sTK* na#W;+JOjN`W$D~rw-E :Z)-<D @Y0gVB.Ki75+8Q2.Od_ 駜_\N&aH '(gHwR8W#JkD6PZIĤa7l֝ٸIT\؆z]uBM'\Q[AKBj1nmMLJ*L^orn/\"8Zz+oMf+ׄ sp0<鸒ÎҺ,l44r݁N[f&(_L)oB3?U C>*N' bHiC)([:aޔ@u=u2X01[~O:lK0T{ϻ n9Ÿ2E&Qo{iuF̫HFh^pF2I#Y":!ejuS LjD:/}?:r"G K& U|:3E4BSn221ç઻]tTR5i;qlŖޯP"<͙O7ltk8yj`'4=;80ѮR>txAv%- A$}4upU۔ӡT~xbZjS!k2 e5Ȏo4 E^^P%{Y4yoQ gGU<^>uf:-dUdRj+>C|t<]W#{{oxAm8]}*g6!\^KPȽRo-" ,q`/4=$*jX%950BNtsoć$mkU6X)-'V@1)?ԭQ S܄}~b*e_ղ:t>CJ~x_d>@H)f|~d?B2"QPB {%CFgHI}99j4lt"y0#Z~Q5%mhL&x;=Yd@Pޟn[hWEBݯP?lJf0-1;̡Ŏr`U!ck pAݓ ,g&mڒ N}l;WjS6J}@ GzX-0H9TNvP&+Ql _5Ƙ ;=QMd.̈́,^ 7 w{ '0=49i@|.5!]쒜vYϿFHqCsf+Wf[(32&kC Y fI2*CF ?aΔp9Xʫl)əaPM^̈́;V{_~4Cn>) DTF=C& Peϴkj\-s3Da8R+$1WfBШ%t*#JW"X3}e'[F&?]kqrÏ Qѣ 4e3=@kҬcHqWbVd+K='̯2_^^x1CnBsN)C%ɫ\eNS5%crc1Kdq0=FS9Ia橝E5萞rȯ̈F 8p-k5>l&c?v9R| J\`vܘ$0vu(I DZ c.nTq 4qv^̸2Rh LO[IV hv,GTi7fG7|%Ynў[Y4:oʄbV[^/qa|rąȲy!y0.|BSk'{j=xfq7C~X=*@Qw3kg udaXi㲮~$BG D]?ܻ xUk \'$w2tVe3)w nPrǗ}SĆ'6/K5j()pG Ka;Y|OdKq]Lpf1LͤIK1~Q]+ׄu#-Pʇ> Œӯ-EK=]\D컹zvAi#vB ʥAl”c b#t+RhkJt}rf[5`z'W Ԋ p)9O +y ԛs(S/aa8 ,kLMd%2{Kf>wODGQ)LuIQU2e]d$)!$+{);7+J63\ټ^*KřE]Pӎ^\~=EaCS+yRg.\ À$^2N4pݕ1i5l 0,K=%,t; FMF<s#$'ൂYߨ\ƍzX-FZ򑯕:kȹ-(D8 r-%P.ɛ~V>g|ks t}qV)Ėnh֯m9|UI] 6 j /-@G"J?wa[Ƌ2Ju9-K%\f.1fJ *v9pjF27+/RLJKg&3;".ʝf PO#htкGqל_DvN(FL4wx*@S.)`18iXpyjlp#v?HoӴ>~abK4F'.,~m/̼/@0 ?1u>1s-T=},o^#mv9lU2!nՖS?t!W08Cq| ;cwsHG PejXb߅1w{%ԈE~hDritNb% ViMiѡ\MrCV@sK$eeݾXJy03<+" ¦[d25pp/{Bd?~HhZ'!G{VH1|P={C~D"OW'ix+0U>?fEj hF-n^6քlI@'iA7 !02ZoZZnCE@ 6hhKBrsjytyCRs{X,4nQ$cb nt@iP3a{lrְȉs^uWW$7Nt1pBID>~|>6GNᶫi7Ƴ.z7Kݯgwnf(Ӽj=ӌ:F1dM "A%@JnP5[*{!hPs|sJƜl`];!(u(Xbּoap *Zʺ6O:X++oJ.={yp44(7^vVeS"/[h=/M!KRu_?ĩRa[A]Pg DQv1*ao 1 &ߪvƖkWHex+s7n:)6K2:N=]%`n`{tK|w됂/Kǻɔj ΉDrSOyuCʻ&nT1Kj &%'a633=Sz{3!ǒ4`7r*&E04NRŸ#]x?ߖ$L&gr8M镭h}K)<ӄJ HsY%nse:{glSoE[2v"f 7D-0!IP*!ɥCb gǷzWA7o">7W^էP X~1vgh ;A&=)]ų8n/؞&c [V0 낒ӱWI,EnFGgU,rJ~͓!z^W–)7G22]#GCC bx%L^\iR*707Vﲻ_-c`OA @?W8<-: jV~&d-M~~lHZ>Ep>`a~>i]wWY%@&xi~q@"_%qyJ!2\$̼&YW ZbI[m>li[-5> stream xڍPX.hpww4w%\ݝw;s)H> %\x&&V&&8 UK_R8 u?N@#ˇ@ `aab01qމ ffi g(D<,-\>20sss:Y\,Ml*&@ Ag`d`d.@Mpt(Nn@SlGPtKbon|l,Mvv@'Gn@h_t] ?G K?LLm<-f6@ C#g#7#K#?$F:g'KggK?*d#%ۙ\'f4uO?%:0Y:e![ft311qrU=*vw}4~y;.N@_*13L-M\@sK;fᏗw0}43Nzejog(%Y^ςxӳrYؙLΏGld/LJۙ"qK&ק`P;GT7.;sD4pSK5_]]>z_cT׸M-]mW+b1v6DKg KgKZ/fcillB331cL?G?~ 37cX9FNNFpOch  v..|fNp''3Q_(7b0J #nQo`T0>>;X?r(>Қ}/ M??3HcUXx:X|l->dY~fo>6?3ss|ѰG)?8~x}ML]?~0u|x{~0W癸:9}?7G[@ ʢ oU]pc0;$Ł7jzg$d-{^=q;U7IJm/> 3mpXSgB>o>ୠ]2\H%=C9d_fcԢu)g-BР]y ϡL&I=a-f}ZڨPeq%!C9N^.)\\h+$AK]Ga8fɨTku_dMDO-m0p"UĬn3Bwewl߫Yr,p$"fGOlht#~)q9QpMZj WMMtl\`6|MC.U^o]Dcoh9b\f0ZPbbI& 1DZD? Kgq~"J%Vc֡QHJRހum_U2TÄdxIB޸7( 90LNkzD88=]G4k08͖w5ékFNA=ޕ) GV43}LɓMW nFҚ@sQrSy+~ZҶ$/ڔվbhe*Q`$o< ׇz)]je< ^D Y8hJ{5:|ɆM}y~$@'.n&cRׇHv{VZkK0].~[8+({:~%?1fh >C{l}㬚#~}Ȥ)ZGP lj16o?~(7@.r#.Ş=C׍қcT l]쓜ݡS%Sc+R_HckBAc;7e, j4'zש4JO-A[r 6;I+OGfֱʠҳ;{mq׸ Z!%K ML@'H H`y4л;F@Vxhk oh&RRZxb,~o.Z1#(eWѳ%a@\z5S7Moѭ5t/jR]jڅYRT}-Qle5vd[j{]m<6YaQ.\RRSi10biwDEr A7}{:iEخloE_e}^c_&UTsH.SAD)^#z<&&ׂoǂWȜ'F+hzJAtɻG;r.mu<>6)j5>D&놱 ;I/(ZqB|l8O.A7Dzh9:,Eᔩqy_c"'q%٣]d'%߂Ohnt6_2ձ}:l6)a{.д/HǛbڄu7"=g>k&nBxsKk`Kt{hcJM课.!bD̤ssZ(g*K`Ag?<1* 2hL2S/ ,c 6[is&ᐸv|TZ)K3V7ǽlUٺK1ap`)ke"HQrGC <0[hTI &_izc=}io׿fH %?jA MrDG .ESӨlit%j.{L9!WB|+;+1T~Q,LM#)x7\$6KڋP`#qb$Mo#Bs?UE[xIXs1W=UzS)H&3-V)q\Fl]S7o82LioӎÔ8_KyRM<`h9*fp *g{mh/+5 K]۲n(:s ci9qw=&p}zyk z?wvZn#8E>"\NOܰ u8Fy#~rTrl ruZ;t8|Be/LZ0 !pj=Oq E*؍:h! #cz˛3P&t*A3GΉPt ::L<ДsM_8B&IU!IlQ$DxBtn$k!F-X' Vp?…-t+E8 x^EVuK'jcd84]|TǖxRG +Ȑ Vi, 0Ⱦi1Lue>;" O?( _Tw8=$"[~ l\n}Sh~'"Kۈ9\an@p{ĉ睗)kRPwZ#Ҥ:jlKa)T;;8wl`| @ $lVwu۫[(e%Fh‘01hMܓsvՋmsog/}=3  SĤ3YašbYː e˴}E,<L d(Ϭw\O͗5 7u x U%&z\¡US7bcHl8e("f&üĨw'-V*c)4ilp,zv^%3f*x`oB0wK?g57Uh.4S{7%Jd٧2e#(˲Jf㰯c(%|^O?N[Ȅt,eWeJ+P93f}AžSdS7'\(xM)A% ¬D)EW 郘py cl>{"LqH׺1ѐb6:-(mV'2Tq%өa}/Aj5[m&.T7cDPJ'Զm '?:,7@3G.7tuOv3~>m)Hxݮ fb5߹u>>jg+i&$ e=`X+-=7F<KNZrJZH+Ztp.q6cT%6[oMXZO.)?F.:GTHDKI=1*- Z$eu!^ %`wF$: IZb:9N31U0BX}@lprsw%z\)O4ΜMu3S YeZ}Zr@.c^l'-5gh%ty|˲g솽A%G.ב.h<%Z CS"!* MC MI<3}] q;4˷E Z>8!Uj-*@߲pD mډ3c^7:yjcy䋸CrfiH ^u.c[( rFg͟>+[%dZgPm*{FP?[ o$}3lWW?K7Gmv^$Ql_~WPgMuYV!t DV.Q'9m@1|½#b |b+#(v*ٝg9Z Z6MȬiK-w􆯨_'H }J8`MQbݫx9?*c.( !t'\g71XfրY_l16kWBq{]iAFNfߣ!W-l^̙gCJԋ5Z2dW|kd6z(W`CĞP^a}NFْ-IX03ѣ#7iFH,?rjڑs51AKPO+Jޱ+r HJZ<9xI| aT!&z;S4vuJLMKH;zܥ:E6ߝX/O? &#:Tku#Fߓ}' zM mb+W~_ 6鉣qMټ]vފ ZnIrHuC 0a- Y<ʑ@1oOa;(1Đ)(&w4ڕ:|<Y"(@k.b(U//92ɕ,qګRڦ2 kRz𧚝g"֦h)Wob,k?56@Vt!g5U bn50ϡt狐<]+ZWN9<)q}rAh-CFc6Tyb5?sj{nZZR25@Guvd}bIoyN7(>-Z3~)>^yG( $\5dCszvY_#+Kד،szD^j_mC%-JUMR|X.h]\1ǧfF]K]Fgj-?wl$0Y;[s{7o{>%XÐG˗_[E^} 9-kHc^a!u ҫQh8+VgtYp2 ~nMBD~ch>^4+sNo8 iW4$\5 8MԓC [qZ9!'@q NV|Uϲ/bͯ%N.^Ƅvaǥ ťvv[Z9 ,ay67c*'o@Rk:C!X#KuލJhmSZ;i`SCi讹W">VrYvچN+cb LBDBDwP|M`ΰKeW&gzw`BiKDGn@D5>=*җD'Z&wL9^]9f-) .ƢD.d(uN/U%{JٛcU wm|;GtWQ!!VJC^-b8%'+D&hBIpnER¥r@ J"oqSEF*aDpv̝cT7;ZI$غ>?s"C`r RaFr>Χ).1Ll.=irZZKoy w}h<@UO|`wO2Bxb3Us ^꠭zuye;ȅnL|i45x? Pkrj#srr#\tyz f!$wx_19A:.c7֛EDK Uo,f϶j!U$[x| '$-Gzbi5LJu؟Z07J64wO\v=L wjS-,(6(U&LkryP"+%sAv3z3ſ䪻V Cڂ EE .ni5ɱM1%O O:8!5=q6{2PhB09/_Z)Fύ5|V7Mrwj]b{ N2!c a@}U+|V %燠]6 :a{Xo05zaZY=ghx^0n6\V!E,3mQ:>rpQ&S;j"/J#\C,W_X:ٓ4]v[iwd*i )Z:6},:OEf"iHr|P]b i'_Zu9>!. $lwy1͚zݕXcBwܼFy8?vhp}F4{\^1,7 c}>7 4ik\d&;M)vȣYLJBܦ+$ϼ){#J~y3Yk۸ʾƗ21U[@β덦vSw(o{~M#YW<~6i@B5WmҮ,JXLQ]`wZFJ'rzJ(8P``()Y!/lsceE'Q*p]m RQ"č*(kT7bxCUpDJd"*Dz[ /# TCn\ƏD硵d,dFZ&r_m\Qqu|YͪKd,S`moλ EĴn0{ܝ<+Ch܇dpg^ר9t47E.|l(墽E^c/~V :=[? ˁzFX/%hqe6sX? 99[~ly!=*.AVx@9ܠ>9Z.P|I#y]Iiҭfm3nbNeavT&,ݻeHL-tIy<N4]*WN*Dmi')(ڝ0Yu:TV׵d5uu6Jw1!^S`D&VړHuh6XYs;? p^yN&gKjҺJbN0FLTw~oճѬmq3ř9yZ, "iX4Q@t`Bh_&⹘QHЏ?'ߡ`%+f:JgY,jn9as DlNZ'@}pUFx*kcg{*OA){]p u S VSc;RF>Qnu*yZYa޹fJxdS"UVo)U(/לw-'7FYL/.4rza5cv`h,^c/ppM 4S×Y ߠp@H-!7y43 y"?u_ewN4"GCk:@;} 81#bEDKˁ-⺬k~"\7]@2,q~9ZĐWd{xɒ[k^DC܎,0usؖ PKpYlo{I[dǷk>_xbHA^ͺw|S\YT͋{CP=11:` e -ƽ z㪍tJtJ )1hꎍ9^=ZWռnnn/3+)RW+_aXֻGk&q]tˊxXhdP9ш3_E噒 woHx| `+$e8W@0L /qx_SxS4FcΎ4ԖqO~ 1eLyﺪuP6wW6ZΣBۨs<3`@'3/ hTp2Dc>_L _[(:B5CU+ aye~Z cD(sΉ;`'耻e^%l|zaуm1&dFnr^ F#Ē ]*twrB06z7) sc%A~\-Un{~Swq/^$|I}7Ub-Tϯ{ޙ7#R‘c}e;%AjrYiEX#W#F~VFEDm(yrrq5wS.%߃s\ΰn]`FQ@x^KP^F_1-TH8Z}jB/BVCNҎ(:,|ޅ~ 0憈%(m[Ɛ~rC+R5qgZ^vδ0ZxՆsh;@UHCzNJ.܆sЉ9x]Y8K[>qki{]ΤElTYPMe6xrů!k-9cϡ-E-mʛj-QSTS$d(1o4ɣ(O"AiW #}F==h466#`Jq}+;鄾C˟ jY%. zRcQIjTja&a*j&MY퀗-t|u >ӛ&'{̾Ɛ6BF+ƕ(wGleyO&z5~e}hjG>vBC|l2fgZNi·bJuFw^qFMֶd8>[$%2d NcYЈ,2Ifœf{\EJWYr#pIX5ޗPȇ>nL.IJK}U+87QʤjiȳʒsYOlrڰ3h BmxAGDĶ l"Ife>un}M( "O)U⮔ޞN<>m#cTrŃ-^̦fiNI٫ Exisa)NFߴ;z;d4-mssJ-:{kԷwkDRCƌFH U~thV5T;p'x"RHU%/^ci{sOZB=KAmg*$=XxLE#A~f+yGY`XZm+b)9""OꙻDA51i6.I^M{rԸaF"jL7Ȩ{c7˅k&e}G*S24@*&M)Wt'¬57^ltVd^d>P)ܰᬡ ZuW&}kbkF#{Y/+s\aE Gaŕؘo@{CuyXODqG[ endstream endobj 134 0 obj << /Length1 1633 /Length2 10279 /Length3 0 /Length 11347 /Filter /FlateDecode >> stream xڍP[- .k4{p0lp N$h5s9~W[S5ݻ^:*U7f { @RISΉBG ڂcG99!bH:L/6)S Qxb p`gph$2u[! g:I{'5L~~^?v ')d ٽT47h؛APJ(d :nnnlvlNV"L70r9, P6 @Cfl K xАW8 ";D`ȟv0 ` Td٠PV)K)M2jӗ ufs#4/, A(O 2w߇kwxY!aԂ]@Rs^L(ج@P;;;'[(/{K %:|oCf +0/f_/'YCl=ywjRtYn7\<7<Nn˃Q5C,-ed׿50;rAnn,?CTGd\lm3EM3^}%YoUY]Wj2 Efcv,TPsT]yC@?n(v{2s[E@/3u! '[Y TZ3^zX;qo@?L"~^^8^D  r@d Z{8X10^lxm|5_I w|/_-r׾89\2˦y@ si{s7eno~srw] lJnK ݞseϊNn߮s?x' U5"Xmz;+pn)pA,{.&YOO ו\>Fb9`C G"B lOm*(lu>>#ٽMY/d%;(\|iK`2 l&yPCF0M~sLl3R^ݪNg+ ^r kf F-R4s=x ۋdqe^vξ;`X7k霐6:[q51fz <) *DaxZ؁)JGvzOO㯝CvhP4xldaʏ{:,29λ;ueC:QCM\L5eYm|5y'M\ʣx/d9c-'7>>V y>SmNtȵ-cP|F2#YĊB*޶<^ {RQYzI_y=P@F]{N-Ftfi欨mKlNFuى-;i,p&z6H|e)&j 6?eNR+Pf}/L'(W27e,2 vr b3N麒0D8Gz}$e2-׍ڢpGa=7D#)E%?>X1 J>&g19e J c'iJ~40.=-Wk%5z"'y)p&VjVrMʫ4Ŗ=8|~i,//ijnӱ _߲aj޾rᬽ zrnxJP\?-lAqpxs-pvg[^ƻ'z4<&X6#!\䱽ϓFVʶ{rw9xwchپJ.X8mbezsIQS2/z.9;KAK)xȐnn&ss,t. 3<6(V"ÿ[oP Q@NjOYT"/bG:R|M)RE"U #Nc_}16ԂȨiKܣCca n>FYly$ϻàɘd*RZ4fEi޻`@j\]TV*7R>M%!11Ȓ&U>KzѢAߚ0~ tHڤɹrE etven*>XwPܤUyrɴ\If~ZBj܂CK1aR ʚvR0' N8.dfp l׶ӡ8yfCv,F$VN'>ϙ̸~O(wB'7lgkF;_ztSiwK$J}pn 8խgJNEn<Q$*WPIB4k?g2?:;?ZE0,#xMiL'6 lR?}\{B:j)5I`2 Gs1cbo:}v긡mkeݑ;|X[ΪӕзeLc5*d\F5fgzoov_tbMh}lyi܆~kr(]"ם%w=b0lu::s:e²koN#I12^MZnY(hWA/ĊVd _|F"SqZ3CV4~Xy{Vծv B÷{`9_]9:p7@Aה9 X0 H܅[Q13!={* 903~4TӊE.P3QL=C  ZFRn^{hKhfD?Qj7xqms6Ӟ58Κn3\iu*C@֕I5XHHyd4*ݕک,8U>Z-l&?ƱUUx-C *cpLk[V(tA>kbz:SF%ƎNm.ѧnqʾvʹ.V4 jQ|XP&&j[D?>K Yb^BO;zmϢH7$XvHot v)rt.ogU[/)Uo3MEhYN@x7 p"Tv#m hawCR VF)X>jfe\ڞ$ef*ч/Hia gLSRX$0$Pׅߐ4s~νc]]W5"Q2yW^/&2JRͮJ]" J};;j?Vy8K\N@Ś3}yn݄:0o5}}8`J];;~1!ɵ  K%TsI5g=c0#LJyuΗ"2Lؓi6W—lג'FWHA# &9*/|_qe jVG wߖǁ# ~G6k˚lӨLئfQ|3`wRaSMϟ!4x^<-QT)?T{?CSӬ+jf*ԥajp *sM.xV/6jRBU6}8cӎ" KtK>>B .bJ% {3D(Z'޸<͒da~ _KdW-2zeRYM8${5c߸~b/D%<Ѵ8PU14T,uJxo)δG;|'Qzm'vrhOy"7q.CѰqTfc*Cx.%{X=EEeD7 Tu_6H(KuF 1"etw4<{J0..2+ s!@wJ6 e4꣟}/Vae#xZ{iwe5^ihykh"!<:)G#ɡϪNEKqF "ŔRA*cy2$))~I#||@öx&ER>2mفKvr+0bt9OnBϷ6"2)JЂB5 [Oo bU#扟( tE89^u~{l~bSRFb&"4IujK8PtgەCx6jƕ2<U3Ou7Ŀ7}V'a<4K7(aX:P, &PmЍ;M(O/Z?cG>yGm {s(+&r8l#D,87ATEuD O<^WN5{]o֢n }aKE5ͦ#|_?M>L]f3͍Hg+XAOJp)'IȽPު#)bПnzwSIRM6F\ և'uKΘ pt4` B]"m æ G'% 7kDS~}vm8{% 6ܧxmI-)U$SUWETT1W½NTʣ ϩvwsи꽶.I4r0BQW;z*˝@NMc+!UɴU] _Ґ+ʃ⳺G:vf_^RLYs‡ÐMcQ7X?8^4N2}:`@xP xӥJpϪPAl߱Y^ڈkio 9{xf$5Wvd~b -L<Ȁ@p/{O0T?;6w3?t<1du0;jYĹ.ϵP34Śwjn/cѭ&ZˎtBU}>9""XbaƷh,d)@"?97zNJ:# br/'d/ ް-0S%Zō v:%m"ֈ?RlU356COE_${5Չ6/ =w4L}teB)h.4tqfrm,UZb#b2>:^855W(L4†n Uؤc{Hm #Μ͗OnIZ;.!͐$L7/w0J쫋V׀n9ew./jW 6stcv+m^oC&X  [݆}WLsQړ@4m[.z[ߛDŽX8%K#Ơ,Xj[2=p8XMU;$_]d>֊MVM͘@1X?խ+D(}r]'zChfk6NHRpD,'4 pkvg}#??e1@-)J@r~6ww2It"bz6o0QIƽ0JرX3cՖ򜵊mɰJpaL{hjͰM?FJ1Ө[]+!lEy I GnXoaN.iWɂ-E M2dD0PћwaKƱ$#kKZwd^JAY//A ^7B{b^݁ks 6*N@X i8SLhe֍b+Ǣ<~!+'t5:f5 3C DN%79Tiy֐ \>oķ4g#ك´w_Q\B>$s*uZߪUf߻b\ͬVdB.\$Hp/ޫʼnJXnm\ܠ6~w\>Ql2!I-:B%$e+fol3'F(Nk"T!K/a(adx> S.^З?jIsS2f1mi6"pR3$‡/l-zb.B>G\ 9f`7-wjw.Z&)^gТVJyNQ"kKUĚUO __槣L z6ߪQ:GtI#5uvp4bb7=nwS(yh-k0|F{%:>KޠikĿy%cK#4FU#LXk=SYmͶ0TvcSCxvY2yCzQr2ԒVd*re W1QC,b(:N8l]R& Sc@x^ʦblO)-uV]z0Ɏ\[|÷ÏSͨ'VmQ-f;䨾ې%LF)ӑLq>o& GPfŕ4\!܋1 pTOSpoVQf|W {퀄,z tmtKDup{'y73K7->H<4/ T-"KH3gIH,2Iq,~=Qo8<ӲWȍ#1qXYxCHV2XQ4͔H0_:)5T+*sNkœSG$Jf ]J:Zx{C C`[vN)x›¬Z(t/K:\ ]Dݸ}tɐ>4h-8F*BJck\)%J]Ey1>I\SqC3ι#P-}s--<@>鳈vt}!.~rY+Y\ W5 {`|(ڪOYCS3{rIQXTV{)H[rsKcwRJ_KĎYqi8gm(Qle>-1!J1f1:IjsːXove[X1rǗ<¹zq$h+L3w>CXQupns|n#h`"b>iftVߞw"Ǔ7@#zB} JPMCy͔j8T9Ax"Jkw2Z>k'@ 19ַ+n~R 3s_2ڜX{uG7fTLM_Չ1Zl*dqy\ |9"CR// n 9ɰ@r:+%D}E@o546<]z|L49J^=LjKh_wѕuy=F_LC5Ȳ=0(>* {/E3ۥ?rFU& 1Tl;A@r!(Lpuw\8"JP;bNF01,REE٦80 OTT>"\1\ Qw@ 3^Rj+ʓr{XJ/ԄbE}^؉NcakGKLw3}Ja)\ӷ?q6+T:-5:ugjKD3Ui҆Hf駺F_z4-%B}g2x6LLSÒ fԙm nQ}s:\t{g!/]즡@$c⳸Z^q]վ<.OJ_ԯiW(h:ENbn׷q]3#UzXkolo'GHrJ h7rڂ#;ɐGG#e]2N7YJ8bWCKi엇󲘩"[(?|}Ah67Dh9pd 4wHaAK 1G='/sK̴gbzQγnu}aμ[휓3F-Ż}BBYM6{ 0&*w`Q $ endstream endobj 136 0 obj << /Length1 1974 /Length2 12809 /Length3 0 /Length 14028 /Filter /FlateDecode >> stream xڍP c\;-NE;]{qw(Zܝn=w2YwP((258}`f`Ȫ03XX((T@NV(Ԁ [?,DNoONo6)g+3+ _C['C @ ektsw;W1 /w5dlh5t2Ze46(NɎՕڑ r2(.@o9Ck(* (mM\ 7hlcte(K61= @ m mA6fS /&D01mhhhob24z3tC"@vN yk5w}@@㷾3}66E 4LUm@@OۼLLL\,=fl;/%ooO;[; 7h898=T/cfF@3 ܿ@wƏ7ݷ 3r#fWIo(mXXY쬜nFQ0]6֥P4%g6@cdyr7㿣H/=  +-mdm6@J:킐?9܀& 'cf?b{f*:~,LLG\ƖoHf15d,CCw8Ibagx2m !02:yLm~)'Q/ `qeEFQhh zeeG[Z忮\F[7~ke01r)~og  ߐ9όo2b?V2`7ۓ[vڽoR*s2t4-ֿyu;:Y%?[%?%? ׽6=&@719[c wUBv?NS쨧|HSp#8ԍ%J}-Hy\4 0?$TGKAEpKC"ޙ I!εWܭti4dnGqCLJ(H8NӢ!\LeMKyGxj|X)Waq%!FOž,.\8D6G5Ar£-#d[|ܻ_6cGiUL6Ch} 5mjLV'`d\Ӫ +̎f۟A܆NB14m ӮȠ~0SJ.<ç<]^tS{'nOʨtւ`edMh:'tJY^Rn`{ص)9  (û~iiZ7Y]oˈ ;1vL:82V{ML2) AUI@ZgX-S/aG x5=[⭜~K_Mb )RZ}W@ g)1L ѨصԸw.#>j#,p#'\Tid .:3v}֓延䏡żȺ &ڟ~p&`<(%4_JTNK"M?;ݡ̘$we,O`Kߐ˂$>J >66i<)vP}̜$:q%Wq*'FLOI į݅XA0z$f{,9lYMe:UKS4S.#D4ZKoČ}?XlBcǸ2#D=ݍeIfw7|F4)Y>9LoֲLwz݊U NGĞAv%*̂?JS.9%p#]}n}%#_Zhf.[m~ce8/.8ǀUO .Kj14qMBz`lؗj",uAv<+*Kth|k2v=j4hˬAǩ*O"6lZU]ZܢYs36cٸ lq7|62L:5LōD\ySm;a e,-=aMߛ=у[xQ~$;hH7C~ÅlSw #ԦIy2u92mP}2BI34"2'j82Tb?bwg8i&|~W pn`Ja-iH ft3uF3WB3:+(QܪbRhv#;CT!&f=rVeBj ⱟx#x]?䨿Rj$]C/` qmՉ除 I)QshP=a#Ɉr3x_y2,^ DoBjJI %M~(Sj8-f; B80d6D1 I'na ?sBi닀`hc^# l~W[cmrr=Uj{%2;.9*Ί<+Ͻ EFGƘ;*0'HB' 2Κ|Z^\]9m@߀6f [t#f&Y@mNAr"#YhM4 Wj{ek4 -><=ppΏ4 8,Q:t "IBEF/6GdV>T6ywI+؀&zg]8֯DT];%4I1o*ngfF&y6O2"'!);J|<=ƌu79l57_ ;Iī, z2f!fKĨٶosN/o*6Ʉ}yɵfN F=(&c8n9mhRkSswAӝu_K=鶌Y; x?eP1BmICg W˭ ]Ϧt@M_3YxXb"EK]>pRBvHp7tD'ow8^="0r;ƅTo(`~ӂ[NR]J?{ m".J3y*.̡Ҋo$x3!T/XЭa_*KC~At =iθ$REWqtYs Z^wuz|ԧ]A@.q=x|b}Xd:2RO"GVn{S褽R53T֜*iU 3_edvpޚ0}aӷB)J 0 [u#0q84OZ&1"AŝllwL v'/2gu uՈ w  ޛ&w%TcBd1{?*5TA:-irLZ[G-VTfHxU(wWU6Ȯ;`:Fv:[KkSAHXg_]$~5UPRTrT S²& L1g̲ [g^4 sXh<׊N竲cˊ=hGJvLhN-BK0 \ۜ qpX ;{>B2*_:^mSIAn [ 9JlB"tl-᠔LឳvxPv)~Oz!J]f&[WSp':ݵi$)C(y1m9Ncdv?l)jN%yv-7=Hp=MIm7sB% hu:mKky5ta#Ԟ"ނ=֬z zmhݨ,(H HmebPdiw bf)5V fx~Ac/}(D'u nkEswɉk$쟕W 1#ϱȈBaC<1sQQ[Lye) N~-N:*k-~X=,@cn2)sCKx25Vs tc_) YL[QD>0C4z, R:xK7Q)ANp\AuHXR1rv'p>VŊܫt{dow6`%Vqx ymP<0 ,1Mi(S4t;$BÂo-Ccȷ]?܇ggH>2W$ʢJ~MjB&2U220geUsYL$D{BI9H1%mX@L֒]˶vc86ivډx7BX}Jvyʖ.(zdJւat iQWpˋWp LЁckV1HHD8gĬ: d%zp5bL@rMo9-ժ;.ywN =O"&QHrIwv3RKС8YSQ >.7$l|($_ҫ>!rӇTT3=dRd+|ɨbdKT;2n./;]jVSou ! |H.҉\{dϫ5\3|0ޢ_X#䐣1DV *4D<^^r0,baҝ!3N6ƸL3h`c9|~i:6Yc@ob>Z)%  F.FݶX9fiN~C89F6.ɥal6#)>^Z/; ߳;j7CŇS)Kw `vqvR=fpHyu;qP)k)n#4'СlxRF| y6BK\ ?t5[=2ۄB~}uW9ǻ/Tq*\}œ$3c)!ςڃ|]nH{UxiUљѮJgg :vėCwuzHD*Q/@B"# e\VU&obJ ¨7hz/;]=4#܃I0ig9V553hW7Nl:C^P^+k]Qv0cۃK]e!1CO>)+2#Eٙh_t)XB6tKD%X+<,+JG8=闄~cc KMH[%!}?P>a[r 4ycIE3Hzb^![='^b&kɦZTgi7vF,F΋D5cڎ[|\zGh>ڡnDW<{׾Ȉ}L5!el݌/}s\U,@"m:80يOx]| 79.k0>G{[V_0 ǿTg( #Hi?gl9ʫlׄsESIm#)XX9" Uz76okUxLgVSPkȸȴSKZŽ7.v KdU9BP,S^\`LCmӶRctپGj uOBဴRGl%Z*9:TQӫa,5QJui#^9$A_EݮAM6/A|5 NDvn,s 7F3>njKU*cDw~#Zu=mk!PU b[ 8o{xR:RVB]S_OCS*NI>5P[5 &SOQzDIG4;ڥ^i8XdN^0>@]2W& $)6⧽8$K1(Q1XvX7tĦjvòG%x$1!QekwW0\j*a" rӕ;:V^cC vFhX\Ua9|O/Wyc [C\CЈ&t7xAt |g^ AeZRQ3ŗ:hOs3'n.m"7iilp3FNb@%s gϩT}{E)pV%Aޏu0~6/2 Sě#C냤X8gI{zLi{bB Iĉ}cg]HrsH'+M C5ߪLдV .P9xɂEBމIC/~D9qۻÁqFQkgWs4Htq{>(M]xr*NVc;r'ٹ˚GI]INkIs+#'\Z!l>ePN%}+9gPy&uB=9;6|_Y`/ld%>mBd:| q9X)C'ҧ|Mփ:z"G&[*0}Wk#$Bu RzJx u>yaWH=c/ 7`O TlYj^n☟GJ|p|DjbUE(7u$3:M-UOc.F_O ,ȼϣ/,@_H*@:bAƗQ-;:\Z^{r$"aD# 6d^6i}]r/ ]җ ,fmk;zRI}ӋPJ RM՚KvZZM3)\N*QK93Ljjd9=}+(JJ΅ޑl </K;6,LQsPULUm8TH%eRpuӗ%O g39!6t"0ׅ&](tm"n=M}kfudsrq +<aJ9KIR2i 5̧_B" "Z?VD|^'IMDNI@O/a; RN`~Xoa|`jbr;WЎz=?5WK&$S/+]6˞7Rj; ZܔIin>Cq/[DbdW2m ȂeۊG7ze^6:ˤ鈴K9Yc-Qy_՞=?u]`G) ?ʹxccS{2Q4s%ȅf$LkϻG@w( _Љ*ڱ`KTի#=O)W9F-,Zqv)Q}1/)mroVY@^Ѿ ~QBW9u2'<ىwG(W.Z gSѯ b8jʎ[~RF0^b-rLKpq;S?& bD|=6P\E' =Ui!L|7$dsZz"l chՖV65~Eګ@9KiOF[W૙D؍9! 㳠Ic@re ƕB˺m,S>p/j]&̦J8}Ç8KQ8:Lyz9u+9cP|rn ( >.`4IIG6ud24} [6s{jZ%?5+Z_, N3 /%~p(+W;'=6-*Qk|&4p.zԁdRJp񒁶A΋V #u*t5e%F<'> <^jTFioeX׵NPɮ m(jR[4Pz> G(O7D5~DP(x'۠_~u!ק p6 KG;n2-UCG'h]Uiyw\I@T%o+r qboWq/$LBK FHoCjJ;Vcu8.sveZ]D˧۶L$]`TFe^7=ow͐XNĥچ.У9j]P 4al.GZ6p,^M϶p%O*{Q4^3Ż=CłFk#Hd4'x҅=)թ11jv)p&0Wo- 2IϺbQ833:3N?ґLtk&,ʄVбޣ~$%t endstream endobj 138 0 obj << /Length1 1453 /Length2 2038 /Length3 0 /Length 2966 /Filter /FlateDecode >> stream xڍT XLmFRhڛ$4M:i3tάMI$Z%$-$!!$B*kFdT\9yyy~s>fL. ;bԌJX/(:BD_D* DX,A0@ 2Қ:ߚB4 =p b(,!Y0RC:!PH+r 8,MT*&r9 01)#p #O( D D2xR9$ )2 :qq^BL*p&C&H";I!5U!p@8`u82O8<#FR I3emv@,,, F?{D s}$n(ѨA<\""b?]>>, ŊNrH!<* QBLxp4ƒ!J@*Q jTE8R :yC6~b$,gC?GLv\i2<򏠝̨F74s`ɰѿVaCp.(f]p0 a~ἅOXP8}0q\Ye`pq( D#pʤ<0\ Хp=`." ="p-0QF"G$)'dCn? 1 YB-!ί+:@b1ILYX(*F.1Hb@&Otр #52$E$Ƞd9짉ӗ0-Yc ptWL,;H'|0,H\smXea;~ [&s 8m0FۆFhjE%97#w+嗎ټyϧ>qu:Q^\0=z]i-PvhӮ5+NdţHiZ:F!+ԌW 2x.;J1ܨ҃ ?E9}0&[>}aөU{>Eq_+seѺE)Sq_LQyaDwF-Οunjwkf巔,f~_ݓγ;M̜^έ,I^i͋_1+敌خ?v8Pvs*)N_v"sڪ{zR^!t˜5 N[BS^;߻PԀpl[H#vꪍ-ӨzוkNjJ(=^@kHJ0?}w˹c%L5Y]0+%PbNC//ZlXnGiBZs 4O>Cc.r5()|\-*c5G 輯MpZ\ȹ+_m)fUz[|ZsUKIa_?7\laE۩QjVeS Ν֜zj?\QWG5.0tXGU7|tjJlvҵ׮립/IS.!b#BٌAn E鄚3g ‹7 ³-fyAqwǿZXީzܥc{i^*ҡuߜGfXM[y6;7N&Ħf}ޣ:}wl]v)]5lM51qx4Oz;]<5D*!fh>Teh"ҾRʧڴ\s8f-QƖ-z}۵xiqk2r&f /.d!ʪ$'@1jQg3:n598Ԙ ,Bݎ J)eU,?Ϗۭ^xDF/*?WuIQcM}=zv _0Սy^D:}aV쎤s6^ Ym4<8WwG ̟Q\b)%peA&LͮSQP -7Ʋ^0qtՊ*O/;O3.acK"XcewkVOz.r{w6oۊKR4$֤=#eJr&i$G#{.ux > <,)ǂӳRu[3w|>Zyxԓ_7xmdt>YbynVd.F}`ZyQ:OҘ'B+ҕSFR}EQ;9)9smEQ E4n(&;{?i=9qu^[ endstream endobj 140 0 obj << /Length1 1684 /Length2 4223 /Length3 0 /Length 5273 /Filter /FlateDecode >> stream xڍt 8m>%4lV?3Qؒ] 3IyEH+;YB'Y-_]s]3ss<|Wĕmpu(*:FFLJDG/3DOqX}<ETQD O.:p).#?'0?D^PE6p *8g UO&rIkBVCw.]E@a? }/,[[hQN/EDup%j:^M"X;Aw>HD 9X>)8W蛔w@ CYElvK!xF$x)hqS0∔mTE4CHqpJ)rbA)jR 2adw)G;pw.e}}P:Ҕal1(AJ)?; 8jSrA uRj%Sݡb04w(XS&m>v1hxTmWETrG嚮Y$w^49i1,w␭AUrLJ kcw|İ)!;nRCA$gWBN?/xR92UOXTjy̫>=EL1jp8۷#Zq.FOpiYNZ|+ YZ|yP8X)0-ܣcOb_Լd *j #?IWһwP))|Wpem1 k䈭vu~*_l8p~@>s9an᱃G5 dj.-?s52da>܃:_s;ùn;O#7yYh"6Kq;>s^ı^0ynա iin'Z,JiK$Kbk^sL\yr 4Z. KBI'ՍɩK* ͨ㑥&Q|qJÃaWl*q!XXuTʊvmݸ PY( WKcMRH͞ʹ=m?Zo] ֓G;7ļ WEN_7sqqkHއk~lNH4*Si)ᢃsJQ}.si;ehg|JTJ8}R}UG(>xڴqW a!,؀|Q܀Sɏ1 L"sռg[S[ /$XXgCf^%%z 7LRʊ6'<7` w{TPt^yޣ]di-FrD6:{}(mjs@C2n>43!k^r.Y;}fmS;e(7\ϺջR_w4J}3|6mi!x/-<5Z,̻pgzy@ ŭtg"@UT:\gY NWEUrOsy>0~sT.HnK_^ȘyjپU3'qߙG0w+'&L|D⪎KSԘ  vpU[|P &}jkv;])V- Sosr_ yȏ CE7eg&lIQ5V%ٝW2יqt}xSjvvUEkLR9s5ontb|j^0)ƞ٨¶XjB3 %(Sm4_X?߷^87&Qs4"AX ~bG|*usxb*:f ´{/dW0tM ]y%L^sUXEVZ*|H_E~4ST_hs5p)= GzyV{2ƺS_A4ޯ#[~1["Jvnn"h6slǥ.+>^K\%0De+\u.f{6',?8ŋi6X#qkDh4oPqs[:|eKrgU֘ڦz̻0CִuEmէ'/U=EJx Z ט* sRDD<rӪrST \U⪳ ɞ|Wn㐑t;2ۅC+'3DyX1ݸy.FBvZ1ee E-87gܲ[W%2<\{˔Y(E94}hu47lO>I  df^c8R.7!2j Pڷ\ ư\s\!pnͰ S^d!Lb6-n{>륡L%8]uxx-t_;6wVEՖLWY\=AđTĜ"ߛe&zcY.7n#RY1WRk-$RGF 樈s,9K`]O_9}<ijDIQ{bԀ֌q' R}ucˀe]H׌إ !;wv%<9ZUq4yL+y\܊JHv=1eH>\^۩Ú< \H?w7CIs)L0)CsZ~,Tg/iIxLhs<~''ZRYd>Ho8t-489ڋ#/ 9  Kʒ7?~pvPtr§`"l ~&USse&^N|mbUfe[zM"El=E$VBU}?8ʰ:U(V(| |SܪG͉(ӁǺE47Ғ$}vZqxf|')xҐ5pF뭋?Z ﴨ/ymVXi9Y|-!ֵ礣0P9^o}Ec26j RÁǣe|0 ~caqƾ&֪A3\[/eFg RRʔ$Y^dK=~ݑ^OC^* 9x-˥kJw՟̒;o%`^C?|o$<7~_>p?Om#;\GǶp%L%.4 ޅ]V=rUE]/?nT8M8?fΧvJb7Գ1Aee|VłM)Qcv!]Yz4G)"VN)nMLT*W~],_Һ*v*ǿJYə:*Fɤ!ņo[]/kUJijts/ߞxRlvUxaE(R~aBS!pss^.wЪImcIT;vmC4QFˀu9'{Y{28`.8 --saNMM@vёY&oӖ9`,Ӭz#E8:[ԱVn֕F3:7˛5$ >RҹR-bs 4b*[?|HS ϙpsDa]^eGdm.'ya-8 VB"=BJ;g?'ꁖqxjd^rP(YD4V/aIĉsTmud0loI, uvǰ=$D=ju5 }8O =[X5q{=nI/}g]Ĝ3Ȉ"]P2SF+D^C.`֡}zgM?3-I^XXNZ| `MJ94e;LRpPӌq=eǐj^Rrt(x)p?x8mw#`=l endstream endobj 142 0 obj << /Length1 1763 /Length2 9585 /Length3 0 /Length 10704 /Filter /FlateDecode >> stream xڍTj-Lwݭt7 0CIwHH7RRҠt#H+%ҍss_5k~z~^F: mikgK(U@ #mbCDu`pSuv<y"܂"@ O@ r9;ݱe]| v0xXn+@;;Zmg+_%X`0..///N;+; hn`k/5#/fX;_vmg +;<7h+]Nlܜ;W!d d @uN7r;A d =9 M st@QU~NֲΎ`';֯ n`+puN^N/.\NW!pֿ6[0 x`WʎWyoo3 N|A`77bXm!NXV6aA@_e7r)7C  3l ? ,M@+Ww (9B>%_NkeU*@5vsw7Z-̺V qk8C~)n |rp=vk坬e/5\N0x `B\L /K_$R AB@?H^'ܭ p^PkQ V ~!8r‰epl|.? ? WFo#䃓qɸ& rc8nx M[y_߫g [a}l%fNʋc{B|q[?[-z*kmNȺەtpʦ<˥~[zd{fǝ߽yv}Aj:R;~~zm]=4 o+">nk <ǾӍ5 .c,̝'GqPc<%:Ɵ%z=Y"A_ /Vtx{((ȩ/Ʀ|e=#[-+]_r",:X]qP\` 8+Fl0ACX##]f|fto9UkBѨ>eO1ܯ>BUiڭaSkȵu=B1ɳ[.ao6hcZyܐIuWR>@|S"}9Jl> 4tP.垎B׿.~`UȪ x&w&™V)T*Ei9"VtkΪݢYɛ7O2Lwpӵ@Ť{CW3|Bzbj9ogV:G;`@К$Ϙ<.S;Sa@X>$ӁǟSEL?%P8L ^UiŸPBZ)W}՛>Ӡdsmet¦oAQ-FInr鶾5k4i?E1W2}IDFTVSݻI%lrw*^WE5V)núN}kJOdžocVTliQYfEFieML;߼yQz]dbsǂPE\6B=VN'N?6򊘱:B &(Du`X{hۛk -9ZYM> !m|)<N4m(xB4 [ z{F>P/,oSv"nBga%;itG97Qe]t" L]̰>[ru:ѣ;§|rN,b^x\G'0`p'J,jHM{iCI窑ǻuz~]׷^7:6{Ho?A[w e loci?KD =lGS+3$/$KXu/ yqߓɕR&}ƴbĩo]\}&+^[!1 2R.3[F7$W\ߥ$m1i!6{`^fzc=*w$ޢXj&qk]ϰ}$~$_}W}JI06kAgLc`S3a@-})`uCT<*Z:, kt|֘qQj&2Hݯۃ˴9ep;DCg8u'ËsW%'.WQ'`4_iK,/:8(ʾHc^1Ýo1:F#(n2&/ޖ_n*5d=KJP).t4pbi]OB@~,0yRfSy,V%G}Qiԧ@&fp c⋍B1=ePʛxO)(`LFXaT_%lbNpNj}~׶nY"_= (.6徚 .W,(g 4vHuj> ?-?]}f"ryd^7L+<8n錒 ϥ裬 C7DVZ_+d9{lW}!Tz^uwWN<:ιf*u<]Ǒ!c[+1a?xQ֑j:w';x WgVPr+RYB˲4G?&D<:O YkOdsCGʫ:2<(6k.O"^VG%X 9n>{ `/gPW>2ڭ7x)҂wP_/zu2yR=-ےZ2YUU0dCuQԳғ~)s(9" gq7N]eQ)Ӎd๘%#gג+|p6.B~bS|5OϽn4-I!3y !Jޟ=y*cLGV<; ")y  &mj~FcƜ \ʙRFdBur|E8v/k-_"ϡV}df(;|Sz& 3yn <|>* tB!xeU?H7x]{s|7*{oEu2H,/`~HF ,~Ov W "o17jM90l^&8v1\'5hKsdLs?؉_}PBWL {`9PJyX!܅aG,Lbo1/".M2inWA]ê]v*7&L/G9x2FQGh1SN)o^Y7h&#k߷O%OqBcʞh|'"8 <{5sDdJb!\q0._6"|bōO]g%]5kSAaˤY JN4-Y4rgL LD Dwھ>2qtT >:{'dDmA6PN̍Fq;cʖ񶤯ݽ6t*KZX•)"``c} o%s(k&?}C_wڢ6tU:m@F#Y?-ǥٙ V_PH۝6L{\!(El~SN}C5TOVk;sb #X_:ݹjvTd.*R=grhۻ6Gp^+}W'plʫurIf[$I(˜MrvN_sJYT} ߹WFPm=ӣM\8[?=+Q/ʾbH9,<l@BRd0t7?C~rcr6\lin?!U? E@T'뺯LJ5e^(. l-"&Ǡhm oI( (i)8JNմm-س؉}xPoHA02N8R1/ܞIRk3UC8Y$\YlxTsl}:sQ\x ۱1-5h=b9C235ݎ>}`stWO,X:_LUT!ξ{q}\ih6wVPxC/zZkGuȌ9\j$O{OHG|(|ֲt 7nPa0 #N4%m_ N*O̤^xm$E ax9K "O ]#lf~wyu*QVLSJNI+e#߇䫸=x7ROqU[U9ze0PSY,;7-R+Un"1kYk{ؐ2ϧΪ\mz;601ӠQ:N0"UzWm#’yYY ;NJ 3YXWAIDži_cmt3ce@Eؕ݁N3啅% jfCo*y k W։W5'Ht.8W"28zʠAyb]ڹlycS( 15tϝU;i4Nj%fstմQj >+ٞ/CHg$T#{``1L/IH$ګ}O@J&"QcT& SU{;s?")scEaG^a3*yJAUS;tdYKd-JD:Ȑre kU-OZP5l j<ا+_SR+\i{3%*ݺԍJL4oz{"[0 ɣl#.3M$*GunJߚq3k|!0%IHkJ )#Xzu;b(( O4IկA!OAi4TmH[}tUE֥*XiS KAv|U%sT* J̳U_Pn5wіSc9W8]AM+F;W FWb@-Ė [ a=1jUZP+UQ8o/-紦["½KYm15Ō lyxȠ/'_\ }zI:,iT"t{1!Uc"j&^Zq aD>F+<&N 86͎@Ziu~qM92Ɋ)jN%(e3 1Ɠ.h5;v2lEjR;=@[V? ph`߻ <:5=\Pdȟ^oW:f9Ig3;,.B&go/%;e7W~jy,XD3[^XwJp5%8o͋f'"yA ztr̅ TT WOl|Q'\a>Zt3E^t[?dP,OԜGAGue!^zy}}i-ru'xVm"QȎsNݟSG[(A(vR۔Et Xs;H}-6iN# 'L j/6N~EI8d8ZFt.a.G0@[Eo+Mߩў9NsRh_͚Mֻ%SG͔9Aj8Xm>;Sf{ 13.tӏRjgn`r 2CNMP+1 "@ rjT7̨>?nq(Yrݘw[>RNXBQl؆}MZ9ɂmE8q7jf^e?cK$TG_(_XWOk52ן@Sٿ.O*(pw/%EIDz+Qx~sp9yRO4OQK%+N4Z׏Ab?/~5ΑآQE5tVAaO%g v(5dVpv ɓ$%k73F\|Oy4iz8țRoI=PЇQ/7E5"C?8,}%rgp60THo5f֝n01x*2JpT84Eou 除h75XEoW|6rf|eMT \ BbL/NqF 'Ir Jv0`& A~Mz}^hJqIΡ{.|r_Q}:N MOb16%wx{8yi|J|t89V?~| | =;X?JNhzRKJFIG1;:W|xd!ovٷW¸mģkD%X\/\k2KbW?!γ#.QXp=]C뇖nMw\ytN l [~7^S{Ӵ7U3^}HB$O$o;>U`&[˹:mj2ewnZCKB$+W#Λ' [$c`7f)Wu'!Z-Kd>oZŦD?4m59"\#;Qx J;̝Пuu-C;X,qD#Le'JCj"N6 ctל`pE]S!]"\٢7l"ntzc)PD>4n>)z#dMb^isp< N0,\էN㎠>1E. H++(WfZz O:j[GȖh CW{NAR ,Ԣi҃LB`[V{Uu 9|4aEO){ ޴ r`lyEp" G&T;HR1d0̕bnրDc K՚XҸ8Cr(g -(1]I7wqL[-vBt½ĒkGO@v)վrvpc2as[E)ڂ,XtS`,iVr-DXQ݁ivgpROݟ2LrDcxm1*41Qu >IGjb(Xf1f {>w,TWSeԈ$M;ƞIk.GRe0D[ =M&ObGl8*j1ԻaX[UT2{N"f,3,d`k(i]IBk퇸*bilR3m=44E+pNĝpH\yho]yF)9m}6ey+AQpuؕNm }&;p[ꃟWWS:U6twL.H{Dž묧n_ҽ.^\ˌqWw]3LҎ{ұzeT*XCG_$h46YH r3?i>V2ϜRtѱ`܌}[#޷߸yeD:IW3aHOɾtxusP QuSժEWإ):ңW$vG,ԉ$5{߂%A"lb}0Ӿ7=s"5(4i^dR.nn[t0'O) e|`>"ɶZje˹e=0]5w,v&0,R/zܙk4o5$VMe#*=p-᥎?ǧ{w^4 ʯ"m"aFn؋:v@Q'BhbK7I om;Q2E [0(zi|A3Sq;|k[`FԠaUFӛ˄>\`6͋9%fMbjEpI7\7,,tzP@06}j/-v,GA#lJ 4ksWGeFCjM\D1?ky@l-yOK^fmZ:Ό2jmIޅ gvgh/~&Χ$Y# ?O7F2[ގn"}D@8)n' ("$}1.UThQ椫ߩ1@nq\2SZ ov^Jt/aIpWSWK!rsw{;­$2 6rᘋK+$MսW#ʬ?= oE =FaΉ'-9}Ӛ~@t`j_'rUecʍC«ո"lX#e$5Q"բރbE6YL0¼,옵ۭ-āD%"׺(rU*1|!Vg:䛧VԒ&bp*\"4FONv&&s>1Iy7FIj߉n֞_rFsXFFdecAȷ}*.g\y[9K!pHEJߋH5K+ڱ].\Ɣՠ+> stream xmxeP-d$nn{9n-kWzWu?= rq4U988lh. 70"c聬Z g' uvڹ t-N`.xxxHx-nv n&`Wȃ  G# A\A  +?  l\NUYmIjYivmi* rqWwZ,k7o ` rXl4vwO/!׿L5dXl,@&i @P' PN`G/", ǿC`W9ZWj ǿ\TA`w׃DG6ِ]I_QFGOZbClZnpo2&U-\^#ǿ,z89@n.'? @еrwqAo/$ dOo(-@d0aY]>3Y휐]j{bPN[nVlHa2Y J[aPQ>AJ ,-se9DOveq?/^CM _1@[,8Svᅧpgfv;z-!=~*?ڪ Qa9*t`x|lمpG;Gjw1f;X"l=JBe\8ߓp+z _Zݟ8ifQ6ۚJ{lhuS5X T4jH65$eБ͐Q}{i0͗?h0i<&xO _" wb*[̀vٟr{1h=x/fgѪob.w0Xdm1[hֱu;ݝV {ׁz5g~AnΒ'S0ӈC 6 V:jEEsdHǢgOY;~˧6d@3Ki-W@'SEYI0 e?"zdb|r?V!۟f5A1Ξ(QЪ .7)ګSZßHaܿz}/CtO/IMAfL;Ptd11ZY^PԇA3n!)&a* xi(.4ZMffo>/P rqh^٨ثqI`!aι6 )} :nztp)& ðvn̹_m,CNo;ET%|%h/i_wlVym1r9E2/s.cNLn$ H-5lgjÅj\RJSd $dR}S1noys9Pzv r_H?Bcr0QҨBs_ ]`Be&2,G-vs/ON! sR/ { L!Uhw٨+Y;2`JOXM.tsR{v}vm]5Ӆe⠄,}"R! 5Z?vR7|ZS{ػ%$Mת M4L|ehu+f}peeWg'Fz94[\tciJ/(sD!g@Cau+d0UXcWv'nR>خ,yeHtiS?aɩ.Hq)KRćXؿ8dig5$݉.#n|RO+fU~:xq=0mv`WRkc/͹6D2үG2]?%e2g^-f]AͫX/oqҔßhӼl/q/$n ̐X{Y^Zdw#ChfbS߼SNejMG/ QI}hR Ix̰Rô#&#QČ赥o$Y.k n<@ِ!̩xg'ks#Uq[=׀%:읷WRڮ8c^~>@~3˞NTInHIfH8xC>fr`I?IްvoNaN&fZLH/AZJ6y/B wƯtۭNJqpF}] MMyF[5N$;OsZY[HsaLm]h7!{3v۲$Ij ,ⲌR/_3t.Q |0٬wA9,?*j+1ujBH;W?+~ 9o_Hlu=qPl`D&,3J"^I~OPQD* c] uI7g`=Bܝ: )r@I;:Zv4["|c&Cbc{MLhE=M:OawgZ j8|%Ǚ\iC 6<93u~h*w}[O.m[ZyʰF]JnE-*뜲ה#1DJVdڌ,.dgkV%F!Wؑ+ta Gg60%uu$T5IVCoo1vU(>}eҷf⾟$"<۝&u=a, W 2%D8XLE޾f.˄ ZRDėQ}SuWV=[<ʼnz*]f&g9 }櫾DiYьݤ(:7<cJOFe'-.p,'ۂ6ʤVEVof:eww@9UnbqB[ӚkZ [h+  .X!bM:4Du6iv _> Z=G49R>Z1/.+%y(vұ舂?/fz(m^YI%+XQ9:]阽L7g|N@b %%,@7^&/L4%O*:WxX}fNɋC ѴyqI~esdd!iRNa8\D}kdD898uMiE-m-%+,fnIct2#rJ5~x[3MpFAZR~N+dA!yG&q w&[?~C9vUJxkDzʍk2i0;gƂ5 ) IK_"{ .DKQ1CyPlz5l^ 5[38v>'||1*:zdȈ5e ~/н '^a.{(!ܵ}W5;k39aVxOݷ(`[ό#B,q&} KQC Wh߳e&g'nۧ-W>'u`2,\82Җ%v7a:^M4ơK=HʚwkUCh?Q^(,wq8/> ٢((EV^=r[s ˩1 춎cU,M!<""TPm`FPU(DAQ&*,ʄ=nQz{/QG"Ęα$/bEҶCG.Jc{[@ԣ/[gVmerCzR=O5S*r-W Ty(H9{"VWv5BX P:mnAw}b nefHqF?idj*]=M%DD4M)Ko٠~|9(|[>vp>j .tջE\JmY{4jZx!͈a:jMY4-҉{x-g3ύDZ\aFCB7{- sR+`M; tB۰{KSVj$T77h.`ʯ#xz${;2=H ƓruP+t!}n!ʣ~Y_W=iģtsFM攡 ݇դa'^.(,8ˮJiOwD6J~M*^^u1m4Z5y&3;QPM?kC6 uS"hcx5PewoF:YՏxQwnd,#uXYĎ^J;LE@ɊrA wA7L?e-k#8y94/&kF(|i}lJ,lBIH﬍abZɌJ0ILR IN8Fy^b}?};*29B^NIAp?6hRO9"( 4u:4jC8ȅ4.DSǞII~[\c_茔vi&`%]ݐ&YAgJ:/VI uaٴT&ݽa pavor17 soq1Սl~;cWRɰȴRȓ$EAZ^0As[OdC;Q-GG/O@)ҋ o 1U:[Bҳ6}ס1_ &\O^Uɨ 5MȻl;b3dDʎ٣; &%ͤu  ] T bB?X=i%}d}?]ם{#4*IPMF@OwIÈ3+=@o4I97@n{66M H'Y>f:7o -ցUoHbU5z3qm#a>PKc*SVQ!*T )XM5<-DDr\b'T{IDU c ֢6X?shHGyXt*TY&,܃TmKA!BU_#g׻}+SW'#}\(w.6}g84זǂ߱[Z⛞Ak]4ȉX!͒\L=l"vً&&jO KE]%_iw +'O4#E"Zb+^PYmz2ɪ;M[ ѦN6HSPn}^Eرv 3uƒ"N"QMJVRiC5w4k|qqkj-g#T8m wr#xImg0$p("!]:hݰpR\1Z'0guZ#*gԼ =.=zZ-9/r&YueJiPp!B 6 L$CnWՔhnL^YvgUW8x^Rl >'e)F'..ePF8 Ӛ2f E!fL䢴ڸAԜsMigFn4 uF}D6˕=|PegM)TBob+2hTJd[Fٯnqe1q笵< U;}rcu0?`~_6p;Y S[>pEYCXڸ~wϾ.m"B>]MA+/iIfSJ7ӊX>#Mm*f&ⅆ2-8&V EIůY\%N ;mНQ] [1A r0gE:!x IUjDce #Z!f!gFj)ݭ8D65 ʖǾH~WŊo~o46O6.YakQ64hc|<@HpWGFGBqo hi07}iU7l_o9o)ifHxvЄ؈y*>AKcF&!hKNz0F?dϺƗyJ?)e5Aarꡎ.+qyb@(/%:K%~N+(fAu|xUSݶOog4 Bä&7,ӭiiaռ/3(`TI>wuCm.U)5Kwrɷ.Gr8AjvN~";|'MTK ̉Hhx6Y 2 s*TiEG4G`)W@kF>WZltY݊{3^7J(kq>.Nb3+*O~H:)2)`%V~%yQNƋ5i͈f-HIyU:|2SNW4pa%8 }=%`uΊD@NBŏ‘njMo\aX"X4ş Ax:e|pijNxMa8^m+OxK.KP}.DSkS>4Nk[E63HbM7}]Prݤ:Gv)b viP7FUټȗ·-$Gڹk({ QWbΕ1&Nci*3ゥ{fw-}vgRdVEՆ6iid'#Z,6.*?w~6د-鸪0w>=~D$~j C~_R?'ceu-/*~*LK-&! L!.,4uoW׶wt,Q'(On;1>CV Nu?Lc|wxf_ثl|u5\ ٠=Ro( ,MWņ랏ÉkfrHG8boA3@>3įew(,X 6.E>M?fD; W*Mw_7`le-ג nXqAm=EnGrǍn?r=H#IHWrJIqG#k* 4N.:ԟ0? (t]"?9? &_ٽhF_?b4}XGFg2KA._kDQ=HrnmuÏ0}'" ƸW ͇~JmIZ'ǤNs3BҋA=pOv;wUoDwlS'`]%GAe%C+|0?t">UNr橣l˲k'ʗv/H$pR6*n=%~y$FvsPmՇ)#v.Yh3Tbx7ՄڸlgB^ O{𤋻$4pA0+dH$^=3=U;2NaoRu\aPclJq&ʹ_a'ӮFAX@^#f,{]@I(JÊڌ҇EBͽ|0s"pg>严$"X@OQ048;{WhSSXo<&-d\޿KH1ЅԔ'DPLN)RSX 7 |,r.Ey64ZKK (d@jsz~ҸP nm;kq845ƈGcvL$ȁ9lەLh,oۉ*u=CdŠkl P0Kn7kGtOi.ޝkKcL->ƌi"[>P|8l1>(4J?2T K57K3zk\g=]X@BХ3cRCSF!g7*}5a skQn\0 endstream endobj 146 0 obj << /Length1 721 /Length2 10037 /Length3 0 /Length 10623 /Filter /FlateDecode >> stream xmxePܲ-`]tpww n{έ[j^צuhz:9Y98J6n::)g`/m t # BrptY@ m;3K vspY\\ٜ]E6i `TT>)䔵r@{@d ڻV' {Kп4# + PєUQHkJ-C\M73odUgGl(K`٣˷OVÖ)WᯇK_`r;B%K=@lfd7ry-UAV[\wQZ\Z:yϕBvUe]Ee.?e{ K5@K3gU@ޞ687W28<lZDF˒tfrsq8yyyG3gO"@  /-a~2E33SZ Ћ=ؠ6&{$7$hӁ"[gnh1TF $4~5Ojp` ekHr*OVISgiYG? SnkrZS .!+dۘaeӢ ҳ(72e 񔴋f*B#o Rk,dʂ4DYij/2ςxH7+UވB]Oa_Uj7Nl"(~łkіǓ 1%~#Oz܏";3p4 G[XhK3 PI`V&L^+Tƕ^?@V*LdҬ(쑰ѳO8"zTN9k ^lRø7Lsߺv?&7Pgn#Y/&Qטȣڟ5vUx O7=K>6Va9`콳Iey[DT5XN͂pK* -L,Ƚ,9)h;ᔀA] 홛 fZBڡ7lJ^x<$69Ѷ;s6̷p̭ϧtAE%ka2΁ˉݝQw!lonmwC[㢻`D$ƟQ~Ho`)ssD'6ӬƕT#Vqg'|2ָ~[NGKfoѩ9fǒt7eW޲[Wy&k1XiϬr> 33a" zZl*rG!Sdz^{har:8o7"TzQ;LNN3K獪HVVwށ+pl[i*$7B"sQQc~Yߋ?*Csތv_ļNHd_4`-Hd\yٳw8\MߊcUEQ'EP-"()XSX>3g}0q 0 `k~pί)f籚kBZ.MTZR+玠If G>{魚X ӕ]iigN릤vV{EܦBjTT=#:].~vg5В5'8l=VTȭt8t}TT5+,̕? *[!ܠE4TAW\qE M3S6Y ?j@W*Y~;D1X=7fڊ%zrrYD~I=ӭ-Q+kc6T}29REQtC0/ඬh{Ӟ:` 4]!N= DqXl ,p1Dh`s4Ϭhˇ ',.-?A.exRTUEw=i0 ԅ!_tܫZQKN L|}{N~}$t!1`Eԩ["nD]{}YJ5WXD;6/5j0a2ˆ6KOg>XoH]Z]K"ՙ"ozwY`?[%-sd6wk[{h ˷ ȻRN3B&T#`u6n}-! w)yc{09 a|91Sz uUځ5u65Y/lRv*8l].P:dpC4:7\B-gXgЊRgtD̬!HZBħ?;Hy,>2|itCNRR ն,>y$GOoYʕɫ犤~(ߌΧhI}pJ6AUEóKʂ؅B?R-h7}"Ȧ5%=.lNAgjޏ*4A6{*IV$MISgxZ@ _懆<21CWFE 8<y$ɡen 3k0{([4 np1ekaÞ_mV%ebrVXඇgG\;|-)nNC} eELO)J |<)Йb4^2SUXв8_.9wGIxvS!:&R 3w-OVёh=)wB\Šx(M:HX Iw'KnmTU4X9~RjG FR{v[%x5z7Nk&bYҧT?gq3!c F'u]@^"j'ϞÀfmQ_FKb8mʅ[L"?kh˄_o:E)i =k17#aw\j㵫\Sl,(w,UcPⴗU54WF|B61VȆnLm>Q,5[~(}- 2if8 fK ǒO9v3 YWXUX+6arzsRA*g& ;IW#wqD|ݝ jaspi ҋ%m5;s\ o,QqA=91ßޔ+7*L2zSR/sG.oU!2ve&RF(9N;K  U@-jE#, WUh@AD.]\Az|S*/g?k|>˞ۭrqqx7G^jBba~ux3ߣ07?,ۉ<&p7MYF-1HLN\Sq ]1җ6ȁ>jepXYϚpp.P_H5;.-iDAJ/׺3fm'۲YY`@nN҈y}p0{aT>l;&*9DA Y@l y::[h+i]+[]Q y[Ǐ)USiq95>$3EyZV]u򄟖+ jO)hEoތǦ}QYfSCH78ZBۣ\ =R(@5ktێ8P#rfά{"q".A[6T򼖰%PH;;Ed5rpD3VNT)S f)3| X\zS;kE,s8* "y=灁S@[3Vv,!1r^mѩCvN M7Y4m!R)1I{ :~Vl2G>/^bS5U#/$rLl8 S֡s*Ở g?e _}8׎yV~^eUY^%xTI;X?B}d8 &ZN6R \0^6t=1gaf] sXvy7;ˉZDba5HN5_&vfxيg{xY.}'[.nי6"7Ɩ&c8JQi bOhS/f+RҊ링J[IƧ- eX{ ).2/}#nXuPGvF @+gzpx&du[>e: 9[fuUm)T5k퓑ʿ2ܳ1sZձÌcpQ:Plf(MK#[yxVN'(aC%.W;=kw:Mk XO-6as&4<+|ן$S)Tԩ X9/`S.[SU%R8=}q:i>v&,1NUlk͚8Ǔ|8ETNп 0#&MyVߟ2)QEs7_yQYla{`MD ֫Q'AUA34 {aҊzQO uʹ#dj乼5UwZZ|θfP22hEJЫk.xeF`8+:aCom-ZCp$B$׌l1Ç$4|Y6z^4I@kc[ c\nc{@pcqBKֶ~H ^(/BHͬBx>tim7RՅMCR1 JG@N'l{4K#& 4plСO%=I'a2=ts <[qH(L. ^CQV^9449n08HB @3*qo q"ܬ/o` A k$̎;pȉɐ]δPόW6z}=.Y7N%kI)>~1Pp!`҂ YE7mirO׆OƾI>j?pvx _|(+j& E<tr4wT  x[hhƿ492bϮBo)[u`+F#3]C"AKPJ-gU)qlL.1BK%E5uAUesC*֧~MQ1ՍGNi3"؈bnYT~xtw1 ^I[۹_&B_ [9V02b{3CyQv}grYҗ`HU ;;h &rAܵwZ6ǐx8 ,%dr 2 5Y!ZtTy]>:۔ty( sZB^X4'/dd@QyHg%a-&sT/ÊYaG- O*z,O댳E]U190M19#5?'&xmjf;UDL?%NE}#CNTkt8U^Z66/herTױu83*ʍoJ3p"E1G|;cT-قG:f,H~EH^&Ue[0k_8Ytd{a) :Zۣ*h?J1"njxۨsPoW5Y4}eaB#u8ŗ0'KQ3 }躗bv!4[0־betr Z&_`1c׌;o!] a z!] ϜN:Mcٞ',aVvԨy8uْ |diْl[SOo јU.Qui%.t؞)v*͎/,:|+G@+W _Qgx8$wDiޤ1> &ϣ)33.q\UEr{ert :X8(O\U ~/BfQ/U ̨QmғA^U Y8Kۺ?)g+,^(\+2?n),ǗO#ϛbu֕dx&9["ĦL{+~Q5U^t{[3D  Sj`Q$T&|EU&ǣddP;8_MyT~N}>%s~߂*]cz~orAބi*s4yYL:lKٱv )悷gم1Yl祉nzi2 өaPkp!{1'$ܾLhXhM=@jш$;c3ڬP$ M%~cL!D$G }ax#W7^l~+q{HS/jPuS9 Ӕ38?S}8.q$96*Oo\^9a ت L I{[hORt*$lGk"n" CbKHdD>xW sE!W=A~I?DYl7K·#7.ء2 u?19LI*0S(5 @XClB]ciHreyж%|\S 5 Y3o>\Y%ID^%p_IV,5ȺOL|J6< uR%MCn׮}V+N Acg^ѱKwEIADϹ9xZJY^ (ɝ@;5Dj9jt׳^v}ljiV4cMo+|]// ur./jB(pe0y6'سL;0iG وzk2{m k(1'-ZYpΓX"#Z%i? ˹{(cOdtQ9xW>%$ebo]ZsJKwwl5B0:)* rȇ+˔ufQBN?:f"U',҈ TEtK| {A7 >E|>eCJ,KBDwTc49SOj_ .l88|p=`]_$E;MH}.aZ "ư`nWDVD5IOtVnG*I sENjB ӐM?碗th\$#jELXCu k FM =7H~O0fF3lT3/4FA!f壖x樀_UܪOِŅR]֋J<Ȓ %j< qQ)7R#n-J79w{K |Qeлdi1`9ORMh¦Р-sDޞM.vXbYΆLzЪ (Fðb%Z*79G;Yїw.7>+vVl34HɅ򚮁v{fH NT#=ϻ袨ZNJCgOy9(|zlK`weLVs@ p{^k3m;L3[Ü-ʐpSԌ_ro}|վ4gWp,e6Njv1u)³i%}sgEisrfJ40U:(N|>!~Bi󇋘eCa X^wD(=6~Ŗ]R2a4؃%t?o}-fh pSX1tiH鏽Wnp؁h+w;KaΕآLWJ_p-mܿsU6㒁;kUd*W;?f덂\jD{e9´irv:~O3ˍe):FU7}jG:,7`hB Kl4Qps^E".2M,IVf:hczR66h9'Q@ͯibEh(8I\qQ`j'&#Uut(z 1!dCLsuy> stream xmrg4ju :ѣ D%.E13 3ѣN"D'щ5DF^7]Zz>쳟˥A!0HDT`n `P<V2`pb 2^ `@D!c ȹ*➋`+\7"=`tBTʹ @F`N6NH@ CqA- p'0h8oM8?Ю,Z-A t4x5â>_//u'!p$ A!dM m<?wt-w p f?wrCQ t1p 0YP_z9 $N醀#VB- ]O?ڏcN;z?<50 ⯽bP? \""X7Oa#i|žc4׻9$ #d |r o Y {igKX /(lok} (V{"B-XOΞuZjuӘ'OM{$ަ,}'OίmE3;1|KyzI!TB3`eda0$3;6/3?=KqrytnEGu2rHtn%MbԈpsڧ BJ ;`e`FX(8WD"Q/]*\ұaRƨoV@~CM…bԙe3'3'>]}TJT!{QyŦr؞{ } 2%.Evpz#J, Jc9u}-*;\pf4ѫ&wϯ,3o;!@ LGl** 7$WWpYQ5Ϛ5# o9-ͰEq?sHf =R=]q'b."_{88  8ixxs=e26R>-MԜy$l$Hr*ReK\w:(_``M:ǦBԲmhR@NP >ѝU%' 13atLjgt4O ")<u@VoYA38IG 4_?)o~[u.ᅬpLw$,ttQ[ \6Qb})Ŏ72K@w>T8~5,N乁c-Tlv#$I2<-fJLZ摳lru^Pd<=.m1MMf+km(=[3/71,(m}!\.·ڔe=D{ωM^ E2 !w/3+H6= M4A'Z,Dƞi*s\F. ONޜՍ 6 ۹,W!#%Xfo߷90 )!Us*@>i}ޟ|Gv-z C-d9Du1N,tA po%ǞMݩvIeʾ&Ĵ6flVk;;v^-YlM.#&l^D3 KYOhlu9ZM:IQtf\jwwŶLaG|-;+qm@٧ N4 8$ZTcg3-KVn*?CmY;S^cyס8'"R\R.E(/^,j&Ny[뙧}x0Q;>vdJKo7f>!ʏs5hr\TesnX͈S)lY,W%!%?b:I9;D>b60*/꘤p&8y\/+5D 8ǒܚsϩRXKIHdݢxN m& V}ih6{͎Q z|yń'<3reh;Xy3E ="A`.jbZ_+2f%vI^ف7Ҥz3q|Po_-g畈 eWGߚ&PJ/$/32pDqDwu&:`O#4) =lp7X\~\m+r-]hQ"eG>xTh "#Ud5i\*!' xAE@}oU4gnş5Y,tl:/IZo8io'"v){gdXߟ;ٺE+u7{</&Uiѝ*v|0l (kN1S#k>w?{Y9Ay|'?8*Yf dW(jP ]~:e!=0iټ౱]PEf-|ѝ6%~R)'ryhz`v,z5bphѵ1[$1ʪ{Jb~Կ s;_<9|9t*ʝX|Jy~>M۩^L(ݡ ֣KHڪzԴDjt³ޘy&m=t9+r[lS3΄QDgy+3f^x_hiޠdd357hm Oڻ;=F!}7;\+9n"jqK5T灁?"(l ,A]Dn,,fhaP)Feɻ3o52i@{;H8dg%lo VUÜ{#gZ#K 2f}{UZIݴzEW1M;7I^_w󱛍^1cŐ=!m endstream endobj 150 0 obj << /Length1 721 /Length2 5420 /Length3 0 /Length 6002 /Filter /FlateDecode >> stream xmUPmצQDR];%Υvaaم$T:A. i ogsssgfeTD!]u@ /(@GyXYPKW8 )o @m:P' Xr('/4n#,mp4@@í.nh7I޻&(j(@NSHEC P"hK@ H(B'k&?P0PWЕQ(,65vjvk:n*]VP[8/T0@oҝ ;};96P аtPNnP4@eE#`%#PqAi{E тY DY7}/P;?nDxȻ16Җq Hk i qm/e {{6-]pO ?_Od_,ӛ\#D|G E1n?zB f&Qb)uKGr[qM1ZMH]v64tizҍZI|]RUd%\d 39֯bR;C>~k+-gEJH\cY-!td.$oJ|y+mw}Vj]^IZё {ҷF_M:m vab% Gt<-Aj-'˩5;kQa/_gU(6ō6\L7LAr K\Llb*a1$^>|:v8$POtKhE~r+gy$KO+]?1>Ey>/萱mtzձ6$ZSzօx<=TDM7eSr 4X~ γG <+P" v(WEv<ZzucY,[@fpwU'nx- ݛpƲ1ItZe4$Z Cd"z1ͥ>O @5ťJ=fFTv>S[Ś yw|bJLC,βɢn<( "F$;pEǀc@kI&u?[CVhVߧ54J9h0a=[ȡ0{M$Pvs|5u)[$Ni]yZILې wiU'g'Z4B{oB qˆY n p*}1x+&<Ly(aaJ>@WX D^BbKM !L0HmdкF0G"k>ŝl oxƥ<] \B>v 7HKgzw>bI%&.HZ/.3.HL`:l.eqakˌ h`E `-o-`z`dRFh1N\^}vc9&i̦Uْ/˹n;p,iU+"7e;Bhaqc5>kmJOt _KhK3E,gƁV;1(60 sDlKd5=U:GͶp<OCGM0{3_*:+W2aw?RI5pN6~šu4JWdNAKEy0G|nRfqolS+/+tў’f!i0^oB; C gާᆲu뢦ez5ndӒA#iqnPY1kAZG ͌,x'pQaR *.B%vq7]@D7#&1/x+z\=[,io֊jywIpAbN뗉pN+FqQ}y4!k 6 SPyi2$Ss'`tHU3C [?~HⒺpVV.}poqƄS5"АȬ+$hfF=rTD:m4y;oӦ|\8Gd0Ha~0NVBn\?}sx'զ?Q̷ U6 u^ b X;(_9%|e4`)FA$12osER6YY L #ĵ|VҸKס {I00LRԹ@֠@-zԩ//ʠ/8ZMW~p8S-j]z՝WRε91jq滾r+J?h1?sW;o~}(>_%ڒ$BybA#|㥯_LS|!x6p/xT\V'{X}82tK9e#Id`%Eg 9e1e 0IzFQm   #_{W $LoVcV^ᇫk &Ga#y{# )%<>c/bTz.5][WHzA (O'=rY>쒴[۔,B!I"ƅR_%uoML^ 0A! @Vj a YoŮm~Êb4-"F"ڴ)n d}wbIdRƆ.Hy=ąg-AsL2Ft= gʘZ XpYŔ(oѬ5l̤ 'pW&w?0:ƧGh3,mI*}b{r^<Bʛ%gc<9p:v YotVC<{8H{۽wD 3v#* R:~W4IP DYLj o1y:r7~b_L 6ERW?+ɹ<9܎HRTR ow\yJ=:et@OLPp',tq XsX;gX˵@B j"rNsh}m2 ϧh_Nb0\F^};{/Y!L,y^yDVqquR70f ,*W\ˏ<"F3y2\uxGl龿] @2Sόn0Rι=y`j}I#6#$(&P/&bN9[KzOO˓R(B7xZ^u2 | DD}n#?*[gLAgr.md˔Rs𾉃{`BL;꾇p*P␰d2h3'uJѭA;_@ vB0~1 fhx0vթw׀z^Bu~M2+UByKW=QW>=bt-~_E]L5씢K$j\UQRZuYIBy 4 b1,,k.R C}%}O:ԷTWe&8dP;W_!->?MЏa,\q^Lb>N[ WH} i17\Ra96#x#CKˇ "e%\Ҵ`m533]o8 nG˰Ѧ%[>Tƭ"_xFPg/o <'5Y HkGI d,}&)R2nYI{:m">t$j? X=c/mϓnxC"jrT&۶uGoYe_4/P -se^)*\@qr40F&w>3ȍXadNUl>ZA&[9.Xu:ϡ>~i܍gpK,aoǺxu u_:M>ʢ899.74}&sCHhǢfY7q>4{&9>[ OR 5n\% m}i<ӀWQu%4LsDc+$sԧlө4QM.8sZ=OsZ8SBq=f^f4L?Xki腒0|xc8(:gH$;lTk9d]S^ʋEkEX">›yN)VQ3aEm)uktqqF#1:v dho^EoyT [(;cA&\`$vifN!,jUa.7 !7n\98g.^8R>1~C>ѓ޽tp>E?ޱDo)v7>ĉaH?~eF"+%r@Y8Ep2 <:M0g:hh'vXz}rxw8f endstream endobj 2 0 obj << /Type /ObjStm /N 100 /First 824 /Length 4507 /Filter /FlateDecode >> stream x\[sI~ׯǙݠ b#s_۶Yd`ˬjelĠRUVV3ZYZ0Epԅxb!= eOR"e ]/j| 4aN)/1 Ncw]x0QD 0 %Ӫ`ރDCY_ dT,qXЃ<.ݾp _xk %1A<%= іe{>Pȥa07"=?>VcDjӜ?GQ=eJi ;`D(OKߖ((. d2nuҁhѢCPRtJ1@W2CPp#tҵ\n=GPJ*ݗ07ÇAUU|~:ʯò>?WɬU.Q"tU;[" R1O{[FԮg mG?[2 B+)d`Ise ׯLOpPIjwP&P#Dmb)`\[CM8M-Z{ʵeB@c?]/F&JW" TVi_6>xYJ8 6469#w[nU3 s՚x5}ߌ{*R ff+P[\lEuAuf:0$گ/GKȫȋ;e ^bkI텿ݯZЀS!90)potMU(2,EzV)oj/,*Is/?:mm?h7?kHug-]#' ՘! GHnwYg$SӔ/!g$c$s\_ Gt~6$F) 9iJTTt-8h\3@s=49It A2ePxB.q.+j ɞ,UJ9>e69ghnFm%LWFzJ8h^Hg<8?LwtF&"> ).B8Eq֡rgF8ҵ 2N.q0Wa__ `mv05t7ܨ3âET($>:S:}U86hY:@մK[fXL("BYK;XIf#A>0tAs0g%(MqڴW&p^ qZrpn]8K{it`y(p%01ִ>pHy-BWږJ4B:c-ey/kh4i.i(Ֆ Srl=YdI̐<>>x/HR/85Q%d%Ȓ WrW>aH@Ikiǭ@iW ix$l~&Nch"J!Qq:FR+y1KθYxR֋vmK:@w_B{(`E +< QyBη&t-UG!'M@1ԬېB6ôf5ocKۦ-A8i$1Nev8a ER"!a2fƐdgpؕg₉6CWL3VEh=iElxBE+Q .aN2-T+Cp"$OwTX5Kc0} i)`f- A%qHgE}rWܗRQBX`AUuE\*^)3V#PK}b6ʨaZRhNa.Iy%#c|1!iɠƥʍ*Bdَm]홒4ɍ8͊ ]Sq/!DmچdicS"8f(m$Aqu($\" 2V_ E?-V^-eF]J%bTk@r.ܒtegcpl!4"gFE0KrtH/ȩy yu:ihɨ#֑)ʶW푄>UeB &M\[OӬmd[~{6q~lI[l0'U 3[[OsC01 X]w;|`Dæb'0򭅙Tϫlo`{>LwHӴO?%P`2ўGzZφ3H7QvJ^CR>!'d69Ȉ^8{bVd^a2Y}6LT/\[gtQ%ϟ`vD-mRԊ!܏Bw eT/Wżf'@pe0^Ued~"dׇ֑l}luh퐭mي|e/9xZqpw*^(N3"Cwo v:|ÎRŽsWXY+d~unAHL~XqxMN,;q47;<9ZqΛI| J,>G|S|z.솴o>/ Ke^;l!dLv?.R{@S+Snsǵ/IMHZ!p[LϞ5%k, uRjh,g`8GG5Tf>g7 1iE"fI.Q= &zYqpWI%$9҅ ]ػ˱"Yl9LW zrn}'6psRY+?xwDTn;ok%^<|uϽݗ‰С$ (MeDhrmώVtQ䤞2VD|pXdL̘6>ƮeCuĥssUOhT ^Iw͋z1( Gx< 'qxUw4Td}SxU8)ADGY?=r"K m9qS^vx4?KO]` endstream endobj 160 0 obj << /Producer (pdfTeX-1.40.20) /Author()/Title()/Subject()/Creator(LaTeX with hyperref)/Keywords() /CreationDate (D:20200516123106+02'00') /ModDate (D:20200516123106+02'00') /Trapped /False /PTEX.Fullbanner (This is pdfTeX, Version 3.14159265-2.6-1.40.20 (TeX Live 2019/Debian) kpathsea version 6.3.1) >> endobj 152 0 obj << /Type /ObjStm /N 35 /First 275 /Length 1083 /Filter /FlateDecode >> stream xڭn8slxkSj'^6X,v~RcFG~ cJpH @ 4?( JTW$Ih 4a)"Q $HSc2 *4A @NAJMtE bYF{iHb;Mg\GֻVkY01 S;B{Z` Q<kL?@u]LI_kq8rԿ#~S 'ćS= <90CB9798E4F73B642A5B019CF2D122EC>] /Length 413 /Filter /FlateDecode >> stream x%ӹRQsn*°/2#&( Z 2H51 ɯ>s9{.Y0OpE'9C6)O yLBT7Z5&*-(*I%'*HP}uC]gZO7Y #JdG"GڈM~ӈ/2eTwIe2p!V͛x#DZtx V] Cd.RG#0 O3 )x/`f /a̻UmҢהҒJnVJ=5/J?6Gt?CÎz:Qz[{;sJy}z'W#Fc endstream endobj startxref 211420 %%EOF octclip-2.0.1/doc/octclip.tex0000644000175000017500000001334413657740347014544 0ustar olafolaf\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/