diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..67c3b85 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,8 @@ +version: 2 +updates: +- package-ecosystem: maven + directory: "/" + schedule: + interval: daily + time: "04:00" + open-pull-requests-limit: 10 diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml new file mode 100644 index 0000000..343a111 --- /dev/null +++ b/.github/workflows/maven.yml @@ -0,0 +1,17 @@ +name: Java CI + +on: [push] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + - name: Set up JDK 11 + uses: actions/setup-java@v1 + with: + java-version: 11 + - name: Build with Maven + run: mvn -B package --file pom.xml -Dmaven.javadoc.skip=true diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6538aa3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/target/ +/.classpath +/.DS_Store +/.project +/.settings/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..70566f2 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ +GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {one line to give the program's name and a brief idea of what it does.} + Copyright (C) {year} {name of author} + + 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: + + {project} Copyright (C) {year} {fullname} + 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 +. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..96b75a7 --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +FreeRouting +=========== +Java Based Printed Circuit Board Routing Software from FreeRouting.net written by Alfons Wirtz. + +this version as been adapted to build with maven, just type "mvn clean install" into your console + +For more information see [here](http://nick-less.github.io/freerouting/). + + +Link to compiled version with dependencies: (https://github.com/nick-less/freerouting/releases/download/1.0.1-SNAPSHOT/freerouting-1.0.1-SNAPSHOT-jar-with-dependencies.jar) diff --git a/autoroute/AutorouteEngine.java b/autoroute/AutorouteEngine.java deleted file mode 100644 index 7b305ad..0000000 --- a/autoroute/AutorouteEngine.java +++ /dev/null @@ -1,684 +0,0 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * AutorouteEngine.java - * - * Created on 11. Januar 2004, 11:14 - */ -package autoroute; - -import geometry.planar.Line; -import geometry.planar.Simplex; -import geometry.planar.TileShape; - -import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.TreeSet; -import java.util.Set; -import java.util.SortedSet; - -import datastructures.Stoppable; -import datastructures.TimeLimit; - -import board.SearchTreeObject; -import board.Item; -import board.RoutingBoard; -import board.ShapeSearchTree; -import board.ShapeSearchTree90Degree; -import board.ShapeSearchTree45Degree; -import board.TestLevel; - -/** - * Temporary autoroute data stored on the RoutingBoard. - * - * @author Alfons Wirtz - */ -public class AutorouteEngine -{ - - /** - * Creates a new instance of BoardAoutorouteEngine - * If p_maintain_database, the autorouter database is maintained after a connection is - * completed for performance reasons. - */ - public AutorouteEngine(RoutingBoard p_board, int p_trace_clearance_class_no, boolean p_maintain_database) - { - this.board = p_board; - this.maintain_database = p_maintain_database; - this.net_no = -1; - this.autoroute_search_tree = p_board.search_tree_manager.get_autoroute_tree(p_trace_clearance_class_no); - int max_drill_page_width = (int) (5 * p_board.rules.get_default_via_diameter()); - max_drill_page_width = Math.max(max_drill_page_width, 10000); - this.drill_page_array = new DrillPageArray(this.board, max_drill_page_width); - this.stoppable_thread = null; - } - - public void init_connection(int p_net_no, Stoppable p_stoppable_thread, TimeLimit p_time_limit) - { - if (this.maintain_database) - { - if (p_net_no != this.net_no) - { - if (this.complete_expansion_rooms != null) - { - // invalidate the net dependent complete free space expansion rooms. - Collection rooms_to_remove = new LinkedList(); - for (CompleteFreeSpaceExpansionRoom curr_room : complete_expansion_rooms) - { - if (curr_room.is_net_dependent()) - { - rooms_to_remove.add(curr_room); - } - } - for (CompleteFreeSpaceExpansionRoom curr_room : rooms_to_remove) - { - this.remove_complete_expansion_room(curr_room); - } - } - // invalidate the neighbour rooms of the items of p_net_no - Collection item_list = this.board.get_items(); - for (Item curr_item : item_list) - { - if (curr_item.contains_net(p_net_no)) - { - this.board.additional_update_after_change(curr_item); - } - } - } - } - this.net_no = p_net_no; - this.stoppable_thread = p_stoppable_thread; - this.time_limit = p_time_limit; - } - - /* Autoroutes a connection between p_start_set and p_dest_set. - * Returns ALREADY_CONNECTED, ROUTED, NOT_ROUTED, or INSERT_ERROR. - */ - public AutorouteResult autoroute_connection(Set p_start_set, Set p_dest_set, - AutorouteControl p_ctrl, SortedSet p_ripped_item_list) - { - MazeSearchAlgo maze_search_algo; - try - { - maze_search_algo = MazeSearchAlgo.get_instance(p_start_set, p_dest_set, this, p_ctrl); - } catch (Exception e) - { - System.out.println("AutorouteEngine.autoroute_connection: Exception in MazeSearchAlgo.get_instance"); - System.out.println(e); - maze_search_algo = null; - } - MazeSearchAlgo.Result search_result = null; - if (maze_search_algo != null) - { - try - { - search_result = maze_search_algo.find_connection(); - } catch (Exception e) - { - System.out.println("AutorouteEngine.autoroute_connection: Exception in maze_search_algo.find_connection"); - } - } - LocateFoundConnectionAlgo autoroute_result = null; - if (search_result != null) - { - try - { - autoroute_result = - LocateFoundConnectionAlgo.get_instance(search_result, p_ctrl, this.autoroute_search_tree, - board.rules.get_trace_angle_restriction(), p_ripped_item_list, board.get_test_level()); - } catch (Exception e) - { - System.out.println("AutorouteEngine.autoroute_connection: Exception in LocateFoundConnectionAlgo.get_instance"); - } - } - if (!this.maintain_database) - { - this.clear(); - } - else - { - this.reset_all_doors(); - } - if (autoroute_result == null) - { - return AutorouteResult.NOT_ROUTED; - } - if (autoroute_result.connection_items == null) - { - if (this.board.get_test_level().ordinal() >= TestLevel.CRITICAL_DEBUGGING_OUTPUT.ordinal()) - { - System.out.println("AutorouteEngine.autoroute_connection: result_items != null expected"); - } - return AutorouteResult.ALREADY_CONNECTED; - } - // Delete the ripped connections. - SortedSet ripped_connections = new TreeSet(); - Set changed_nets = new TreeSet(); - Item.StopConnectionOption stop_connection_option; - if (p_ctrl.remove_unconnected_vias) - { - stop_connection_option = Item.StopConnectionOption.NONE; - } - else - { - stop_connection_option = Item.StopConnectionOption.FANOUT_VIA; - } - - for (Item curr_ripped_item : p_ripped_item_list) - { - ripped_connections.addAll(curr_ripped_item.get_connection_items(stop_connection_option)); - for (int i = 0; i < curr_ripped_item.net_count(); ++i) - { - changed_nets.add(curr_ripped_item.get_net_no(i)); - } - } - // let the observers know the changes in the board database. - boolean observers_activated = !this.board.observers_active(); - if (observers_activated) - { - this.board.start_notify_observers(); - } - - board.remove_items(ripped_connections, false); - - for (int curr_net_no : changed_nets) - { - this.board.remove_trace_tails(curr_net_no, stop_connection_option); - } - InsertFoundConnectionAlgo insert_found_connection_algo = - InsertFoundConnectionAlgo.get_instance(autoroute_result, board, p_ctrl); - - if (observers_activated) - { - this.board.end_notify_observers(); - } - if (insert_found_connection_algo == null) - { - return AutorouteResult.INSERT_ERROR; - } - return AutorouteResult.ROUTED; - } - - /** - * Returns the net number of the current connection to route. - */ - public int get_net_no() - { - return this.net_no; - } - - /** - * Returns if the user has stopped the autorouter. - */ - public boolean is_stop_requested() - { - if (this.time_limit != null) - { - if (this.time_limit.limit_exceeded()) - { - return true; - } - } - if (this.stoppable_thread == null) - { - return false; - } - return this.stoppable_thread.is_stop_requested(); - } - - /** - * Clears all temporary data - */ - public void clear() - { - if (complete_expansion_rooms != null) - { - for (CompleteFreeSpaceExpansionRoom curr_room : complete_expansion_rooms) - { - curr_room.remove_from_tree(this.autoroute_search_tree); - } - } - complete_expansion_rooms = null; - incomplete_expansion_rooms = null; - expansion_room_instance_count = 0; - board.clear_all_item_temporary_autoroute_data(); - } - - /** - * Draws the shapes of the expansion rooms created so far. - */ - public void draw(java.awt.Graphics p_graphics, boardgraphics.GraphicsContext p_graphics_context, double p_intensity) - { - if (complete_expansion_rooms == null) - { - return; - } - for (CompleteFreeSpaceExpansionRoom curr_room : complete_expansion_rooms) - { - curr_room.draw(p_graphics, p_graphics_context, p_intensity); - } - Collection item_list = this.board.get_items(); - for (Item curr_item : item_list) - { - ItemAutorouteInfo autoroute_info = curr_item.get_autoroute_info(); - if (autoroute_info != null) - { - autoroute_info.draw(p_graphics, p_graphics_context, p_intensity); - } - } - // this.drill_page_array.draw(p_graphics, p_graphics_context, p_intensity); - } - - /** - * Creates a new FreeSpaceExpansionRoom and adds it to the room list. - * Its shape is normally unbounded at construction time of the room. - * The final (completed) shape will be a subshape of the start shape, which - * does not overlap with any obstacle, and it is as big as possible. - * p_contained_points will remain contained in the shape, after it is completed. - */ - public IncompleteFreeSpaceExpansionRoom add_incomplete_expansion_room(TileShape p_shape, int p_layer, TileShape p_contained_shape) - { - IncompleteFreeSpaceExpansionRoom new_room = new IncompleteFreeSpaceExpansionRoom(p_shape, p_layer, p_contained_shape); - if (this.incomplete_expansion_rooms == null) - { - this.incomplete_expansion_rooms = new LinkedList(); - } - this.incomplete_expansion_rooms.add(new_room); - return new_room; - } - - /** - * Returns the first elemment in the list of incomplete expansion rooms or null, if the list is empty. - */ - public IncompleteFreeSpaceExpansionRoom get_first_incomplete_expansion_room() - { - if (incomplete_expansion_rooms == null) - { - return null; - } - if (incomplete_expansion_rooms.isEmpty()) - { - return null; - } - Iterator it = incomplete_expansion_rooms.iterator(); - return it.next(); - } - - /** - * Removes an incomplete room from the database. - */ - public void remove_incomplete_expansion_room(IncompleteFreeSpaceExpansionRoom p_room) - { - this.remove_all_doors(p_room); - incomplete_expansion_rooms.remove(p_room); - } - - /** - * Removes a complete expansion room from the database and creates - * new incomplete expansion rooms for the neighbours. - */ - public void remove_complete_expansion_room(CompleteFreeSpaceExpansionRoom p_room) - { - // create new incomplete expansion rooms for all neighbours - TileShape room_shape = p_room.get_shape(); - int room_layer = p_room.get_layer(); - Collection room_doors = p_room.get_doors(); - for (ExpansionDoor curr_door : room_doors) - { - ExpansionRoom curr_neighbour = curr_door.other_room(p_room); - if (curr_neighbour != null) - { - curr_neighbour.remove_door(curr_door); - TileShape neighbour_shape = curr_neighbour.get_shape(); - TileShape intersection = room_shape.intersection(neighbour_shape); - if (intersection.dimension() == 1) - { - // add a new incomplete room to curr_neighbour. - int[] touching_sides = room_shape.touching_sides(neighbour_shape); - Line[] line_arr = new Line[1]; - line_arr[0] = neighbour_shape.border_line(touching_sides[1]).opposite(); - Simplex new_incomplete_room_shape = Simplex.get_instance(line_arr); - IncompleteFreeSpaceExpansionRoom new_incomplete_room = - add_incomplete_expansion_room(new_incomplete_room_shape, room_layer, intersection); - ExpansionDoor new_door = new ExpansionDoor(curr_neighbour, new_incomplete_room, 1); - curr_neighbour.add_door(new_door); - new_incomplete_room.add_door(new_door); - } - } - } - this.remove_all_doors(p_room); - p_room.remove_from_tree(this.autoroute_search_tree); - if (complete_expansion_rooms != null) - { - complete_expansion_rooms.remove(p_room); - } - else - { - System.out.println("AutorouteEngine.remove_complete_expansion_room: this.complete_expansion_rooms is null"); - } - this.drill_page_array.invalidate(room_shape); - } - - /** - * Completes the shape of p_room. - * Returns the resulting rooms after completing the shape. - * p_room will no more exist after this function. - */ - public Collection complete_expansion_room(IncompleteFreeSpaceExpansionRoom p_room) - { - - try - { - Collection result = new LinkedList(); - TileShape from_door_shape = null; - SearchTreeObject ignore_object = null; - Collection room_doors = p_room.get_doors(); - for (ExpansionDoor curr_door : room_doors) - { - ExpansionRoom other_room = curr_door.other_room(p_room); - if (other_room instanceof CompleteFreeSpaceExpansionRoom && curr_door.dimension == 2) - { - from_door_shape = curr_door.get_shape(); - ignore_object = (CompleteFreeSpaceExpansionRoom) other_room; - break; - } - } - Collection completed_shapes = - this.autoroute_search_tree.complete_shape(p_room, this.net_no, ignore_object, from_door_shape); - this.remove_incomplete_expansion_room(p_room); - Iterator it = completed_shapes.iterator(); - boolean is_first_completed_room = true; - while (it.hasNext()) - { - IncompleteFreeSpaceExpansionRoom curr_incomplete_room = it.next(); - if (curr_incomplete_room.get_shape().dimension() != 2) - { - continue; - } - if (is_first_completed_room) - { - is_first_completed_room = false; - CompleteFreeSpaceExpansionRoom completed_room = this.add_complete_room(curr_incomplete_room); - if (completed_room != null) - { - result.add(completed_room); - } - } - else - { - // the shape of the first completed room may have changed and may - // intersect now with the other shapes. Therefore the completed shapes - // have to be recalculated. - Collection curr_completed_shapes = - this.autoroute_search_tree.complete_shape(curr_incomplete_room, this.net_no, - ignore_object, from_door_shape); - Iterator it2 = curr_completed_shapes.iterator(); - while (it2.hasNext()) - { - IncompleteFreeSpaceExpansionRoom tmp_room = it2.next(); - CompleteFreeSpaceExpansionRoom completed_room = this.add_complete_room(tmp_room); - if (completed_room != null) - { - result.add(completed_room); - } - } - } - } - return result; - } catch (Exception e) - { - System.out.print("AutorouteEngine.complete_expansion_room: "); - System.out.println(e); - return new LinkedList(); - } - - } - - /** - * Calculates the doors and adds the completed room to the room database. - */ - private CompleteFreeSpaceExpansionRoom add_complete_room(IncompleteFreeSpaceExpansionRoom p_room) - { - CompleteFreeSpaceExpansionRoom completed_room = (CompleteFreeSpaceExpansionRoom) calculate_doors(p_room); - CompleteFreeSpaceExpansionRoom result; - if (completed_room != null && completed_room.get_shape().dimension() == 2) - { - if (complete_expansion_rooms == null) - { - complete_expansion_rooms = new LinkedList(); - } - complete_expansion_rooms.add(completed_room); - this.autoroute_search_tree.insert(completed_room); - result = completed_room; - } - else - { - result = null; - } - return result; - } - - /** - * Calculates the neighbours of p_room and inserts doors to - * the new created neighbour rooms. - * The shape of the result room may be different to the shape of p_room - */ - private CompleteExpansionRoom calculate_doors(ExpansionRoom p_room) - { - CompleteExpansionRoom result; - if (this.autoroute_search_tree instanceof ShapeSearchTree90Degree) - { - result = SortedOrthogonalRoomNeighbours.calculate(p_room, this); - } - else if (this.autoroute_search_tree instanceof ShapeSearchTree45Degree) - { - result = Sorted45DegreeRoomNeighbours.calculate(p_room, this); - } - else - { - result = SortedRoomNeighbours.calculate(p_room, this); - } - return result; - } - - /** Completes the shapes of the neigbour rooms of p_room, so that the - * doors of p_room will not change later on. - */ - public void complete_neigbour_rooms(CompleteExpansionRoom p_room) - { - if (p_room.get_doors() == null) - { - return; - } - Iterator it = p_room.get_doors().iterator(); - while (it.hasNext()) - { - ExpansionDoor curr_door = it.next(); - // cast to ExpansionRoom becaus ExpansionDoor.other_room works differently with - // parameter type CompleteExpansionRoom. - ExpansionRoom neighbour_room = curr_door.other_room((ExpansionRoom) p_room); - if (neighbour_room != null) - { - if (neighbour_room instanceof IncompleteFreeSpaceExpansionRoom) - { - this.complete_expansion_room((IncompleteFreeSpaceExpansionRoom) neighbour_room); - // restart reading because the doors have changed - it = p_room.get_doors().iterator(); - } - else if (neighbour_room instanceof ObstacleExpansionRoom) - { - ObstacleExpansionRoom obstacle_neighbour_room = (ObstacleExpansionRoom) neighbour_room; - if (!obstacle_neighbour_room.all_doors_calculated()) - { - this.calculate_doors(obstacle_neighbour_room); - obstacle_neighbour_room.set_doors_calculated(true); - } - } - } - } - } - - /** - * Invalidates all drill pages intersecting with p_shape, so the they must be recalculated at the next - * call of get_ddrills() - */ - public void invalidate_drill_pages(TileShape p_shape) - { - this.drill_page_array.invalidate(p_shape); - } - - /** - * Removes all doors from p_room - */ - void remove_all_doors(ExpansionRoom p_room) - { - - Iterator it = p_room.get_doors().iterator(); - while (it.hasNext()) - { - ExpansionDoor curr_door = it.next(); - ExpansionRoom other_room = curr_door.other_room(p_room); - if (other_room != null) - { - other_room.remove_door(curr_door); - if (other_room instanceof IncompleteFreeSpaceExpansionRoom) - { - this.remove_incomplete_expansion_room((IncompleteFreeSpaceExpansionRoom) other_room); - } - } - } - p_room.clear_doors(); - } - - /** - * Returns all complete free space expansion rooms with a target door to an item in the set p_items. - */ - Set get_rooms_with_target_items(Set p_items) - { - Set result = new TreeSet(); - if (this.complete_expansion_rooms != null) - { - for (CompleteFreeSpaceExpansionRoom curr_room : this.complete_expansion_rooms) - { - Collection target_door_list = curr_room.get_target_doors(); - for (TargetItemExpansionDoor curr_target_door : target_door_list) - { - Item curr_target_item = curr_target_door.item; - if (p_items.contains(curr_target_item)) - { - result.add(curr_room); - } - } - } - } - return result; - } - - /** - * Checks, if the internal datastructure is valid. - */ - public boolean validate() - { - if (complete_expansion_rooms == null) - { - return true; - } - boolean result = true; - for (CompleteFreeSpaceExpansionRoom curr_room : complete_expansion_rooms) - { - if (!curr_room.validate(this)) - { - result = false; - } - } - return result; - } - - /** - * Reset all doors for autorouting the next connnection, in case the autorouting database is retained. - */ - private void reset_all_doors() - { - if (this.complete_expansion_rooms != null) - { - for (ExpansionRoom curr_room : this.complete_expansion_rooms) - { - curr_room.reset_doors(); - } - } - Collection item_list = this.board.get_items(); - for (Item curr_item : item_list) - { - ItemAutorouteInfo curr_autoroute_info = curr_item.get_autoroute_info_pur(); - if (curr_autoroute_info != null) - { - curr_autoroute_info.reset_doors(); - curr_autoroute_info.set_precalculated_connection(null); - } - } - this.drill_page_array.reset(); - } - - protected int generate_room_id_no() - { - ++expansion_room_instance_count; - return expansion_room_instance_count; - } - /** - * The current search tree used in autorouting. - * It depends on the trac clearance class used in the autoroute algorithm. - */ - public final ShapeSearchTree autoroute_search_tree; - /** If maintain_database, the autorouter database is maintained after a connection is - * completed for performance reasons. - */ - public final boolean maintain_database; - static final int TRACE_WIDTH_TOLERANCE = 2; - /** - * The net number used for routing in this autoroute algorithm. - */ - private int net_no; - /** - * The 2-dimensional array of rectangular pages of ExpansionDrills - */ - final DrillPageArray drill_page_array; - /** - * To be able to stop the expansion algorithm. - */ - Stoppable stoppable_thread; - /** - * To stop the expansion algorithm after a time limit is exceeded. - */ - private TimeLimit time_limit; - /** The PCB-board of this autoroute algorithm. */ - final RoutingBoard board; - /** The list of incomplete expansion rooms on the routing board */ - private List incomplete_expansion_rooms = null; - /** The list of complete expansion rooms on the routing board */ - private List complete_expansion_rooms = null; - /** The count of expansion rooms created so far */ - private int expansion_room_instance_count = 0; - - /** - * The pussible results of autorouting a connection - */ - public enum AutorouteResult - { - - ALREADY_CONNECTED, ROUTED, NOT_ROUTED, INSERT_ERROR - } -} diff --git a/gui/BoardFrame.java b/gui/BoardFrame.java deleted file mode 100644 index 49160cf..0000000 --- a/gui/BoardFrame.java +++ /dev/null @@ -1,805 +0,0 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - */ - -package gui; - -import interactive.ScreenMessages; - -import java.io.File; - -import datastructures.FileFilter; -import datastructures.IdNoGenerator; - -import board.TestLevel; -import board.BoardObservers; - -import designformats.specctra.DsnFile; - -/** - * - * Graphical frame of for interactive editing of a routing board. - * - * @author Alfons Wirtz - */ - -public class BoardFrame extends javax.swing.JFrame -{ - public enum Option - { - FROM_START_MENU, SINGLE_FRAME, SESSION_FILE, WEBSTART, EXTENDED_TOOL_BAR - } - - /** - * Creates a new board frame with the input design file imbedded into a host cad software. - */ - public static BoardFrame get_embedded_instance(String p_design_file_path_name, - BoardObservers p_observers, IdNoGenerator p_id_no_generator, java.util.Locale p_locale) - { - final gui.DesignFile design_file = gui.DesignFile.get_instance(p_design_file_path_name, false); - if (design_file == null) - { - WindowMessage.show("designfile not found"); - return null; - } - gui.BoardFrame board_frame = new gui.BoardFrame(design_file, gui.BoardFrame.Option.SINGLE_FRAME, - TestLevel.RELEASE_VERSION, p_observers, p_id_no_generator, p_locale, false); - - - if (board_frame == null) - { - WindowMessage.show("board_frame is null"); - return null; - } - java.io.InputStream input_stream = design_file.get_input_stream(); - boolean read_ok = board_frame.read(input_stream, true, null); - if (!read_ok) - { - String error_message = "Unable to read design file with pathname " + p_design_file_path_name; - board_frame.setVisible(true); // to be able to display the status message - board_frame.screen_messages.set_status_message(error_message); - } - return board_frame; - } - - /** - * Creates new form BoardFrame. - * If p_option = FROM_START_MENU this frame is created from a start menu frame. - * If p_option = SINGLE_FRAME, this frame is created directly a single frame. - * If p_option = Option.IN_SAND_BOX, no security sensitive actions like for example choosing - * If p_option = Option.WEBSTART, the application has been started with Java Webstart. - * files are allowed, so that the frame can be used in an applet. - * Currently Option.EXTENDED_TOOL_BAR is used only if a new board is - * created by the application from scratch. - * If p_test_level > RELEASE_VERSION, functionality not yet ready for release is included. - * Also the warning output depends on p_test_level. - */ - public BoardFrame(DesignFile p_design, Option p_option, TestLevel p_test_level, - java.util.Locale p_locale, boolean p_confirm_cancel) - { - this(p_design, p_option, p_test_level, - new board.BoardObserverAdaptor(), new board.ItemIdNoGenerator(), - p_locale, p_confirm_cancel); - } - - /** - * Creates new form BoardFrame. - * The parameters p_item_observers and p_item_id_no_generator are used for syncronizing purposes, - * if the frame is embedded into a host system, - */ - BoardFrame(DesignFile p_design, Option p_option, TestLevel p_test_level, BoardObservers p_observers, - datastructures.IdNoGenerator p_item_id_no_generator, java.util.Locale p_locale, boolean p_confirm_cancel) - { - this.design_file = p_design; - this.is_web_start = (p_option == Option.WEBSTART); - this.test_level = p_test_level; - - this.confirm_cancel = p_confirm_cancel; - this.board_observers = p_observers; - this.item_id_no_generator = p_item_id_no_generator; - this.locale = p_locale; - this.resources = java.util.ResourceBundle.getBundle("gui.resources.BoardFrame", p_locale); - BoardMenuBar curr_menubar; - boolean session_file_option = (p_option == Option.SESSION_FILE); - boolean curr_help_system_used = true; - try - { - curr_menubar = BoardMenuBar.get_instance(this, curr_help_system_used, session_file_option); - } - catch (java.lang.NoClassDefFoundError e) - { - // the system-file jh.jar may be missing - curr_help_system_used = false; - curr_menubar = BoardMenuBar.get_instance(this, false, session_file_option); - System.out.println("Online-Help deactivated because system file jh.jar is missing"); - } - this.menubar = curr_menubar; - this.help_system_used = curr_help_system_used; - setJMenuBar(this.menubar); - - this.toolbar_panel = new BoardToolbar(this); - this.add(this.toolbar_panel, java.awt.BorderLayout.NORTH); - - this.message_panel = new BoardPanelStatus(this.locale); - this.add(this.message_panel, java.awt.BorderLayout.SOUTH); - - this.select_toolbar = new BoardToolbarSelectedItem(this, p_option == Option.EXTENDED_TOOL_BAR); - - this.screen_messages = - new ScreenMessages(this.message_panel.status_message, this.message_panel.add_message, - this.message_panel.current_layer, this.message_panel.mouse_position, this.locale); - - this.scroll_pane = new javax.swing.JScrollPane(); - this.scroll_pane.setPreferredSize(new java.awt.Dimension(1150, 800)); - this.scroll_pane.setVerifyInputWhenFocusTarget(false); - this.add(scroll_pane, java.awt.BorderLayout.CENTER); - - this.board_panel = new BoardPanel(screen_messages, this, this.is_web_start, p_locale); - this.scroll_pane.setViewportView(board_panel); - - this.setTitle(resources.getString("title")); - this.addWindowListener(new WindowStateListener()); - - this.pack(); - } - - /** - * Reads interactive actions from a logfile. - */ - void read_logfile(java.io.InputStream p_input_stream) - { - board_panel.board_handling.read_logfile(p_input_stream); - } - - - /** - * Reads an existing board design from file. - * If p_is_import, the design is read from a scpecctra dsn file. - * Returns false, if the file is invalid. - */ - boolean read(java.io.InputStream p_input_stream, boolean p_is_import, javax.swing.JTextField p_message_field) - { - java.awt.Point viewport_position = null; - if (p_is_import) - { - DsnFile.ReadResult read_result = board_panel.board_handling.import_design(p_input_stream, this.board_observers, - this.item_id_no_generator, this.test_level); - if (read_result != DsnFile.ReadResult.OK) - { - if (p_message_field != null) - { - if (read_result == DsnFile.ReadResult.OUTLINE_MISSING) - { - p_message_field.setText(resources.getString("error_7")); - } - else - { - p_message_field.setText(resources.getString("error_6")); - } - } - return false; - } - viewport_position = new java.awt.Point(0,0); - initialize_windows(); - } - else - { - java.io.ObjectInputStream object_stream = null; - try - { - object_stream = new java.io.ObjectInputStream(p_input_stream); - } - catch (java.io.IOException e) - { - return false; - } - boolean read_ok = board_panel.board_handling.read_design(object_stream, this.test_level); - if (!read_ok) - { - return false; - } - java.awt.Point frame_location; - java.awt.Rectangle frame_bounds; - try - { - viewport_position = (java.awt.Point) object_stream.readObject(); - frame_location = (java.awt.Point) object_stream.readObject(); - frame_bounds = (java.awt.Rectangle) object_stream.readObject(); - } - catch (Exception e) - { - return false; - } - this.setLocation(frame_location); - this.setBounds(frame_bounds); - - allocate_permanent_subwindows(); - - for (int i = 0; i < this.permanent_subwindows.length; ++i) - { - this.permanent_subwindows[i].read(object_stream); - } - } - try - { - p_input_stream.close(); - } - catch (java.io.IOException e) - { - return false; - } - - java.awt.Dimension panel_size = board_panel.board_handling.graphics_context.get_panel_size(); - board_panel.setSize(panel_size); - board_panel.setPreferredSize(panel_size); - if (viewport_position != null) - { - board_panel.set_viewport_position(viewport_position); - } - board_panel.create_popup_menus(); - board_panel.init_colors(); - board_panel.board_handling.create_ratsnest(); - this.hilight_selected_button(); - this.toolbar_panel.unit_factor_field.setValue(board_panel.board_handling.coordinate_transform.user_unit_factor); - this.toolbar_panel.unit_combo_box.setSelectedItem(board_panel.board_handling.coordinate_transform.user_unit); - this.setVisible(true); - if (p_is_import) - { - // Read the default gui settings, if gui default file exists. - java.io.InputStream input_stream = null; - boolean defaults_file_found; - if (this.is_web_start) - { - input_stream = WebStart.get_file_input_stream(BoardFrame.GUI_DEFAULTS_FILE_NAME); - defaults_file_found = (input_stream != null); - } - else - { - File defaults_file = new File(this.design_file.get_parent(), GUI_DEFAULTS_FILE_NAME); - defaults_file_found = true; - try - { - input_stream = new java.io.FileInputStream(defaults_file); - } - catch (java.io.FileNotFoundException e) - { - defaults_file_found = false; - } - } - if (defaults_file_found) - { - boolean read_ok = gui.GUIDefaultsFile.read(this, board_panel.board_handling, input_stream); - if (!read_ok) - { - screen_messages.set_status_message(resources.getString("error_1")); - } - try - { - input_stream.close(); - } - catch (java.io.IOException e) - { - return false; - } - } - this.zoom_all(); - } - return true; - } - - - /** - * Saves the interactive settings and the design file to disk. - * Returns false, if the save failed. - */ - boolean save() - { - if (this.design_file == null) - { - return false; - } - java.io.OutputStream output_stream = null; - java.io.ObjectOutputStream object_stream = null; - try - { - output_stream = new java.io.FileOutputStream(this.design_file.get_output_file()); - object_stream = new java.io.ObjectOutputStream(output_stream); - } - catch (java.io.IOException e) - { - screen_messages.set_status_message(resources.getString("error_2")); - return false; - } - catch (java.security.AccessControlException e) - { - screen_messages.set_status_message(resources.getString("error_3")); - return false; - } - boolean save_ok = board_panel.board_handling.save_design_file(object_stream); - if (!save_ok) - { - return false; - } - try - { - object_stream.writeObject(board_panel.get_viewport_position()); - object_stream.writeObject(this.getLocation()); - object_stream.writeObject(this.getBounds()); - } - catch (java.io.IOException e) - { - screen_messages.set_status_message(resources.getString("error_4")); - return false; - } - for (int i = 0; i < this.permanent_subwindows.length; ++i) - { - this.permanent_subwindows[i].save(object_stream); - } - try - { - object_stream.flush(); - output_stream.close(); - } - catch (java.io.IOException e) - { - screen_messages.set_status_message(resources.getString("error_5")); - return false; - } - return true; - } - - /** - * Sets contexts sensitive help for the input component, if the help system is used. - */ - public void set_context_sensitive_help(java.awt.Component p_component, String p_help_id) - { - if (this.help_system_used) - { - java.awt.Component curr_component; - if (p_component instanceof javax.swing.JFrame) - { - curr_component = ((javax.swing.JFrame) p_component).getRootPane(); - } - else - { - curr_component = p_component; - } - String help_id = "html_files." + p_help_id; - javax.help.CSH.setHelpIDString(curr_component, help_id); - if (!this.is_web_start) - { - help_broker.enableHelpKey(curr_component, help_id, help_set); - } - } - } - - /** Sets the toolbar to the buttons of the selected item state. */ - public void set_select_toolbar() - { - getContentPane().remove(toolbar_panel); - getContentPane().add(select_toolbar, java.awt.BorderLayout.NORTH); - repaint(); - } - - /** Sets the toolbar buttons to the select. route and drag menu buttons of the main menu. */ - public void set_menu_toolbar() - { - getContentPane().remove(select_toolbar); - getContentPane().add(toolbar_panel, java.awt.BorderLayout.NORTH); - repaint(); - } - - /** - * Calculates the absolute location of the board frame in his outmost parent frame. - */ - java.awt.Point absolute_panel_location() - { - int x = this.scroll_pane.getX(); - int y = this.scroll_pane.getY(); - java.awt.Container curr_parent = this.scroll_pane.getParent(); - while (curr_parent != null) - { - x += curr_parent.getX(); - y += curr_parent.getY(); - curr_parent = curr_parent.getParent(); - } - return new java.awt.Point(x, y); - } - - /** Sets the displayed region to the whole board. */ - public void zoom_all() - { - board_panel.board_handling.adjust_design_bounds(); - java.awt.Rectangle display_rect = board_panel.get_viewport_bounds(); - java.awt.Rectangle design_bounds = board_panel.board_handling.graphics_context.get_design_bounds(); - double width_factor = display_rect.getWidth() /design_bounds.getWidth(); - double height_factor = display_rect.getHeight() /design_bounds.getHeight(); - double zoom_factor = Math.min(width_factor, height_factor); - java.awt.geom.Point2D zoom_center = board_panel.board_handling.graphics_context.get_design_center(); - board_panel.zoom(zoom_factor, zoom_center); - java.awt.geom.Point2D new_vieport_center = board_panel.board_handling.graphics_context.get_design_center(); - board_panel.set_viewport_center(new_vieport_center); - - } - - /** - * Actions to be taken when this frame vanishes. - */ - public void dispose() - { - for (int i = 0; i < this.permanent_subwindows.length; ++i) - { - if (this.permanent_subwindows[i] != null) - { - this.permanent_subwindows[i].dispose(); - this.permanent_subwindows[i] = null; - } - } - for (BoardTemporarySubWindow curr_subwindow : this.temporary_subwindows) - { - if (curr_subwindow != null) - { - curr_subwindow.board_frame_disposed(); - } - } - if (board_panel.board_handling != null) - { - board_panel.board_handling.dispose(); - board_panel.board_handling = null; - } - super.dispose(); - } - - private void allocate_permanent_subwindows() - { - this.color_manager = new ColorManager(this); - this.permanent_subwindows[0] = this.color_manager; - this.object_visibility_window = WindowObjectVisibility.get_instance(this); - this.permanent_subwindows[1] = this.object_visibility_window; - this.layer_visibility_window = WindowLayerVisibility.get_instance(this); - this.permanent_subwindows[2] = this.layer_visibility_window; - this.display_misc_window = new WindowDisplayMisc(this); - this.permanent_subwindows[3] = this.display_misc_window; - this.snapshot_window = new WindowSnapshot(this); - this.permanent_subwindows[4] = this.snapshot_window; - this.route_parameter_window = new WindowRouteParameter(this); - this.permanent_subwindows[5] = this.route_parameter_window; - this.select_parameter_window = new WindowSelectParameter(this); - this.permanent_subwindows[6] = this.select_parameter_window; - this.clearance_matrix_window = new WindowClearanceMatrix(this); - this.permanent_subwindows[7] = this.clearance_matrix_window; - this.padstacks_window = new WindowPadstacks(this); - this.permanent_subwindows[8] = this.padstacks_window; - this.packages_window = new WindowPackages(this); - this.permanent_subwindows[9] = this.packages_window; - this.components_window = new WindowComponents(this); - this.permanent_subwindows[10] = this.components_window; - this.incompletes_window = new WindowIncompletes(this); - this.permanent_subwindows[11] = this.incompletes_window; - this.clearance_violations_window = new WindowClearanceViolations(this); - this.permanent_subwindows[12] = this.clearance_violations_window; - this.net_info_window = new WindowNets(this); - this.permanent_subwindows[13] = this.net_info_window; - this.via_window = new WindowVia(this); - this.permanent_subwindows[14] = this.via_window; - this.edit_vias_window = new WindowEditVias(this); - this.permanent_subwindows[15] = this.edit_vias_window; - this.edit_net_rules_window = new WindowNetClasses(this); - this.permanent_subwindows[16] = this.edit_net_rules_window; - this.assign_net_classes_window = new WindowAssignNetClass(this); - this.permanent_subwindows[17] = this.assign_net_classes_window; - this.length_violations_window = new WindowLengthViolations(this); - this.permanent_subwindows[18] = this.length_violations_window; - this.about_window = new WindowAbout(this.locale); - this.permanent_subwindows[19] = this.about_window; - this.move_parameter_window = new WindowMoveParameter(this); - this.permanent_subwindows[20] = this.move_parameter_window; - this.unconnected_route_window = new WindowUnconnectedRoute(this); - this.permanent_subwindows[21] = this.unconnected_route_window; - this.route_stubs_window = new WindowRouteStubs(this); - this.permanent_subwindows[22] = this.route_stubs_window; - this.autoroute_parameter_window = new WindowAutorouteParameter(this); - this.permanent_subwindows[23] = this.autoroute_parameter_window; - } - - /** - * Creates the additional frames of the board frame. - */ - private void initialize_windows() - { - allocate_permanent_subwindows(); - - this.setLocation(120, 0); - - this.select_parameter_window.setLocation(0, 0); - this.select_parameter_window.setVisible(true); - - this.route_parameter_window.setLocation(0, 100); - this.autoroute_parameter_window.setLocation(0, 200); - this.move_parameter_window.setLocation(0, 50); - this.clearance_matrix_window.setLocation(0, 150); - this.via_window.setLocation(50, 150); - this.edit_vias_window.setLocation(100, 150); - this.edit_net_rules_window.setLocation(100, 200); - this.assign_net_classes_window.setLocation(100, 250); - this.padstacks_window.setLocation(100, 30); - this.packages_window.setLocation(200, 30); - this.components_window.setLocation(300, 30); - this.incompletes_window.setLocation(400, 30); - this.clearance_violations_window.setLocation(500, 30); - this.length_violations_window.setLocation(550, 30); - this.net_info_window.setLocation(350, 30); - this.unconnected_route_window.setLocation(650, 30); - this.route_stubs_window.setLocation(600, 30); - this.snapshot_window.setLocation(0, 250); - this.layer_visibility_window.setLocation(0, 450); - this.object_visibility_window.setLocation(0, 550); - this.display_misc_window.setLocation(0, 350); - this.color_manager.setLocation(0, 600); - this.about_window.setLocation(200, 200); - } - - /** - * Returns the currently used locale for the language dependent output. - */ - public java.util.Locale get_locale() - { - return this.locale; - } - - /** - * Sets the background of the board panel - */ - public void set_board_background(java.awt.Color p_color) - { - this.board_panel.setBackground(p_color); - } - - /** - * Refreshs all displayed coordinates after the user unit has changed. - */ - public void refresh_windows() - { - for (int i = 0; i < this.permanent_subwindows.length; ++i) - { - if (permanent_subwindows[i] != null) - { - permanent_subwindows[i].refresh(); - } - } - } - - /** - * Sets the selected button in the menu button button group - */ - public void hilight_selected_button() - { - this.toolbar_panel.hilight_selected_button(); - } - - /** - * Restore the selected snapshot in the snapshot window. - */ - public void goto_selected_snapshot() - { - if (this.snapshot_window != null) - { - this.snapshot_window.goto_selected(); - } - } - - /** - * Selects the snapshot, which is previous to the current selected snapshot. - * Thecurent selected snapshot will be no more selected. - */ - public void select_previous_snapshot() - { - if (this.snapshot_window != null) - { - this.snapshot_window.select_previous_item(); - } - } - - /** - * Selects the snapshot, which is next to the current selected snapshot. - * Thecurent selected snapshot will be no more selected. - */ - public void select_next_snapshot() - { - if (this.snapshot_window != null) - { - this.snapshot_window.select_next_item(); - } - } - - /** - * Used for storing the subwindowfilters in a snapshot. - */ - public SubwindowSelections get_snapshot_subwindow_selections() - { - SubwindowSelections result = new SubwindowSelections(); - result.incompletes_selection = this.incompletes_window.get_snapshot_info(); - result.packages_selection = this.packages_window.get_snapshot_info(); - result.nets_selection = this.net_info_window.get_snapshot_info(); - result.components_selection = this.components_window.get_snapshot_info(); - result.padstacks_selection = this.padstacks_window.get_snapshot_info(); - return result; - } - - /** - * Used for restoring the subwindowfilters from a snapshot. - */ - public void set_snapshot_subwindow_selections(SubwindowSelections p_filters) - { - this.incompletes_window.set_snapshot_info(p_filters.incompletes_selection); - this.packages_window.set_snapshot_info(p_filters.packages_selection); - this.net_info_window.set_snapshot_info(p_filters.nets_selection); - this.components_window.set_snapshot_info(p_filters.components_selection); - this.padstacks_window.set_snapshot_info(p_filters.padstacks_selection); - } - - /** - * Repaints this board frame and all the subwindows of the board. - */ - public void repaint_all() - { - this.repaint(); - for (int i = 0; i < permanent_subwindows.length; ++i) - { - permanent_subwindows[i].repaint(); - } - } - - /** The scroll pane for the panel of the routing board. */ - final javax.swing.JScrollPane scroll_pane; - - /** The menubar of this frame */ - final BoardMenuBar menubar; - - /** The panel with the graphical representation of the board. */ - final BoardPanel board_panel; - - /** The panel with the toolbars */ - private final BoardToolbar toolbar_panel; - - /** The toolbar used in the selected item state. */ - private final javax.swing.JToolBar select_toolbar; - - /** The panel with the message line */ - private final BoardPanelStatus message_panel; - - final ScreenMessages screen_messages; - - private final TestLevel test_level; - - /** true, if the frame is created by an application running under Java Web Start */ - final boolean is_web_start; - - private final boolean help_system_used; - static javax.help.HelpSet help_set = null; - static javax.help.HelpBroker help_broker = null; - - private final boolean confirm_cancel; - - private final java.util.ResourceBundle resources; - private java.util.Locale locale; - - private final BoardObservers board_observers; - private final datastructures.IdNoGenerator item_id_no_generator; - - WindowAbout about_window = null; - WindowRouteParameter route_parameter_window = null; - WindowAutorouteParameter autoroute_parameter_window = null; - WindowSelectParameter select_parameter_window = null; - WindowMoveParameter move_parameter_window = null; - WindowClearanceMatrix clearance_matrix_window = null; - WindowVia via_window = null; - WindowEditVias edit_vias_window = null; - WindowNetClasses edit_net_rules_window = null; - WindowAssignNetClass assign_net_classes_window = null; - WindowPadstacks padstacks_window = null; - WindowPackages packages_window = null; - WindowIncompletes incompletes_window = null; - WindowNets net_info_window = null; - WindowClearanceViolations clearance_violations_window = null; - WindowLengthViolations length_violations_window = null; - WindowUnconnectedRoute unconnected_route_window = null; - WindowRouteStubs route_stubs_window = null; - WindowComponents components_window = null; - WindowLayerVisibility layer_visibility_window = null; - WindowObjectVisibility object_visibility_window = null; - WindowDisplayMisc display_misc_window = null; - WindowSnapshot snapshot_window = null; - ColorManager color_manager = null; - - /** The windows above stored in an array */ - static final int SUBWINDOW_COUNT = 24; - BoardSavableSubWindow[] permanent_subwindows = new BoardSavableSubWindow[SUBWINDOW_COUNT]; - - java.util.Collection temporary_subwindows = new java.util.LinkedList(); - - - DesignFile design_file = null; - - static final String [] log_file_extensions = { "log" }; - - static final String GUI_DEFAULTS_FILE_NAME = "gui_defaults.par"; - static final String GUI_DEFAULTS_FILE_BACKUP_NAME = "gui_defaults.par.bak"; - - static final FileFilter logfile_filter = new FileFilter(log_file_extensions); - - private class WindowStateListener extends java.awt.event.WindowAdapter - { - public void windowClosing(java.awt.event.WindowEvent evt) - { - setDefaultCloseOperation(DISPOSE_ON_CLOSE ); - if (confirm_cancel) - { - int option = javax.swing.JOptionPane.showConfirmDialog(null, resources.getString("confirm_cancel"), - null, javax.swing.JOptionPane.YES_NO_OPTION); - if (option == javax.swing.JOptionPane.NO_OPTION) - { - setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); - } - } - } - - public void windowIconified(java.awt.event.WindowEvent evt) - { - for (int i = 0; i < permanent_subwindows.length; ++i) - { - permanent_subwindows[i].parent_iconified(); - } - for (BoardSubWindow curr_subwindow : temporary_subwindows) - { - if (curr_subwindow != null) - { - curr_subwindow.parent_iconified(); - } - } - } - - public void windowDeiconified(java.awt.event.WindowEvent evt) - { - for (int i = 0; i < permanent_subwindows.length; ++i) - { - if (permanent_subwindows[i] != null) - { - permanent_subwindows[i].parent_deiconified(); - } - } - for (BoardSubWindow curr_subwindow : temporary_subwindows) - { - if (curr_subwindow != null) - { - curr_subwindow.parent_deiconified(); - } - } - } - } - - /** - * Used for storing the subwindow filters in a snapshot. - */ - public static class SubwindowSelections implements java.io.Serializable - { - private WindowObjectListWithFilter.SnapshotInfo incompletes_selection; - private WindowObjectListWithFilter.SnapshotInfo packages_selection; - private WindowObjectListWithFilter.SnapshotInfo nets_selection; - private WindowObjectListWithFilter.SnapshotInfo components_selection; - private WindowObjectListWithFilter.SnapshotInfo padstacks_selection; - } -} - diff --git a/gui/BoardMenuFile.java b/gui/BoardMenuFile.java deleted file mode 100644 index e594063..0000000 --- a/gui/BoardMenuFile.java +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * BoardFileMenu.java - * - * Created on 11. Februar 2005, 11:26 - */ -package gui; - -/** - * Creates the file menu of a board frame. - * - * @author Alfons Wirtz - */ -public class BoardMenuFile extends javax.swing.JMenu -{ - - /** Returns a new file menu for the board frame. */ - public static BoardMenuFile get_instance(BoardFrame p_board_frame, boolean p_session_file_option) - { - final BoardMenuFile file_menu = new BoardMenuFile(p_board_frame, p_session_file_option); - file_menu.setText(file_menu.resources.getString("file")); - - // Create the menu items. - - if (!p_session_file_option && !p_board_frame.is_web_start) - { - javax.swing.JMenuItem save_item = new javax.swing.JMenuItem(); - save_item.setText(file_menu.resources.getString("save")); - save_item.setToolTipText(file_menu.resources.getString("save_tooltip")); - save_item.addActionListener(new java.awt.event.ActionListener() - { - - public void actionPerformed(java.awt.event.ActionEvent evt) - { - boolean save_ok = file_menu.board_frame.save(); - file_menu.board_frame.board_panel.board_handling.close_files(); - if (save_ok) - { - file_menu.board_frame.screen_messages.set_status_message(file_menu.resources.getString("save_message")); - } - } - }); - - file_menu.add(save_item); - } - - if (!p_board_frame.is_web_start) - { - javax.swing.JMenuItem save_and_exit_item = new javax.swing.JMenuItem(); - save_and_exit_item.setText(file_menu.resources.getString("save_and_exit")); - save_and_exit_item.setToolTipText(file_menu.resources.getString("save_and_exit_tooltip")); - save_and_exit_item.addActionListener(new java.awt.event.ActionListener() - { - - public void actionPerformed(java.awt.event.ActionEvent evt) - { - if (file_menu.session_file_option) - { - file_menu.board_frame.design_file.write_specctra_session_file(file_menu.board_frame); - } - else - { - file_menu.board_frame.save(); - } - file_menu.board_frame.dispose(); - } - }); - - file_menu.add(save_and_exit_item); - } - - javax.swing.JMenuItem cancel_and_exit_item = new javax.swing.JMenuItem(); - cancel_and_exit_item.setText(file_menu.resources.getString("cancel_and_exit")); - cancel_and_exit_item.setToolTipText(file_menu.resources.getString("cancel_and_exit_tooltip")); - cancel_and_exit_item.addActionListener(new java.awt.event.ActionListener() - { - - public void actionPerformed(java.awt.event.ActionEvent evt) - { - file_menu.board_frame.dispose(); - } - }); - - file_menu.add(cancel_and_exit_item); - - if (!file_menu.session_file_option) - { - javax.swing.JMenuItem save_as_item = new javax.swing.JMenuItem(); - save_as_item.setText(file_menu.resources.getString("save_as")); - save_as_item.setToolTipText(file_menu.resources.getString("save_as_tooltip")); - save_as_item.addActionListener(new java.awt.event.ActionListener() - { - - public void actionPerformed(java.awt.event.ActionEvent evt) - { - file_menu.save_as_action(); - } - }); - - file_menu.add(save_as_item); - - if (!p_board_frame.is_web_start) - { - javax.swing.JMenuItem write_logfile_item = new javax.swing.JMenuItem(); - write_logfile_item.setText(file_menu.resources.getString("generate_logfile")); - write_logfile_item.setToolTipText(file_menu.resources.getString("generate_logfile_tooltip")); - write_logfile_item.addActionListener(new java.awt.event.ActionListener() - { - - public void actionPerformed(java.awt.event.ActionEvent evt) - { - file_menu.write_logfile_action(); - } - }); - - file_menu.add(write_logfile_item); - - javax.swing.JMenuItem replay_logfile_item = new javax.swing.JMenuItem(); - replay_logfile_item.setText(file_menu.resources.getString("replay_logfile")); - replay_logfile_item.setToolTipText(file_menu.resources.getString("replay_logfile_tooltip")); - replay_logfile_item.addActionListener(new java.awt.event.ActionListener() - { - - public void actionPerformed(java.awt.event.ActionEvent evt) - { - file_menu.read_logfile_action(); - } - }); - - file_menu.add(replay_logfile_item); - } - } - - file_menu.add_save_settings_item(); - - return file_menu; - } - - public void add_design_dependent_items() - { - if (this.session_file_option) - { - return; - } - board.BasicBoard routing_board = this.board_frame.board_panel.board_handling.get_routing_board(); - boolean host_cad_is_eagle = routing_board.communication.host_cad_is_eagle(); - - javax.swing.JMenuItem write_session_file_item = new javax.swing.JMenuItem(); - write_session_file_item.setText(resources.getString("session_file")); - write_session_file_item.setToolTipText(resources.getString("session_file_tooltip")); - write_session_file_item.addActionListener(new java.awt.event.ActionListener() - { - - public void actionPerformed(java.awt.event.ActionEvent evt) - { - board_frame.design_file.write_specctra_session_file(board_frame); - } - }); - - if ((routing_board.get_test_level() != board.TestLevel.RELEASE_VERSION || !host_cad_is_eagle)) - { - this.add(write_session_file_item); - } - - javax.swing.JMenuItem write_eagle_session_script_item = new javax.swing.JMenuItem(); - write_eagle_session_script_item.setText(resources.getString("eagle_script")); - write_eagle_session_script_item.setToolTipText(resources.getString("eagle_script_tooltip")); - write_eagle_session_script_item.addActionListener(new java.awt.event.ActionListener() - { - - public void actionPerformed(java.awt.event.ActionEvent evt) - { - board_frame.design_file.update_eagle(board_frame); - } - }); - - if (routing_board.get_test_level() != board.TestLevel.RELEASE_VERSION || host_cad_is_eagle) - { - this.add(write_eagle_session_script_item); - } - } - - /** - * Adds a menu item for saving the current interactive settings as default. - */ - private void add_save_settings_item() - { - javax.swing.JMenuItem save_settings_item = new javax.swing.JMenuItem(); - save_settings_item.setText(resources.getString("settings")); - save_settings_item.setToolTipText(resources.getString("settings_tooltip")); - save_settings_item.addActionListener(new java.awt.event.ActionListener() - { - - public void actionPerformed(java.awt.event.ActionEvent evt) - { - save_defaults_action(); - } - }); - add(save_settings_item); - } - - private void save_as_action() - { - if (this.board_frame.design_file != null) - { - this.board_frame.design_file.save_as_dialog(this, this.board_frame); - } - } - - private void write_logfile_action() - { - javax.swing.JFileChooser file_chooser = new javax.swing.JFileChooser(); - java.io.File logfile_dir = board_frame.design_file.get_parent_file(); - file_chooser.setCurrentDirectory(logfile_dir); - file_chooser.setFileFilter(BoardFrame.logfile_filter); - file_chooser.showOpenDialog(this); - java.io.File filename = file_chooser.getSelectedFile(); - if (filename == null) - { - board_frame.screen_messages.set_status_message(resources.getString("message_8")); - } - else - { - board_frame.screen_messages.set_status_message(resources.getString("message_9")); - board_frame.board_panel.board_handling.start_logfile(filename); - } - } - - private void read_logfile_action() - { - javax.swing.JFileChooser file_chooser = new javax.swing.JFileChooser(); - java.io.File logfile_dir = board_frame.design_file.get_parent_file(); - file_chooser.setCurrentDirectory(logfile_dir); - file_chooser.setFileFilter(BoardFrame.logfile_filter); - file_chooser.showOpenDialog(this); - java.io.File filename = file_chooser.getSelectedFile(); - if (filename == null) - { - board_frame.screen_messages.set_status_message(resources.getString("message_10")); - } - else - { - java.io.InputStream input_stream = null; - try - { - input_stream = new java.io.FileInputStream(filename); - } catch (java.io.FileNotFoundException e) - { - return; - } - board_frame.read_logfile(input_stream); - } - } - - private void save_defaults_action() - { - java.io.OutputStream output_stream = null; - if (board_frame.is_web_start) - { - output_stream = WebStart.get_file_output_stream(BoardFrame.GUI_DEFAULTS_FILE_NAME); - } - else - { - java.io.File defaults_file = new java.io.File(board_frame.design_file.get_parent(), BoardFrame.GUI_DEFAULTS_FILE_NAME); - if (defaults_file.exists()) - { - // Make a backup copy of the old defaulds file. - java.io.File defaults_file_backup = new java.io.File(board_frame.design_file.get_parent(), BoardFrame.GUI_DEFAULTS_FILE_BACKUP_NAME); - if (defaults_file_backup.exists()) - { - defaults_file_backup.delete(); - } - defaults_file.renameTo(defaults_file_backup); - } - try - { - output_stream = new java.io.FileOutputStream(defaults_file); - } catch (Exception e) - { - output_stream = null; - } - } - boolean write_ok; - if (output_stream == null) - { - write_ok = false; - } - else - { - write_ok = gui.GUIDefaultsFile.write(board_frame, board_frame.board_panel.board_handling, output_stream); - } - if (write_ok) - { - board_frame.screen_messages.set_status_message(resources.getString("message_17")); - } - else - { - board_frame.screen_messages.set_status_message(resources.getString("message_18")); - } - - } - - /** Creates a new instance of BoardFileMenu */ - private BoardMenuFile(BoardFrame p_board_frame, boolean p_session_file_option) - { - session_file_option = p_session_file_option; - board_frame = p_board_frame; - resources = java.util.ResourceBundle.getBundle("gui.resources.BoardMenuFile", p_board_frame.get_locale()); - } - private final BoardFrame board_frame; - private final boolean session_file_option; - private final java.util.ResourceBundle resources; -} diff --git a/gui/DesignFile.java b/gui/DesignFile.java deleted file mode 100644 index d270395..0000000 --- a/gui/DesignFile.java +++ /dev/null @@ -1,598 +0,0 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * DesignFile.java - * - * Created on 25. Oktober 2006, 07:48 - * - */ -package gui; - -import datastructures.FileFilter; - -/** - * File functionality with security restrictions used, when the application is opened with Java Webstart - * - * @author Alfons Wirtz - */ -public class DesignFile -{ - - public static final String[] all_file_extensions = {"bin", "dsn"}; - public static final String[] text_file_extensions = {"dsn"}; - public static final String binary_file_extension = "bin"; - - public static DesignFile get_instance(String p_design_file_name, boolean p_is_webstart) - { - if (p_design_file_name == null) - { - return null; - } - DesignFile result = new DesignFile(p_is_webstart, null, new java.io.File(p_design_file_name), null); - return result; - } - - /** - * Shows a file chooser for opening a design file. - * If p_is_webstart there are security restrictions because the application was opened with java web start. - */ - public static DesignFile open_dialog(boolean p_is_webstart, String p_design_dir_name) - { - DesignFile result; - if (p_is_webstart) - { - result = webstart_open_dialog(p_design_dir_name); - } - else - { - javax.swing.JFileChooser file_chooser = new javax.swing.JFileChooser(p_design_dir_name); - FileFilter file_filter = new FileFilter(all_file_extensions); - file_chooser.setFileFilter(file_filter); - file_chooser.showOpenDialog(null); - java.io.File curr_design_file = file_chooser.getSelectedFile(); - if (curr_design_file == null) - { - return null; - } - result = new DesignFile(false, null, curr_design_file, file_chooser); - } - return result; - } - - /** - * Creates a new instance of DesignFile. - * If p_is_webstart, the application was opened with Java Web Start. - */ - private DesignFile(boolean p_is_webstart, javax.jnlp.FileContents p_file_contents, - java.io.File p_design_file, javax.swing.JFileChooser p_file_chooser) - { - this.is_webstart = p_is_webstart; - this.file_contents = p_file_contents; - this.file_chooser = p_file_chooser; - this.input_file = p_design_file; - this.output_file = p_design_file; - if (p_design_file != null) - { - String file_name = p_design_file.getName(); - String[] name_parts = file_name.split("\\."); - if (name_parts[name_parts.length - 1].compareToIgnoreCase(binary_file_extension) != 0) - { - String binfile_name = name_parts[0] + "." + binary_file_extension; - this.output_file = new java.io.File(p_design_file.getParent(), binfile_name); - } - } - } - - /** - * Gets an InputStream from the file. Returns null, if the algorithm failed. - */ - public java.io.InputStream get_input_stream() - { - java.io.InputStream result; - if (this.is_webstart) - { - - if (this.file_contents == null) - { - return null; - } - try - { - result = this.file_contents.getInputStream(); - } catch (Exception e) - { - result = null; - } - } - else - { - if (this.input_file == null) - { - return null; - } - try - { - result = new java.io.FileInputStream(this.input_file); - } catch (Exception e) - { - result = null; - } - } - return result; - } - - /** - * Gets the file name as a String. Returns null on failure. - */ - public String get_name() - { - - String result; - if (this.file_contents != null) - { - try - { - result = this.file_contents.getName(); - } catch (Exception e) - { - result = null; - } - } - else if (this.input_file != null) - { - result = this.input_file.getName(); - } - else - { - result = null; - } - return result; - } - - public void save_as_dialog(java.awt.Component p_parent, BoardFrame p_board_frame) - { - final java.util.ResourceBundle resources = - java.util.ResourceBundle.getBundle("gui.resources.BoardMenuFile", p_board_frame.get_locale()); - String[] file_name_parts = this.get_name().split("\\.", 2); - String design_name = file_name_parts[0]; - if (this.is_webstart) - { - javax.jnlp.FileContents new_file_contents; - java.io.ByteArrayOutputStream output_stream = new java.io.ByteArrayOutputStream(); - - if (p_board_frame.board_panel.board_handling.export_to_dsn_file(output_stream, design_name, false)) - { - java.io.InputStream input_stream = new java.io.ByteArrayInputStream(output_stream.toByteArray()); - new_file_contents = WebStart.save_dialog(this.get_parent(), DesignFile.text_file_extensions, - input_stream, this.get_name()); - } - else - { - new_file_contents = null; - } - - - if (new_file_contents != null) - { - this.file_contents = new_file_contents; - p_board_frame.screen_messages.set_status_message(resources.getString("message_4") + " " + this.get_name() + " " + resources.getString("message_5")); - } - else - { - p_board_frame.screen_messages.set_status_message(resources.getString("message_19")); - } - return; - } - - if (this.file_chooser == null) - { - String design_dir_name; - if (this.output_file == null) - { - design_dir_name = null; - } - else - { - design_dir_name = this.output_file.getParent(); - } - this.file_chooser = new javax.swing.JFileChooser(design_dir_name); - FileFilter file_filter = new FileFilter(all_file_extensions); - this.file_chooser.setFileFilter(file_filter); - } - - this.file_chooser.showSaveDialog(p_parent); - java.io.File new_file = file_chooser.getSelectedFile(); - if (new_file == null) - { - p_board_frame.screen_messages.set_status_message(resources.getString("message_1")); - return; - } - String new_file_name = new_file.getName(); - String[] new_name_parts = new_file_name.split("\\."); - String found_file_extension = new_name_parts[new_name_parts.length - 1]; - if (found_file_extension.compareToIgnoreCase(binary_file_extension) == 0) - { - p_board_frame.screen_messages.set_status_message(resources.getString("message_2") + " " + new_file.getName()); - this.output_file = new_file; - p_board_frame.save(); - } - else - { - if (found_file_extension.compareToIgnoreCase("dsn") != 0) - { - p_board_frame.screen_messages.set_status_message(resources.getString("message_3")); - return; - } - java.io.OutputStream output_stream; - try - { - output_stream = new java.io.FileOutputStream(new_file); - } catch (Exception e) - { - output_stream = null; - } - if (p_board_frame.board_panel.board_handling.export_to_dsn_file(output_stream, design_name, false)) - { - p_board_frame.screen_messages.set_status_message(resources.getString("message_4") + " " + new_file_name + " " + resources.getString("message_5")); - } - else - { - p_board_frame.screen_messages.set_status_message(resources.getString("message_6") + " " + new_file_name + " " + resources.getString("message_7")); - } - } - } - - /** - * Writes a Specctra Session File to update the design file in the host system. - * Returns false, if the write failed - */ - public boolean write_specctra_session_file(BoardFrame p_board_frame) - { - final java.util.ResourceBundle resources = - java.util.ResourceBundle.getBundle("gui.resources.BoardMenuFile", p_board_frame.get_locale()); - String design_file_name = this.get_name(); - String[] file_name_parts = design_file_name.split("\\.", 2); - String design_name = file_name_parts[0]; - if (this.is_webstart) - { - String session_file_name = secure_write_session_file(p_board_frame); - if (session_file_name == null) - { - p_board_frame.screen_messages.set_status_message(resources.getString("message_13") + " " + - resources.getString("message_7")); - return false; - } - p_board_frame.screen_messages.set_status_message(resources.getString("message_11") + " " + - session_file_name + " " + resources.getString("message_12")); - } - else - { - String output_file_name = design_name + ".ses"; - java.io.File curr_output_file = new java.io.File(get_parent(), output_file_name); - java.io.OutputStream output_stream; - try - { - output_stream = new java.io.FileOutputStream(curr_output_file); - } catch (Exception e) - { - output_stream = null; - } - - if (p_board_frame.board_panel.board_handling.export_specctra_session_file(design_file_name, output_stream)) - { - p_board_frame.screen_messages.set_status_message(resources.getString("message_11") + " " + - output_file_name + " " + resources.getString("message_12")); - } - else - { - p_board_frame.screen_messages.set_status_message(resources.getString("message_13") + " " + - output_file_name + " " + resources.getString("message_7")); - return false; - } - } - if (WindowMessage.confirm(resources.getString("confirm"))) - { - return write_rules_file(design_name, p_board_frame.board_panel.board_handling); - } - return true; - } - - /** - * Saves the board rule to file, so that they can be reused later on. - */ - private boolean write_rules_file(String p_design_name, interactive.BoardHandling p_board_handling) - { - String rules_file_name = p_design_name + RULES_FILE_EXTENSION; - java.io.OutputStream output_stream; - if (this.is_webstart) - { - output_stream = WebStart.get_file_output_stream(rules_file_name); - } - else - { - java.io.File rules_file = new java.io.File(this.get_parent(), rules_file_name); - try - { - output_stream = new java.io.FileOutputStream(rules_file); - } catch (java.io.IOException e) - { - System.out.println("unable to create rules file"); - return false; - } - } - designformats.specctra.RulesFile.write(p_board_handling, output_stream, p_design_name); - return true; - } - - public static boolean read_rules_file(String p_design_name, String p_parent_name, - interactive.BoardHandling p_board_handling, boolean p_is_web_start, String p_confirm_message) - { - - boolean result = true; - String rule_file_name = p_design_name + ".rules"; - boolean dsn_file_generated_by_host = p_board_handling.get_routing_board().communication.specctra_parser_info.dsn_file_generated_by_host; - if (p_is_web_start) - { - java.io.InputStream input_stream = WebStart.get_file_input_stream(rule_file_name); - if (input_stream != null && dsn_file_generated_by_host && WindowMessage.confirm(p_confirm_message)) - { - result = designformats.specctra.RulesFile.read(input_stream, p_design_name, p_board_handling); - try - { - input_stream.close(); - } catch (Exception e) - { - result = false; - } - } - else - { - result = false; - } - WebStart.delete_files(RULES_FILE_EXTENSION, null); - } - else - { - try - { - java.io.File rules_file = new java.io.File(p_parent_name, rule_file_name); - java.io.InputStream input_stream = new java.io.FileInputStream(rules_file); - if (input_stream != null && dsn_file_generated_by_host && WindowMessage.confirm(p_confirm_message)) - { - result = designformats.specctra.RulesFile.read(input_stream, p_design_name, p_board_handling); - } - else - { - result = false; - } - try - { - if (input_stream != null) - { - input_stream.close(); - } - rules_file.delete(); - } catch (java.io.IOException e) - { - result = false; - } - } catch (java.io.FileNotFoundException e) - { - result = false; - } - } - return result; - } - - public void update_eagle(BoardFrame p_board_frame) - { - final java.util.ResourceBundle resources = - java.util.ResourceBundle.getBundle("gui.resources.BoardMenuFile", p_board_frame.get_locale()); - String design_file_name = get_name(); - java.io.ByteArrayOutputStream session_output_stream = new java.io.ByteArrayOutputStream(); - if (!p_board_frame.board_panel.board_handling.export_specctra_session_file(design_file_name, session_output_stream)) - { - return; - } - java.io.InputStream input_stream = new java.io.ByteArrayInputStream(session_output_stream.toByteArray()); - - String[] file_name_parts = design_file_name.split("\\.", 2); - String design_name = file_name_parts[0]; - String output_file_name = design_name + ".scr"; - if (this.is_webstart) - { - String script_file_name = webstart_update_eagle(p_board_frame, output_file_name, input_stream); - - if (script_file_name == null) - { - p_board_frame.screen_messages.set_status_message(resources.getString("message_16") + " " + - resources.getString("message_7")); - return; - } - p_board_frame.screen_messages.set_status_message(resources.getString("message_14") + " " + script_file_name + " " + resources.getString("message_15")); - } - else - { - java.io.File curr_output_file = new java.io.File(get_parent(), output_file_name); - java.io.OutputStream output_stream; - try - { - output_stream = new java.io.FileOutputStream(curr_output_file); - } catch (Exception e) - { - output_stream = null; - } - - if (p_board_frame.board_panel.board_handling.export_eagle_session_file(input_stream, output_stream)) - { - p_board_frame.screen_messages.set_status_message(resources.getString("message_14") + " " + output_file_name + " " + resources.getString("message_15")); - } - else - { - p_board_frame.screen_messages.set_status_message(resources.getString("message_16") + " " + output_file_name + " " + resources.getString("message_7")); - } - } - if (WindowMessage.confirm(resources.getString("confirm"))) - { - write_rules_file(design_name, p_board_frame.board_panel.board_handling); - } - } - - private static DesignFile webstart_open_dialog(String p_design_dir_name) - { - try - { - javax.jnlp.FileOpenService file_open_service = - (javax.jnlp.FileOpenService) javax.jnlp.ServiceManager.lookup("javax.jnlp.FileOpenService"); - javax.jnlp.FileContents file_contents = - file_open_service.openFileDialog(p_design_dir_name, DesignFile.text_file_extensions); - return new DesignFile(true, file_contents, null, null); - } catch (Exception e) - { - return null; - } - } - - /** - * Returns the name of the created session file or null, if the write failed. - * Put into a separate function to avoid undefines in the offline version. - */ - private String secure_write_session_file(BoardFrame p_board_frame) - { - java.io.ByteArrayOutputStream output_stream = new java.io.ByteArrayOutputStream(); - String file_name = this.get_name(); - if (file_name == null) - { - return null; - } - String session_file_name = file_name.replace(".dsn", ".ses"); - - if (!p_board_frame.board_panel.board_handling.export_specctra_session_file(file_name, output_stream)) - { - return null; - } - - java.io.InputStream input_stream = new java.io.ByteArrayInputStream(output_stream.toByteArray()); - - javax.jnlp.FileContents session_file_contents = - WebStart.save_dialog(this.get_parent(), null, input_stream, session_file_name); - - if (session_file_contents == null) - { - return null; - } - String new_session_file_name; - try - { - new_session_file_name = session_file_contents.getName(); - } catch (Exception e) - { - return null; - } - if (!new_session_file_name.equalsIgnoreCase(session_file_name)) - { - final java.util.ResourceBundle resources = - java.util.ResourceBundle.getBundle("gui.resources.BoardMenuFile", p_board_frame.get_locale()); - String curr_message = resources.getString("message_20") + " " + session_file_name + "\n" + resources.getString("message_21"); - WindowMessage.ok(curr_message); - } - return new_session_file_name; - } - - /** - * Returns the name of the created script file or null, if the write failed. - * Put into a separate function to avoid undefines in the offline version. - */ - private String webstart_update_eagle(BoardFrame p_board_frame, - String p_outfile_name, java.io.InputStream p_input_stream) - { - java.io.ByteArrayOutputStream output_stream = new java.io.ByteArrayOutputStream(); - if (!p_board_frame.board_panel.board_handling.export_eagle_session_file(p_input_stream, output_stream)) - { - return null; - } - java.io.InputStream input_stream = new java.io.ByteArrayInputStream(output_stream.toByteArray()); - javax.jnlp.FileContents script_file_contents = - WebStart.save_dialog(this.get_parent(), null, input_stream, p_outfile_name); - - if (script_file_contents == null) - { - return null; - } - String new_script_file_name; - try - { - new_script_file_name = script_file_contents.getName(); - } catch (Exception e) - { - return null; - } - - if (!new_script_file_name.endsWith(".scr")) - { - final java.util.ResourceBundle resources = - java.util.ResourceBundle.getBundle("gui.resources.BoardMenuFile", p_board_frame.get_locale()); - String curr_message = resources.getString("message_22") + "\n" + resources.getString("message_21"); - WindowMessage.ok(curr_message); - } - - return new_script_file_name; - } - - /** - * Gets the binary file for saving or null, if the design file is not available - * because the application is run with Java Web Start. - */ - public java.io.File get_output_file() - { - return this.output_file; - } - - public java.io.File get_input_file() - { - return this.input_file; - } - - public String get_parent() - { - if (input_file != null) - { - return input_file.getParent(); - } - return null; - } - - public java.io.File get_parent_file() - { - if (input_file != null) - { - return input_file.getParentFile(); - } - return null; - } - - public boolean is_created_from_text_file() - { - return this.is_webstart || this.input_file != this.output_file; - } - private final boolean is_webstart; - /** Used, if the application is run with Java Web Start. */ - private javax.jnlp.FileContents file_contents; - /** Used, if the application is run without Java Web Start. */ - private java.io.File output_file; - private final java.io.File input_file; - private javax.swing.JFileChooser file_chooser; - private static final String RULES_FILE_EXTENSION = ".rules"; -} diff --git a/gui/WebStart.java b/gui/WebStart.java deleted file mode 100644 index a34a64c..0000000 --- a/gui/WebStart.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * WebStart.java - * - * Created on 4. Dezember 2006, 07:01 - * - */ - -package gui; - -/** - * Function used for Java Websrart. - * Some put to a separate class to avoid runtime undefined in offline applications. - * @author Alfons Wirtz - */ -public class WebStart -{ - /* - * Separate function to avoid runtime undefines in an offline application. - */ - public static java.net.URL get_code_base() - { - try - { - javax.jnlp.BasicService basic_service = - (javax.jnlp.BasicService)javax.jnlp.ServiceManager.lookup("javax.jnlp.BasicService"); - return basic_service.getCodeBase(); - } - catch(Exception e) - { - return null; - } - } - - - public static javax.jnlp.FileContents save_dialog(String p_parent, String[] p_file_extensions, - java.io.InputStream p_input_stream, String p_name) - { - try - { - javax.jnlp.FileSaveService file_save_service = - (javax.jnlp.FileSaveService)javax.jnlp.ServiceManager.lookup("javax.jnlp.FileSaveService"); - javax.jnlp.FileContents curr_file_contents = - file_save_service.saveFileDialog(p_parent, p_file_extensions, p_input_stream, p_name); - return curr_file_contents; - } - catch (Exception e) - { - return null; - } - } - - /** - * Looks up a file with the input name in the Cookie file system of Java Web Start. - * Returns an input stream from that file or null, if no such file was found. - */ - public static java.io.InputStream get_file_input_stream(String p_file_name) - { - java.net.URL code_base = WebStart.get_code_base(); - if (code_base != null) - { - try - { - javax.jnlp.PersistenceService persistence_service = - (javax.jnlp.PersistenceService)javax.jnlp.ServiceManager.lookup("javax.jnlp.PersistenceService"); - String [] muffins = persistence_service.getNames(code_base); - for (int i = 0; i < muffins.length; ++i) - { - if (muffins[i].equals(p_file_name)) - { - java.net.URL defaults_file_url = new java.net.URL(code_base.toString() + muffins[i]); - javax.jnlp.FileContents file_contents = persistence_service.get(defaults_file_url); - return file_contents.getInputStream(); - } - } - } - catch(Exception e) - { - - } - } - return null; - } - - /** - * Looks up a file with the input name in the Cookie file system of Java Web Start. - * This file will be overwritten. - * Creates a new file, if no such file exists yet. - */ - public static java.io.OutputStream get_file_output_stream(String p_file_name) - { - java.io.OutputStream output_stream = null; - String [] muffins = null; - javax.jnlp.PersistenceService persistence_service = null; - java.net.URL code_base = get_code_base(); - if (code_base != null) - { - try - { - persistence_service = - (javax.jnlp.PersistenceService)javax.jnlp.ServiceManager.lookup("javax.jnlp.PersistenceService"); - muffins = persistence_service.getNames(code_base); - } - catch(Exception e) - { - muffins = null; - } - } - try - { - boolean file_exists = false; - java.net.URL file_url = null; - if (muffins != null) - { - for (int i = 0; i < muffins.length; ++i) - { - if (muffins[i].equals(p_file_name)) - { - file_url = new java.net.URL(code_base.toString() + muffins[i]); - file_exists = true; - } - } - } - if (!file_exists) - { - file_url = new java.net.URL(code_base.toString() + p_file_name); - long act_size = persistence_service.create(file_url, MAX_FILE_SIZE); - if (act_size < MAX_FILE_SIZE) - { - return null; - } - } - javax.jnlp.FileContents file_contents = persistence_service.get(file_url); - output_stream = file_contents.getOutputStream(true); - - } - catch(Exception e) - { - return null; - } - return output_stream; - } - - /* - * Deletes all files ending with p_file_ending from the cookie file system. - * Return false, if no file to delete was found - * If p_confirm_message != null, the user is asked to confirm the delete action. - */ - public static boolean delete_files(String p_file_ending, String p_confirm_messsage) - { - boolean file_deleted = false; - try - { - java.net.URL code_base = WebStart.get_code_base(); - if (code_base == null) - { - return false; - } - javax.jnlp.PersistenceService persistence_service = - (javax.jnlp.PersistenceService)javax.jnlp.ServiceManager.lookup("javax.jnlp.PersistenceService"); - String [] muffins = persistence_service.getNames(code_base); - java.net.URL file_url = null; - if (muffins != null) - { - for (int i = 0; i < muffins.length; ++i) - { - if (muffins[i].endsWith(p_file_ending)) - { - file_url = new java.net.URL(code_base.toString() + muffins[i]); - if (p_confirm_messsage == null || WindowMessage.confirm(p_confirm_messsage)) - { - persistence_service.delete(file_url); - file_deleted = true; - } - } - } - } - } - catch(Exception e) - { - file_deleted = false; - } - return file_deleted; - } - - private static final long MAX_FILE_SIZE = 100000; -} diff --git a/gui/WindowNetDemonstrations.java b/gui/WindowNetDemonstrations.java deleted file mode 100644 index 06a721e..0000000 --- a/gui/WindowNetDemonstrations.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * WindowNetDemonstration.java - * - * Created on 14. November 2006, 12:20 - * - */ - -package gui; - -import java.util.zip.ZipInputStream; - -/** - * Window with a list for selecting router demonstrations in the net. - * - * @author Alfons Wirtz - */ -public class WindowNetDemonstrations extends WindowNetSamples -{ - - /** Creates a new instance of WindowNetDemonstration */ - public WindowNetDemonstrations(java.util.Locale p_locale) - { - super(p_locale, "router_demonstrations", "replay_example", 7); - } - - /** - * To be edited when the demonstration examples change. - * For every String in the second column a String has to be added to the resource file WindowNetSamples. - */ - protected void fill_list() - { - add("sample_45.dsn", "45_degree_logfile", AdditionalAction.READ_LOGFILE); - add("int_ar.dsn", "drag_component_logfile", AdditionalAction.READ_LOGFILE); - add("single_layer.dsn", "any_angle_logfile", AdditionalAction.READ_LOGFILE); - add("hexapod_empty.dsn", "autorouter_example_1", AdditionalAction.AUTOROUTE); - add("at14_empty.dsn", "autorouter_example_2", AdditionalAction.AUTOROUTE); - add("sharp_empty.dsn", "autorouter_example_3", AdditionalAction.AUTOROUTE); - } - - protected void button_pushed() - { - int index = list.getSelectedIndex(); - if (index < 0 || index >= list_model.getSize()) - { - return; - } - ListElement selected_element = (ListElement) list_model.elementAt(index); - String[] name_parts = selected_element.design_name.split("\\."); - String archive_name = name_parts[0]; - BoardFrame new_frame = open_design(archive_name, selected_element.design_name, this.locale); - if (new_frame != null) - { - selected_element.additional_action.perform(new_frame, archive_name); - } - } - - /** - * Adds an element to the list. - */ - private void add(String p_design_name, String p_message_name, AdditionalAction p_additional_action) - { - list_model.addElement(new ListElement(p_design_name, - resources.getString(p_message_name), p_additional_action)); - } - - - /** - * Replays a zipped logfile from an URL in the net. - */ - private static void read_zipped_logfile(BoardFrame p_board_frame, String p_archive_name, String p_logfile_name) - { - if (p_board_frame == null) - { - return; - } - ZipInputStream zip_input_stream = WindowNetSamples.open_zipped_file(p_archive_name, p_logfile_name); - if (zip_input_stream == null) - { - return; - } - p_board_frame.read_logfile(zip_input_stream); - } - - /** - * Additional Acction to be performed after opening the board. - */ - private enum AdditionalAction - { - READ_LOGFILE - { - void perform(BoardFrame p_board_frame, String p_archive_name) - { - String logfile_archive_name = "route_" + p_archive_name; - read_zipped_logfile(p_board_frame, logfile_archive_name, logfile_archive_name + ".log"); - } - }, - - - AUTOROUTE - { - void perform(BoardFrame p_board_frame, String p_archive_name) - { - p_board_frame.board_panel.board_handling.start_batch_autorouter(); - } - }, - - NONE - { - void perform(BoardFrame p_board_frame, String p_archive_name) - { - - } - }; - - abstract void perform(BoardFrame p_board_frame, String p_archive_name); - } - - /** - * Structure of the elements in the list - * For every instance in a String has to be added to the resource file WindowNetSamples fo the - * String in the field message_name. - */ - private static class ListElement - { - ListElement(String p_design_name, String p_message_name, AdditionalAction p_additional_action) - { - design_name = p_design_name; - message_name = p_message_name; - additional_action = p_additional_action; - } - - public String toString() - { - return message_name; - } - - final String design_name; - final String message_name; - final AdditionalAction additional_action; - } -} diff --git a/gui/WindowNetSampleDesigns.java b/gui/WindowNetSampleDesigns.java deleted file mode 100644 index 13223f8..0000000 --- a/gui/WindowNetSampleDesigns.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * WindowNeetSampleDesigns.java - * - * Created on 14. November 2006, 10:13 - * - */ -package gui; - -/** - * - * Window with a list for selecting sample board designs in the net. - * - * @author Alfons Wirtz - */ -public class WindowNetSampleDesigns extends WindowNetSamples -{ - - /** Creates a new instance of WindowNeetSampleDesigns */ - public WindowNetSampleDesigns(java.util.Locale p_locale) - { - super(p_locale, "sample_designs", "open_sample_design", 11); - } - - protected void fill_list() - { - list_model.addElement("hexapod_empty.dsn"); - list_model.addElement("hexapod_autorouted.dsn"); - list_model.addElement("sharc_handrouted.dsn"); - list_model.addElement("at14_empty.dsn"); - list_model.addElement("at14_autorouted.dsn"); - list_model.addElement("sharp_empty.dsn"); - list_model.addElement("sharp_autorouted.dsn"); - list_model.addElement("bigdesign_unrouted.dsn"); - list_model.addElement("int_empty.dsn"); - list_model.addElement("int_autorouted.dsn"); - list_model.addElement("single_layer_empty.dsn"); - list_model.addElement("single_layer_handrouted.dsn"); - } - - protected void button_pushed() - { - int index = list.getSelectedIndex(); - if (index < 0 || index >= list_model.getSize()) - { - return; - } - String design_name = (String) list_model.elementAt(index); - String[] name_parts = design_name.split("\\."); - String archive_name = name_parts[0]; - open_design(archive_name, design_name, this.locale); - } -} diff --git a/gui/WindowNetSamples.java b/gui/WindowNetSamples.java deleted file mode 100644 index 4c43f25..0000000 --- a/gui/WindowNetSamples.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * WindowNetSampleDesigns.java - * - * Created on 11. November 2006, 07:49 - * - */ - -package gui; - -import java.util.zip.ZipInputStream; - -import java.net.URL; -import java.net.URLConnection; - -/** - * Window with a list for selecting samples in the net. - * - * @author Alfons Wirtz - */ -public abstract class WindowNetSamples extends BoardSubWindow -{ - - /** Creates a new instance of WindowNetSampleDesigns */ - public WindowNetSamples(java.util.Locale p_locale, String p_title, String p_button_name, int p_row_count) - { - this.locale = p_locale; - this.resources = java.util.ResourceBundle.getBundle("gui.resources.WindowNetSamples", p_locale); - this.setTitle(resources.getString(p_title)); - - this.setDefaultCloseOperation(DISPOSE_ON_CLOSE ); - - // create main panel - final javax.swing.JPanel main_panel = new javax.swing.JPanel(); - this.add(main_panel); - main_panel.setLayout(new java.awt.BorderLayout()); - javax.swing.border.Border panel_border = javax.swing.BorderFactory.createEmptyBorder(10, 10, 10, 10); - main_panel.setBorder(panel_border); - - - // create open button - javax.swing.JButton open_button = new javax.swing.JButton(resources.getString(p_button_name)); - open_button.addActionListener(new OpenListener()); - main_panel.add(open_button, java.awt.BorderLayout.SOUTH); - - // create list with the sample designs - this.list = new javax.swing.JList(this.list_model); - fill_list(); - this.list.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); - this.list.setSelectedIndex(0); - this.list.setVisibleRowCount(p_row_count); - this.list.addMouseListener(new java.awt.event.MouseAdapter() - { - public void mouseClicked(java.awt.event.MouseEvent evt) - { - if (evt.getClickCount() > 1) - { - button_pushed(); - } - } - }); - - javax.swing.JScrollPane list_scroll_pane = new javax.swing.JScrollPane(this.list); - list_scroll_pane.setPreferredSize(new java.awt.Dimension(200, 20 * p_row_count)); - main_panel.add(list_scroll_pane, java.awt.BorderLayout.CENTER); - this.pack(); - } - - - /** - * Fill the list with the examples. - */ - protected abstract void fill_list(); - - /** - * Action to be perfomed. when the button is pushed after selecting an item in the list. - */ - protected abstract void button_pushed(); - - /** - * Opens a zipped archive from an URL in the net. - * Returns a zipped input stream, who is positioned at the start of p_file_name, - * or null, if an error occured, - */ - protected static ZipInputStream open_zipped_file(String p_archive_name, String p_file_name) - { - String archive_path_name = MainApplication.WEB_FILE_BASE_NAME + p_archive_name + ".zip"; - URL archive_url = null; - try - { - archive_url = new URL(archive_path_name); - } - catch(java.net.MalformedURLException e) - { - return null; - } - java.io.InputStream input_stream = null; - ZipInputStream zip_input_stream = null; - URLConnection net_connection = null; - try - { - net_connection = archive_url.openConnection(); - } - catch (Exception e) - { - return null; - } - try - { - input_stream = net_connection.getInputStream(); - } - catch (java.io.IOException e) - { - return null; - } - catch (java.security.AccessControlException e) - { - return null; - } - try - { - zip_input_stream = new ZipInputStream(input_stream); - } - catch (Exception e) - { - WindowMessage.show("unable to get zip input stream"); - return null; - } - String compare_name = p_archive_name + "/" + p_file_name; - java.util.zip.ZipEntry curr_entry = null; - for (;;) - { - try - { - curr_entry = zip_input_stream.getNextEntry(); - } - catch (Exception E) - { - return null; - } - if (curr_entry == null) - { - return null; - } - String design_name = curr_entry.getName(); - if (design_name.equals(compare_name)) - { - break; - } - } - return zip_input_stream; - } - - - /** - * Opens a sample design on the website. - */ - protected static BoardFrame open_design(String p_archive_name, String p_design_name, java.util.Locale p_locale) - { - ZipInputStream zip_input_stream = open_zipped_file(p_archive_name, p_design_name); - if (zip_input_stream == null) - { - return null; - } - DesignFile design_file = DesignFile.get_instance("sharc_routed.dsn", true); - BoardFrame new_frame = - new BoardFrame(design_file, BoardFrame.Option.WEBSTART, board.TestLevel.RELEASE_VERSION, - p_locale, false); - boolean read_ok = new_frame.read(zip_input_stream, true, null); - if (!read_ok) - { - return null; - } - new_frame.setVisible(true); - return new_frame; - } - - protected final java.util.ResourceBundle resources; - protected final java.util.Locale locale; - - protected javax.swing.DefaultListModel list_model = new javax.swing.DefaultListModel(); - protected final javax.swing.JList list; - - private class OpenListener implements java.awt.event.ActionListener - { - public void actionPerformed(java.awt.event.ActionEvent p_evt) - { - button_pushed(); - } - } -} diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..a266dd0 --- /dev/null +++ b/pom.xml @@ -0,0 +1,187 @@ + + 4.0.0 + net.freerouting + freerouting + 1.0.2-SNAPSHOT + jar + + ISO-8859-1 + ISO-8859-1 + -Xdoclint:none + + + + https://github.com/nick-less/freerouting/issues + GitHub Issues + + + + + GNU General Public License (GPL) + http://www.gnu.org/licenses/gpl.txt + + + + + + https://github.com/nick-less/freerouting + scm:git:git://github.com/nick-less/freerouting.git + scm:git:git@github.com:nick-less/freerouting.git + + + + alfons + Alfons Wirtz + + developer + + + + nick-less + + developer + + + + + + + org.apache.maven.plugins + maven-project-info-reports-plugin + 3.9.0 + + true + true + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.12.0 + + + org.apache.maven.plugins + maven-surefire-report-plugin + 3.5.4 + + + org.apache.maven.plugins + maven-checkstyle-plugin + 3.6.0 + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.5.0 + + + true + + true + true + true + gui.MainApplication + + + development + ${project.url} + value + + + + + + commons-io + commons-io + 2.21.0 + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.12.0 + + + + jar + + + + + + org.apache.maven.plugins + maven-source-plugin + 3.4.0 + + + + jar + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.14.1 + + 1.7 + 1.7 + + + + maven-assembly-plugin + + + package + + single + + + + + + + gui.MainApplication + + + + jar-with-dependencies + + + + + + + + javax.help + javahelp + 2.0.05 + + + org.slf4j + slf4j-api + 2.0.17 + + + org.slf4j + slf4j-simple + 2.0.17 + + + + + github + GitHub nick-less Apache Maven Packages + https://maven.pkg.github.com/nick-less + + + + diff --git a/autoroute/AutorouteControl.java b/src/main/java/autoroute/AutorouteControl.java similarity index 93% rename from autoroute/AutorouteControl.java rename to src/main/java/autoroute/AutorouteControl.java index d9f9611..1f7569b 100644 --- a/autoroute/AutorouteControl.java +++ b/src/main/java/autoroute/AutorouteControl.java @@ -30,18 +30,33 @@ * Structure for controlling the autoroute algorithm. * * @author Alfons Wirtz + * @version $Id: $Id */ public class AutorouteControl { - /** Creates a new instance of AutorouteControl for the input net */ + /** + * Creates a new instance of AutorouteControl for the input net + * + * @param p_board a {@link board.RoutingBoard} object. + * @param p_net_no a int. + * @param p_settings a {@link interactive.Settings} object. + */ public AutorouteControl(RoutingBoard p_board, int p_net_no, interactive.Settings p_settings) { this(p_board, p_settings, p_settings.autoroute_settings.get_trace_cost_arr()); init_net(p_net_no, p_board, p_settings.autoroute_settings.get_via_costs()); } - /** Creates a new instance of AutorouteControl for the input net */ + /** + * Creates a new instance of AutorouteControl for the input net + * + * @param p_board a {@link board.RoutingBoard} object. + * @param p_net_no a int. + * @param p_settings a {@link interactive.Settings} object. + * @param p_via_costs a int. + * @param p_trace_cost_arr an array of {@link autoroute.AutorouteControl.ExpansionCostFactor} objects. + */ public AutorouteControl(RoutingBoard p_board, int p_net_no, interactive.Settings p_settings, int p_via_costs, ExpansionCostFactor[] p_trace_cost_arr) { this(p_board, p_settings, p_trace_cost_arr); diff --git a/src/main/java/autoroute/AutorouteEngine.java b/src/main/java/autoroute/AutorouteEngine.java new file mode 100644 index 0000000..3c7e03e --- /dev/null +++ b/src/main/java/autoroute/AutorouteEngine.java @@ -0,0 +1,644 @@ +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * AutorouteEngine.java + * + * Created on 11. Januar 2004, 11:14 + */ +package autoroute; + +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import board.Item; +import board.RoutingBoard; +import board.SearchTreeObject; +import board.ShapeSearchTree; +import board.ShapeSearchTree45Degree; +import board.ShapeSearchTree90Degree; +import board.TestLevel; +import datastructures.Stoppable; +import datastructures.TimeLimit; +import geometry.planar.Line; +import geometry.planar.Simplex; +import geometry.planar.TileShape; + +/** + * Temporary autoroute data stored on the RoutingBoard. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class AutorouteEngine { + private static final Logger LOGGER = LoggerFactory.getLogger(AutorouteEngine.class); + + /** + * Creates a new instance of BoardAoutorouteEngine If p_maintain_database, the + * autorouter database is maintained after a connection is completed for + * performance reasons. + * + * @param p_board a {@link board.RoutingBoard} object. + * @param p_trace_clearance_class_no a int. + * @param p_maintain_database a boolean. + */ + public AutorouteEngine(RoutingBoard p_board, int p_trace_clearance_class_no, boolean p_maintain_database) { + this.board = p_board; + this.maintain_database = p_maintain_database; + this.net_no = -1; + this.autoroute_search_tree = p_board.search_tree_manager.get_autoroute_tree(p_trace_clearance_class_no); + int max_drill_page_width = (int) (5 * p_board.rules.get_default_via_diameter()); + max_drill_page_width = Math.max(max_drill_page_width, 10000); + this.drill_page_array = new DrillPageArray(this.board, max_drill_page_width); + this.stoppable_thread = null; + } + + /** + *

+ * init_connection. + *

+ * + * @param p_net_no a int. + * @param p_stoppable_thread a {@link datastructures.Stoppable} object. + * @param p_time_limit a {@link datastructures.TimeLimit} object. + */ + public void init_connection(int p_net_no, Stoppable p_stoppable_thread, TimeLimit p_time_limit) { + if (this.maintain_database) { + if (p_net_no != this.net_no) { + if (this.complete_expansion_rooms != null) { + // invalidate the net dependent complete free space expansion rooms. + Collection rooms_to_remove = new LinkedList(); + for (CompleteFreeSpaceExpansionRoom curr_room : complete_expansion_rooms) { + if (curr_room.is_net_dependent()) { + rooms_to_remove.add(curr_room); + } + } + for (CompleteFreeSpaceExpansionRoom curr_room : rooms_to_remove) { + this.remove_complete_expansion_room(curr_room); + } + } + // invalidate the neighbour rooms of the items of p_net_no + Collection item_list = this.board.get_items(); + for (Item curr_item : item_list) { + if (curr_item.contains_net(p_net_no)) { + this.board.additional_update_after_change(curr_item); + } + } + } + } + this.net_no = p_net_no; + this.stoppable_thread = p_stoppable_thread; + this.time_limit = p_time_limit; + } + + /* + * Autoroutes a connection between p_start_set and p_dest_set. Returns + * ALREADY_CONNECTED, ROUTED, NOT_ROUTED, or INSERT_ERROR. + */ + /** + *

+ * autoroute_connection. + *

+ * + * @param p_start_set a {@link java.util.Set} object. + * @param p_dest_set a {@link java.util.Set} object. + * @param p_ctrl a {@link autoroute.AutorouteControl} object. + * @param p_ripped_item_list a {@link java.util.SortedSet} object. + * @return a {@link autoroute.AutorouteEngine.AutorouteResult} object. + */ + public AutorouteResult autoroute_connection(Set p_start_set, Set p_dest_set, AutorouteControl p_ctrl, + SortedSet p_ripped_item_list) { + MazeSearchAlgo maze_search_algo; + try { + maze_search_algo = MazeSearchAlgo.get_instance(p_start_set, p_dest_set, this, p_ctrl); + } catch (Exception e) { + LOGGER.error("AutorouteEngine.autoroute_connection: Exception in MazeSearchAlgo.get_instance"); + LOGGER.error(e.getMessage(), e); + + maze_search_algo = null; + } + MazeSearchAlgo.Result search_result = null; + if (maze_search_algo != null) { + try { + search_result = maze_search_algo.find_connection(); + } catch (Exception e) { + LOGGER.error("AutorouteEngine.autoroute_connection: Exception in maze_search_algo.find_connection"); + LOGGER.error(e.getMessage(), e); + } + } + LocateFoundConnectionAlgo autoroute_result = null; + if (search_result != null) { + try { + autoroute_result = LocateFoundConnectionAlgo.get_instance(search_result, p_ctrl, + this.autoroute_search_tree, board.rules.get_trace_angle_restriction(), p_ripped_item_list, + board.get_test_level()); + } catch (Exception e) { + LOGGER.error( + "AutorouteEngine.autoroute_connection: Exception in LocateFoundConnectionAlgo.get_instance"); + LOGGER.error(e.getMessage(), e); + } + } + if (!this.maintain_database) { + this.clear(); + } else { + this.reset_all_doors(); + } + if (autoroute_result == null) { + return AutorouteResult.NOT_ROUTED; + } + if (autoroute_result.connection_items == null) { + if (this.board.get_test_level().ordinal() >= TestLevel.CRITICAL_DEBUGGING_OUTPUT.ordinal()) { + LOGGER.warn("AutorouteEngine.autoroute_connection: result_items != null expected"); + } + return AutorouteResult.ALREADY_CONNECTED; + } + // Delete the ripped connections. + SortedSet ripped_connections = new TreeSet(); + Set changed_nets = new TreeSet(); + Item.StopConnectionOption stop_connection_option; + if (p_ctrl.remove_unconnected_vias) { + stop_connection_option = Item.StopConnectionOption.NONE; + } else { + stop_connection_option = Item.StopConnectionOption.FANOUT_VIA; + } + + for (Item curr_ripped_item : p_ripped_item_list) { + ripped_connections.addAll(curr_ripped_item.get_connection_items(stop_connection_option)); + for (int i = 0; i < curr_ripped_item.net_count(); ++i) { + changed_nets.add(curr_ripped_item.get_net_no(i)); + } + } + // let the observers know the changes in the board database. + boolean observers_activated = !this.board.observers_active(); + if (observers_activated) { + this.board.start_notify_observers(); + } + + board.remove_items(ripped_connections, false); + + for (int curr_net_no : changed_nets) { + this.board.remove_trace_tails(curr_net_no, stop_connection_option); + } + InsertFoundConnectionAlgo insert_found_connection_algo = InsertFoundConnectionAlgo + .get_instance(autoroute_result, board, p_ctrl); + + if (observers_activated) { + this.board.end_notify_observers(); + } + if (insert_found_connection_algo == null) { + return AutorouteResult.INSERT_ERROR; + } + return AutorouteResult.ROUTED; + } + + /** + * Returns the net number of the current connection to route. + * + * @return a int. + */ + public int get_net_no() { + return this.net_no; + } + + /** + * Returns if the user has stopped the autorouter. + * + * @return a boolean. + */ + public boolean is_stop_requested() { + if (this.time_limit != null) { + if (this.time_limit.limit_exceeded()) { + return true; + } + } + if (this.stoppable_thread == null) { + return false; + } + return this.stoppable_thread.is_stop_requested(); + } + + /** + * Clears all temporary data + */ + public void clear() { + if (complete_expansion_rooms != null) { + for (CompleteFreeSpaceExpansionRoom curr_room : complete_expansion_rooms) { + curr_room.remove_from_tree(this.autoroute_search_tree); + } + } + complete_expansion_rooms = null; + incomplete_expansion_rooms = null; + expansion_room_instance_count = 0; + board.clear_all_item_temporary_autoroute_data(); + } + + /** + * Draws the shapes of the expansion rooms created so far. + * + * @param p_graphics a {@link java.awt.Graphics} object. + * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object. + * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object. + * @param p_intensity a double. + */ + public void draw(java.awt.Graphics p_graphics, boardgraphics.GraphicsContext p_graphics_context, + double p_intensity) { + if (complete_expansion_rooms == null) { + return; + } + for (CompleteFreeSpaceExpansionRoom curr_room : complete_expansion_rooms) { + curr_room.draw(p_graphics, p_graphics_context, p_intensity); + } + Collection item_list = this.board.get_items(); + for (Item curr_item : item_list) { + ItemAutorouteInfo autoroute_info = curr_item.get_autoroute_info(); + if (autoroute_info != null) { + autoroute_info.draw(p_graphics, p_graphics_context, p_intensity); + } + } + // this.drill_page_array.draw(p_graphics, p_graphics_context, p_intensity); + } + + /** + * Creates a new FreeSpaceExpansionRoom and adds it to the room list. Its shape + * is normally unbounded at construction time of the room. The final (completed) + * shape will be a subshape of the start shape, which does not overlap with any + * obstacle, and it is as big as possible. p_contained_points will remain + * contained in the shape, after it is completed. + * + * @param p_shape a {@link geometry.planar.TileShape} object. + * @param p_layer a int. + * @param p_contained_shape a {@link geometry.planar.TileShape} object. + * @return a {@link autoroute.IncompleteFreeSpaceExpansionRoom} object. + */ + public IncompleteFreeSpaceExpansionRoom add_incomplete_expansion_room(TileShape p_shape, int p_layer, + TileShape p_contained_shape) { + IncompleteFreeSpaceExpansionRoom new_room = new IncompleteFreeSpaceExpansionRoom(p_shape, p_layer, + p_contained_shape); + if (this.incomplete_expansion_rooms == null) { + this.incomplete_expansion_rooms = new LinkedList(); + } + this.incomplete_expansion_rooms.add(new_room); + return new_room; + } + + /** + * Returns the first elemment in the list of incomplete expansion rooms or null, + * if the list is empty. + * + * @return a {@link autoroute.IncompleteFreeSpaceExpansionRoom} object. + */ + public IncompleteFreeSpaceExpansionRoom get_first_incomplete_expansion_room() { + if (incomplete_expansion_rooms == null) { + return null; + } + if (incomplete_expansion_rooms.isEmpty()) { + return null; + } + Iterator it = incomplete_expansion_rooms.iterator(); + return it.next(); + } + + /** + * Removes an incomplete room from the database. + * + * @param p_room a {@link autoroute.IncompleteFreeSpaceExpansionRoom} object. + */ + public void remove_incomplete_expansion_room(IncompleteFreeSpaceExpansionRoom p_room) { + this.remove_all_doors(p_room); + incomplete_expansion_rooms.remove(p_room); + } + + /** + * Removes a complete expansion room from the database and creates new + * incomplete expansion rooms for the neighbours. + * + * @param p_room a {@link autoroute.CompleteFreeSpaceExpansionRoom} object. + */ + public void remove_complete_expansion_room(CompleteFreeSpaceExpansionRoom p_room) { + // create new incomplete expansion rooms for all neighbours + TileShape room_shape = p_room.get_shape(); + int room_layer = p_room.get_layer(); + Collection room_doors = p_room.get_doors(); + for (ExpansionDoor curr_door : room_doors) { + ExpansionRoom curr_neighbour = curr_door.other_room(p_room); + if (curr_neighbour != null) { + curr_neighbour.remove_door(curr_door); + TileShape neighbour_shape = curr_neighbour.get_shape(); + TileShape intersection = room_shape.intersection(neighbour_shape); + if (intersection.dimension() == 1) { + // add a new incomplete room to curr_neighbour. + int[] touching_sides = room_shape.touching_sides(neighbour_shape); + Line[] line_arr = new Line[1]; + line_arr[0] = neighbour_shape.border_line(touching_sides[1]).opposite(); + Simplex new_incomplete_room_shape = Simplex.get_instance(line_arr); + IncompleteFreeSpaceExpansionRoom new_incomplete_room = add_incomplete_expansion_room( + new_incomplete_room_shape, room_layer, intersection); + ExpansionDoor new_door = new ExpansionDoor(curr_neighbour, new_incomplete_room, 1); + curr_neighbour.add_door(new_door); + new_incomplete_room.add_door(new_door); + } + } + } + this.remove_all_doors(p_room); + p_room.remove_from_tree(this.autoroute_search_tree); + if (complete_expansion_rooms != null) { + complete_expansion_rooms.remove(p_room); + } else { + LOGGER.info("AutorouteEngine.remove_complete_expansion_room: this.complete_expansion_rooms is null"); + } + this.drill_page_array.invalidate(room_shape); + } + + /** + * Completes the shape of p_room. Returns the resulting rooms after completing + * the shape. p_room will no more exist after this function. + * + * @param p_room a {@link autoroute.IncompleteFreeSpaceExpansionRoom} object. + * @return a {@link java.util.Collection} object. + */ + public Collection complete_expansion_room(IncompleteFreeSpaceExpansionRoom p_room) { + + try { + Collection result = new LinkedList(); + TileShape from_door_shape = null; + SearchTreeObject ignore_object = null; + Collection room_doors = p_room.get_doors(); + for (ExpansionDoor curr_door : room_doors) { + ExpansionRoom other_room = curr_door.other_room(p_room); + if (other_room instanceof CompleteFreeSpaceExpansionRoom && curr_door.dimension == 2) { + from_door_shape = curr_door.get_shape(); + ignore_object = (CompleteFreeSpaceExpansionRoom) other_room; + break; + } + } + Collection completed_shapes = this.autoroute_search_tree + .complete_shape(p_room, this.net_no, ignore_object, from_door_shape); + this.remove_incomplete_expansion_room(p_room); + Iterator it = completed_shapes.iterator(); + boolean is_first_completed_room = true; + while (it.hasNext()) { + IncompleteFreeSpaceExpansionRoom curr_incomplete_room = it.next(); + if (curr_incomplete_room.get_shape().dimension() != 2) { + continue; + } + if (is_first_completed_room) { + is_first_completed_room = false; + CompleteFreeSpaceExpansionRoom completed_room = this.add_complete_room(curr_incomplete_room); + if (completed_room != null) { + result.add(completed_room); + } + } else { + // the shape of the first completed room may have changed and may + // intersect now with the other shapes. Therefore the completed shapes + // have to be recalculated. + Collection curr_completed_shapes = this.autoroute_search_tree + .complete_shape(curr_incomplete_room, this.net_no, ignore_object, from_door_shape); + Iterator it2 = curr_completed_shapes.iterator(); + while (it2.hasNext()) { + IncompleteFreeSpaceExpansionRoom tmp_room = it2.next(); + CompleteFreeSpaceExpansionRoom completed_room = this.add_complete_room(tmp_room); + if (completed_room != null) { + result.add(completed_room); + } + } + } + } + return result; + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + return new LinkedList(); + } + + } + + /** + * Calculates the doors and adds the completed room to the room database. + */ + private CompleteFreeSpaceExpansionRoom add_complete_room(IncompleteFreeSpaceExpansionRoom p_room) { + CompleteFreeSpaceExpansionRoom completed_room = (CompleteFreeSpaceExpansionRoom) calculate_doors(p_room); + CompleteFreeSpaceExpansionRoom result; + if (completed_room != null && completed_room.get_shape().dimension() == 2) { + if (complete_expansion_rooms == null) { + complete_expansion_rooms = new LinkedList(); + } + complete_expansion_rooms.add(completed_room); + this.autoroute_search_tree.insert(completed_room); + result = completed_room; + } else { + result = null; + } + return result; + } + + /** + * Calculates the neighbours of p_room and inserts doors to the new created + * neighbour rooms. The shape of the result room may be different to the shape + * of p_room + */ + private CompleteExpansionRoom calculate_doors(ExpansionRoom p_room) { + CompleteExpansionRoom result; + if (this.autoroute_search_tree instanceof ShapeSearchTree90Degree) { + result = SortedOrthogonalRoomNeighbours.calculate(p_room, this); + } else if (this.autoroute_search_tree instanceof ShapeSearchTree45Degree) { + result = Sorted45DegreeRoomNeighbours.calculate(p_room, this); + } else { + result = SortedRoomNeighbours.calculate(p_room, this); + } + return result; + } + + /** + * Completes the shapes of the neigbour rooms of p_room, so that the doors of + * p_room will not change later on. + * + * @param p_room a {@link autoroute.CompleteExpansionRoom} object. + */ + public void complete_neigbour_rooms(CompleteExpansionRoom p_room) { + if (p_room.get_doors() == null) { + return; + } + Iterator it = p_room.get_doors().iterator(); + while (it.hasNext()) { + ExpansionDoor curr_door = it.next(); + // cast to ExpansionRoom becaus ExpansionDoor.other_room works differently with + // parameter type CompleteExpansionRoom. + ExpansionRoom neighbour_room = curr_door.other_room((ExpansionRoom) p_room); + if (neighbour_room != null) { + if (neighbour_room instanceof IncompleteFreeSpaceExpansionRoom) { + this.complete_expansion_room((IncompleteFreeSpaceExpansionRoom) neighbour_room); + // restart reading because the doors have changed + it = p_room.get_doors().iterator(); + } else if (neighbour_room instanceof ObstacleExpansionRoom) { + ObstacleExpansionRoom obstacle_neighbour_room = (ObstacleExpansionRoom) neighbour_room; + if (!obstacle_neighbour_room.all_doors_calculated()) { + this.calculate_doors(obstacle_neighbour_room); + obstacle_neighbour_room.set_doors_calculated(true); + } + } + } + } + } + + /** + * Invalidates all drill pages intersecting with p_shape, so the they must be + * recalculated at the next call of get_ddrills() + * + * @param p_shape a {@link geometry.planar.TileShape} object. + */ + public void invalidate_drill_pages(TileShape p_shape) { + this.drill_page_array.invalidate(p_shape); + } + + /** + * Removes all doors from p_room + */ + void remove_all_doors(ExpansionRoom p_room) { + + Iterator it = p_room.get_doors().iterator(); + while (it.hasNext()) { + ExpansionDoor curr_door = it.next(); + ExpansionRoom other_room = curr_door.other_room(p_room); + if (other_room != null) { + other_room.remove_door(curr_door); + if (other_room instanceof IncompleteFreeSpaceExpansionRoom) { + this.remove_incomplete_expansion_room((IncompleteFreeSpaceExpansionRoom) other_room); + } + } + } + p_room.clear_doors(); + } + + /** + * Returns all complete free space expansion rooms with a target door to an item + * in the set p_items. + */ + Set get_rooms_with_target_items(Set p_items) { + Set result = new TreeSet(); + if (this.complete_expansion_rooms != null) { + for (CompleteFreeSpaceExpansionRoom curr_room : this.complete_expansion_rooms) { + Collection target_door_list = curr_room.get_target_doors(); + for (TargetItemExpansionDoor curr_target_door : target_door_list) { + Item curr_target_item = curr_target_door.item; + if (p_items.contains(curr_target_item)) { + result.add(curr_room); + } + } + } + } + return result; + } + + /** + * Checks, if the internal datastructure is valid. + * + * @return a boolean. + */ + public boolean validate() { + if (complete_expansion_rooms == null) { + return true; + } + boolean result = true; + for (CompleteFreeSpaceExpansionRoom curr_room : complete_expansion_rooms) { + if (!curr_room.validate(this)) { + result = false; + } + } + return result; + } + + /** + * Reset all doors for autorouting the next connnection, in case the autorouting + * database is retained. + */ + private void reset_all_doors() { + if (this.complete_expansion_rooms != null) { + for (ExpansionRoom curr_room : this.complete_expansion_rooms) { + curr_room.reset_doors(); + } + } + Collection item_list = this.board.get_items(); + for (Item curr_item : item_list) { + ItemAutorouteInfo curr_autoroute_info = curr_item.get_autoroute_info_pur(); + if (curr_autoroute_info != null) { + curr_autoroute_info.reset_doors(); + curr_autoroute_info.set_precalculated_connection(null); + } + } + this.drill_page_array.reset(); + } + + /** + *

+ * generate_room_id_no. + *

+ * + * @return a int. + */ + protected int generate_room_id_no() { + ++expansion_room_instance_count; + return expansion_room_instance_count; + } + + /** + * The current search tree used in autorouting. It depends on the trac clearance + * class used in the autoroute algorithm. + */ + public final ShapeSearchTree autoroute_search_tree; + /** + * If maintain_database, the autorouter database is maintained after a + * connection is completed for performance reasons. + */ + public final boolean maintain_database; + static final int TRACE_WIDTH_TOLERANCE = 2; + /** + * The net number used for routing in this autoroute algorithm. + */ + private int net_no; + /** + * The 2-dimensional array of rectangular pages of ExpansionDrills + */ + final DrillPageArray drill_page_array; + /** + * To be able to stop the expansion algorithm. + */ + Stoppable stoppable_thread; + /** + * To stop the expansion algorithm after a time limit is exceeded. + */ + private TimeLimit time_limit; + /** The PCB-board of this autoroute algorithm. */ + final RoutingBoard board; + /** The list of incomplete expansion rooms on the routing board */ + private List incomplete_expansion_rooms = null; + /** The list of complete expansion rooms on the routing board */ + private List complete_expansion_rooms = null; + /** The count of expansion rooms created so far */ + private int expansion_room_instance_count = 0; + + /** + * The pussible results of autorouting a connection + */ + public enum AutorouteResult { + + ALREADY_CONNECTED, ROUTED, NOT_ROUTED, INSERT_ERROR + } +} diff --git a/autoroute/BatchAutorouter.java b/src/main/java/autoroute/BatchAutorouter.java similarity index 96% rename from autoroute/BatchAutorouter.java rename to src/main/java/autoroute/BatchAutorouter.java index 5bdd0ca..79f5c87 100644 --- a/autoroute/BatchAutorouter.java +++ b/src/main/java/autoroute/BatchAutorouter.java @@ -37,8 +37,9 @@ /** * Handles the sequencing of the batch autoroute passes. - * + * * @author Alfons Wirtz + * @version $Id: $Id */ public class BatchAutorouter { @@ -48,6 +49,12 @@ public class BatchAutorouter * or if p_max_pass_count is exceeded. Is currently used in the optimize via batch pass. * Returns the number of oasses to complete the board or p_max_pass_count + 1, * if the board is not completed. + * + * @param p_thread a {@link interactive.InteractiveActionThread} object. + * @param p_max_pass_count a int. + * @param p_ripup_costs a int. + * @param p_with_prefered_directions a boolean. + * @return a int. */ public static int autoroute_passes_for_optimizing_item(InteractiveActionThread p_thread, int p_max_pass_count, int p_ripup_costs, boolean p_with_prefered_directions) @@ -78,6 +85,11 @@ public static int autoroute_passes_for_optimizing_item(InteractiveActionThread p /** * Creates a new batch autorouter. + * + * @param p_thread a {@link interactive.InteractiveActionThread} object. + * @param p_remove_unconnected_vias a boolean. + * @param p_with_preferred_directions a boolean. + * @param p_start_ripup_costs a int. */ public BatchAutorouter(InteractiveActionThread p_thread, boolean p_remove_unconnected_vias, boolean p_with_preferred_directions, int p_start_ripup_costs) @@ -108,6 +120,8 @@ public BatchAutorouter(InteractiveActionThread p_thread, boolean p_remove_unconn /** * Autoroutes ripup passes until the board is completed or the autorouter is stopped by the user. * Returns true if the board is completed. + * + * @return a boolean. */ public boolean autoroute_passes() { @@ -338,6 +352,8 @@ private boolean autoroute_item(Item p_item, int p_route_net_no, SortedSet /** * Returns the airline of the current autorouted connnection or null, * if no such airline exists + * + * @return a {@link geometry.planar.FloatLine} object. */ public FloatLine get_air_line() { diff --git a/autoroute/BatchFanout.java b/src/main/java/autoroute/BatchFanout.java similarity index 98% rename from autoroute/BatchFanout.java rename to src/main/java/autoroute/BatchFanout.java index f1d968c..330df31 100644 --- a/autoroute/BatchFanout.java +++ b/src/main/java/autoroute/BatchFanout.java @@ -28,12 +28,18 @@ /** * Handles the sequencing of the fanout inside the batch autorouter. - * + * * @author Alfons Wirtz + * @version $Id: $Id */ public class BatchFanout { + /** + *

fanout_board.

+ * + * @param p_thread a {@link interactive.InteractiveActionThread} object. + */ public static void fanout_board(InteractiveActionThread p_thread) { BatchFanout fanout_instance = new BatchFanout(p_thread); diff --git a/autoroute/BatchOptRoute.java b/src/main/java/autoroute/BatchOptRoute.java similarity index 98% rename from autoroute/BatchOptRoute.java rename to src/main/java/autoroute/BatchOptRoute.java index 18dfa3f..b51e177 100644 --- a/autoroute/BatchOptRoute.java +++ b/src/main/java/autoroute/BatchOptRoute.java @@ -34,14 +34,17 @@ /** * To optimize the vias and traces after the batch autorouter has completed the board. - * + * * @author Alfons Wirtz + * @version $Id: $Id */ public class BatchOptRoute { /** * To optimize the route on the board after the autoroute task is finished. + * + * @param p_thread a {@link interactive.InteractiveActionThread} object. */ public BatchOptRoute(InteractiveActionThread p_thread) { @@ -249,6 +252,8 @@ private static double calc_weighted_trace_length(RoutingBoard p_board) /** * Returns the current position of the item, which will be rerouted or null, if the optimizer is not active. + * + * @return a {@link geometry.planar.FloatPoint} object. */ public FloatPoint get_current_position() { diff --git a/autoroute/CompleteExpansionRoom.java b/src/main/java/autoroute/CompleteExpansionRoom.java similarity index 74% rename from autoroute/CompleteExpansionRoom.java rename to src/main/java/autoroute/CompleteExpansionRoom.java index fad0eb8..c1a0db5 100644 --- a/autoroute/CompleteExpansionRoom.java +++ b/src/main/java/autoroute/CompleteExpansionRoom.java @@ -1,47 +1,58 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * CompleteExpansionRoom.java - * - * Created on 16. April 2006, 07:47 - * - */ - -package autoroute; - -import java.util.Collection; - -/** - * - * @author alfons - */ -public interface CompleteExpansionRoom extends ExpansionRoom -{ - - /** - * Returns the list of doors to target items of this room - */ - Collection get_target_doors(); - - /** - * Returns the object of tthis complete_expansion_rooom. - */ - board.SearchTreeObject get_object(); - - /** - * Draws the shape of this room for test purposes - */ - void draw(java.awt.Graphics p_graphics, boardgraphics.GraphicsContext p_graphics_context, double p_intensity); -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * CompleteExpansionRoom.java + * + * Created on 16. April 2006, 07:47 + * + */ + +package autoroute; + +import java.util.Collection; + +/** + *

CompleteExpansionRoom interface.

+ * + * @author alfons + * @version $Id: $Id + */ +public interface CompleteExpansionRoom extends ExpansionRoom +{ + + /** + * Returns the list of doors to target items of this room + * + * @return a {@link java.util.Collection} object. + */ + Collection get_target_doors(); + + /** + * Returns the object of tthis complete_expansion_rooom. + * + * @return a {@link board.SearchTreeObject} object. + */ + board.SearchTreeObject get_object(); + + /** + * Draws the shape of this room for test purposes + * + * @param p_graphics a {@link java.awt.Graphics} object. + * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object. + * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object. + * @param p_intensity a double. + */ + void draw(java.awt.Graphics p_graphics, boardgraphics.GraphicsContext p_graphics_context, double p_intensity); +} diff --git a/autoroute/CompleteFreeSpaceExpansionRoom.java b/src/main/java/autoroute/CompleteFreeSpaceExpansionRoom.java similarity index 88% rename from autoroute/CompleteFreeSpaceExpansionRoom.java rename to src/main/java/autoroute/CompleteFreeSpaceExpansionRoom.java index ad41913..374e33b 100644 --- a/autoroute/CompleteFreeSpaceExpansionRoom.java +++ b/src/main/java/autoroute/CompleteFreeSpaceExpansionRoom.java @@ -39,12 +39,17 @@ * so that it can be stored in a shape tree. * * @author Alfons Wirtz + * @version $Id: $Id */ public class CompleteFreeSpaceExpansionRoom extends FreeSpaceExpansionRoom implements CompleteExpansionRoom, SearchTreeObject { /** * Creates a new instance of CompleteFreeSpaceExpansionRoom + * + * @param p_shape a {@link geometry.planar.TileShape} object. + * @param p_layer a int. + * @param p_id_no a int. */ public CompleteFreeSpaceExpansionRoom(TileShape p_shape, int p_layer, int p_id_no) { @@ -53,11 +58,13 @@ public CompleteFreeSpaceExpansionRoom(TileShape p_shape, int p_layer, int p_id_n id_no = p_id_no; } + /** {@inheritDoc} */ public void set_search_tree_entries(ShapeTree.Leaf [] p_entries, ShapeTree p_tree) { tree_entries = p_entries; } + /** {@inheritDoc} */ public int compareTo(Object p_other) { int result; @@ -74,32 +81,39 @@ public int compareTo(Object p_other) /** * Removes the tree entries of this roomm from p_shape_tree. + * + * @param p_shape_tree a {@link datastructures.ShapeTree} object. */ public void remove_from_tree(ShapeTree p_shape_tree) { p_shape_tree.remove(this.tree_entries); } + /** {@inheritDoc} */ public int tree_shape_count(ShapeTree p_shape_tree) { return 1; } + /** {@inheritDoc} */ public TileShape get_tree_shape(ShapeTree p_shape_tree, int p_index) { return this.get_shape(); } + /** {@inheritDoc} */ public int shape_layer(int p_index) { return this.get_layer(); } + /** {@inheritDoc} */ public boolean is_obstacle(int p_net_no) { return true; } + /** {@inheritDoc} */ public boolean is_trace_obstacle(int p_net_no) { return true; @@ -116,6 +130,8 @@ public void set_net_dependent() /** * Returns, if the room overlaps with net dependent objects. * In this case it cannot be retained, when the net number changes in autorouting. + * + * @return a boolean. */ public boolean is_net_dependent() { @@ -124,6 +140,8 @@ public boolean is_net_dependent() /** * Returns the list doors to target items of this room + * + * @return a {@link java.util.Collection} object. */ public Collection get_target_doors() { @@ -132,12 +150,15 @@ public Collection get_target_doors() /** * Adds p_door to the list of target doors of this room. + * + * @param p_door a {@link autoroute.TargetItemExpansionDoor} object. */ public void add_target_door(TargetItemExpansionDoor p_door) { this.target_doors.add(p_door); } + /** {@inheritDoc} */ public boolean remove_door(ExpandableObject p_door) { boolean result; @@ -152,6 +173,11 @@ public boolean remove_door(ExpandableObject p_door) return result; } + /** + *

get_object.

+ * + * @return a {@link board.SearchTreeObject} object. + */ public SearchTreeObject get_object() { return this; @@ -159,6 +185,10 @@ public SearchTreeObject get_object() /** * Calculates the doors to the start and destination items of the autoroute algorithm. + * + * @param p_own_net_object a {@link datastructures.ShapeTree.TreeEntry} object. + * @param p_net_no a int. + * @param p_autoroute_search_tree a {@link board.ShapeSearchTree} object. */ public void calculate_target_doors(ShapeTree.TreeEntry p_own_net_object, int p_net_no, ShapeSearchTree p_autoroute_search_tree) { @@ -184,6 +214,8 @@ public void calculate_target_doors(ShapeTree.TreeEntry p_own_net_object, int p_ } /** + * {@inheritDoc} + * * Draws the shape of this room. */ public void draw(java.awt.Graphics p_graphics, boardgraphics.GraphicsContext p_graphics_context, double p_intensity) @@ -196,6 +228,9 @@ public void draw(java.awt.Graphics p_graphics, boardgraphics.GraphicsContext p_g /** * Check, if this FreeSpaceExpansionRoom is valid. + * + * @param p_autoroute_engine a {@link autoroute.AutorouteEngine} object. + * @return a boolean. */ public boolean validate( AutorouteEngine p_autoroute_engine) { @@ -243,6 +278,9 @@ public void clear_doors() this.target_doors = new LinkedList(); } + /** + *

reset_doors.

+ */ public void reset_doors() { super.reset_doors(); diff --git a/autoroute/Connection.java b/src/main/java/autoroute/Connection.java similarity index 97% rename from autoroute/Connection.java rename to src/main/java/autoroute/Connection.java index 2cfc9de..b96c532 100644 --- a/autoroute/Connection.java +++ b/src/main/java/autoroute/Connection.java @@ -1,215 +1,223 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * Connection.java - * - * Created on 4. Juni 2006, 07:24 - * - */ - -package autoroute; - -import java.util.Collection; -import java.util.Set; -import java.util.TreeSet; - -import geometry.planar.Point; - -import board.Item; -import board.Trace; - -/** - * Describes a routing connection ending at the next fork or terminal item. - * - * @author Alfons Wirtz - */ -public class Connection -{ - - /** - * Gets the connection this item belongs to. A connection ends at the next fork or terminal item. - * Returns null, if p_item is not a route item, or if it is a via belonging to more than 1 connection. - */ - public static Connection get(Item p_item) - { - if (!p_item.is_route()) - { - return null; - } - Connection precalculated_connection = p_item.get_autoroute_info().get_precalculated_connection(); - if (precalculated_connection != null) - { - return precalculated_connection; - } - Set contacts = p_item.get_normal_contacts(); - Set connection_items = new TreeSet(); - connection_items.add(p_item); - - Point start_point = null; - int start_layer = 0; - Point end_point = null; - int end_layer = 0; - - for (Item curr_item : contacts) - { - Point prev_contact_point = p_item.normal_contact_point(curr_item); - if (prev_contact_point == null) - { - // no unique contact point - continue; - } - int prev_contact_layer = p_item.first_common_layer(curr_item); - boolean fork_found = false; - if (p_item instanceof Trace) - { - // Check, that there is only 1 contact at this location. - // Only for pins and vias items of more than 1 connection - // are collected - Trace start_trace = (Trace) p_item; - Collection check_contacts = start_trace.get_normal_contacts(prev_contact_point, false); - if (check_contacts.size() != 1) - { - fork_found = true; - } - } - // Search from curr_item along the contacts - // until the next fork or nonroute item. - for (;;) - { - if(!curr_item.is_route() || fork_found) - { - // connection ends - if (start_point == null) - { - start_point = prev_contact_point; - start_layer = prev_contact_layer; - } - else if (!prev_contact_point.equals(start_point)) - { - end_point = prev_contact_point; - end_layer = prev_contact_layer; - } - break; - } - connection_items.add(curr_item); - Collection curr_item_contacts = curr_item.get_normal_contacts(); - // filter the contacts at the previous contact point, - // because we were already there. - // If then there is not exactly 1 new contact left, there is - // a stub or a fork. - Point next_contact_point = null; - int next_contact_layer = -1; - Item next_contact = null; - for (Item tmp_contact : curr_item_contacts) - { - int tmp_contact_layer = curr_item.first_common_layer(tmp_contact); - if (tmp_contact_layer >= 0) - { - Point tmp_contact_point = curr_item.normal_contact_point(tmp_contact); - if (tmp_contact_point == null) - { - // no unique contact point - fork_found = true; - break; - } - if (prev_contact_layer != tmp_contact_layer || - !prev_contact_point.equals(tmp_contact_point)) - { - next_contact_point = tmp_contact_point; - next_contact_layer = tmp_contact_layer; - if (next_contact != null) - { - // second new contact found - fork_found = true; - break; - } - next_contact = tmp_contact; - } - } - } - if (next_contact == null) - { - break; - } - curr_item = next_contact; - prev_contact_point = next_contact_point; - prev_contact_layer = next_contact_layer; - } - } - Connection result = new Connection(start_point, start_layer, end_point, end_layer, connection_items); - for (Item curr_item : connection_items) - { - curr_item.get_autoroute_info().set_precalculated_connection(result); - } - return result; - } - - /** - * Creates a new instance of Connection - */ - private Connection(Point p_start_point, int p_start_layer, Point p_end_point, int p_end_layer, Set p_item_list) - { - start_point = p_start_point; - start_layer = p_start_layer; - end_point = p_end_point; - end_layer = p_end_layer; - item_list = p_item_list; - } - - /** - * Returns the cumulative length of the traces in this connection. - */ - public double trace_length() - { - double result = 0; - for (Item curr_item : item_list) - { - if (curr_item instanceof Trace) - { - result += ((Trace) curr_item).get_length(); - } - } - return result; - } - - - /** - * Returns an estimation of the actual length of the connection divided by the minimal possible length. - */ - public double get_detour() - { - if (start_point == null || end_point == null) - { - return Integer.MAX_VALUE; - } - double min_trace_length = start_point.to_float().distance(end_point.to_float()); - double detour = (this.trace_length() + DETOUR_ADD) / (min_trace_length + DETOUR_ADD) + - DETOUR_ITEM_COST * (item_list.size() - 1); - return detour; - } - - - /** - * If the connection ens in empty space, start_point or end_point may be null. - */ - public final Point start_point; - public final int start_layer; - public final Point end_point; - public final int end_layer; - public final Set item_list; - - private static final double DETOUR_ADD = 100; - private static final double DETOUR_ITEM_COST = 0.1; -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * Connection.java + * + * Created on 4. Juni 2006, 07:24 + * + */ + +package autoroute; + +import java.util.Collection; +import java.util.Set; +import java.util.TreeSet; + +import geometry.planar.Point; + +import board.Item; +import board.Trace; + +/** + * Describes a routing connection ending at the next fork or terminal item. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class Connection +{ + + /** + * Gets the connection this item belongs to. A connection ends at the next fork or terminal item. + * Returns null, if p_item is not a route item, or if it is a via belonging to more than 1 connection. + * + * @param p_item a {@link board.Item} object. + * @return a {@link autoroute.Connection} object. + */ + public static Connection get(Item p_item) + { + if (!p_item.is_route()) + { + return null; + } + Connection precalculated_connection = p_item.get_autoroute_info().get_precalculated_connection(); + if (precalculated_connection != null) + { + return precalculated_connection; + } + Set contacts = p_item.get_normal_contacts(); + Set connection_items = new TreeSet(); + connection_items.add(p_item); + + Point start_point = null; + int start_layer = 0; + Point end_point = null; + int end_layer = 0; + + for (Item curr_item : contacts) + { + Point prev_contact_point = p_item.normal_contact_point(curr_item); + if (prev_contact_point == null) + { + // no unique contact point + continue; + } + int prev_contact_layer = p_item.first_common_layer(curr_item); + boolean fork_found = false; + if (p_item instanceof Trace) + { + // Check, that there is only 1 contact at this location. + // Only for pins and vias items of more than 1 connection + // are collected + Trace start_trace = (Trace) p_item; + Collection check_contacts = start_trace.get_normal_contacts(prev_contact_point, false); + if (check_contacts.size() != 1) + { + fork_found = true; + } + } + // Search from curr_item along the contacts + // until the next fork or nonroute item. + for (;;) + { + if(!curr_item.is_route() || fork_found) + { + // connection ends + if (start_point == null) + { + start_point = prev_contact_point; + start_layer = prev_contact_layer; + } + else if (!prev_contact_point.equals(start_point)) + { + end_point = prev_contact_point; + end_layer = prev_contact_layer; + } + break; + } + connection_items.add(curr_item); + Collection curr_item_contacts = curr_item.get_normal_contacts(); + // filter the contacts at the previous contact point, + // because we were already there. + // If then there is not exactly 1 new contact left, there is + // a stub or a fork. + Point next_contact_point = null; + int next_contact_layer = -1; + Item next_contact = null; + for (Item tmp_contact : curr_item_contacts) + { + int tmp_contact_layer = curr_item.first_common_layer(tmp_contact); + if (tmp_contact_layer >= 0) + { + Point tmp_contact_point = curr_item.normal_contact_point(tmp_contact); + if (tmp_contact_point == null) + { + // no unique contact point + fork_found = true; + break; + } + if (prev_contact_layer != tmp_contact_layer || + !prev_contact_point.equals(tmp_contact_point)) + { + next_contact_point = tmp_contact_point; + next_contact_layer = tmp_contact_layer; + if (next_contact != null) + { + // second new contact found + fork_found = true; + break; + } + next_contact = tmp_contact; + } + } + } + if (next_contact == null) + { + break; + } + curr_item = next_contact; + prev_contact_point = next_contact_point; + prev_contact_layer = next_contact_layer; + } + } + Connection result = new Connection(start_point, start_layer, end_point, end_layer, connection_items); + for (Item curr_item : connection_items) + { + curr_item.get_autoroute_info().set_precalculated_connection(result); + } + return result; + } + + /** + * Creates a new instance of Connection + */ + private Connection(Point p_start_point, int p_start_layer, Point p_end_point, int p_end_layer, Set p_item_list) + { + start_point = p_start_point; + start_layer = p_start_layer; + end_point = p_end_point; + end_layer = p_end_layer; + item_list = p_item_list; + } + + /** + * Returns the cumulative length of the traces in this connection. + * + * @return a double. + */ + public double trace_length() + { + double result = 0; + for (Item curr_item : item_list) + { + if (curr_item instanceof Trace) + { + result += ((Trace) curr_item).get_length(); + } + } + return result; + } + + + /** + * Returns an estimation of the actual length of the connection divided by the minimal possible length. + * + * @return a double. + */ + public double get_detour() + { + if (start_point == null || end_point == null) + { + return Integer.MAX_VALUE; + } + double min_trace_length = start_point.to_float().distance(end_point.to_float()); + double detour = (this.trace_length() + DETOUR_ADD) / (min_trace_length + DETOUR_ADD) + + DETOUR_ITEM_COST * (item_list.size() - 1); + return detour; + } + + + /** + * If the connection ens in empty space, start_point or end_point may be null. + */ + public final Point start_point; + public final int start_layer; + public final Point end_point; + public final int end_layer; + public final Set item_list; + + private static final double DETOUR_ADD = 100; + private static final double DETOUR_ITEM_COST = 0.1; +} diff --git a/autoroute/DestinationDistance.java b/src/main/java/autoroute/DestinationDistance.java similarity index 95% rename from autoroute/DestinationDistance.java rename to src/main/java/autoroute/DestinationDistance.java index 9548138..4d66ae0 100644 --- a/autoroute/DestinationDistance.java +++ b/src/main/java/autoroute/DestinationDistance.java @@ -31,6 +31,7 @@ * and the destination set of the expansion. * * @author Alfons Wirtz + * @version $Id: $Id */ public class DestinationDistance { @@ -38,6 +39,11 @@ public class DestinationDistance /** * Creates a new instance of DestinationDistance. * p_trace_costs and p_layer_active are arrays of dimension layer_count. + * + * @param p_trace_costs an array of {@link autoroute.AutorouteControl.ExpansionCostFactor} objects. + * @param p_layer_active an array of boolean. + * @param p_min_normal_via_cost a double. + * @param p_min_cheap_via_cost a double. */ public DestinationDistance( ExpansionCostFactor [] p_trace_costs, boolean [] p_layer_active, double p_min_normal_via_cost, double p_min_cheap_via_cost) @@ -105,6 +111,12 @@ public DestinationDistance( ExpansionCostFactor [] p_trace_costs, min_component_solder_inner_trace_cost = Math.min(min_component_inner_trace_cost, min_solder_inner_trace_cost); } + /** + *

join.

+ * + * @param p_box a {@link geometry.planar.IntBox} object. + * @param p_layer a int. + */ public void join(IntBox p_box, int p_layer) { if (p_layer == 0) @@ -125,11 +137,25 @@ else if (p_layer == layer_count - 1) box_is_empty = false; } + /** + *

calculate.

+ * + * @param p_point a {@link geometry.planar.FloatPoint} object. + * @param p_layer a int. + * @return a double. + */ public double calculate(FloatPoint p_point, int p_layer) { return calculate( p_point.bounding_box(), p_layer); } + /** + *

calculate.

+ * + * @param p_box a {@link geometry.planar.IntBox} object. + * @param p_layer a int. + * @return a double. + */ public double calculate(IntBox p_box, int p_layer) { if (box_is_empty) @@ -450,6 +476,13 @@ else if (p_box.ur.y < inner_side_box.ll.y) return result; } + /** + *

calculate_cheap_distance.

+ * + * @param p_box a {@link geometry.planar.IntBox} object. + * @param p_layer a int. + * @return a double. + */ public double calculate_cheap_distance(IntBox p_box, int p_layer) { double min_normal_via_cost_save = min_normal_via_cost; diff --git a/autoroute/DrillPage.java b/src/main/java/autoroute/DrillPage.java similarity index 89% rename from autoroute/DrillPage.java rename to src/main/java/autoroute/DrillPage.java index 532ff37..535dbb9 100644 --- a/autoroute/DrillPage.java +++ b/src/main/java/autoroute/DrillPage.java @@ -1,247 +1,281 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * DrillPage.java - * - * Created on 26. Maerz 2006, 10:46 - * - */ - -package autoroute; - -import java.util.Collection; -import java.util.LinkedList; -import java.util.Iterator; - -import geometry.planar.Point; -import geometry.planar.IntBox; -import geometry.planar.TileShape; -import geometry.planar.PolylineArea; - -import datastructures.ShapeTree.TreeEntry; - -import board.RoutingBoard; -import board.ShapeSearchTree; -import board.Item; - -/** - * - * @author Alfons Wirtz - */ -class DrillPage implements ExpandableObject -{ - - /** Creates a new instance of DrillPage */ - public DrillPage(IntBox p_shape, RoutingBoard p_board) - { - shape = p_shape; - board = p_board; - maze_search_info_arr = new MazeSearchElement[p_board.get_layer_count()]; - for (int i = 0; i < maze_search_info_arr.length; ++i) - { - maze_search_info_arr[i] = new MazeSearchElement(); - } - } - - /** - * Returns the drills on this page. - * If p_atttach_smd, drilling to smd pins is allowed. - */ - public Collection get_drills(AutorouteEngine p_autoroute_engine, boolean p_attach_smd) - { - if (this.drills == null || p_autoroute_engine.get_net_no() != this.net_no) - { - this.net_no = p_autoroute_engine.get_net_no(); - this.drills = new LinkedList(); - ShapeSearchTree search_tree = this.board.search_tree_manager.get_default_tree(); - Collection overlaps = new LinkedList(); - search_tree.overlapping_tree_entries(this.shape, -1, overlaps); - Collection cutout_shapes = new LinkedList(); - // drills on top of existing vias are used in the ripup algorithm - TileShape prev_obstacle_shape = IntBox.EMPTY; - for (TreeEntry curr_entry : overlaps) - { - if (!(curr_entry.object instanceof Item)) - { - continue; - } - Item curr_item = (Item) curr_entry.object; - if (curr_item.is_drillable(this.net_no)) - { - continue; - } - if (curr_item instanceof board.Pin) - { - if (p_attach_smd && ((board.Pin) curr_item).drill_allowed()) - { - continue; - } - } - TileShape curr_obstacle_shape = - curr_item.get_tree_shape(search_tree, curr_entry.shape_index_in_object); - if (!prev_obstacle_shape.contains(curr_obstacle_shape)) - { - // Checked to avoid multiple cutout for example for vias with the same shape on all layers. - TileShape curr_cutout_shape = curr_obstacle_shape.intersection(this.shape); - if (curr_cutout_shape.dimension() == 2) - { - cutout_shapes.add(curr_cutout_shape); - } - } - prev_obstacle_shape = curr_obstacle_shape; - } - TileShape[] holes = new TileShape[cutout_shapes.size()]; - Iterator it = cutout_shapes.iterator(); - for (int i = 0; i < holes.length; ++i) - { - holes[i] = it.next(); - } - PolylineArea shape_with_holes = new PolylineArea(this.shape, holes); - TileShape [] drill_shapes = shape_with_holes.split_to_convex(p_autoroute_engine.stoppable_thread); - - // Use the center points of these drill shapes to try making a via. - int drill_first_layer = 0; - int drill_last_layer = this.board.get_layer_count() - 1; - for (int i = 0; i < drill_shapes.length; ++i) - { - TileShape curr_drill_shape = drill_shapes[i]; - Point curr_drill_location = null; - if (p_attach_smd) - { - curr_drill_location = - calc_pin_center_in_drill(curr_drill_shape, drill_first_layer, p_autoroute_engine.board); - if (curr_drill_location == null) - { - curr_drill_location = - calc_pin_center_in_drill(curr_drill_shape, drill_last_layer, p_autoroute_engine.board); - } - } - if (curr_drill_location == null) - { - curr_drill_location = curr_drill_shape.centre_of_gravity().round(); - } - ExpansionDrill new_drill = - new ExpansionDrill(curr_drill_shape, curr_drill_location, drill_first_layer, drill_last_layer); - if (new_drill.calculate_expansion_rooms(p_autoroute_engine)) - { - this.drills.add(new_drill); - } - } - } - return this.drills; - } - - public TileShape get_shape() - { - return this.shape; - } - - public int get_dimension() - { - return 2; - } - - public int maze_search_element_count() - { - return this.maze_search_info_arr.length; - } - - public MazeSearchElement get_maze_search_element (int p_no) - { - return this.maze_search_info_arr[p_no]; - } - - /** - * Resets all drills of this page for autorouting the next connection. - */ - public void reset() - { - if (this.drills != null) - { - for (ExpansionDrill curr_drill : this.drills) - { - curr_drill.reset(); - } - } - for (MazeSearchElement curr_info : maze_search_info_arr) - { - curr_info.reset(); - } - } - - /** - * Invalidates the drills of this page so that they are recalculated at the next call of get_drills(). - */ - public void invalidate() - { - this.drills = null; - } - - /* - * Test draw of the drills on this page. - */ - public void draw(java.awt.Graphics p_graphics, - boardgraphics.GraphicsContext p_graphics_context, double p_intensity) - { - if (true || drills == null) - { - return; - } - for (ExpansionDrill curr_drill : drills) - { - curr_drill.draw(p_graphics, p_graphics_context, p_intensity); - } - } - - public CompleteExpansionRoom other_room(CompleteExpansionRoom p_room) - { - return null; - } - - /** - * Looks if p_drill_shape contains the center of a drillable Pin on p_layer. - * Returns null, if no such Pin was found. - */ - private static Point calc_pin_center_in_drill(TileShape p_drill_shape, int p_layer, RoutingBoard p_board) - { - Collection overlapping_items = p_board.overlapping_items(p_drill_shape, p_layer); - Point result = null; - for (Item curr_item : overlapping_items) - { - if (curr_item instanceof board.Pin) - { - board.Pin curr_pin = (board.Pin) curr_item; - if (curr_pin.drill_allowed() && p_drill_shape.contains_inside(curr_pin.get_center())) - { - result = curr_pin.get_center(); - } - } - } - return result; - } - - private final MazeSearchElement[] maze_search_info_arr; - - /** The shape of the page */ - final IntBox shape; - - /** The list of expansion drills on this page. Null, if not yet calculated. */ - private Collection drills = null; - - private final RoutingBoard board; - - /** The number of the net, for which the drills are calculated */ - private int net_no = -1; -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * DrillPage.java + * + * Created on 26. Maerz 2006, 10:46 + * + */ + +package autoroute; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.Iterator; + +import geometry.planar.Point; +import geometry.planar.IntBox; +import geometry.planar.TileShape; +import geometry.planar.PolylineArea; + +import datastructures.ShapeTree.TreeEntry; + +import board.RoutingBoard; +import board.ShapeSearchTree; +import board.Item; + +/** + * + * @author Alfons Wirtz + */ +class DrillPage implements ExpandableObject +{ + + /** + * Creates a new instance of DrillPage + * + * @param p_shape a {@link geometry.planar.IntBox} object. + * @param p_board a {@link board.RoutingBoard} object. + */ + public DrillPage(IntBox p_shape, RoutingBoard p_board) + { + shape = p_shape; + board = p_board; + maze_search_info_arr = new MazeSearchElement[p_board.get_layer_count()]; + for (int i = 0; i < maze_search_info_arr.length; ++i) + { + maze_search_info_arr[i] = new MazeSearchElement(); + } + } + + /** + * Returns the drills on this page. + * If p_atttach_smd, drilling to smd pins is allowed. + * + * @param p_autoroute_engine a {@link autoroute.AutorouteEngine} object. + * @param p_attach_smd a boolean. + * @return a {@link java.util.Collection} object. + */ + public Collection get_drills(AutorouteEngine p_autoroute_engine, boolean p_attach_smd) + { + if (this.drills == null || p_autoroute_engine.get_net_no() != this.net_no) + { + this.net_no = p_autoroute_engine.get_net_no(); + this.drills = new LinkedList(); + ShapeSearchTree search_tree = this.board.search_tree_manager.get_default_tree(); + Collection overlaps = new LinkedList(); + search_tree.overlapping_tree_entries(this.shape, -1, overlaps); + Collection cutout_shapes = new LinkedList(); + // drills on top of existing vias are used in the ripup algorithm + TileShape prev_obstacle_shape = IntBox.EMPTY; + for (TreeEntry curr_entry : overlaps) + { + if (!(curr_entry.object instanceof Item)) + { + continue; + } + Item curr_item = (Item) curr_entry.object; + if (curr_item.is_drillable(this.net_no)) + { + continue; + } + if (curr_item instanceof board.Pin) + { + if (p_attach_smd && ((board.Pin) curr_item).drill_allowed()) + { + continue; + } + } + TileShape curr_obstacle_shape = + curr_item.get_tree_shape(search_tree, curr_entry.shape_index_in_object); + if (!prev_obstacle_shape.contains(curr_obstacle_shape)) + { + // Checked to avoid multiple cutout for example for vias with the same shape on all layers. + TileShape curr_cutout_shape = curr_obstacle_shape.intersection(this.shape); + if (curr_cutout_shape.dimension() == 2) + { + cutout_shapes.add(curr_cutout_shape); + } + } + prev_obstacle_shape = curr_obstacle_shape; + } + TileShape[] holes = new TileShape[cutout_shapes.size()]; + Iterator it = cutout_shapes.iterator(); + for (int i = 0; i < holes.length; ++i) + { + holes[i] = it.next(); + } + PolylineArea shape_with_holes = new PolylineArea(this.shape, holes); + TileShape [] drill_shapes = shape_with_holes.split_to_convex(p_autoroute_engine.stoppable_thread); + + // Use the center points of these drill shapes to try making a via. + int drill_first_layer = 0; + int drill_last_layer = this.board.get_layer_count() - 1; + for (int i = 0; i < drill_shapes.length; ++i) + { + TileShape curr_drill_shape = drill_shapes[i]; + Point curr_drill_location = null; + if (p_attach_smd) + { + curr_drill_location = + calc_pin_center_in_drill(curr_drill_shape, drill_first_layer, p_autoroute_engine.board); + if (curr_drill_location == null) + { + curr_drill_location = + calc_pin_center_in_drill(curr_drill_shape, drill_last_layer, p_autoroute_engine.board); + } + } + if (curr_drill_location == null) + { + curr_drill_location = curr_drill_shape.centre_of_gravity().round(); + } + ExpansionDrill new_drill = + new ExpansionDrill(curr_drill_shape, curr_drill_location, drill_first_layer, drill_last_layer); + if (new_drill.calculate_expansion_rooms(p_autoroute_engine)) + { + this.drills.add(new_drill); + } + } + } + return this.drills; + } + + /** + *

get_shape.

+ * + * @return a {@link geometry.planar.TileShape} object. + */ + public TileShape get_shape() + { + return this.shape; + } + + /** + *

get_dimension.

+ * + * @return a int. + */ + public int get_dimension() + { + return 2; + } + + /** + *

maze_search_element_count.

+ * + * @return a int. + */ + public int maze_search_element_count() + { + return this.maze_search_info_arr.length; + } + + /** {@inheritDoc} */ + public MazeSearchElement get_maze_search_element (int p_no) + { + return this.maze_search_info_arr[p_no]; + } + + /** + * Resets all drills of this page for autorouting the next connection. + */ + public void reset() + { + if (this.drills != null) + { + for (ExpansionDrill curr_drill : this.drills) + { + curr_drill.reset(); + } + } + for (MazeSearchElement curr_info : maze_search_info_arr) + { + curr_info.reset(); + } + } + + /** + * Invalidates the drills of this page so that they are recalculated at the next call of get_drills(). + */ + public void invalidate() + { + this.drills = null; + } + + /* + * Test draw of the drills on this page. + */ + /** + *

draw.

+ * + * @param p_graphics a {@link java.awt.Graphics} object. + * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object. + * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object. + * @param p_intensity a double. + */ + public void draw(java.awt.Graphics p_graphics, + boardgraphics.GraphicsContext p_graphics_context, double p_intensity) + { + if (true || drills == null) + { + return; + } + for (ExpansionDrill curr_drill : drills) + { + curr_drill.draw(p_graphics, p_graphics_context, p_intensity); + } + } + + /** {@inheritDoc} */ + public CompleteExpansionRoom other_room(CompleteExpansionRoom p_room) + { + return null; + } + + /** + * Looks if p_drill_shape contains the center of a drillable Pin on p_layer. + * Returns null, if no such Pin was found. + */ + private static Point calc_pin_center_in_drill(TileShape p_drill_shape, int p_layer, RoutingBoard p_board) + { + Collection overlapping_items = p_board.overlapping_items(p_drill_shape, p_layer); + Point result = null; + for (Item curr_item : overlapping_items) + { + if (curr_item instanceof board.Pin) + { + board.Pin curr_pin = (board.Pin) curr_item; + if (curr_pin.drill_allowed() && p_drill_shape.contains_inside(curr_pin.get_center())) + { + result = curr_pin.get_center(); + } + } + } + return result; + } + + private final MazeSearchElement[] maze_search_info_arr; + + /** The shape of the page */ + final IntBox shape; + + /** The list of expansion drills on this page. Null, if not yet calculated. */ + private Collection drills = null; + + private final RoutingBoard board; + + /** The number of the net, for which the drills are calculated */ + private int net_no = -1; +} diff --git a/autoroute/DrillPageArray.java b/src/main/java/autoroute/DrillPageArray.java similarity index 88% rename from autoroute/DrillPageArray.java rename to src/main/java/autoroute/DrillPageArray.java index 5b1717f..c351b99 100644 --- a/autoroute/DrillPageArray.java +++ b/src/main/java/autoroute/DrillPageArray.java @@ -1,177 +1,196 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * DrillPageArray.java - * - * Created on 26. Maerz 2006, 06:54 - * - */ - -package autoroute; - -import java.util.Collection; -import java.util.LinkedList; - -import geometry.planar.IntBox; -import geometry.planar.TileShape; - -import board.RoutingBoard; - -/** - * Describes the 2 dimensional array of pages of ExpansionDrill`s used in the maze search algorithm. - * The pages are rectangles of about equal width and height covering covering the bounding box of the board area. - * - * @author Alfons Wirtz - */ -public class DrillPageArray -{ - - /** Creates a new instance of DrillPageArray */ - public DrillPageArray(RoutingBoard p_board, int p_max_page_width) - { - this.bounds = p_board.bounding_box; - double length = bounds.ur.x - bounds.ll.x; - double height = bounds.ur.y - bounds.ll.y; - this.COLUMN_COUNT = (int) Math.ceil(length / p_max_page_width); - this.ROW_COUNT = (int) Math.ceil(height/ p_max_page_width); - this.PAGE_WIDTH = (int) Math.ceil(length / COLUMN_COUNT); - this.PAGE_HEIGHT = (int) Math.ceil(height / ROW_COUNT); - this.page_arr = new DrillPage[ROW_COUNT] [COLUMN_COUNT]; - for (int j = 0; j < this.ROW_COUNT; ++j) - { - for (int i = 0; i < this.COLUMN_COUNT; ++i) - { - int ll_x = bounds.ll.x + i * PAGE_WIDTH; - int ur_x; - if (i == COLUMN_COUNT - 1) - { - ur_x = bounds.ur.x; - } - else - { - ur_x = ll_x + PAGE_WIDTH; - } - int ll_y = bounds.ll.y + j * PAGE_HEIGHT; - int ur_y; - if (j == ROW_COUNT - 1) - { - ur_y = bounds.ur.y; - } - else - { - ur_y = ll_y + PAGE_HEIGHT; - } - page_arr [j] [i] = new DrillPage(new IntBox(ll_x, ll_y, ur_x, ur_y), p_board); - } - } - } - - /** - * Invalidates all drill pages intersecting with p_shape, so the they must be recalculated at the next - * call of get_ddrills() - */ - public void invalidate(TileShape p_shape) - { - Collection overlaps = overlapping_pages( p_shape); - for (DrillPage curr_page : overlaps) - { - curr_page.invalidate(); - } - } - - /** - * Collects all drill pages with a 2-dimensional overlap with p_shape. - */ - public Collection overlapping_pages(TileShape p_shape) - { - Collection result = new LinkedList(); - - IntBox shape_box = p_shape.bounding_box().intersection(this.bounds); - - int min_j = (int) Math.floor(((double)(shape_box.ll.y - bounds.ll.y))/ (double) PAGE_HEIGHT); - double max_j = ((double) (shape_box.ur.y - bounds.ll.y)) / (double) PAGE_HEIGHT; - - int min_i = (int) Math.floor(((double) (shape_box.ll.x - bounds.ll.x))/ (double) PAGE_WIDTH ); - double max_i = ((double) (shape_box.ur.x - bounds.ll.x)) / (double) PAGE_WIDTH; - - for (int j = min_j; j < max_j; ++j) - { - for (int i = min_i; i < max_i; ++i) - { - DrillPage curr_page = this.page_arr[j] [i]; - TileShape intersection = p_shape.intersection(curr_page.shape); - if (intersection.dimension() > 1) - { - result.add(this.page_arr[j] [i]); - } - } - } - return result; - } - - /** - * Resets all drill pages for autorouting the next connection. - */ - public void reset() - { - for (int j = 0; j < page_arr.length; ++j) - { - DrillPage [] curr_row = page_arr[j]; - for (int i = 0; i < curr_row.length; ++i) - { - curr_row[i].reset(); - } - } - } - - /* - * Test draw of the all drills - */ - public void draw(java.awt.Graphics p_graphics, boardgraphics.GraphicsContext p_graphics_context, double p_intensity) - { - for (int j = 0; j < page_arr.length; ++j) - { - DrillPage [] curr_row = page_arr[j]; - for (int i = 0; i < curr_row.length; ++i) - { - curr_row[i].draw(p_graphics, p_graphics_context, p_intensity); - } - } - } - - private final IntBox bounds; - - /** - * The number of colums in the array. - */ - private final int COLUMN_COUNT; - - /** - * The number of rows in the array. - */ - private final int ROW_COUNT; - - /** - * The width of a single page in this array. - */ - private final int PAGE_WIDTH; - - /** - * The height of a single page in this array. - */ - private final int PAGE_HEIGHT; - - private final DrillPage [][] page_arr; -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * DrillPageArray.java + * + * Created on 26. Maerz 2006, 06:54 + * + */ + +package autoroute; + +import java.util.Collection; +import java.util.LinkedList; + +import geometry.planar.IntBox; +import geometry.planar.TileShape; + +import board.RoutingBoard; + +/** + * Describes the 2 dimensional array of pages of ExpansionDrill`s used in the maze search algorithm. + * The pages are rectangles of about equal width and height covering covering the bounding box of the board area. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class DrillPageArray +{ + + /** + * Creates a new instance of DrillPageArray + * + * @param p_board a {@link board.RoutingBoard} object. + * @param p_max_page_width a int. + */ + public DrillPageArray(RoutingBoard p_board, int p_max_page_width) + { + this.bounds = p_board.bounding_box; + double length = bounds.ur.x - bounds.ll.x; + double height = bounds.ur.y - bounds.ll.y; + this.COLUMN_COUNT = (int) Math.ceil(length / p_max_page_width); + this.ROW_COUNT = (int) Math.ceil(height/ p_max_page_width); + this.PAGE_WIDTH = (int) Math.ceil(length / COLUMN_COUNT); + this.PAGE_HEIGHT = (int) Math.ceil(height / ROW_COUNT); + this.page_arr = new DrillPage[ROW_COUNT] [COLUMN_COUNT]; + for (int j = 0; j < this.ROW_COUNT; ++j) + { + for (int i = 0; i < this.COLUMN_COUNT; ++i) + { + int ll_x = bounds.ll.x + i * PAGE_WIDTH; + int ur_x; + if (i == COLUMN_COUNT - 1) + { + ur_x = bounds.ur.x; + } + else + { + ur_x = ll_x + PAGE_WIDTH; + } + int ll_y = bounds.ll.y + j * PAGE_HEIGHT; + int ur_y; + if (j == ROW_COUNT - 1) + { + ur_y = bounds.ur.y; + } + else + { + ur_y = ll_y + PAGE_HEIGHT; + } + page_arr [j] [i] = new DrillPage(new IntBox(ll_x, ll_y, ur_x, ur_y), p_board); + } + } + } + + /** + * Invalidates all drill pages intersecting with p_shape, so the they must be recalculated at the next + * call of get_ddrills() + * + * @param p_shape a {@link geometry.planar.TileShape} object. + */ + public void invalidate(TileShape p_shape) + { + Collection overlaps = overlapping_pages( p_shape); + for (DrillPage curr_page : overlaps) + { + curr_page.invalidate(); + } + } + + /** + * Collects all drill pages with a 2-dimensional overlap with p_shape. + * + * @param p_shape a {@link geometry.planar.TileShape} object. + * @return a java$util$Collection object. + */ + public Collection overlapping_pages(TileShape p_shape) + { + Collection result = new LinkedList(); + + IntBox shape_box = p_shape.bounding_box().intersection(this.bounds); + + int min_j = (int) Math.floor(((double)(shape_box.ll.y - bounds.ll.y))/ (double) PAGE_HEIGHT); + double max_j = ((double) (shape_box.ur.y - bounds.ll.y)) / (double) PAGE_HEIGHT; + + int min_i = (int) Math.floor(((double) (shape_box.ll.x - bounds.ll.x))/ (double) PAGE_WIDTH ); + double max_i = ((double) (shape_box.ur.x - bounds.ll.x)) / (double) PAGE_WIDTH; + + for (int j = min_j; j < max_j; ++j) + { + for (int i = min_i; i < max_i; ++i) + { + DrillPage curr_page = this.page_arr[j] [i]; + TileShape intersection = p_shape.intersection(curr_page.shape); + if (intersection.dimension() > 1) + { + result.add(this.page_arr[j] [i]); + } + } + } + return result; + } + + /** + * Resets all drill pages for autorouting the next connection. + */ + public void reset() + { + for (int j = 0; j < page_arr.length; ++j) + { + DrillPage [] curr_row = page_arr[j]; + for (int i = 0; i < curr_row.length; ++i) + { + curr_row[i].reset(); + } + } + } + + /* + * Test draw of the all drills + */ + /** + *

draw.

+ * + * @param p_graphics a {@link java.awt.Graphics} object. + * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object. + * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object. + * @param p_intensity a double. + */ + public void draw(java.awt.Graphics p_graphics, boardgraphics.GraphicsContext p_graphics_context, double p_intensity) + { + for (int j = 0; j < page_arr.length; ++j) + { + DrillPage [] curr_row = page_arr[j]; + for (int i = 0; i < curr_row.length; ++i) + { + curr_row[i].draw(p_graphics, p_graphics_context, p_intensity); + } + } + } + + private final IntBox bounds; + + /** + * The number of colums in the array. + */ + private final int COLUMN_COUNT; + + /** + * The number of rows in the array. + */ + private final int ROW_COUNT; + + /** + * The width of a single page in this array. + */ + private final int PAGE_WIDTH; + + /** + * The height of a single page in this array. + */ + private final int PAGE_HEIGHT; + + private final DrillPage [][] page_arr; +} diff --git a/autoroute/ExpandableObject.java b/src/main/java/autoroute/ExpandableObject.java similarity index 82% rename from autoroute/ExpandableObject.java rename to src/main/java/autoroute/ExpandableObject.java index d798b22..b5a21b2 100644 --- a/autoroute/ExpandableObject.java +++ b/src/main/java/autoroute/ExpandableObject.java @@ -25,33 +25,46 @@ * An object, which can be expanded by the maze expansion algorithm. * * @author alfons + * @version $Id: $Id */ public interface ExpandableObject { /** * Calculates the intersection of the shapes of the 2 objecta belonging to this door. + * + * @return a {@link geometry.planar.TileShape} object. */ TileShape get_shape(); /** * Returns the dimension ot the intersection of the shapes of the 2 objecta belonging to this door. + * + * @return a int. */ int get_dimension(); /** * Returns the other room to p_room if this is a door and the other room is a CompleteExpansionRoom. * Else null is returned. + * + * @param p_room a {@link autoroute.CompleteExpansionRoom} object. + * @return a {@link autoroute.CompleteExpansionRoom} object. */ CompleteExpansionRoom other_room(CompleteExpansionRoom p_room); /** * Returns the count of MazeSearchElements in this expandable object + * + * @return a int. */ int maze_search_element_count(); /** * Returns the p_no-th MazeSearchElements in this expandable object + * + * @param p_no a int. + * @return a {@link autoroute.MazeSearchElement} object. */ MazeSearchElement get_maze_search_element(int p_no); diff --git a/autoroute/ExpansionDoor.java b/src/main/java/autoroute/ExpansionDoor.java similarity index 89% rename from autoroute/ExpansionDoor.java rename to src/main/java/autoroute/ExpansionDoor.java index 47d1b40..5a1552d 100644 --- a/autoroute/ExpansionDoor.java +++ b/src/main/java/autoroute/ExpansionDoor.java @@ -27,13 +27,19 @@ /** * An ExpansionDoor is a common edge between two ExpansionRooms * - * * @author Alfons Wirtz + * @version $Id: $Id */ public class ExpansionDoor implements ExpandableObject { - /** Creates a new instance of ExpansionDoor */ + /** + * Creates a new instance of ExpansionDoor + * + * @param p_first_room a {@link autoroute.ExpansionRoom} object. + * @param p_second_room a {@link autoroute.ExpansionRoom} object. + * @param p_dimension a int. + */ public ExpansionDoor(ExpansionRoom p_first_room, ExpansionRoom p_second_room, int p_dimension) { first_room = p_first_room; @@ -41,7 +47,12 @@ public ExpansionDoor(ExpansionRoom p_first_room, ExpansionRoom p_second_room, in dimension = p_dimension; } - /** Creates a new instance of ExpansionDoor */ + /** + * Creates a new instance of ExpansionDoor + * + * @param p_first_room a {@link autoroute.ExpansionRoom} object. + * @param p_second_room a {@link autoroute.ExpansionRoom} object. + */ public ExpansionDoor(ExpansionRoom p_first_room, ExpansionRoom p_second_room) { first_room = p_first_room; @@ -51,6 +62,8 @@ public ExpansionDoor(ExpansionRoom p_first_room, ExpansionRoom p_second_room) /** * Calculates the intersection of the shapes of the 2 rooms belonging to this door. + * + * @return a {@link geometry.planar.TileShape} object. */ public TileShape get_shape() { @@ -62,6 +75,8 @@ public TileShape get_shape() /** * The dimension of a door may be 1 or 2. * 2-dimensional doors can only exist between ObstacleExpansionRooms + * + * @return a int. */ public int get_dimension() { @@ -71,6 +86,9 @@ public int get_dimension() /** * Returns the other room of this door, or null, if p_roon * is neither equal to this.first_room nor to this.second_room. + * + * @param p_room a {@link autoroute.ExpansionRoom} object. + * @return a {@link autoroute.ExpansionRoom} object. */ public ExpansionRoom other_room(ExpansionRoom p_room) { @@ -91,6 +109,8 @@ else if (p_room == second_room) } /** + * {@inheritDoc} + * * Returns the other room of this door, or null, if p_roon * is neither equal to this.first_room nor to this.second_room, * or if the other room is not a CompleteExpansionRoom. @@ -117,11 +137,17 @@ else if (p_room == second_room) return (CompleteExpansionRoom) result; } + /** + *

maze_search_element_count.

+ * + * @return a int. + */ public int maze_search_element_count() { return this.section_arr.length; } + /** {@inheritDoc} */ public MazeSearchElement get_maze_search_element(int p_no) { return this.section_arr[p_no]; @@ -129,6 +155,9 @@ public MazeSearchElement get_maze_search_element(int p_no) /** * Calculates the Line segments of the sections of this door. + * + * @param p_offset a double. + * @return an array of {@link geometry.planar.FloatLine} objects. */ public FloatLine[] get_section_segments(double p_offset) { diff --git a/autoroute/ExpansionDrill.java b/src/main/java/autoroute/ExpansionDrill.java similarity index 83% rename from autoroute/ExpansionDrill.java rename to src/main/java/autoroute/ExpansionDrill.java index 82e6033..8be355e 100644 --- a/autoroute/ExpansionDrill.java +++ b/src/main/java/autoroute/ExpansionDrill.java @@ -29,11 +29,19 @@ * Layer change expansion object in the maze search algorithm. * * @author alfons + * @version $Id: $Id */ public class ExpansionDrill implements ExpandableObject { - /** Creates a new instance of Drill */ + /** + * Creates a new instance of Drill + * + * @param p_shape a {@link geometry.planar.TileShape} object. + * @param p_location a {@link geometry.planar.Point} object. + * @param p_first_layer a int. + * @param p_last_layer a int. + */ public ExpansionDrill(TileShape p_shape, Point p_location, int p_first_layer, int p_last_layer) { shape = p_shape; @@ -54,6 +62,9 @@ public ExpansionDrill(TileShape p_shape, Point p_location, int p_first_layer, in * Creates a CompleteFreeSpaceExpansionRoom, if no expansion room is found. * Returns false, if that was not possible because of an obstacle at this.location * on some layer in the compensated search tree. + * + * @param p_autoroute_engine a {@link autoroute.AutorouteEngine} object. + * @return a boolean. */ public boolean calculate_expansion_rooms(AutorouteEngine p_autoroute_engine) { @@ -102,31 +113,51 @@ public boolean calculate_expansion_rooms(AutorouteEngine p_autoroute_engine) return true; } + /** + *

get_shape.

+ * + * @return a {@link geometry.planar.TileShape} object. + */ public TileShape get_shape() { return this.shape; } + /** + *

get_dimension.

+ * + * @return a int. + */ public int get_dimension() { return 2; } + /** {@inheritDoc} */ public CompleteExpansionRoom other_room(CompleteExpansionRoom p_room) { return null; } + /** + *

maze_search_element_count.

+ * + * @return a int. + */ public int maze_search_element_count() { return this.maze_search_info_arr.length; } + /** {@inheritDoc} */ public MazeSearchElement get_maze_search_element(int p_no) { return this.maze_search_info_arr[p_no]; } + /** + *

reset.

+ */ public void reset() { for (MazeSearchElement curr_info : maze_search_info_arr) @@ -138,6 +169,14 @@ public void reset() /* * Test draw of the the shape of this drill. */ + /** + *

draw.

+ * + * @param p_graphics a {@link java.awt.Graphics} object. + * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object. + * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object. + * @param p_intensity a double. + */ public void draw(java.awt.Graphics p_graphics, boardgraphics.GraphicsContext p_graphics_context, double p_intensity) { diff --git a/autoroute/ExpansionRoom.java b/src/main/java/autoroute/ExpansionRoom.java similarity index 78% rename from autoroute/ExpansionRoom.java rename to src/main/java/autoroute/ExpansionRoom.java index e7a8124..12444b6 100644 --- a/autoroute/ExpansionRoom.java +++ b/src/main/java/autoroute/ExpansionRoom.java @@ -1,74 +1,90 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * ExpansionRoom.java - * - * Created on 15. April 2006, 10:12 - * - */ - -package autoroute; - -import java.util.List; - -import geometry.planar.TileShape; - -/** - * - * @author alfons - */ -public interface ExpansionRoom -{ - /** - * Adds p_door to the list of doors of this room. - */ - void add_door(ExpansionDoor p_door); - - /** - * Returns the list of doors of this room to neighbour expansion rooms - */ - List get_doors(); - - /** - * Removes all doors from this room. - */ - void clear_doors(); - - /** - * Clears the autorouting info of all doors for routing the next connection. - */ - void reset_doors(); - - /** - * Checks, if this room has already a door to p_other - */ - boolean door_exists(ExpansionRoom p_other); - - /** - * Removes p_door from this room. - * Returns false, if p_room did not contain p_door. - */ - boolean remove_door (ExpandableObject p_door); - - /** - * Gets the shape of this room. - */ - TileShape get_shape(); - - /** - * Returns the layer of this expansion room. - */ - int get_layer(); -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * ExpansionRoom.java + * + * Created on 15. April 2006, 10:12 + * + */ + +package autoroute; + +import java.util.List; + +import geometry.planar.TileShape; + +/** + *

ExpansionRoom interface.

+ * + * @author alfons + * @version $Id: $Id + */ +public interface ExpansionRoom +{ + /** + * Adds p_door to the list of doors of this room. + * + * @param p_door a {@link autoroute.ExpansionDoor} object. + */ + void add_door(ExpansionDoor p_door); + + /** + * Returns the list of doors of this room to neighbour expansion rooms + * + * @return a {@link java.util.List} object. + */ + List get_doors(); + + /** + * Removes all doors from this room. + */ + void clear_doors(); + + /** + * Clears the autorouting info of all doors for routing the next connection. + */ + void reset_doors(); + + /** + * Checks, if this room has already a door to p_other + * + * @param p_other a {@link autoroute.ExpansionRoom} object. + * @return a boolean. + */ + boolean door_exists(ExpansionRoom p_other); + + /** + * Removes p_door from this room. + * Returns false, if p_room did not contain p_door. + * + * @param p_door a {@link autoroute.ExpandableObject} object. + * @return a boolean. + */ + boolean remove_door (ExpandableObject p_door); + + /** + * Gets the shape of this room. + * + * @return a {@link geometry.planar.TileShape} object. + */ + TileShape get_shape(); + + /** + * Returns the layer of this expansion room. + * + * @return a int. + */ + int get_layer(); +} diff --git a/autoroute/FreeSpaceExpansionRoom.java b/src/main/java/autoroute/FreeSpaceExpansionRoom.java similarity index 87% rename from autoroute/FreeSpaceExpansionRoom.java rename to src/main/java/autoroute/FreeSpaceExpansionRoom.java index 48a7941..b096617 100644 --- a/autoroute/FreeSpaceExpansionRoom.java +++ b/src/main/java/autoroute/FreeSpaceExpansionRoom.java @@ -35,6 +35,7 @@ * Expansion Areas used by the maze search algorithm. * * @author Alfons Wirtz + * @version $Id: $Id */ public abstract class FreeSpaceExpansionRoom implements ExpansionRoom { @@ -45,6 +46,9 @@ public abstract class FreeSpaceExpansionRoom implements ExpansionRoom * The final (completed) shape will be a subshape of the start shape, which * does not overlap with any obstacle, and is as big as possible. * p_contained_points will remain contained in the shape, after it is completed. + * + * @param p_shape a {@link geometry.planar.TileShape} object. + * @param p_layer a int. */ public FreeSpaceExpansionRoom(TileShape p_shape, int p_layer) { @@ -54,6 +58,8 @@ public FreeSpaceExpansionRoom(TileShape p_shape, int p_layer) } /** + * {@inheritDoc} + * * Adds p_door to the list of doors of this room. */ public void add_door(ExpansionDoor p_door) @@ -63,6 +69,8 @@ public void add_door(ExpansionDoor p_door) /** * Returns the list of doors of this room to neighbour expansion rooms + * + * @return a {@link java.util.List} object. */ public List get_doors() { @@ -77,6 +85,9 @@ public void clear_doors() this.doors = new LinkedList(); } + /** + *

reset_doors.

+ */ public void reset_doors() { for (ExpandableObject curr_door : this.doors) @@ -85,6 +96,7 @@ public void reset_doors() } } + /** {@inheritDoc} */ public boolean remove_door(ExpandableObject p_door) { return this.doors.remove(p_door); @@ -92,6 +104,8 @@ public boolean remove_door(ExpandableObject p_door) /** * Gets the shape of this room + * + * @return a {@link geometry.planar.TileShape} object. */ public TileShape get_shape() { @@ -100,18 +114,27 @@ public TileShape get_shape() /** * sets the shape of this room + * + * @param p_shape a {@link geometry.planar.TileShape} object. */ public void set_shape(TileShape p_shape) { this.shape = p_shape; } + /** + *

get_layer.

+ * + * @return a int. + */ public int get_layer() { return this.layer; } /** + * {@inheritDoc} + * * Checks, if this room has already a door to p_other */ public boolean door_exists(ExpansionRoom p_other) diff --git a/autoroute/IncompleteFreeSpaceExpansionRoom.java b/src/main/java/autoroute/IncompleteFreeSpaceExpansionRoom.java similarity index 76% rename from autoroute/IncompleteFreeSpaceExpansionRoom.java rename to src/main/java/autoroute/IncompleteFreeSpaceExpansionRoom.java index bf97931..8b702f6 100644 --- a/autoroute/IncompleteFreeSpaceExpansionRoom.java +++ b/src/main/java/autoroute/IncompleteFreeSpaceExpansionRoom.java @@ -29,6 +29,7 @@ * An expansion room, whose shape is not yet completely calculated. * * @author Alfons Wirtz + * @version $Id: $Id */ public class IncompleteFreeSpaceExpansionRoom extends FreeSpaceExpansionRoom { @@ -36,6 +37,10 @@ public class IncompleteFreeSpaceExpansionRoom extends FreeSpaceExpansionRoom /** * Creates a new instance of IncompleteFreeSpaceExpansionRoom. * If p_shape == null means p_shape is the whole plane. + * + * @param p_shape a {@link geometry.planar.TileShape} object. + * @param p_layer a int. + * @param p_contained_shape a {@link geometry.planar.TileShape} object. */ public IncompleteFreeSpaceExpansionRoom(TileShape p_shape, int p_layer, TileShape p_contained_shape) { @@ -43,16 +48,31 @@ public IncompleteFreeSpaceExpansionRoom(TileShape p_shape, int p_layer, TileShap contained_shape = p_contained_shape; } + /** + *

get_contained_shape.

+ * + * @return a {@link geometry.planar.TileShape} object. + */ public TileShape get_contained_shape() { return this.contained_shape; } + /** + *

set_contained_shape.

+ * + * @param p_shape a {@link geometry.planar.TileShape} object. + */ public void set_contained_shape(TileShape p_shape) { this.contained_shape = p_shape; } + /** + *

get_target_doors.

+ * + * @return a {@link java.util.Collection} object. + */ public Collection get_target_doors() { return new java.util.LinkedList(); diff --git a/autoroute/InsertFoundConnectionAlgo.java b/src/main/java/autoroute/InsertFoundConnectionAlgo.java similarity index 98% rename from autoroute/InsertFoundConnectionAlgo.java rename to src/main/java/autoroute/InsertFoundConnectionAlgo.java index e36ca3c..99d180d 100644 --- a/autoroute/InsertFoundConnectionAlgo.java +++ b/src/main/java/autoroute/InsertFoundConnectionAlgo.java @@ -42,6 +42,7 @@ * Inserts the traces and vias of the connection found by the autoroute algorithm. * * @author Alfons Wirtz + * @version $Id: $Id */ public class InsertFoundConnectionAlgo { @@ -49,6 +50,11 @@ public class InsertFoundConnectionAlgo /** * Creates a new instance of InsertFoundConnectionAlgo . * Returns null, if the insertion did not succeed. + * + * @param p_connection a {@link autoroute.LocateFoundConnectionAlgo} object. + * @param p_board a {@link board.RoutingBoard} object. + * @param p_ctrl a {@link autoroute.AutorouteControl} object. + * @return a {@link autoroute.InsertFoundConnectionAlgo} object. */ public static InsertFoundConnectionAlgo get_instance(LocateFoundConnectionAlgo p_connection, RoutingBoard p_board, AutorouteControl p_ctrl) diff --git a/autoroute/ItemAutorouteInfo.java b/src/main/java/autoroute/ItemAutorouteInfo.java similarity index 84% rename from autoroute/ItemAutorouteInfo.java rename to src/main/java/autoroute/ItemAutorouteInfo.java index 3219944..5258a00 100644 --- a/autoroute/ItemAutorouteInfo.java +++ b/src/main/java/autoroute/ItemAutorouteInfo.java @@ -29,10 +29,15 @@ * Temporary data stored in board Items used in the autoroute algorithm * * @author Alfons Wirtz + * @version $Id: $Id */ - public class ItemAutorouteInfo { + /** + *

Constructor for ItemAutorouteInfo.

+ * + * @param p_item a {@link board.Item} object. + */ public ItemAutorouteInfo(Item p_item) { this.item = p_item; @@ -40,6 +45,8 @@ public ItemAutorouteInfo(Item p_item) /** * Looks, if the corresponding item belongs to the start or destination set of the autoroute algorithm. * Only used, if the item belongs to the net, which will be currently routed. + * + * @return a boolean. */ public boolean is_start_info() { @@ -49,6 +56,8 @@ public boolean is_start_info() /** * Sets, if the corresponding item belongs to the start or destination set of the autoroute algorithm. * Only used, if the item belongs to the net, which will be currently routed. + * + * @param p_value a boolean. */ public void set_start_info(boolean p_value) { @@ -58,6 +67,8 @@ public void set_start_info(boolean p_value) /** * Returns the precalculated connection of this item * or null, if it is not yet precalculated. + * + * @return a {@link autoroute.Connection} object. */ public Connection get_precalculated_connection() { @@ -66,6 +77,8 @@ public Connection get_precalculated_connection() /** * Sets the precalculated connnection of this item. + * + * @param p_connection a {@link autoroute.Connection} object. */ public void set_precalculated_connection(Connection p_connection) { @@ -75,6 +88,10 @@ public void set_precalculated_connection(Connection p_connection) /** * Gets the ExpansionRoom of of index p_index. * Creates it, if it is not yet existing. + * + * @param p_index a int. + * @param p_autoroute_tree a {@link board.ShapeSearchTree} object. + * @return a {@link autoroute.ObstacleExpansionRoom} object. */ public ObstacleExpansionRoom get_expansion_room(int p_index, ShapeSearchTree p_autoroute_tree) { @@ -113,6 +130,11 @@ public void reset_doors() /** * Draws the shapes of the expansion rooms of this info for testing purposes. + * + * @param p_graphics a {@link java.awt.Graphics} object. + * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object. + * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object. + * @param p_intensity a double. */ public void draw(java.awt.Graphics p_graphics, boardgraphics.GraphicsContext p_graphics_context, double p_intensity) { diff --git a/autoroute/LocateFoundConnectionAlgo.java b/src/main/java/autoroute/LocateFoundConnectionAlgo.java similarity index 93% rename from autoroute/LocateFoundConnectionAlgo.java rename to src/main/java/autoroute/LocateFoundConnectionAlgo.java index 2c79777..2eec6a0 100644 --- a/autoroute/LocateFoundConnectionAlgo.java +++ b/src/main/java/autoroute/LocateFoundConnectionAlgo.java @@ -36,8 +36,10 @@ import board.TestLevel; /** + *

Abstract LocateFoundConnectionAlgo class.

* * @author Alfons Wirtz + * @version $Id: $Id */ public abstract class LocateFoundConnectionAlgo { @@ -45,6 +47,14 @@ public abstract class LocateFoundConnectionAlgo /** * Returns a new Instance of LocateFoundConnectionAlgo or null, * if p_destination_door is null. + * + * @param p_maze_search_result a {@link autoroute.MazeSearchAlgo.Result} object. + * @param p_ctrl a {@link autoroute.AutorouteControl} object. + * @param p_search_tree a {@link board.ShapeSearchTree} object. + * @param p_angle_restriction a {@link board.AngleRestriction} object. + * @param p_ripped_item_list a {@link java.util.SortedSet} object. + * @param p_test_level a {@link board.TestLevel} object. + * @return a {@link autoroute.LocateFoundConnectionAlgo} object. */ public static LocateFoundConnectionAlgo get_instance(MazeSearchAlgo.Result p_maze_search_result, AutorouteControl p_ctrl, ShapeSearchTree p_search_tree, AngleRestriction p_angle_restriction, SortedSet p_ripped_item_list, TestLevel p_test_level) @@ -67,7 +77,16 @@ public static LocateFoundConnectionAlgo get_instance(MazeSearchAlgo.Result p_maz return result; } - /** Creates a new instance of LocateFoundConnectionAlgo */ + /** + * Creates a new instance of LocateFoundConnectionAlgo + * + * @param p_maze_search_result a {@link autoroute.MazeSearchAlgo.Result} object. + * @param p_ctrl a {@link autoroute.AutorouteControl} object. + * @param p_search_tree a {@link board.ShapeSearchTree} object. + * @param p_angle_restriction a {@link board.AngleRestriction} object. + * @param p_ripped_item_list a {@link java.util.SortedSet} object. + * @param p_test_level a {@link board.TestLevel} object. + */ protected LocateFoundConnectionAlgo(MazeSearchAlgo.Result p_maze_search_result, AutorouteControl p_ctrl, ShapeSearchTree p_search_tree, AngleRestriction p_angle_restriction, SortedSet p_ripped_item_list, TestLevel p_test_level) { @@ -265,10 +284,18 @@ private ResultItem calculate_next_trace(boolean p_layer_changed, boolean p_at_fa /** * Returns the next list of corners for the construction of the trace * in calculate_next_trace. If the result is emppty, the trace is already completed. + * + * @return a java$util$Collection object. */ protected abstract Collection calculate_next_trace_corners(); - /** Test display of the baktrack rooms. */ + /** + * Test display of the baktrack rooms. + * + * @param p_graphics a {@link java.awt.Graphics} object. + * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object. + * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object. + */ public void draw(java.awt.Graphics p_graphics, boardgraphics.GraphicsContext p_graphics_context) { for (int i = 0; i < backtrack_array.length; ++i) diff --git a/autoroute/LocateFoundConnectionAlgo45Degree.java b/src/main/java/autoroute/LocateFoundConnectionAlgo45Degree.java similarity index 95% rename from autoroute/LocateFoundConnectionAlgo45Degree.java rename to src/main/java/autoroute/LocateFoundConnectionAlgo45Degree.java index 051ea30..c63dd76 100644 --- a/autoroute/LocateFoundConnectionAlgo45Degree.java +++ b/src/main/java/autoroute/LocateFoundConnectionAlgo45Degree.java @@ -39,14 +39,23 @@ import board.TestLevel; /** + *

LocateFoundConnectionAlgo45Degree class.

* * @author Alfons Wirtz + * @version $Id: $Id */ public class LocateFoundConnectionAlgo45Degree extends LocateFoundConnectionAlgo { /** * Creates a new instance of LocateFoundConnectionAlgo45Degree + * + * @param p_maze_search_result a {@link autoroute.MazeSearchAlgo.Result} object. + * @param p_ctrl a {@link autoroute.AutorouteControl} object. + * @param p_search_tree a {@link board.ShapeSearchTree} object. + * @param p_angle_restriction a {@link board.AngleRestriction} object. + * @param p_ripped_item_list a {@link java.util.SortedSet} object. + * @param p_test_level a {@link board.TestLevel} object. */ public LocateFoundConnectionAlgo45Degree(MazeSearchAlgo.Result p_maze_search_result, AutorouteControl p_ctrl, ShapeSearchTree p_search_tree, AngleRestriction p_angle_restriction, @@ -55,6 +64,11 @@ public LocateFoundConnectionAlgo45Degree(MazeSearchAlgo.Result p_maze_search_res super(p_maze_search_result, p_ctrl, p_search_tree, p_angle_restriction, p_ripped_item_list, p_test_level); } + /** + *

calculate_next_trace_corners.

+ * + * @return a {@link java.util.Collection} object. + */ protected Collection calculate_next_trace_corners() { Collection result = new LinkedList(); diff --git a/autoroute/LocateFoundConnectionAlgoAnyAngle.java b/src/main/java/autoroute/LocateFoundConnectionAlgoAnyAngle.java similarity index 97% rename from autoroute/LocateFoundConnectionAlgoAnyAngle.java rename to src/main/java/autoroute/LocateFoundConnectionAlgoAnyAngle.java index e907d2a..d6df3dc 100644 --- a/autoroute/LocateFoundConnectionAlgoAnyAngle.java +++ b/src/main/java/autoroute/LocateFoundConnectionAlgoAnyAngle.java @@ -44,7 +44,16 @@ class LocateFoundConnectionAlgoAnyAngle extends LocateFoundConnectionAlgo { - /** Creates a new instance of LocateFoundConnectionAlgo */ + /** + * Creates a new instance of LocateFoundConnectionAlgo + * + * @param p_maze_search_result a {@link autoroute.MazeSearchAlgo.Result} object. + * @param p_ctrl a {@link autoroute.AutorouteControl} object. + * @param p_search_tree a {@link board.ShapeSearchTree} object. + * @param p_angle_restriction a {@link board.AngleRestriction} object. + * @param p_ripped_item_list a {@link java.util.SortedSet} object. + * @param p_test_level a {@link board.TestLevel} object. + */ protected LocateFoundConnectionAlgoAnyAngle(MazeSearchAlgo.Result p_maze_search_result, AutorouteControl p_ctrl, ShapeSearchTree p_search_tree, AngleRestriction p_angle_restriction, SortedSet p_ripped_item_list, TestLevel p_test_level) @@ -55,6 +64,8 @@ protected LocateFoundConnectionAlgoAnyAngle(MazeSearchAlgo.Result p_maze_search_ /** * Calculates a list with the next point of the trace under construction. * If the trace is completed, the result list will be empty. + * + * @return a {@link java.util.Collection} object. */ protected Collection calculate_next_trace_corners() { diff --git a/autoroute/MazeListElement.java b/src/main/java/autoroute/MazeListElement.java similarity index 80% rename from autoroute/MazeListElement.java rename to src/main/java/autoroute/MazeListElement.java index 46527c6..e92e66c 100644 --- a/autoroute/MazeListElement.java +++ b/src/main/java/autoroute/MazeListElement.java @@ -27,11 +27,26 @@ * while the maze expanding algorithm is in progress. * * @author Alfons Wirtz + * @version $Id: $Id */ public class MazeListElement implements Comparable { - /** Creates a new instance of ExpansionInfo */ + /** + * Creates a new instance of ExpansionInfo + * + * @param p_door a {@link autoroute.ExpandableObject} object. + * @param p_section_no_of_door a int. + * @param p_backtrack_door a {@link autoroute.ExpandableObject} object. + * @param p_section_no_of_backtrack_door a int. + * @param p_expansion_value a double. + * @param p_sorting_value a double. + * @param p_next_room a {@link autoroute.CompleteExpansionRoom} object. + * @param p_shape_entry a {@link geometry.planar.FloatLine} object. + * @param p_room_ripped a boolean. + * @param p_adjustment a {@link autoroute.MazeSearchElement.Adjustment} object. + * @param p_already_checked a boolean. + */ public MazeListElement(ExpandableObject p_door, int p_section_no_of_door, ExpandableObject p_backtrack_door, int p_section_no_of_backtrack_door, double p_expansion_value, double p_sorting_value, @@ -51,6 +66,12 @@ public MazeListElement(ExpandableObject p_door, int p_section_no_of_door, already_checked = p_already_checked; } + /** + *

compareTo.

+ * + * @param p_other a {@link autoroute.MazeListElement} object. + * @return a int. + */ public int compareTo(MazeListElement p_other) { double compare_value = (this.sorting_value - p_other.sorting_value); diff --git a/autoroute/MazeSearchAlgo.java b/src/main/java/autoroute/MazeSearchAlgo.java similarity index 99% rename from autoroute/MazeSearchAlgo.java rename to src/main/java/autoroute/MazeSearchAlgo.java index 56c1452..02511ff 100644 --- a/autoroute/MazeSearchAlgo.java +++ b/src/main/java/autoroute/MazeSearchAlgo.java @@ -49,6 +49,7 @@ * Class for autorouting an incomplete connection via a maze search algorithm. * * @author Alfons Wirtz + * @version $Id: $Id */ public class MazeSearchAlgo { @@ -57,6 +58,12 @@ public class MazeSearchAlgo * Initializes a new instance of MazeSearchAlgo for secrching a connection * between p_start_items and p_destination_items. * Returns null, if the initialisation failed. + * + * @param p_start_items a {@link java.util.Set} object. + * @param p_destination_items a {@link java.util.Set} object. + * @param p_autoroute_database a {@link autoroute.AutorouteEngine} object. + * @param p_ctrl a {@link autoroute.AutorouteControl} object. + * @return a {@link autoroute.MazeSearchAlgo} object. */ public static MazeSearchAlgo get_instance(Set p_start_items, Set p_destination_items, AutorouteEngine p_autoroute_database, AutorouteControl p_ctrl) @@ -92,6 +99,8 @@ public static MazeSearchAlgo get_instance(Set p_start_items, * destination items. If the algorithm succeeds, the ExpansionDoor and its section number of * the found destination is returned, from where the whole found connection * can be backtracked. Otherwise the return value will be null. + * + * @return a {@link autoroute.MazeSearchAlgo.Result} object. */ public Result find_connection() { @@ -108,6 +117,8 @@ public Result find_connection() /** * Expands the next element in the maze expansion list. * Returns false, if the expansion list is exhausted or the destination is reached. + * + * @return a boolean. */ public boolean occupy_next_element() { diff --git a/autoroute/MazeSearchElement.java b/src/main/java/autoroute/MazeSearchElement.java similarity index 98% rename from autoroute/MazeSearchElement.java rename to src/main/java/autoroute/MazeSearchElement.java index e7cccf6..aa11257 100644 --- a/autoroute/MazeSearchElement.java +++ b/src/main/java/autoroute/MazeSearchElement.java @@ -24,6 +24,7 @@ * Describes the structure of a section of an ExpandebleObject. * * @author Alfons Wirtz + * @version $Id: $Id */ public class MazeSearchElement { diff --git a/autoroute/MazeShoveTraceAlgo.java b/src/main/java/autoroute/MazeShoveTraceAlgo.java similarity index 97% rename from autoroute/MazeShoveTraceAlgo.java rename to src/main/java/autoroute/MazeShoveTraceAlgo.java index 93f7868..b5fa8ca 100644 --- a/autoroute/MazeShoveTraceAlgo.java +++ b/src/main/java/autoroute/MazeShoveTraceAlgo.java @@ -1,408 +1,417 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * MazeShoveTraceAlgo.java - * - * Created on 10. Mai 2006, 06:41 - * - */ - -package autoroute; - -import java.util.Collection; - -import geometry.planar.TileShape; -import geometry.planar.Line; -import geometry.planar.Polyline; -import geometry.planar.Point; -import geometry.planar.FloatPoint; -import geometry.planar.FloatLine; -import geometry.planar.Side; -import geometry.planar.Direction; -import geometry.planar.LineSegment; - -import board.Item; -import board.RoutingBoard; -import board.ShoveTraceAlgo; - -/** - * Auxiliary functions used in MazeSearchAlgo. - * - * @author Alfons Wirtz - */ -public class MazeShoveTraceAlgo -{ - - /** - * Returns false, if the algorithm did not succeed and trying to shove from another door section - * may be more successful. - */ - public static boolean check_shove_trace_line(MazeListElement p_list_element, - ObstacleExpansionRoom p_obstacle_room, RoutingBoard p_board, AutorouteControl p_ctrl, - boolean p_shove_to_the_left, Collection p_to_door_list) - { - if (!(p_list_element.door instanceof ExpansionDoor)) - { - return true; - } - ExpansionDoor from_door = (ExpansionDoor) p_list_element.door; - if (!(p_obstacle_room.get_item() instanceof board.PolylineTrace)) - { - return true; - } - board.PolylineTrace obstacle_trace = (board.PolylineTrace)p_obstacle_room.get_item(); - int trace_layer = p_obstacle_room.get_layer(); - // only traces with the same halfwidth and the same clearance class can be shoved. - if (obstacle_trace.get_half_width() != p_ctrl.trace_half_width[trace_layer] - || obstacle_trace.clearance_class_no() != p_ctrl.trace_clearance_class_no) - { - return true; - } - double compensated_trace_half_width = p_ctrl.compensated_trace_half_width[trace_layer]; - TileShape from_door_shape = from_door.get_shape(); - if (from_door_shape.max_width() < 2 * compensated_trace_half_width) - { - return true; - } - int trace_corner_no = p_obstacle_room.get_index_in_item(); - - Polyline trace_polyline = obstacle_trace.polyline(); - - if (trace_corner_no >= trace_polyline.arr.length - 1) - { - System.out.println("MazeShoveTraceAlgo.check_shove_trace_line: trace_corner_no to big"); - return false; - } - Collection room_doors = p_obstacle_room.get_doors(); - // The side of the trace line seen from the doors to expand. - // Used to determine, if a door is on the right side to put it into the p_door_list. - LineSegment shove_line_segment; - if (from_door.dimension == 2) - { - // shove from a link door into the direction of the other link door. - CompleteExpansionRoom other_room = from_door.other_room(p_obstacle_room); - if (!(other_room instanceof ObstacleExpansionRoom)) - { - return false; - } - if (!end_points_matching(obstacle_trace, ((ObstacleExpansionRoom)other_room).get_item())) - { - return false; - } - FloatPoint door_center = from_door_shape.centre_of_gravity(); - FloatPoint corner_1 = trace_polyline.corner_approx(trace_corner_no); - FloatPoint corner_2 = trace_polyline.corner_approx(trace_corner_no + 1); - if (corner_1.distance_square(corner_2) < 1) - { - // shove_line_segment may be reduced to a point - return false; - } - boolean shove_into_direction_of_trace_start = - door_center.distance_square(corner_2) < door_center.distance_square(corner_1); - shove_line_segment = new LineSegment(trace_polyline, trace_corner_no + 1); - if (shove_into_direction_of_trace_start) - { - - // shove from the endpoint to the start point of the line segment - shove_line_segment = shove_line_segment.opposite(); - } - } - else - { - CompleteExpansionRoom from_room = from_door.other_room(p_obstacle_room); - FloatPoint from_point = from_room.get_shape().centre_of_gravity(); - Line shove_trace_line = trace_polyline.arr[trace_corner_no + 1]; - FloatLine door_line_segment = from_door_shape.diagonal_corner_segment(); - Side side_of_trace_line = shove_trace_line.side_of(door_line_segment.a, 0); - - FloatLine polar_line_segment = from_door_shape.polar_line_segment(from_point); - - boolean door_line_swapped = - polar_line_segment.b.distance_square(door_line_segment.a) < - polar_line_segment.a.distance_square(door_line_segment.a); - - boolean section_ok; - // shove only from the right most section to the right or from the left most section to the left. - - double shape_entry_check_distance = compensated_trace_half_width + 5; - double check_dist_square = shape_entry_check_distance * shape_entry_check_distance; - - if (p_shove_to_the_left && !door_line_swapped || !p_shove_to_the_left && door_line_swapped) - { - section_ok = - p_list_element.section_no_of_door == p_list_element.door.maze_search_element_count() - 1 - && (p_list_element.shape_entry.a.distance_square(door_line_segment.b) <= check_dist_square - || p_list_element.shape_entry.b.distance_square(door_line_segment.b) <= check_dist_square); - } - else - { - section_ok = - p_list_element.section_no_of_door == 0 - && (p_list_element.shape_entry.a.distance_square(door_line_segment.a) <= check_dist_square - || p_list_element.shape_entry.b.distance_square(door_line_segment.a) <= check_dist_square); - } - if (!section_ok) - { - return false; - } - - - // create the line segment for shoving - - FloatLine shrinked_line_segment = polar_line_segment.shrink_segment(compensated_trace_half_width); - Direction perpendicular_direction = shove_trace_line.direction().turn_45_degree(2); - if (side_of_trace_line == Side.ON_THE_LEFT) - { - if (p_shove_to_the_left) - { - Line start_closing_line = new Line(shrinked_line_segment.b.round(), perpendicular_direction); - shove_line_segment = - new LineSegment(start_closing_line, trace_polyline.arr[trace_corner_no + 1], - trace_polyline.arr[trace_corner_no + 2]); - } - else - { - Line start_closing_line = new Line(shrinked_line_segment.a.round(), perpendicular_direction); - shove_line_segment = - new LineSegment(start_closing_line, trace_polyline.arr[trace_corner_no + 1].opposite(), - trace_polyline.arr[trace_corner_no].opposite()); - } - } - else - { - if (p_shove_to_the_left) - { - Line start_closing_line = new Line(shrinked_line_segment.b.round(), perpendicular_direction); - shove_line_segment = - new LineSegment(start_closing_line, trace_polyline.arr[trace_corner_no + 1].opposite(), - trace_polyline.arr[trace_corner_no].opposite()); - } - else - { - Line start_closing_line = new Line(shrinked_line_segment.a.round(), perpendicular_direction); - shove_line_segment = - new LineSegment(start_closing_line, trace_polyline.arr[trace_corner_no + 1], - trace_polyline.arr[trace_corner_no + 2]); - } - } - } - int trace_half_width = p_ctrl.trace_half_width[trace_layer]; - int [] net_no_arr = new int[1]; - net_no_arr[0] = p_ctrl.net_no; - - double shove_width = - p_board.check_trace_segment(shove_line_segment, trace_layer, net_no_arr, trace_half_width, - p_ctrl.trace_clearance_class_no, true); - boolean segment_shortened = false; - if (shove_width < Integer.MAX_VALUE) - { - // shorten shove_line_segment - shove_width = shove_width - 1; - if (shove_width <= 0) - { - return true; - } - shove_line_segment = shove_line_segment.change_length_approx(shove_width); - segment_shortened = true; - } - - FloatPoint from_corner = shove_line_segment.start_point_approx(); - FloatPoint to_corner = shove_line_segment.end_point_approx(); - boolean segment_ist_point = from_corner.distance_square(to_corner) < 0.1; - - if (!segment_ist_point) - { - shove_width = ShoveTraceAlgo.check(p_board, shove_line_segment, p_shove_to_the_left, trace_layer, net_no_arr, trace_half_width, - p_ctrl.trace_clearance_class_no, p_ctrl.max_shove_trace_recursion_depth, p_ctrl.max_shove_via_recursion_depth); - - if (shove_width <= 0) - { - return true; - } - } - - // Put the doors on this side of the room into p_to_door_list with - if (segment_shortened) - { - shove_width = Math.min(shove_width, from_corner.distance(to_corner)); - } - - Line shove_line = shove_line_segment.get_line(); - - // From_door_compare_distance is used to check, that a door is between from_door and the end point - // of the shove line. - double from_door_compare_distance; - if (from_door.dimension == 2 || segment_ist_point) - { - from_door_compare_distance = Double.MAX_VALUE; - } - else - { - from_door_compare_distance = to_corner.distance_square(from_door_shape.corner_approx(0)); - } - - for (ExpansionDoor curr_door : room_doors) - { - if (curr_door == from_door) - { - continue; - } - if (curr_door.first_room instanceof ObstacleExpansionRoom && - curr_door.second_room instanceof ObstacleExpansionRoom) - { - Item first_room_item = ((ObstacleExpansionRoom)curr_door.first_room).get_item(); - Item second_room_item = ((ObstacleExpansionRoom)curr_door.second_room).get_item(); - if (first_room_item != second_room_item) - { - // there may be topological problems at a trace fork - continue; - } - } - TileShape curr_door_shape = curr_door.get_shape(); - if (curr_door.dimension == 2 && shove_width >= Integer.MAX_VALUE) - { - boolean add_link_door = curr_door_shape.contains(to_corner); - - - if (add_link_door) - { - FloatLine[] line_sections = curr_door.get_section_segments(compensated_trace_half_width); - p_to_door_list.add(new DoorSection(curr_door, 0, line_sections[0])); - } - continue; - } - else if (!segment_ist_point) - { - // now curr_door is 1-dimensional - - // check, that curr_door is on the same border_line as p_from_door. - FloatLine curr_door_segment = curr_door_shape.diagonal_corner_segment(); - if (curr_door_segment == null) - { - if (p_board.get_test_level() == board.TestLevel.ALL_DEBUGGING_OUTPUT) - { - System.out.println("MazeShoveTraceAlgo.check_shove_trace_line: door shape is empty"); - } - continue; - } - Side start_corner_side_of_trace_line = shove_line.side_of(curr_door_segment.a, 0); - Side end_corner_side_of_trace_line = shove_line.side_of(curr_door_segment.b, 0); - if (p_shove_to_the_left) - { - if (start_corner_side_of_trace_line != Side.ON_THE_LEFT || end_corner_side_of_trace_line != Side.ON_THE_LEFT) - { - continue; - } - } - else - { - if (start_corner_side_of_trace_line != Side.ON_THE_RIGHT || end_corner_side_of_trace_line != Side.ON_THE_RIGHT) - { - continue; - } - } - FloatLine curr_door_line = curr_door_shape.polar_line_segment(from_corner); - FloatPoint curr_door_nearest_corner; - if (curr_door_line.a.distance_square(from_corner) <= curr_door_line.b.distance_square(from_corner)) - { - curr_door_nearest_corner = curr_door_line.a; - } - else - { - curr_door_nearest_corner = curr_door_line.b; - } - if (to_corner.distance_square(curr_door_nearest_corner) >= from_door_compare_distance) - { - // curr_door is not located into the direction of to_corner. - continue; - } - FloatPoint curr_door_projection = curr_door_nearest_corner.projection_approx(shove_line); - - if (curr_door_projection.distance(from_corner) + compensated_trace_half_width <= shove_width) - { - FloatLine[] line_sections = curr_door.get_section_segments(compensated_trace_half_width); - for (int i = 0; i < line_sections.length; ++i) - { - FloatLine curr_line_section = line_sections[i]; - FloatPoint curr_section_nearest_corner; - if (curr_line_section.a.distance_square(from_corner) <= curr_line_section.b.distance_square(from_corner)) - { - curr_section_nearest_corner = curr_line_section.a; - } - else - { - curr_section_nearest_corner = curr_line_section.b; - } - FloatPoint curr_section_projection = curr_section_nearest_corner.projection_approx(shove_line); - if (curr_section_projection.distance(from_corner) <= shove_width) - { - p_to_door_list.add(new DoorSection(curr_door, i, curr_line_section)); - } - } - } - } - } - return true; - } - - /** - * Check if the endpoints of p_trace and p_from_item are maching, so that the - * shove can continue through a link door. - */ - private static boolean end_points_matching(board.PolylineTrace p_trace, Item p_from_item) - { - if (p_from_item == p_trace) - { - return true; - } - if (!p_trace.shares_net(p_from_item)) - { - return false; - } - boolean points_matching; - if (p_from_item instanceof board.DrillItem) - { - Point from_center = ((board.DrillItem) p_from_item).get_center(); - points_matching = from_center.equals(p_trace.first_corner()) || from_center.equals(p_trace.last_corner()); - } - else if (p_from_item instanceof board.PolylineTrace) - { - board.PolylineTrace from_trace = (board.PolylineTrace) p_from_item; - points_matching = p_trace.first_corner().equals(from_trace.first_corner()) || - p_trace.first_corner().equals(from_trace.last_corner()) || - p_trace.last_corner().equals(from_trace.first_corner()) || - p_trace.last_corner().equals(from_trace.last_corner()); - } - else - { - points_matching = false; - } - return points_matching; - } - - public static class DoorSection - { - DoorSection(ExpansionDoor p_door, int p_section_no, FloatLine p_section_line) - { - door = p_door; - section_no = p_section_no; - section_line = p_section_line; - - } - final ExpansionDoor door; - final int section_no; - final FloatLine section_line; - } -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * MazeShoveTraceAlgo.java + * + * Created on 10. Mai 2006, 06:41 + * + */ + +package autoroute; + +import java.util.Collection; + +import geometry.planar.TileShape; +import geometry.planar.Line; +import geometry.planar.Polyline; +import geometry.planar.Point; +import geometry.planar.FloatPoint; +import geometry.planar.FloatLine; +import geometry.planar.Side; +import geometry.planar.Direction; +import geometry.planar.LineSegment; + +import board.Item; +import board.RoutingBoard; +import board.ShoveTraceAlgo; + +/** + * Auxiliary functions used in MazeSearchAlgo. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class MazeShoveTraceAlgo +{ + + /** + * Returns false, if the algorithm did not succeed and trying to shove from another door section + * may be more successful. + * + * @param p_list_element a {@link autoroute.MazeListElement} object. + * @param p_obstacle_room a {@link autoroute.ObstacleExpansionRoom} object. + * @param p_board a {@link board.RoutingBoard} object. + * @param p_ctrl a {@link autoroute.AutorouteControl} object. + * @param p_shove_to_the_left a boolean. + * @param p_to_door_list a {@link java.util.Collection} object. + * @return a boolean. + */ + public static boolean check_shove_trace_line(MazeListElement p_list_element, + ObstacleExpansionRoom p_obstacle_room, RoutingBoard p_board, AutorouteControl p_ctrl, + boolean p_shove_to_the_left, Collection p_to_door_list) + { + if (!(p_list_element.door instanceof ExpansionDoor)) + { + return true; + } + ExpansionDoor from_door = (ExpansionDoor) p_list_element.door; + if (!(p_obstacle_room.get_item() instanceof board.PolylineTrace)) + { + return true; + } + board.PolylineTrace obstacle_trace = (board.PolylineTrace)p_obstacle_room.get_item(); + int trace_layer = p_obstacle_room.get_layer(); + // only traces with the same halfwidth and the same clearance class can be shoved. + if (obstacle_trace.get_half_width() != p_ctrl.trace_half_width[trace_layer] + || obstacle_trace.clearance_class_no() != p_ctrl.trace_clearance_class_no) + { + return true; + } + double compensated_trace_half_width = p_ctrl.compensated_trace_half_width[trace_layer]; + TileShape from_door_shape = from_door.get_shape(); + if (from_door_shape.max_width() < 2 * compensated_trace_half_width) + { + return true; + } + int trace_corner_no = p_obstacle_room.get_index_in_item(); + + Polyline trace_polyline = obstacle_trace.polyline(); + + if (trace_corner_no >= trace_polyline.arr.length - 1) + { + System.out.println("MazeShoveTraceAlgo.check_shove_trace_line: trace_corner_no to big"); + return false; + } + Collection room_doors = p_obstacle_room.get_doors(); + // The side of the trace line seen from the doors to expand. + // Used to determine, if a door is on the right side to put it into the p_door_list. + LineSegment shove_line_segment; + if (from_door.dimension == 2) + { + // shove from a link door into the direction of the other link door. + CompleteExpansionRoom other_room = from_door.other_room(p_obstacle_room); + if (!(other_room instanceof ObstacleExpansionRoom)) + { + return false; + } + if (!end_points_matching(obstacle_trace, ((ObstacleExpansionRoom)other_room).get_item())) + { + return false; + } + FloatPoint door_center = from_door_shape.centre_of_gravity(); + FloatPoint corner_1 = trace_polyline.corner_approx(trace_corner_no); + FloatPoint corner_2 = trace_polyline.corner_approx(trace_corner_no + 1); + if (corner_1.distance_square(corner_2) < 1) + { + // shove_line_segment may be reduced to a point + return false; + } + boolean shove_into_direction_of_trace_start = + door_center.distance_square(corner_2) < door_center.distance_square(corner_1); + shove_line_segment = new LineSegment(trace_polyline, trace_corner_no + 1); + if (shove_into_direction_of_trace_start) + { + + // shove from the endpoint to the start point of the line segment + shove_line_segment = shove_line_segment.opposite(); + } + } + else + { + CompleteExpansionRoom from_room = from_door.other_room(p_obstacle_room); + FloatPoint from_point = from_room.get_shape().centre_of_gravity(); + Line shove_trace_line = trace_polyline.arr[trace_corner_no + 1]; + FloatLine door_line_segment = from_door_shape.diagonal_corner_segment(); + Side side_of_trace_line = shove_trace_line.side_of(door_line_segment.a, 0); + + FloatLine polar_line_segment = from_door_shape.polar_line_segment(from_point); + + boolean door_line_swapped = + polar_line_segment.b.distance_square(door_line_segment.a) < + polar_line_segment.a.distance_square(door_line_segment.a); + + boolean section_ok; + // shove only from the right most section to the right or from the left most section to the left. + + double shape_entry_check_distance = compensated_trace_half_width + 5; + double check_dist_square = shape_entry_check_distance * shape_entry_check_distance; + + if (p_shove_to_the_left && !door_line_swapped || !p_shove_to_the_left && door_line_swapped) + { + section_ok = + p_list_element.section_no_of_door == p_list_element.door.maze_search_element_count() - 1 + && (p_list_element.shape_entry.a.distance_square(door_line_segment.b) <= check_dist_square + || p_list_element.shape_entry.b.distance_square(door_line_segment.b) <= check_dist_square); + } + else + { + section_ok = + p_list_element.section_no_of_door == 0 + && (p_list_element.shape_entry.a.distance_square(door_line_segment.a) <= check_dist_square + || p_list_element.shape_entry.b.distance_square(door_line_segment.a) <= check_dist_square); + } + if (!section_ok) + { + return false; + } + + + // create the line segment for shoving + + FloatLine shrinked_line_segment = polar_line_segment.shrink_segment(compensated_trace_half_width); + Direction perpendicular_direction = shove_trace_line.direction().turn_45_degree(2); + if (side_of_trace_line == Side.ON_THE_LEFT) + { + if (p_shove_to_the_left) + { + Line start_closing_line = new Line(shrinked_line_segment.b.round(), perpendicular_direction); + shove_line_segment = + new LineSegment(start_closing_line, trace_polyline.arr[trace_corner_no + 1], + trace_polyline.arr[trace_corner_no + 2]); + } + else + { + Line start_closing_line = new Line(shrinked_line_segment.a.round(), perpendicular_direction); + shove_line_segment = + new LineSegment(start_closing_line, trace_polyline.arr[trace_corner_no + 1].opposite(), + trace_polyline.arr[trace_corner_no].opposite()); + } + } + else + { + if (p_shove_to_the_left) + { + Line start_closing_line = new Line(shrinked_line_segment.b.round(), perpendicular_direction); + shove_line_segment = + new LineSegment(start_closing_line, trace_polyline.arr[trace_corner_no + 1].opposite(), + trace_polyline.arr[trace_corner_no].opposite()); + } + else + { + Line start_closing_line = new Line(shrinked_line_segment.a.round(), perpendicular_direction); + shove_line_segment = + new LineSegment(start_closing_line, trace_polyline.arr[trace_corner_no + 1], + trace_polyline.arr[trace_corner_no + 2]); + } + } + } + int trace_half_width = p_ctrl.trace_half_width[trace_layer]; + int [] net_no_arr = new int[1]; + net_no_arr[0] = p_ctrl.net_no; + + double shove_width = + p_board.check_trace_segment(shove_line_segment, trace_layer, net_no_arr, trace_half_width, + p_ctrl.trace_clearance_class_no, true); + boolean segment_shortened = false; + if (shove_width < Integer.MAX_VALUE) + { + // shorten shove_line_segment + shove_width = shove_width - 1; + if (shove_width <= 0) + { + return true; + } + shove_line_segment = shove_line_segment.change_length_approx(shove_width); + segment_shortened = true; + } + + FloatPoint from_corner = shove_line_segment.start_point_approx(); + FloatPoint to_corner = shove_line_segment.end_point_approx(); + boolean segment_ist_point = from_corner.distance_square(to_corner) < 0.1; + + if (!segment_ist_point) + { + shove_width = ShoveTraceAlgo.check(p_board, shove_line_segment, p_shove_to_the_left, trace_layer, net_no_arr, trace_half_width, + p_ctrl.trace_clearance_class_no, p_ctrl.max_shove_trace_recursion_depth, p_ctrl.max_shove_via_recursion_depth); + + if (shove_width <= 0) + { + return true; + } + } + + // Put the doors on this side of the room into p_to_door_list with + if (segment_shortened) + { + shove_width = Math.min(shove_width, from_corner.distance(to_corner)); + } + + Line shove_line = shove_line_segment.get_line(); + + // From_door_compare_distance is used to check, that a door is between from_door and the end point + // of the shove line. + double from_door_compare_distance; + if (from_door.dimension == 2 || segment_ist_point) + { + from_door_compare_distance = Double.MAX_VALUE; + } + else + { + from_door_compare_distance = to_corner.distance_square(from_door_shape.corner_approx(0)); + } + + for (ExpansionDoor curr_door : room_doors) + { + if (curr_door == from_door) + { + continue; + } + if (curr_door.first_room instanceof ObstacleExpansionRoom && + curr_door.second_room instanceof ObstacleExpansionRoom) + { + Item first_room_item = ((ObstacleExpansionRoom)curr_door.first_room).get_item(); + Item second_room_item = ((ObstacleExpansionRoom)curr_door.second_room).get_item(); + if (first_room_item != second_room_item) + { + // there may be topological problems at a trace fork + continue; + } + } + TileShape curr_door_shape = curr_door.get_shape(); + if (curr_door.dimension == 2 && shove_width >= Integer.MAX_VALUE) + { + boolean add_link_door = curr_door_shape.contains(to_corner); + + + if (add_link_door) + { + FloatLine[] line_sections = curr_door.get_section_segments(compensated_trace_half_width); + p_to_door_list.add(new DoorSection(curr_door, 0, line_sections[0])); + } + continue; + } + else if (!segment_ist_point) + { + // now curr_door is 1-dimensional + + // check, that curr_door is on the same border_line as p_from_door. + FloatLine curr_door_segment = curr_door_shape.diagonal_corner_segment(); + if (curr_door_segment == null) + { + if (p_board.get_test_level() == board.TestLevel.ALL_DEBUGGING_OUTPUT) + { + System.out.println("MazeShoveTraceAlgo.check_shove_trace_line: door shape is empty"); + } + continue; + } + Side start_corner_side_of_trace_line = shove_line.side_of(curr_door_segment.a, 0); + Side end_corner_side_of_trace_line = shove_line.side_of(curr_door_segment.b, 0); + if (p_shove_to_the_left) + { + if (start_corner_side_of_trace_line != Side.ON_THE_LEFT || end_corner_side_of_trace_line != Side.ON_THE_LEFT) + { + continue; + } + } + else + { + if (start_corner_side_of_trace_line != Side.ON_THE_RIGHT || end_corner_side_of_trace_line != Side.ON_THE_RIGHT) + { + continue; + } + } + FloatLine curr_door_line = curr_door_shape.polar_line_segment(from_corner); + FloatPoint curr_door_nearest_corner; + if (curr_door_line.a.distance_square(from_corner) <= curr_door_line.b.distance_square(from_corner)) + { + curr_door_nearest_corner = curr_door_line.a; + } + else + { + curr_door_nearest_corner = curr_door_line.b; + } + if (to_corner.distance_square(curr_door_nearest_corner) >= from_door_compare_distance) + { + // curr_door is not located into the direction of to_corner. + continue; + } + FloatPoint curr_door_projection = curr_door_nearest_corner.projection_approx(shove_line); + + if (curr_door_projection.distance(from_corner) + compensated_trace_half_width <= shove_width) + { + FloatLine[] line_sections = curr_door.get_section_segments(compensated_trace_half_width); + for (int i = 0; i < line_sections.length; ++i) + { + FloatLine curr_line_section = line_sections[i]; + FloatPoint curr_section_nearest_corner; + if (curr_line_section.a.distance_square(from_corner) <= curr_line_section.b.distance_square(from_corner)) + { + curr_section_nearest_corner = curr_line_section.a; + } + else + { + curr_section_nearest_corner = curr_line_section.b; + } + FloatPoint curr_section_projection = curr_section_nearest_corner.projection_approx(shove_line); + if (curr_section_projection.distance(from_corner) <= shove_width) + { + p_to_door_list.add(new DoorSection(curr_door, i, curr_line_section)); + } + } + } + } + } + return true; + } + + /** + * Check if the endpoints of p_trace and p_from_item are maching, so that the + * shove can continue through a link door. + */ + private static boolean end_points_matching(board.PolylineTrace p_trace, Item p_from_item) + { + if (p_from_item == p_trace) + { + return true; + } + if (!p_trace.shares_net(p_from_item)) + { + return false; + } + boolean points_matching; + if (p_from_item instanceof board.DrillItem) + { + Point from_center = ((board.DrillItem) p_from_item).get_center(); + points_matching = from_center.equals(p_trace.first_corner()) || from_center.equals(p_trace.last_corner()); + } + else if (p_from_item instanceof board.PolylineTrace) + { + board.PolylineTrace from_trace = (board.PolylineTrace) p_from_item; + points_matching = p_trace.first_corner().equals(from_trace.first_corner()) || + p_trace.first_corner().equals(from_trace.last_corner()) || + p_trace.last_corner().equals(from_trace.first_corner()) || + p_trace.last_corner().equals(from_trace.last_corner()); + } + else + { + points_matching = false; + } + return points_matching; + } + + public static class DoorSection + { + DoorSection(ExpansionDoor p_door, int p_section_no, FloatLine p_section_line) + { + door = p_door; + section_no = p_section_no; + section_line = p_section_line; + + } + final ExpansionDoor door; + final int section_no; + final FloatLine section_line; + } +} diff --git a/autoroute/ObstacleExpansionRoom.java b/src/main/java/autoroute/ObstacleExpansionRoom.java similarity index 86% rename from autoroute/ObstacleExpansionRoom.java rename to src/main/java/autoroute/ObstacleExpansionRoom.java index f63bc89..a6b1240 100644 --- a/autoroute/ObstacleExpansionRoom.java +++ b/src/main/java/autoroute/ObstacleExpansionRoom.java @@ -1,207 +1,253 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * ObstacleExpansionRoom.java - * - * Created on 17. April 2006, 06:45 - * - */ - -package autoroute; - -import java.util.List; -import java.util.Collection; - -import board.ShapeSearchTree; -import board.SearchTreeObject; -import board.PolylineTrace; - -import geometry.planar.TileShape; - -import board.Item; - -/** - * Expansion Room used for pushing and ripping obstacles in the autoroute algorithm. - * - * @author Alfons Wirtz - */ -public class ObstacleExpansionRoom implements CompleteExpansionRoom -{ - - /** Creates a new instance of ObstacleExpansionRoom */ - ObstacleExpansionRoom(Item p_item, int p_index_in_item, ShapeSearchTree p_shape_tree) - { - this.item = p_item; - this.index_in_item = p_index_in_item; - this.shape = p_item.get_tree_shape(p_shape_tree, p_index_in_item); - this.doors = new java.util.LinkedList(); - } - - public int get_index_in_item() - { - return this.index_in_item; - } - - public int get_layer() - { - return this.item.shape_layer(this.index_in_item); - } - - public TileShape get_shape() - { - return this.shape; - } - - /** - * Checks, if this room has already a 1-dimensional door to p_other - */ - public boolean door_exists(ExpansionRoom p_other) - { - if (doors != null) - { - for (ExpansionDoor curr_door : this.doors) - { - if (curr_door.first_room == p_other || curr_door.second_room == p_other) - { - return true; - } - } - } - return false; - } - - /** - * Adds a door to the door list of this room. - */ - public void add_door(ExpansionDoor p_door) - { - this.doors.add(p_door); - } - - /** - * Creates a 2-dim door with the other obstacle room, if that is useful for the autoroute algorithm. - * It is assumed that this room and p_other have a 2-dimensional overlap. - * Returns false, if no door was created. - */ - public boolean create_overlap_door(ObstacleExpansionRoom p_other) - { - if (this.door_exists(p_other)) - { - return false; - } - if (!(this.item.is_route() && p_other.item.is_route())) - { - return false; - } - if (!this.item.shares_net(p_other.item)) - { - return false; - } - if (this.item == p_other.item) - { - if (!(this.item instanceof PolylineTrace)) - { - return false; - } - // create only doors between consecutive trace segments - if (this.index_in_item != p_other.index_in_item + 1 && this.index_in_item != p_other.index_in_item - 1) - { - return false; - } - } - ExpansionDoor new_door = new ExpansionDoor(this, p_other, 2); - this.add_door(new_door); - p_other.add_door(new_door); - return true; - } - - /** - * Returns the list of doors of this room to neighbour expansion rooms - */ - public List get_doors() - { - return this.doors; - } - - /** - * Removes all doors from this room. - */ - public void clear_doors() - { - this.doors = new java.util.LinkedList(); - } - - public void reset_doors() - { - for (ExpandableObject curr_door : this.doors) - { - curr_door.reset(); - } - } - - public Collection get_target_doors() - { - return new java.util.LinkedList(); - } - - public Item get_item() - { - return this.item; - } - - public SearchTreeObject get_object() - { - return this.item; - } - - public boolean remove_door(ExpandableObject p_door) - { - return this.doors.remove(p_door); - } - - /** - * Returns, if all doors to the neighbour rooms are calculated. - */ - boolean all_doors_calculated() - { - return this.doors_calculated; - } - - void set_doors_calculated(boolean p_value) - { - this.doors_calculated = p_value; - } - - - /** - * Draws the shape of this room. - */ - public void draw(java.awt.Graphics p_graphics, boardgraphics.GraphicsContext p_graphics_context, double p_intensity) - { - java.awt.Color draw_color = java.awt.Color.WHITE; - double layer_visibility = p_graphics_context.get_layer_visibility(this.get_layer()); - p_graphics_context.fill_area(this.get_shape(), p_graphics, draw_color, p_intensity * layer_visibility); - p_graphics_context.draw_boundary(this.get_shape(), 0, draw_color, p_graphics, layer_visibility); - } - - private final Item item; - private final int index_in_item; - private final TileShape shape; - - /** The list of doors to neighbour expansion rooms */ - private List doors; - - private boolean doors_calculated = false; -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * ObstacleExpansionRoom.java + * + * Created on 17. April 2006, 06:45 + * + */ + +package autoroute; + +import java.util.List; +import java.util.Collection; + +import board.ShapeSearchTree; +import board.SearchTreeObject; +import board.PolylineTrace; + +import geometry.planar.TileShape; + +import board.Item; + +/** + * Expansion Room used for pushing and ripping obstacles in the autoroute algorithm. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class ObstacleExpansionRoom implements CompleteExpansionRoom +{ + + /** Creates a new instance of ObstacleExpansionRoom */ + ObstacleExpansionRoom(Item p_item, int p_index_in_item, ShapeSearchTree p_shape_tree) + { + this.item = p_item; + this.index_in_item = p_index_in_item; + this.shape = p_item.get_tree_shape(p_shape_tree, p_index_in_item); + this.doors = new java.util.LinkedList(); + } + + /** + *

get_index_in_item.

+ * + * @return a int. + */ + public int get_index_in_item() + { + return this.index_in_item; + } + + /** + *

get_layer.

+ * + * @return a int. + */ + public int get_layer() + { + return this.item.shape_layer(this.index_in_item); + } + + /** + *

get_shape.

+ * + * @return a {@link geometry.planar.TileShape} object. + */ + public TileShape get_shape() + { + return this.shape; + } + + /** + * {@inheritDoc} + * + * Checks, if this room has already a 1-dimensional door to p_other + */ + public boolean door_exists(ExpansionRoom p_other) + { + if (doors != null) + { + for (ExpansionDoor curr_door : this.doors) + { + if (curr_door.first_room == p_other || curr_door.second_room == p_other) + { + return true; + } + } + } + return false; + } + + /** + * {@inheritDoc} + * + * Adds a door to the door list of this room. + */ + public void add_door(ExpansionDoor p_door) + { + this.doors.add(p_door); + } + + /** + * Creates a 2-dim door with the other obstacle room, if that is useful for the autoroute algorithm. + * It is assumed that this room and p_other have a 2-dimensional overlap. + * Returns false, if no door was created. + * + * @param p_other a {@link autoroute.ObstacleExpansionRoom} object. + * @return a boolean. + */ + public boolean create_overlap_door(ObstacleExpansionRoom p_other) + { + if (this.door_exists(p_other)) + { + return false; + } + if (!(this.item.is_route() && p_other.item.is_route())) + { + return false; + } + if (!this.item.shares_net(p_other.item)) + { + return false; + } + if (this.item == p_other.item) + { + if (!(this.item instanceof PolylineTrace)) + { + return false; + } + // create only doors between consecutive trace segments + if (this.index_in_item != p_other.index_in_item + 1 && this.index_in_item != p_other.index_in_item - 1) + { + return false; + } + } + ExpansionDoor new_door = new ExpansionDoor(this, p_other, 2); + this.add_door(new_door); + p_other.add_door(new_door); + return true; + } + + /** + * Returns the list of doors of this room to neighbour expansion rooms + * + * @return a {@link java.util.List} object. + */ + public List get_doors() + { + return this.doors; + } + + /** + * Removes all doors from this room. + */ + public void clear_doors() + { + this.doors = new java.util.LinkedList(); + } + + /** + *

reset_doors.

+ */ + public void reset_doors() + { + for (ExpandableObject curr_door : this.doors) + { + curr_door.reset(); + } + } + + /** + *

get_target_doors.

+ * + * @return a {@link java.util.Collection} object. + */ + public Collection get_target_doors() + { + return new java.util.LinkedList(); + } + + /** + *

get_item.

+ * + * @return a {@link board.Item} object. + */ + public Item get_item() + { + return this.item; + } + + /** + *

get_object.

+ * + * @return a {@link board.SearchTreeObject} object. + */ + public SearchTreeObject get_object() + { + return this.item; + } + + /** {@inheritDoc} */ + public boolean remove_door(ExpandableObject p_door) + { + return this.doors.remove(p_door); + } + + /** + * Returns, if all doors to the neighbour rooms are calculated. + */ + boolean all_doors_calculated() + { + return this.doors_calculated; + } + + void set_doors_calculated(boolean p_value) + { + this.doors_calculated = p_value; + } + + + /** + * {@inheritDoc} + * + * Draws the shape of this room. + */ + public void draw(java.awt.Graphics p_graphics, boardgraphics.GraphicsContext p_graphics_context, double p_intensity) + { + java.awt.Color draw_color = java.awt.Color.WHITE; + double layer_visibility = p_graphics_context.get_layer_visibility(this.get_layer()); + p_graphics_context.fill_area(this.get_shape(), p_graphics, draw_color, p_intensity * layer_visibility); + p_graphics_context.draw_boundary(this.get_shape(), 0, draw_color, p_graphics, layer_visibility); + } + + private final Item item; + private final int index_in_item; + private final TileShape shape; + + /** The list of doors to neighbour expansion rooms */ + private List doors; + + private boolean doors_calculated = false; +} diff --git a/autoroute/Sorted45DegreeRoomNeighbours.java b/src/main/java/autoroute/Sorted45DegreeRoomNeighbours.java similarity index 97% rename from autoroute/Sorted45DegreeRoomNeighbours.java rename to src/main/java/autoroute/Sorted45DegreeRoomNeighbours.java index 3cde936..355d25c 100644 --- a/autoroute/Sorted45DegreeRoomNeighbours.java +++ b/src/main/java/autoroute/Sorted45DegreeRoomNeighbours.java @@ -1,1131 +1,1140 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * Sorted45DegreeRoomNeighbours.java - * - * Created on 6. Juli 2007, 07:28 - * - */ - -package autoroute; - -import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.SortedSet; -import java.util.TreeSet; - -import datastructures.ShapeTree; - -import geometry.planar.Limits; -import geometry.planar.IntOctagon; -import geometry.planar.IntPoint; -import geometry.planar.TileShape; -import geometry.planar.FloatPoint; - -import board.ShapeSearchTree; -import board.SearchTreeObject; -import board.Item; - -/** - * - * @author Alfons Wirtz - */ -public class Sorted45DegreeRoomNeighbours -{ - - public static CompleteExpansionRoom calculate(ExpansionRoom p_room, AutorouteEngine p_autoroute_engine) - { - int net_no = p_autoroute_engine.get_net_no(); - Sorted45DegreeRoomNeighbours room_neighbours = Sorted45DegreeRoomNeighbours.calculate_neighbours(p_room, net_no, - p_autoroute_engine.autoroute_search_tree, p_autoroute_engine.generate_room_id_no()); - if (room_neighbours == null) - { - return null; - } - - // Check, that each side of the romm shape has at least one touching neighbour. - // Otherwise improve the room shape by enlarging. - boolean edge_removed = room_neighbours.try_remove_edge_line(net_no, p_autoroute_engine.autoroute_search_tree); - CompleteExpansionRoom result = room_neighbours.completed_room; - if (edge_removed) - { - p_autoroute_engine.remove_all_doors(result); - return calculate(p_room, p_autoroute_engine); - } - - // Now calculate the new incomplete rooms together with the doors - // between this room and the sorted neighbours. - - if (room_neighbours.sorted_neighbours.isEmpty()) - { - if (result instanceof ObstacleExpansionRoom) - { - room_neighbours.calculate_edge_incomplete_rooms_of_obstacle_expansion_room(0, 7, p_autoroute_engine); - } - } - else - { - room_neighbours.calculate_new_incomplete_rooms(p_autoroute_engine); - } - return result; - } - - /** - * Calculates all touching neighbours of p_room and sorts them in - * counterclock sense around the boundary of the room shape. - */ - private static Sorted45DegreeRoomNeighbours calculate_neighbours(ExpansionRoom p_room, int p_net_no, - ShapeSearchTree p_autoroute_search_tree, int p_room_id_no) - { - TileShape room_shape = p_room.get_shape(); - CompleteExpansionRoom completed_room; - if (p_room instanceof IncompleteFreeSpaceExpansionRoom) - { - completed_room = new CompleteFreeSpaceExpansionRoom(room_shape, p_room.get_layer(), p_room_id_no); - } - else if (p_room instanceof ObstacleExpansionRoom) - { - completed_room = (ObstacleExpansionRoom)p_room; - } - else - { - System.out.println("Sorted45DegreeRoomNeighbours.calculate_neighbours: unexpected expansion room type"); - return null; - } - IntOctagon room_oct = room_shape.bounding_octagon(); - Sorted45DegreeRoomNeighbours result = new Sorted45DegreeRoomNeighbours(p_room, completed_room); - Collection overlapping_objects = new LinkedList(); - p_autoroute_search_tree.overlapping_tree_entries(room_shape, p_room.get_layer(), overlapping_objects); - // Calculate the touching neigbour objects and sort them in counterclock sence - // around the border of the room shape. - for (ShapeTree.TreeEntry curr_entry : overlapping_objects) - { - SearchTreeObject curr_object = (SearchTreeObject) curr_entry.object; - if (curr_object == p_room) - { - continue; - } - if ((completed_room instanceof CompleteFreeSpaceExpansionRoom) && !curr_object.is_trace_obstacle(p_net_no)) - { - ((CompleteFreeSpaceExpansionRoom) completed_room).calculate_target_doors(curr_entry, - p_net_no, p_autoroute_search_tree); - continue; - } - TileShape curr_shape = - curr_object.get_tree_shape(p_autoroute_search_tree, curr_entry.shape_index_in_object); - IntOctagon curr_oct = curr_shape.bounding_octagon(); - IntOctagon intersection = room_oct.intersection(curr_oct); - int dimension = intersection.dimension(); - if (dimension > 1 && completed_room instanceof ObstacleExpansionRoom) - { - if (curr_object instanceof Item) - { - // only Obstacle expansion roos may have a 2-dim overlap - Item curr_item = (Item) curr_object; - if (curr_item.is_route()) - { - ItemAutorouteInfo item_info = curr_item.get_autoroute_info(); - ObstacleExpansionRoom curr_overlap_room = - item_info.get_expansion_room(curr_entry.shape_index_in_object, p_autoroute_search_tree); - ((ObstacleExpansionRoom) completed_room).create_overlap_door(curr_overlap_room); - } - } - continue; - } - if (dimension < 0) - { - // may happen at a corner from 2 diagonal lines with non integer coordinates (--.5, ---.5). - continue; - } - result.add_sorted_neighbour(curr_oct, intersection); - if (dimension > 0) - { - // make shure, that there is a door to the neighbour room. - ExpansionRoom neighbour_room = null; - if (curr_object instanceof ExpansionRoom) - { - neighbour_room = (ExpansionRoom) curr_object; - } - else if (curr_object instanceof Item) - { - Item curr_item = (Item) curr_object; - if (curr_item.is_route()) - { - // expand the item for ripup and pushing purposes - ItemAutorouteInfo item_info = curr_item.get_autoroute_info(); - neighbour_room = - item_info.get_expansion_room(curr_entry.shape_index_in_object, p_autoroute_search_tree); - } - } - if (neighbour_room != null) - { - if (SortedRoomNeighbours.insert_door_ok(completed_room, neighbour_room, intersection)) - { - ExpansionDoor new_door = new ExpansionDoor(completed_room, neighbour_room); - neighbour_room.add_door(new_door); - completed_room.add_door(new_door); - } - } - } - } - return result; - } - - - /** Creates a new instance of Sorted45DegreeRoomNeighbours */ - private Sorted45DegreeRoomNeighbours(ExpansionRoom p_from_room, CompleteExpansionRoom p_completed_room) - { - from_room = p_from_room; - completed_room = p_completed_room; - room_shape = p_completed_room.get_shape().bounding_octagon(); - sorted_neighbours = new TreeSet(); - - edge_interiour_touches_obstacle = new boolean[8]; - for (int i = 0; i < 8; ++i) - { - edge_interiour_touches_obstacle[i] = false; - } - } - - private void add_sorted_neighbour(IntOctagon p_neighbour_shape, IntOctagon p_intersection) - { - SortedRoomNeighbour new_neighbour = new SortedRoomNeighbour(p_neighbour_shape, p_intersection); - if (new_neighbour.last_touching_side >= 0) - { - sorted_neighbours.add(new_neighbour); - } - } - - /** - * Calculates an incomplete room for each edge side from p_from_side_no to p_to_side_no. - */ - private void calculate_edge_incomplete_rooms_of_obstacle_expansion_room(int p_from_side_no, int p_to_side_no, AutorouteEngine p_autoroute_engine) - { - if (!(this.from_room instanceof ObstacleExpansionRoom)) - { - System.out.println("Sorted45DegreeRoomNeighbours.calculate_side_incomplete_rooms_of_obstacle_expansion_room: ObstacleExpansionRoom expected for this.from_room"); - return; - } - IntOctagon board_bounding_oct = p_autoroute_engine.board.get_bounding_box().bounding_octagon(); - IntPoint curr_corner = this.room_shape.corner(p_from_side_no); - int curr_side_no = p_from_side_no; - for (;;) - { - int next_side_no = (curr_side_no + 1) % 8; - IntPoint next_corner = this.room_shape.corner(next_side_no); - if (!curr_corner.equals(next_corner)) - { - int lx = board_bounding_oct.lx; - int ly = board_bounding_oct.ly; - int rx = board_bounding_oct.rx; - int uy = board_bounding_oct.uy; - int ulx = board_bounding_oct.ulx; - int lrx = board_bounding_oct.lrx; - int llx = board_bounding_oct.llx; - int urx = board_bounding_oct.urx; - if (curr_side_no == 0) - { - uy = this.room_shape.ly; - } - else if (curr_side_no == 1) - { - ulx = this.room_shape.lrx; - } - else if (curr_side_no == 2) - { - lx = this.room_shape.rx; - } - else if (curr_side_no == 3) - { - llx = this.room_shape.urx; - } - else if (curr_side_no == 4) - { - ly = this.room_shape.uy; - } - else if (curr_side_no == 5) - { - lrx = this.room_shape.ulx; - } - else if (curr_side_no == 6) - { - rx = this.room_shape.lx; - } - else if (curr_side_no == 7) - { - urx = this.room_shape.llx; - } - else - { - System.out.println("SortedOrthoganelRoomNeighbours.calculate_edge_incomplete_rooms_of_obstacle_expansion_room: curr_side_no illegal"); - return; - } - insert_incomplete_room(p_autoroute_engine, lx, ly, rx, uy, ulx, lrx, llx, urx); - } - if (curr_side_no == p_to_side_no) - { - break; - } - curr_side_no = next_side_no; - } - } - - private static IntOctagon remove_not_touching_border_lines( IntOctagon p_room_oct, - boolean[] p_edge_interiour_touches_obstacle) - { - int lx; - if (p_edge_interiour_touches_obstacle[6]) - { - lx = p_room_oct.lx; - } - else - { - lx = -Limits.CRIT_INT; - } - - int ly; - if (p_edge_interiour_touches_obstacle[0]) - { - ly = p_room_oct.ly; - } - else - { - ly = -Limits.CRIT_INT; - } - - int rx; - if (p_edge_interiour_touches_obstacle[2]) - { - rx = p_room_oct.rx; - } - else - { - rx = Limits.CRIT_INT; - } - - - int uy; - if (p_edge_interiour_touches_obstacle[4]) - { - uy = p_room_oct.uy; - } - else - { - uy = Limits.CRIT_INT; - } - - int ulx; - if (p_edge_interiour_touches_obstacle[5]) - { - ulx = p_room_oct.ulx; - } - else - { - ulx = -Limits.CRIT_INT; - } - - int lrx; - if (p_edge_interiour_touches_obstacle[1]) - { - lrx = p_room_oct.lrx; - } - else - { - lrx = Limits.CRIT_INT; - } - - int llx; - if (p_edge_interiour_touches_obstacle[7]) - { - llx = p_room_oct.llx; - } - else - { - llx = -Limits.CRIT_INT; - } - - int urx; - if (p_edge_interiour_touches_obstacle[3]) - { - urx = p_room_oct.urx; - } - else - { - urx = Limits.CRIT_INT; - } - - IntOctagon result = new IntOctagon( lx, ly, rx, uy, ulx, lrx, llx, urx); - return result.normalize(); - } - /** - * Check, that each side of the romm shape has at least one touching neighbour. - * Otherwise the room shape will be improved the by enlarging. - * Returns true, if the room shape was changed. - */ - private boolean try_remove_edge_line(int p_net_no, ShapeSearchTree p_autoroute_search_tree) - { - if (!(this.from_room instanceof IncompleteFreeSpaceExpansionRoom)) - { - return false; - } - IncompleteFreeSpaceExpansionRoom curr_incomplete_room = (IncompleteFreeSpaceExpansionRoom) this.from_room; - if (!(curr_incomplete_room.get_shape() instanceof IntOctagon)) - { - System.out.println("Sorted45DegreeRoomNeighbours.try_remove_edge_line: IntOctagon expected for room_shape type"); - return false; - } - IntOctagon room_oct = (IntOctagon) curr_incomplete_room.get_shape(); - double room_area = room_oct.area(); - - boolean try_remove_edge_lines = false; - for (int i = 0; i < 8; ++i) - { - if (!this.edge_interiour_touches_obstacle[i]) - { - FloatPoint prev_corner = this.room_shape.corner_approx(i); - FloatPoint next_corner = this.room_shape.corner_approx(this.room_shape.next_no(i)); - if(prev_corner.distance_square(next_corner) > 1) - { - try_remove_edge_lines = true; - break; - } - } - } - - if (try_remove_edge_lines) - { - // Touching neighbour missing at the edge side with index remove_edge_no - // Remove the edge line and restart the algorithm. - - IntOctagon enlarged_oct = remove_not_touching_border_lines( room_oct, this.edge_interiour_touches_obstacle); - - Collection door_list = this.completed_room.get_doors(); - TileShape ignore_shape = null; - SearchTreeObject ignore_object = null; - double max_door_area = 0; - for (ExpansionDoor curr_door: door_list) - { - // insert the overlapping doors with CompleteFreeSpaceExpansionRooms - // for the information in complete_shape about the objects to ignore. - if (curr_door.dimension == 2) - { - CompleteExpansionRoom other_room = curr_door.other_room(this.completed_room); - { - if (other_room instanceof CompleteFreeSpaceExpansionRoom) - { - TileShape curr_door_shape = curr_door.get_shape(); - double curr_door_area = curr_door_shape.area(); - if (curr_door_area > max_door_area) - { - max_door_area = curr_door_area; - ignore_shape = curr_door_shape; - ignore_object = (CompleteFreeSpaceExpansionRoom) other_room; - } - } - } - } - } - IncompleteFreeSpaceExpansionRoom enlarged_room = - new IncompleteFreeSpaceExpansionRoom(enlarged_oct, curr_incomplete_room.get_layer(), - curr_incomplete_room.get_contained_shape()); - Collection new_rooms = - p_autoroute_search_tree.complete_shape(enlarged_room, p_net_no, ignore_object, ignore_shape); - if (new_rooms.size() == 1) - { - // Check, that the area increases to prevent endless loop. - IncompleteFreeSpaceExpansionRoom new_room = new_rooms.iterator().next(); - if (new_room.get_shape().area() > room_area) - { - curr_incomplete_room.set_shape(new_room.get_shape()); - curr_incomplete_room.set_contained_shape(new_room.get_contained_shape()); - return true; - } - } - } - return false; - } - - /** - * Inserts a new incomplete room with an octagon shape. - */ - private void insert_incomplete_room(AutorouteEngine p_autoroute_engine, int p_lx, int p_ly, int p_rx, int p_uy, - int p_ulx, int p_lrx, int p_llx, int p_urx) - { - IntOctagon new_incomplete_room_shape = new IntOctagon(p_lx, p_ly, p_rx, p_uy, p_ulx, p_lrx, p_llx, p_urx); - new_incomplete_room_shape = new_incomplete_room_shape.normalize(); - if (new_incomplete_room_shape.dimension() == 2) - { - IntOctagon new_contained_shape = this.room_shape.intersection(new_incomplete_room_shape); - if (!new_contained_shape.is_empty()) - { - int door_dimension = new_contained_shape.dimension(); - if (door_dimension > 0) - { - FreeSpaceExpansionRoom new_room = - p_autoroute_engine.add_incomplete_expansion_room(new_incomplete_room_shape, this.from_room.get_layer(), new_contained_shape); - ExpansionDoor new_door = new ExpansionDoor(this.completed_room, new_room, door_dimension); - this.completed_room.add_door(new_door); - new_room.add_door(new_door); - } - } - } - } - - private void calculate_new_incomplete_rooms_for_obstacle_expansion_room(SortedRoomNeighbour p_prev_neighbour, - SortedRoomNeighbour p_next_neighbour, AutorouteEngine p_autoroute_engine) - { - int from_side_no = p_prev_neighbour.last_touching_side; - int to_side_no = p_next_neighbour.first_touching_side; - if (from_side_no == to_side_no && p_prev_neighbour != p_next_neighbour) - { - // no return in case of only 1 neighbour. - return; - } - IntOctagon board_bounding_oct = p_autoroute_engine.board.bounding_box.bounding_octagon(); - - // insert the new incomplete room from p_prev_neighbour to the next corner of the room shape. - - int lx = board_bounding_oct.lx; - int ly = board_bounding_oct.ly; - int rx = board_bounding_oct.rx; - int uy = board_bounding_oct.uy; - int ulx = board_bounding_oct.ulx; - int lrx = board_bounding_oct.lrx; - int llx = board_bounding_oct.llx; - int urx = board_bounding_oct.urx; - if (from_side_no == 0) - { - uy = this.room_shape.ly; - ulx = p_prev_neighbour.intersection.lrx; - } - else if (from_side_no == 1) - { - ulx = this.room_shape.lrx; - lx = p_prev_neighbour.intersection.rx; - } - else if (from_side_no == 2) - { - lx = this.room_shape.rx; - llx = p_prev_neighbour.intersection.urx; - } - else if (from_side_no == 3) - { - llx = this.room_shape.urx; - ly = p_prev_neighbour.intersection.uy; - } - else if (from_side_no == 4) - { - ly = this.room_shape.uy; - lrx = p_prev_neighbour.intersection.ulx; - } - else if (from_side_no == 5) - { - lrx = this.room_shape.ulx; - rx = p_prev_neighbour.intersection.lx; - } - else if (from_side_no == 6) - { - rx = this.room_shape.lx; - urx = p_prev_neighbour.intersection.llx; - } - else if (from_side_no == 7) - { - urx = this.room_shape.llx; - uy = p_prev_neighbour.intersection.ly; - } - insert_incomplete_room(p_autoroute_engine, lx, ly, rx, uy, ulx, lrx, llx, urx); - - // insert the new incomplete room from p_prev_neighbour to the next corner of the room shape. - - lx = board_bounding_oct.lx; - ly = board_bounding_oct.ly; - rx = board_bounding_oct.rx; - uy = board_bounding_oct.uy; - ulx = board_bounding_oct.ulx; - lrx = board_bounding_oct.lrx; - llx = board_bounding_oct.llx; - urx = board_bounding_oct.urx; - - if (to_side_no == 0) - { - uy = this.room_shape.ly; - urx = p_next_neighbour.intersection.llx; - } - else if (to_side_no == 1) - { - ulx = this.room_shape.lrx; - uy = p_next_neighbour.intersection.ly; - } - else if (to_side_no == 2) - { - lx = this.room_shape.rx; - ulx = p_next_neighbour.intersection.lrx; - } - else if (to_side_no == 3) - { - llx = this.room_shape.urx; - lx = p_next_neighbour.intersection.rx; - } - else if (to_side_no == 4) - { - ly = this.room_shape.uy; - llx = p_next_neighbour.intersection.urx; - } - else if (to_side_no == 5) - { - lrx = this.room_shape.ulx; - ly = p_next_neighbour.intersection.uy; - } - else if (to_side_no == 6) - { - rx = this.room_shape.lx; - lrx = p_next_neighbour.intersection.ulx; - } - else if (to_side_no == 7) - { - urx = this.room_shape.llx; - rx = p_next_neighbour.intersection.lx; - } - insert_incomplete_room(p_autoroute_engine, lx, ly, rx, uy, ulx, lrx, llx, urx); - - // Insert the new incomplete rooms on the intermediate free sides of the obstacle expansion room. - int curr_from_side_no = (from_side_no + 1) % 8; - if (curr_from_side_no == to_side_no) - { - return; - } - int curr_to_side_no = (to_side_no + 7) % 8; - this.calculate_edge_incomplete_rooms_of_obstacle_expansion_room(curr_from_side_no, - curr_to_side_no, p_autoroute_engine); - } - - private void calculate_new_incomplete_rooms(AutorouteEngine p_autoroute_engine) - { - IntOctagon board_bounding_oct = p_autoroute_engine.board.bounding_box.bounding_octagon(); - SortedRoomNeighbour prev_neighbour = this.sorted_neighbours.last(); - if (this.from_room instanceof ObstacleExpansionRoom && this.sorted_neighbours.size() == 1) - { - // ObstacleExpansionRoom has only only 1 neighbour - calculate_new_incomplete_rooms_for_obstacle_expansion_room(prev_neighbour, prev_neighbour, p_autoroute_engine); - return; - } - Iterator it = this.sorted_neighbours.iterator(); - - while (it.hasNext()) - { - SortedRoomNeighbour next_neighbour = it.next(); - - boolean insert_incomplete_room; - - if (this.completed_room instanceof ObstacleExpansionRoom && this.sorted_neighbours.size() == 2) - { - // check, if this site is touching or open. - TileShape intersection = next_neighbour.intersection.intersection(prev_neighbour.intersection); - if (intersection.is_empty()) - { - insert_incomplete_room = true; - } - else if (intersection.dimension() >= 1) - { - insert_incomplete_room = false; - } - else // dimension = 1 - { - if (prev_neighbour.last_touching_side == next_neighbour.first_touching_side) - { - // touch along the side of the room shape - insert_incomplete_room = false; - } - else if(prev_neighbour.last_touching_side == (next_neighbour.first_touching_side + 1) % 8) - { - // touch at a corner of the room shape - insert_incomplete_room = false; - } - else - { - insert_incomplete_room = true; - } - } - } - else - { - // the 2 neigbours do not touch - insert_incomplete_room = !next_neighbour.intersection.intersects(prev_neighbour.intersection); - } - - - if (insert_incomplete_room) - { - // create a door to a new incomplete expansion room between - // the last corner of the previous neighbour and the first corner of the - // current neighbour - - if (this.from_room instanceof ObstacleExpansionRoom && - next_neighbour.first_touching_side != prev_neighbour.last_touching_side) - { - calculate_new_incomplete_rooms_for_obstacle_expansion_room(prev_neighbour, next_neighbour, p_autoroute_engine); - } - else - { - int lx = board_bounding_oct.lx; - int ly = board_bounding_oct.ly; - int rx = board_bounding_oct.rx; - int uy = board_bounding_oct.uy; - int ulx = board_bounding_oct.ulx; - int lrx = board_bounding_oct.lrx; - int llx = board_bounding_oct.llx; - int urx = board_bounding_oct.urx; - - if (next_neighbour.first_touching_side == 0) - { - if (prev_neighbour.intersection.llx < next_neighbour.intersection.llx) - { - urx = next_neighbour.intersection.llx; - uy = prev_neighbour.intersection.ly; - if (prev_neighbour.last_touching_side == 0) - { - ulx = prev_neighbour.intersection.lrx; - } - } - else if (prev_neighbour.intersection.llx > next_neighbour.intersection.llx) - { - rx = next_neighbour.intersection.lx; - urx = prev_neighbour.intersection.llx; - } - else // prev_neighbour.intersection.llx == next_neighbour.intersection.llx - { - urx = next_neighbour.intersection.llx; - } - } - else if (next_neighbour.first_touching_side == 1) - { - if (prev_neighbour.intersection.ly < next_neighbour.intersection.ly) - { - uy = next_neighbour.intersection.ly; - ulx = prev_neighbour.intersection.lrx; - if (prev_neighbour.last_touching_side == 1) - { - lx = prev_neighbour.intersection.rx; - } - } - else if (prev_neighbour.intersection.ly > next_neighbour.intersection.ly) - { - uy = prev_neighbour.intersection.ly; - urx = next_neighbour.intersection.llx; - } - else // prev_neighbour.intersection.ly == next_neighbour.intersection.ly - { - uy = next_neighbour.intersection.ly; - } - } - else if (next_neighbour.first_touching_side == 2) - { - if (prev_neighbour.intersection.lrx > next_neighbour.intersection.lrx) - { - ulx = next_neighbour.intersection.lrx; - lx = prev_neighbour.intersection.rx; - if (prev_neighbour.last_touching_side == 2) - { - llx = prev_neighbour.intersection.urx; - } - } - else if (prev_neighbour.intersection.lrx < next_neighbour.intersection.lrx) - { - uy = next_neighbour.intersection.ly; - ulx = prev_neighbour.intersection.lrx; - } - else // prev_neighbour.intersection.lrx == next_neighbour.intersection.lrx - { - ulx = next_neighbour.intersection.lrx; - } - } - else if (next_neighbour.first_touching_side == 3) - { - if (prev_neighbour.intersection.rx > next_neighbour.intersection.rx) - { - lx = next_neighbour.intersection.rx; - llx = prev_neighbour.intersection.urx; - if (prev_neighbour.last_touching_side == 3) - { - ly = prev_neighbour.intersection.uy; - } - } - else if (prev_neighbour.intersection.rx < next_neighbour.intersection.rx) - { - lx = prev_neighbour.intersection.rx; - ulx = next_neighbour.intersection.lrx; - } - else // prev_neighbour.intersection.ry == next_neighbour.intersection.ry - { - lx = next_neighbour.intersection.rx; - } - } - else if (next_neighbour.first_touching_side == 4) - { - if (prev_neighbour.intersection.urx > next_neighbour.intersection.urx) - { - llx = next_neighbour.intersection.urx; - ly = prev_neighbour.intersection.uy; - if (prev_neighbour.last_touching_side == 4) - { - lrx = prev_neighbour.intersection.ulx; - } - } - else if (prev_neighbour.intersection.urx < next_neighbour.intersection.urx) - { - lx = next_neighbour.intersection.rx; - llx = prev_neighbour.intersection.urx; - } - else // prev_neighbour.intersection.urx == next_neighbour.intersection.urx - { - llx = next_neighbour.intersection.urx; - } - } - else if (next_neighbour.first_touching_side == 5) - { - if (prev_neighbour.intersection.uy > next_neighbour.intersection.uy) - { - ly = next_neighbour.intersection.uy; - lrx = prev_neighbour.intersection.ulx; - if (prev_neighbour.last_touching_side == 5) - { - rx = prev_neighbour.intersection.lx; - } - } - else if (prev_neighbour.intersection.uy < next_neighbour.intersection.uy) - { - ly = prev_neighbour.intersection.uy; - llx = next_neighbour.intersection.urx; - } - else // prev_neighbour.intersection.uy == next_neighbour.intersection.uy - { - ly = next_neighbour.intersection.uy; - } - } - else if (next_neighbour.first_touching_side == 6) - { - if (prev_neighbour.intersection.ulx < next_neighbour.intersection.ulx) - { - lrx = next_neighbour.intersection.ulx; - rx = prev_neighbour.intersection.lx; - if (prev_neighbour.last_touching_side == 6) - { - urx = prev_neighbour.intersection.llx; - } - } - else if (prev_neighbour.intersection.ulx > next_neighbour.intersection.ulx) - { - ly = next_neighbour.intersection.uy; - lrx = prev_neighbour.intersection.ulx; - } - else // prev_neighbour.intersection.ulx == next_neighbour.intersection.ulx - { - lrx = next_neighbour.intersection.ulx; - } - } - else if (next_neighbour.first_touching_side == 7) - { - if (prev_neighbour.intersection.lx < next_neighbour.intersection.lx) - { - rx = next_neighbour.intersection.lx; - urx = prev_neighbour.intersection.llx; - if (prev_neighbour.last_touching_side == 7) - { - uy = prev_neighbour.intersection.ly; - } - } - else if (prev_neighbour.intersection.lx > next_neighbour.intersection.lx) - { - rx = prev_neighbour.intersection.lx; - lrx = next_neighbour.intersection.ulx; - } - else // prev_neighbour.intersection.lx == next_neighbour.intersection.lx - { - rx = next_neighbour.intersection.lx; - } - } - else - { - System.out.println("Sorted45DegreeRoomNeighbour.calculate_new_incomplete: illegal touching side"); - } - insert_incomplete_room(p_autoroute_engine, lx, ly, rx, uy, ulx, lrx, llx, urx); - } - } - prev_neighbour = next_neighbour; - } - } - - public final CompleteExpansionRoom completed_room; - public final SortedSet sorted_neighbours; - private final ExpansionRoom from_room; - private final IntOctagon room_shape; - - private final boolean[] edge_interiour_touches_obstacle; - - /** - * Helper class to sort the doors of an expansion room counterclockwise - * arount the border of the room shape. - */ - - private class SortedRoomNeighbour implements Comparable - { - - /** - * Creates a new instance of SortedRoomNeighbour and calculates the first and last - * touching sides with the room shape. - * this.last_touching_side will be -1, if sorting did not work because - * the room_shape is contained in the neighbour shape. - */ - public SortedRoomNeighbour(IntOctagon p_neighbour_shape, IntOctagon p_intersection) - { - shape = p_neighbour_shape; - intersection = p_intersection; - - if (intersection.ly == room_shape.ly && intersection.llx > room_shape.llx) - { - this.first_touching_side = 0; - } - else if (intersection.lrx == room_shape.lrx && intersection.ly > room_shape.ly) - { - this.first_touching_side = 1; - } - else if (intersection.rx == room_shape.rx && intersection.lrx < room_shape.lrx) - { - this.first_touching_side = 2; - } - else if (intersection.urx == room_shape.urx && intersection.rx < room_shape.rx) - { - this.first_touching_side = 3; - } - else if (intersection.uy == room_shape.uy && intersection.urx < room_shape.urx) - { - this.first_touching_side = 4; - } - else if (intersection.ulx == room_shape.ulx && intersection.uy < room_shape.uy) - { - this.first_touching_side = 5; - } - else if (intersection.lx == room_shape.lx && intersection.ulx > room_shape.ulx) - { - this.first_touching_side = 6; - } - else if (intersection.llx == room_shape.llx && intersection.lx > room_shape.lx) - { - this.first_touching_side = 7; - } - else - { - // the room_shape may be contained in the neighbour_shape - this.first_touching_side = -1; - this.last_touching_side = -1; - return; - } - - if (intersection.llx == room_shape.llx && intersection.ly > room_shape.ly) - { - this.last_touching_side = 7; - } - else if (intersection.lx == room_shape.lx && intersection.llx > room_shape.llx) - { - this.last_touching_side = 6; - } - else if (intersection.ulx == room_shape.ulx && intersection.lx > room_shape.lx) - { - this.last_touching_side = 5; - } - else if (intersection.uy == room_shape.uy && intersection.ulx > room_shape.ulx) - { - this.last_touching_side = 4; - } - else if (intersection.urx == room_shape.urx && intersection.uy < room_shape.uy) - { - this.last_touching_side = 3; - } - else if (intersection.rx == room_shape.rx && intersection.urx < room_shape.urx) - { - this.last_touching_side = 2; - } - else if (intersection.lrx == room_shape.lrx && intersection.rx < room_shape.rx) - { - this.last_touching_side = 1; - } - else if (intersection.ly == room_shape.ly && intersection.lrx < room_shape.lrx) - { - this.last_touching_side = 0; - } - else - { - // the room_shape may be contained in the neighbour_shape - this.last_touching_side = -1; - return; - } - - int next_side_no = this.first_touching_side; - for (;;) - { - int curr_side_no = next_side_no; - next_side_no = (next_side_no + 1) % 8; - if (!edge_interiour_touches_obstacle[curr_side_no]) - { - boolean touch_only_at_corner = false; - if (curr_side_no == this.first_touching_side) - { - if (intersection.corner(curr_side_no).equals(room_shape.corner(next_side_no))) - { - touch_only_at_corner = true; - } - } - if (curr_side_no == this.last_touching_side) - { - if (intersection.corner(next_side_no).equals(room_shape.corner(curr_side_no))) - { - touch_only_at_corner = true; - } - } - if (!touch_only_at_corner) - { - edge_interiour_touches_obstacle[curr_side_no] = true; - } - } - if (curr_side_no == this.last_touching_side) - { - break; - } - - } - } - - /** - * Compare function for or sorting the neighbours in counterclock sense - * around the border of the room shape in ascending order. - */ - public int compareTo(SortedRoomNeighbour p_other) - { - if (this.first_touching_side > p_other.first_touching_side) - { - return 1; - } - if (this.first_touching_side < p_other.first_touching_side) - { - return -1; - } - - // now the first touch of this and p_other is at the same side - IntOctagon is1 = this.intersection; - IntOctagon is2 = p_other.intersection; - int cmp_value; - - if (first_touching_side == 0) - { - cmp_value = is1.corner(0).x - is2.corner(0).x; - } - else if (first_touching_side == 1) - { - cmp_value = is1.corner(1).x - is2.corner(1).x; - } - else if (first_touching_side == 2) - { - cmp_value = is1.corner(2).y - is2.corner(2).y; - } - else if (first_touching_side == 3) - { - cmp_value = is1.corner(3).y - is2.corner(3).y; - } - else if (first_touching_side == 4) - { - cmp_value = is2.corner(4).x - is1.corner(4).x; - } - else if (first_touching_side == 5) - { - cmp_value = is2.corner(5).x - is1.corner(5).x; - } - else if (first_touching_side == 6) - { - cmp_value = is2.corner(6).y - is1.corner(6).y; - } - else if (first_touching_side == 7) - { - cmp_value = is2.corner(7).y - is1.corner(7).y; - } - else - { - System.out.println("SortedRoomNeighbour.compareTo: first_touching_side out of range "); - return 0; - } - - if (cmp_value == 0) - { - // The first touching points of this neighbour and p_other with the room shape are equal. - // Compare the last touching points. - int this_touching_side_diff = (this.last_touching_side - this.first_touching_side + 8) % 8; - int other_touching_side_diff = (p_other.last_touching_side - p_other.first_touching_side + 8) % 8; - if (this_touching_side_diff > other_touching_side_diff) - { - return 1; - } - if (this_touching_side_diff < other_touching_side_diff) - { - return -1; - } - // now the last touch of this and p_other is at the same side - if (last_touching_side == 0) - { - cmp_value = is1.corner(1).x - is2.corner(1).x; - } - else if (last_touching_side == 1) - { - cmp_value = is1.corner(2).x - is2.corner(2).x; - } - else if (last_touching_side == 2) - { - cmp_value = is1.corner(3).y - is2.corner(3).y; - } - else if (last_touching_side == 3) - { - cmp_value = is1.corner(4).y - is2.corner(4).y; - } - else if (last_touching_side == 4) - { - cmp_value = is2.corner(5).x - is1.corner(5).x; - } - else if (last_touching_side == 5) - { - cmp_value = is2.corner(6).x - is1.corner(6).x; - } - else if (last_touching_side == 6) - { - cmp_value = is2.corner(7).y - is1.corner(7).y; - } - else if (last_touching_side == 7) - { - cmp_value = is2.corner(0).y - is1.corner(0).y; - } - } - return cmp_value; - } - /** The shape of the neighbour room */ - public final IntOctagon shape; - - /** The intersection of tnis ExpansionRoom shape with the neighbour_shape */ - public final IntOctagon intersection; - - /** The first side of the room shape, where the neighbour_shape touches */ - public final int first_touching_side; - - /** The last side of the room shape, where the neighbour_shape touches */ - public final int last_touching_side; - } -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * Sorted45DegreeRoomNeighbours.java + * + * Created on 6. Juli 2007, 07:28 + * + */ + +package autoroute; + +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.SortedSet; +import java.util.TreeSet; + +import datastructures.ShapeTree; + +import geometry.planar.Limits; +import geometry.planar.IntOctagon; +import geometry.planar.IntPoint; +import geometry.planar.TileShape; +import geometry.planar.FloatPoint; + +import board.ShapeSearchTree; +import board.SearchTreeObject; +import board.Item; + +/** + *

Sorted45DegreeRoomNeighbours class.

+ * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class Sorted45DegreeRoomNeighbours +{ + + /** + *

calculate.

+ * + * @param p_room a {@link autoroute.ExpansionRoom} object. + * @param p_autoroute_engine a {@link autoroute.AutorouteEngine} object. + * @return a {@link autoroute.CompleteExpansionRoom} object. + */ + public static CompleteExpansionRoom calculate(ExpansionRoom p_room, AutorouteEngine p_autoroute_engine) + { + int net_no = p_autoroute_engine.get_net_no(); + Sorted45DegreeRoomNeighbours room_neighbours = Sorted45DegreeRoomNeighbours.calculate_neighbours(p_room, net_no, + p_autoroute_engine.autoroute_search_tree, p_autoroute_engine.generate_room_id_no()); + if (room_neighbours == null) + { + return null; + } + + // Check, that each side of the romm shape has at least one touching neighbour. + // Otherwise improve the room shape by enlarging. + boolean edge_removed = room_neighbours.try_remove_edge_line(net_no, p_autoroute_engine.autoroute_search_tree); + CompleteExpansionRoom result = room_neighbours.completed_room; + if (edge_removed) + { + p_autoroute_engine.remove_all_doors(result); + return calculate(p_room, p_autoroute_engine); + } + + // Now calculate the new incomplete rooms together with the doors + // between this room and the sorted neighbours. + + if (room_neighbours.sorted_neighbours.isEmpty()) + { + if (result instanceof ObstacleExpansionRoom) + { + room_neighbours.calculate_edge_incomplete_rooms_of_obstacle_expansion_room(0, 7, p_autoroute_engine); + } + } + else + { + room_neighbours.calculate_new_incomplete_rooms(p_autoroute_engine); + } + return result; + } + + /** + * Calculates all touching neighbours of p_room and sorts them in + * counterclock sense around the boundary of the room shape. + */ + private static Sorted45DegreeRoomNeighbours calculate_neighbours(ExpansionRoom p_room, int p_net_no, + ShapeSearchTree p_autoroute_search_tree, int p_room_id_no) + { + TileShape room_shape = p_room.get_shape(); + CompleteExpansionRoom completed_room; + if (p_room instanceof IncompleteFreeSpaceExpansionRoom) + { + completed_room = new CompleteFreeSpaceExpansionRoom(room_shape, p_room.get_layer(), p_room_id_no); + } + else if (p_room instanceof ObstacleExpansionRoom) + { + completed_room = (ObstacleExpansionRoom)p_room; + } + else + { + System.out.println("Sorted45DegreeRoomNeighbours.calculate_neighbours: unexpected expansion room type"); + return null; + } + IntOctagon room_oct = room_shape.bounding_octagon(); + Sorted45DegreeRoomNeighbours result = new Sorted45DegreeRoomNeighbours(p_room, completed_room); + Collection overlapping_objects = new LinkedList(); + p_autoroute_search_tree.overlapping_tree_entries(room_shape, p_room.get_layer(), overlapping_objects); + // Calculate the touching neigbour objects and sort them in counterclock sence + // around the border of the room shape. + for (ShapeTree.TreeEntry curr_entry : overlapping_objects) + { + SearchTreeObject curr_object = (SearchTreeObject) curr_entry.object; + if (curr_object == p_room) + { + continue; + } + if ((completed_room instanceof CompleteFreeSpaceExpansionRoom) && !curr_object.is_trace_obstacle(p_net_no)) + { + ((CompleteFreeSpaceExpansionRoom) completed_room).calculate_target_doors(curr_entry, + p_net_no, p_autoroute_search_tree); + continue; + } + TileShape curr_shape = + curr_object.get_tree_shape(p_autoroute_search_tree, curr_entry.shape_index_in_object); + IntOctagon curr_oct = curr_shape.bounding_octagon(); + IntOctagon intersection = room_oct.intersection(curr_oct); + int dimension = intersection.dimension(); + if (dimension > 1 && completed_room instanceof ObstacleExpansionRoom) + { + if (curr_object instanceof Item) + { + // only Obstacle expansion roos may have a 2-dim overlap + Item curr_item = (Item) curr_object; + if (curr_item.is_route()) + { + ItemAutorouteInfo item_info = curr_item.get_autoroute_info(); + ObstacleExpansionRoom curr_overlap_room = + item_info.get_expansion_room(curr_entry.shape_index_in_object, p_autoroute_search_tree); + ((ObstacleExpansionRoom) completed_room).create_overlap_door(curr_overlap_room); + } + } + continue; + } + if (dimension < 0) + { + // may happen at a corner from 2 diagonal lines with non integer coordinates (--.5, ---.5). + continue; + } + result.add_sorted_neighbour(curr_oct, intersection); + if (dimension > 0) + { + // make shure, that there is a door to the neighbour room. + ExpansionRoom neighbour_room = null; + if (curr_object instanceof ExpansionRoom) + { + neighbour_room = (ExpansionRoom) curr_object; + } + else if (curr_object instanceof Item) + { + Item curr_item = (Item) curr_object; + if (curr_item.is_route()) + { + // expand the item for ripup and pushing purposes + ItemAutorouteInfo item_info = curr_item.get_autoroute_info(); + neighbour_room = + item_info.get_expansion_room(curr_entry.shape_index_in_object, p_autoroute_search_tree); + } + } + if (neighbour_room != null) + { + if (SortedRoomNeighbours.insert_door_ok(completed_room, neighbour_room, intersection)) + { + ExpansionDoor new_door = new ExpansionDoor(completed_room, neighbour_room); + neighbour_room.add_door(new_door); + completed_room.add_door(new_door); + } + } + } + } + return result; + } + + + /** Creates a new instance of Sorted45DegreeRoomNeighbours */ + private Sorted45DegreeRoomNeighbours(ExpansionRoom p_from_room, CompleteExpansionRoom p_completed_room) + { + from_room = p_from_room; + completed_room = p_completed_room; + room_shape = p_completed_room.get_shape().bounding_octagon(); + sorted_neighbours = new TreeSet(); + + edge_interiour_touches_obstacle = new boolean[8]; + for (int i = 0; i < 8; ++i) + { + edge_interiour_touches_obstacle[i] = false; + } + } + + private void add_sorted_neighbour(IntOctagon p_neighbour_shape, IntOctagon p_intersection) + { + SortedRoomNeighbour new_neighbour = new SortedRoomNeighbour(p_neighbour_shape, p_intersection); + if (new_neighbour.last_touching_side >= 0) + { + sorted_neighbours.add(new_neighbour); + } + } + + /** + * Calculates an incomplete room for each edge side from p_from_side_no to p_to_side_no. + */ + private void calculate_edge_incomplete_rooms_of_obstacle_expansion_room(int p_from_side_no, int p_to_side_no, AutorouteEngine p_autoroute_engine) + { + if (!(this.from_room instanceof ObstacleExpansionRoom)) + { + System.out.println("Sorted45DegreeRoomNeighbours.calculate_side_incomplete_rooms_of_obstacle_expansion_room: ObstacleExpansionRoom expected for this.from_room"); + return; + } + IntOctagon board_bounding_oct = p_autoroute_engine.board.get_bounding_box().bounding_octagon(); + IntPoint curr_corner = this.room_shape.corner(p_from_side_no); + int curr_side_no = p_from_side_no; + for (;;) + { + int next_side_no = (curr_side_no + 1) % 8; + IntPoint next_corner = this.room_shape.corner(next_side_no); + if (!curr_corner.equals(next_corner)) + { + int lx = board_bounding_oct.lx; + int ly = board_bounding_oct.ly; + int rx = board_bounding_oct.rx; + int uy = board_bounding_oct.uy; + int ulx = board_bounding_oct.ulx; + int lrx = board_bounding_oct.lrx; + int llx = board_bounding_oct.llx; + int urx = board_bounding_oct.urx; + if (curr_side_no == 0) + { + uy = this.room_shape.ly; + } + else if (curr_side_no == 1) + { + ulx = this.room_shape.lrx; + } + else if (curr_side_no == 2) + { + lx = this.room_shape.rx; + } + else if (curr_side_no == 3) + { + llx = this.room_shape.urx; + } + else if (curr_side_no == 4) + { + ly = this.room_shape.uy; + } + else if (curr_side_no == 5) + { + lrx = this.room_shape.ulx; + } + else if (curr_side_no == 6) + { + rx = this.room_shape.lx; + } + else if (curr_side_no == 7) + { + urx = this.room_shape.llx; + } + else + { + System.out.println("SortedOrthoganelRoomNeighbours.calculate_edge_incomplete_rooms_of_obstacle_expansion_room: curr_side_no illegal"); + return; + } + insert_incomplete_room(p_autoroute_engine, lx, ly, rx, uy, ulx, lrx, llx, urx); + } + if (curr_side_no == p_to_side_no) + { + break; + } + curr_side_no = next_side_no; + } + } + + private static IntOctagon remove_not_touching_border_lines( IntOctagon p_room_oct, + boolean[] p_edge_interiour_touches_obstacle) + { + int lx; + if (p_edge_interiour_touches_obstacle[6]) + { + lx = p_room_oct.lx; + } + else + { + lx = -Limits.CRIT_INT; + } + + int ly; + if (p_edge_interiour_touches_obstacle[0]) + { + ly = p_room_oct.ly; + } + else + { + ly = -Limits.CRIT_INT; + } + + int rx; + if (p_edge_interiour_touches_obstacle[2]) + { + rx = p_room_oct.rx; + } + else + { + rx = Limits.CRIT_INT; + } + + + int uy; + if (p_edge_interiour_touches_obstacle[4]) + { + uy = p_room_oct.uy; + } + else + { + uy = Limits.CRIT_INT; + } + + int ulx; + if (p_edge_interiour_touches_obstacle[5]) + { + ulx = p_room_oct.ulx; + } + else + { + ulx = -Limits.CRIT_INT; + } + + int lrx; + if (p_edge_interiour_touches_obstacle[1]) + { + lrx = p_room_oct.lrx; + } + else + { + lrx = Limits.CRIT_INT; + } + + int llx; + if (p_edge_interiour_touches_obstacle[7]) + { + llx = p_room_oct.llx; + } + else + { + llx = -Limits.CRIT_INT; + } + + int urx; + if (p_edge_interiour_touches_obstacle[3]) + { + urx = p_room_oct.urx; + } + else + { + urx = Limits.CRIT_INT; + } + + IntOctagon result = new IntOctagon( lx, ly, rx, uy, ulx, lrx, llx, urx); + return result.normalize(); + } + /** + * Check, that each side of the romm shape has at least one touching neighbour. + * Otherwise the room shape will be improved the by enlarging. + * Returns true, if the room shape was changed. + */ + private boolean try_remove_edge_line(int p_net_no, ShapeSearchTree p_autoroute_search_tree) + { + if (!(this.from_room instanceof IncompleteFreeSpaceExpansionRoom)) + { + return false; + } + IncompleteFreeSpaceExpansionRoom curr_incomplete_room = (IncompleteFreeSpaceExpansionRoom) this.from_room; + if (!(curr_incomplete_room.get_shape() instanceof IntOctagon)) + { + System.out.println("Sorted45DegreeRoomNeighbours.try_remove_edge_line: IntOctagon expected for room_shape type"); + return false; + } + IntOctagon room_oct = (IntOctagon) curr_incomplete_room.get_shape(); + double room_area = room_oct.area(); + + boolean try_remove_edge_lines = false; + for (int i = 0; i < 8; ++i) + { + if (!this.edge_interiour_touches_obstacle[i]) + { + FloatPoint prev_corner = this.room_shape.corner_approx(i); + FloatPoint next_corner = this.room_shape.corner_approx(this.room_shape.next_no(i)); + if(prev_corner.distance_square(next_corner) > 1) + { + try_remove_edge_lines = true; + break; + } + } + } + + if (try_remove_edge_lines) + { + // Touching neighbour missing at the edge side with index remove_edge_no + // Remove the edge line and restart the algorithm. + + IntOctagon enlarged_oct = remove_not_touching_border_lines( room_oct, this.edge_interiour_touches_obstacle); + + Collection door_list = this.completed_room.get_doors(); + TileShape ignore_shape = null; + SearchTreeObject ignore_object = null; + double max_door_area = 0; + for (ExpansionDoor curr_door: door_list) + { + // insert the overlapping doors with CompleteFreeSpaceExpansionRooms + // for the information in complete_shape about the objects to ignore. + if (curr_door.dimension == 2) + { + CompleteExpansionRoom other_room = curr_door.other_room(this.completed_room); + { + if (other_room instanceof CompleteFreeSpaceExpansionRoom) + { + TileShape curr_door_shape = curr_door.get_shape(); + double curr_door_area = curr_door_shape.area(); + if (curr_door_area > max_door_area) + { + max_door_area = curr_door_area; + ignore_shape = curr_door_shape; + ignore_object = (CompleteFreeSpaceExpansionRoom) other_room; + } + } + } + } + } + IncompleteFreeSpaceExpansionRoom enlarged_room = + new IncompleteFreeSpaceExpansionRoom(enlarged_oct, curr_incomplete_room.get_layer(), + curr_incomplete_room.get_contained_shape()); + Collection new_rooms = + p_autoroute_search_tree.complete_shape(enlarged_room, p_net_no, ignore_object, ignore_shape); + if (new_rooms.size() == 1) + { + // Check, that the area increases to prevent endless loop. + IncompleteFreeSpaceExpansionRoom new_room = new_rooms.iterator().next(); + if (new_room.get_shape().area() > room_area) + { + curr_incomplete_room.set_shape(new_room.get_shape()); + curr_incomplete_room.set_contained_shape(new_room.get_contained_shape()); + return true; + } + } + } + return false; + } + + /** + * Inserts a new incomplete room with an octagon shape. + */ + private void insert_incomplete_room(AutorouteEngine p_autoroute_engine, int p_lx, int p_ly, int p_rx, int p_uy, + int p_ulx, int p_lrx, int p_llx, int p_urx) + { + IntOctagon new_incomplete_room_shape = new IntOctagon(p_lx, p_ly, p_rx, p_uy, p_ulx, p_lrx, p_llx, p_urx); + new_incomplete_room_shape = new_incomplete_room_shape.normalize(); + if (new_incomplete_room_shape.dimension() == 2) + { + IntOctagon new_contained_shape = this.room_shape.intersection(new_incomplete_room_shape); + if (!new_contained_shape.is_empty()) + { + int door_dimension = new_contained_shape.dimension(); + if (door_dimension > 0) + { + FreeSpaceExpansionRoom new_room = + p_autoroute_engine.add_incomplete_expansion_room(new_incomplete_room_shape, this.from_room.get_layer(), new_contained_shape); + ExpansionDoor new_door = new ExpansionDoor(this.completed_room, new_room, door_dimension); + this.completed_room.add_door(new_door); + new_room.add_door(new_door); + } + } + } + } + + private void calculate_new_incomplete_rooms_for_obstacle_expansion_room(SortedRoomNeighbour p_prev_neighbour, + SortedRoomNeighbour p_next_neighbour, AutorouteEngine p_autoroute_engine) + { + int from_side_no = p_prev_neighbour.last_touching_side; + int to_side_no = p_next_neighbour.first_touching_side; + if (from_side_no == to_side_no && p_prev_neighbour != p_next_neighbour) + { + // no return in case of only 1 neighbour. + return; + } + IntOctagon board_bounding_oct = p_autoroute_engine.board.bounding_box.bounding_octagon(); + + // insert the new incomplete room from p_prev_neighbour to the next corner of the room shape. + + int lx = board_bounding_oct.lx; + int ly = board_bounding_oct.ly; + int rx = board_bounding_oct.rx; + int uy = board_bounding_oct.uy; + int ulx = board_bounding_oct.ulx; + int lrx = board_bounding_oct.lrx; + int llx = board_bounding_oct.llx; + int urx = board_bounding_oct.urx; + if (from_side_no == 0) + { + uy = this.room_shape.ly; + ulx = p_prev_neighbour.intersection.lrx; + } + else if (from_side_no == 1) + { + ulx = this.room_shape.lrx; + lx = p_prev_neighbour.intersection.rx; + } + else if (from_side_no == 2) + { + lx = this.room_shape.rx; + llx = p_prev_neighbour.intersection.urx; + } + else if (from_side_no == 3) + { + llx = this.room_shape.urx; + ly = p_prev_neighbour.intersection.uy; + } + else if (from_side_no == 4) + { + ly = this.room_shape.uy; + lrx = p_prev_neighbour.intersection.ulx; + } + else if (from_side_no == 5) + { + lrx = this.room_shape.ulx; + rx = p_prev_neighbour.intersection.lx; + } + else if (from_side_no == 6) + { + rx = this.room_shape.lx; + urx = p_prev_neighbour.intersection.llx; + } + else if (from_side_no == 7) + { + urx = this.room_shape.llx; + uy = p_prev_neighbour.intersection.ly; + } + insert_incomplete_room(p_autoroute_engine, lx, ly, rx, uy, ulx, lrx, llx, urx); + + // insert the new incomplete room from p_prev_neighbour to the next corner of the room shape. + + lx = board_bounding_oct.lx; + ly = board_bounding_oct.ly; + rx = board_bounding_oct.rx; + uy = board_bounding_oct.uy; + ulx = board_bounding_oct.ulx; + lrx = board_bounding_oct.lrx; + llx = board_bounding_oct.llx; + urx = board_bounding_oct.urx; + + if (to_side_no == 0) + { + uy = this.room_shape.ly; + urx = p_next_neighbour.intersection.llx; + } + else if (to_side_no == 1) + { + ulx = this.room_shape.lrx; + uy = p_next_neighbour.intersection.ly; + } + else if (to_side_no == 2) + { + lx = this.room_shape.rx; + ulx = p_next_neighbour.intersection.lrx; + } + else if (to_side_no == 3) + { + llx = this.room_shape.urx; + lx = p_next_neighbour.intersection.rx; + } + else if (to_side_no == 4) + { + ly = this.room_shape.uy; + llx = p_next_neighbour.intersection.urx; + } + else if (to_side_no == 5) + { + lrx = this.room_shape.ulx; + ly = p_next_neighbour.intersection.uy; + } + else if (to_side_no == 6) + { + rx = this.room_shape.lx; + lrx = p_next_neighbour.intersection.ulx; + } + else if (to_side_no == 7) + { + urx = this.room_shape.llx; + rx = p_next_neighbour.intersection.lx; + } + insert_incomplete_room(p_autoroute_engine, lx, ly, rx, uy, ulx, lrx, llx, urx); + + // Insert the new incomplete rooms on the intermediate free sides of the obstacle expansion room. + int curr_from_side_no = (from_side_no + 1) % 8; + if (curr_from_side_no == to_side_no) + { + return; + } + int curr_to_side_no = (to_side_no + 7) % 8; + this.calculate_edge_incomplete_rooms_of_obstacle_expansion_room(curr_from_side_no, + curr_to_side_no, p_autoroute_engine); + } + + private void calculate_new_incomplete_rooms(AutorouteEngine p_autoroute_engine) + { + IntOctagon board_bounding_oct = p_autoroute_engine.board.bounding_box.bounding_octagon(); + SortedRoomNeighbour prev_neighbour = this.sorted_neighbours.last(); + if (this.from_room instanceof ObstacleExpansionRoom && this.sorted_neighbours.size() == 1) + { + // ObstacleExpansionRoom has only only 1 neighbour + calculate_new_incomplete_rooms_for_obstacle_expansion_room(prev_neighbour, prev_neighbour, p_autoroute_engine); + return; + } + Iterator it = this.sorted_neighbours.iterator(); + + while (it.hasNext()) + { + SortedRoomNeighbour next_neighbour = it.next(); + + boolean insert_incomplete_room; + + if (this.completed_room instanceof ObstacleExpansionRoom && this.sorted_neighbours.size() == 2) + { + // check, if this site is touching or open. + TileShape intersection = next_neighbour.intersection.intersection(prev_neighbour.intersection); + if (intersection.is_empty()) + { + insert_incomplete_room = true; + } + else if (intersection.dimension() >= 1) + { + insert_incomplete_room = false; + } + else // dimension = 1 + { + if (prev_neighbour.last_touching_side == next_neighbour.first_touching_side) + { + // touch along the side of the room shape + insert_incomplete_room = false; + } + else if(prev_neighbour.last_touching_side == (next_neighbour.first_touching_side + 1) % 8) + { + // touch at a corner of the room shape + insert_incomplete_room = false; + } + else + { + insert_incomplete_room = true; + } + } + } + else + { + // the 2 neigbours do not touch + insert_incomplete_room = !next_neighbour.intersection.intersects(prev_neighbour.intersection); + } + + + if (insert_incomplete_room) + { + // create a door to a new incomplete expansion room between + // the last corner of the previous neighbour and the first corner of the + // current neighbour + + if (this.from_room instanceof ObstacleExpansionRoom && + next_neighbour.first_touching_side != prev_neighbour.last_touching_side) + { + calculate_new_incomplete_rooms_for_obstacle_expansion_room(prev_neighbour, next_neighbour, p_autoroute_engine); + } + else + { + int lx = board_bounding_oct.lx; + int ly = board_bounding_oct.ly; + int rx = board_bounding_oct.rx; + int uy = board_bounding_oct.uy; + int ulx = board_bounding_oct.ulx; + int lrx = board_bounding_oct.lrx; + int llx = board_bounding_oct.llx; + int urx = board_bounding_oct.urx; + + if (next_neighbour.first_touching_side == 0) + { + if (prev_neighbour.intersection.llx < next_neighbour.intersection.llx) + { + urx = next_neighbour.intersection.llx; + uy = prev_neighbour.intersection.ly; + if (prev_neighbour.last_touching_side == 0) + { + ulx = prev_neighbour.intersection.lrx; + } + } + else if (prev_neighbour.intersection.llx > next_neighbour.intersection.llx) + { + rx = next_neighbour.intersection.lx; + urx = prev_neighbour.intersection.llx; + } + else // prev_neighbour.intersection.llx == next_neighbour.intersection.llx + { + urx = next_neighbour.intersection.llx; + } + } + else if (next_neighbour.first_touching_side == 1) + { + if (prev_neighbour.intersection.ly < next_neighbour.intersection.ly) + { + uy = next_neighbour.intersection.ly; + ulx = prev_neighbour.intersection.lrx; + if (prev_neighbour.last_touching_side == 1) + { + lx = prev_neighbour.intersection.rx; + } + } + else if (prev_neighbour.intersection.ly > next_neighbour.intersection.ly) + { + uy = prev_neighbour.intersection.ly; + urx = next_neighbour.intersection.llx; + } + else // prev_neighbour.intersection.ly == next_neighbour.intersection.ly + { + uy = next_neighbour.intersection.ly; + } + } + else if (next_neighbour.first_touching_side == 2) + { + if (prev_neighbour.intersection.lrx > next_neighbour.intersection.lrx) + { + ulx = next_neighbour.intersection.lrx; + lx = prev_neighbour.intersection.rx; + if (prev_neighbour.last_touching_side == 2) + { + llx = prev_neighbour.intersection.urx; + } + } + else if (prev_neighbour.intersection.lrx < next_neighbour.intersection.lrx) + { + uy = next_neighbour.intersection.ly; + ulx = prev_neighbour.intersection.lrx; + } + else // prev_neighbour.intersection.lrx == next_neighbour.intersection.lrx + { + ulx = next_neighbour.intersection.lrx; + } + } + else if (next_neighbour.first_touching_side == 3) + { + if (prev_neighbour.intersection.rx > next_neighbour.intersection.rx) + { + lx = next_neighbour.intersection.rx; + llx = prev_neighbour.intersection.urx; + if (prev_neighbour.last_touching_side == 3) + { + ly = prev_neighbour.intersection.uy; + } + } + else if (prev_neighbour.intersection.rx < next_neighbour.intersection.rx) + { + lx = prev_neighbour.intersection.rx; + ulx = next_neighbour.intersection.lrx; + } + else // prev_neighbour.intersection.ry == next_neighbour.intersection.ry + { + lx = next_neighbour.intersection.rx; + } + } + else if (next_neighbour.first_touching_side == 4) + { + if (prev_neighbour.intersection.urx > next_neighbour.intersection.urx) + { + llx = next_neighbour.intersection.urx; + ly = prev_neighbour.intersection.uy; + if (prev_neighbour.last_touching_side == 4) + { + lrx = prev_neighbour.intersection.ulx; + } + } + else if (prev_neighbour.intersection.urx < next_neighbour.intersection.urx) + { + lx = next_neighbour.intersection.rx; + llx = prev_neighbour.intersection.urx; + } + else // prev_neighbour.intersection.urx == next_neighbour.intersection.urx + { + llx = next_neighbour.intersection.urx; + } + } + else if (next_neighbour.first_touching_side == 5) + { + if (prev_neighbour.intersection.uy > next_neighbour.intersection.uy) + { + ly = next_neighbour.intersection.uy; + lrx = prev_neighbour.intersection.ulx; + if (prev_neighbour.last_touching_side == 5) + { + rx = prev_neighbour.intersection.lx; + } + } + else if (prev_neighbour.intersection.uy < next_neighbour.intersection.uy) + { + ly = prev_neighbour.intersection.uy; + llx = next_neighbour.intersection.urx; + } + else // prev_neighbour.intersection.uy == next_neighbour.intersection.uy + { + ly = next_neighbour.intersection.uy; + } + } + else if (next_neighbour.first_touching_side == 6) + { + if (prev_neighbour.intersection.ulx < next_neighbour.intersection.ulx) + { + lrx = next_neighbour.intersection.ulx; + rx = prev_neighbour.intersection.lx; + if (prev_neighbour.last_touching_side == 6) + { + urx = prev_neighbour.intersection.llx; + } + } + else if (prev_neighbour.intersection.ulx > next_neighbour.intersection.ulx) + { + ly = next_neighbour.intersection.uy; + lrx = prev_neighbour.intersection.ulx; + } + else // prev_neighbour.intersection.ulx == next_neighbour.intersection.ulx + { + lrx = next_neighbour.intersection.ulx; + } + } + else if (next_neighbour.first_touching_side == 7) + { + if (prev_neighbour.intersection.lx < next_neighbour.intersection.lx) + { + rx = next_neighbour.intersection.lx; + urx = prev_neighbour.intersection.llx; + if (prev_neighbour.last_touching_side == 7) + { + uy = prev_neighbour.intersection.ly; + } + } + else if (prev_neighbour.intersection.lx > next_neighbour.intersection.lx) + { + rx = prev_neighbour.intersection.lx; + lrx = next_neighbour.intersection.ulx; + } + else // prev_neighbour.intersection.lx == next_neighbour.intersection.lx + { + rx = next_neighbour.intersection.lx; + } + } + else + { + System.out.println("Sorted45DegreeRoomNeighbour.calculate_new_incomplete: illegal touching side"); + } + insert_incomplete_room(p_autoroute_engine, lx, ly, rx, uy, ulx, lrx, llx, urx); + } + } + prev_neighbour = next_neighbour; + } + } + + public final CompleteExpansionRoom completed_room; + public final SortedSet sorted_neighbours; + private final ExpansionRoom from_room; + private final IntOctagon room_shape; + + private final boolean[] edge_interiour_touches_obstacle; + + /** + * Helper class to sort the doors of an expansion room counterclockwise + * arount the border of the room shape. + */ + + private class SortedRoomNeighbour implements Comparable + { + + /** + * Creates a new instance of SortedRoomNeighbour and calculates the first and last + * touching sides with the room shape. + * this.last_touching_side will be -1, if sorting did not work because + * the room_shape is contained in the neighbour shape. + */ + public SortedRoomNeighbour(IntOctagon p_neighbour_shape, IntOctagon p_intersection) + { + shape = p_neighbour_shape; + intersection = p_intersection; + + if (intersection.ly == room_shape.ly && intersection.llx > room_shape.llx) + { + this.first_touching_side = 0; + } + else if (intersection.lrx == room_shape.lrx && intersection.ly > room_shape.ly) + { + this.first_touching_side = 1; + } + else if (intersection.rx == room_shape.rx && intersection.lrx < room_shape.lrx) + { + this.first_touching_side = 2; + } + else if (intersection.urx == room_shape.urx && intersection.rx < room_shape.rx) + { + this.first_touching_side = 3; + } + else if (intersection.uy == room_shape.uy && intersection.urx < room_shape.urx) + { + this.first_touching_side = 4; + } + else if (intersection.ulx == room_shape.ulx && intersection.uy < room_shape.uy) + { + this.first_touching_side = 5; + } + else if (intersection.lx == room_shape.lx && intersection.ulx > room_shape.ulx) + { + this.first_touching_side = 6; + } + else if (intersection.llx == room_shape.llx && intersection.lx > room_shape.lx) + { + this.first_touching_side = 7; + } + else + { + // the room_shape may be contained in the neighbour_shape + this.first_touching_side = -1; + this.last_touching_side = -1; + return; + } + + if (intersection.llx == room_shape.llx && intersection.ly > room_shape.ly) + { + this.last_touching_side = 7; + } + else if (intersection.lx == room_shape.lx && intersection.llx > room_shape.llx) + { + this.last_touching_side = 6; + } + else if (intersection.ulx == room_shape.ulx && intersection.lx > room_shape.lx) + { + this.last_touching_side = 5; + } + else if (intersection.uy == room_shape.uy && intersection.ulx > room_shape.ulx) + { + this.last_touching_side = 4; + } + else if (intersection.urx == room_shape.urx && intersection.uy < room_shape.uy) + { + this.last_touching_side = 3; + } + else if (intersection.rx == room_shape.rx && intersection.urx < room_shape.urx) + { + this.last_touching_side = 2; + } + else if (intersection.lrx == room_shape.lrx && intersection.rx < room_shape.rx) + { + this.last_touching_side = 1; + } + else if (intersection.ly == room_shape.ly && intersection.lrx < room_shape.lrx) + { + this.last_touching_side = 0; + } + else + { + // the room_shape may be contained in the neighbour_shape + this.last_touching_side = -1; + return; + } + + int next_side_no = this.first_touching_side; + for (;;) + { + int curr_side_no = next_side_no; + next_side_no = (next_side_no + 1) % 8; + if (!edge_interiour_touches_obstacle[curr_side_no]) + { + boolean touch_only_at_corner = false; + if (curr_side_no == this.first_touching_side) + { + if (intersection.corner(curr_side_no).equals(room_shape.corner(next_side_no))) + { + touch_only_at_corner = true; + } + } + if (curr_side_no == this.last_touching_side) + { + if (intersection.corner(next_side_no).equals(room_shape.corner(curr_side_no))) + { + touch_only_at_corner = true; + } + } + if (!touch_only_at_corner) + { + edge_interiour_touches_obstacle[curr_side_no] = true; + } + } + if (curr_side_no == this.last_touching_side) + { + break; + } + + } + } + + /** + * Compare function for or sorting the neighbours in counterclock sense + * around the border of the room shape in ascending order. + */ + public int compareTo(SortedRoomNeighbour p_other) + { + if (this.first_touching_side > p_other.first_touching_side) + { + return 1; + } + if (this.first_touching_side < p_other.first_touching_side) + { + return -1; + } + + // now the first touch of this and p_other is at the same side + IntOctagon is1 = this.intersection; + IntOctagon is2 = p_other.intersection; + int cmp_value; + + if (first_touching_side == 0) + { + cmp_value = is1.corner(0).x - is2.corner(0).x; + } + else if (first_touching_side == 1) + { + cmp_value = is1.corner(1).x - is2.corner(1).x; + } + else if (first_touching_side == 2) + { + cmp_value = is1.corner(2).y - is2.corner(2).y; + } + else if (first_touching_side == 3) + { + cmp_value = is1.corner(3).y - is2.corner(3).y; + } + else if (first_touching_side == 4) + { + cmp_value = is2.corner(4).x - is1.corner(4).x; + } + else if (first_touching_side == 5) + { + cmp_value = is2.corner(5).x - is1.corner(5).x; + } + else if (first_touching_side == 6) + { + cmp_value = is2.corner(6).y - is1.corner(6).y; + } + else if (first_touching_side == 7) + { + cmp_value = is2.corner(7).y - is1.corner(7).y; + } + else + { + System.out.println("SortedRoomNeighbour.compareTo: first_touching_side out of range "); + return 0; + } + + if (cmp_value == 0) + { + // The first touching points of this neighbour and p_other with the room shape are equal. + // Compare the last touching points. + int this_touching_side_diff = (this.last_touching_side - this.first_touching_side + 8) % 8; + int other_touching_side_diff = (p_other.last_touching_side - p_other.first_touching_side + 8) % 8; + if (this_touching_side_diff > other_touching_side_diff) + { + return 1; + } + if (this_touching_side_diff < other_touching_side_diff) + { + return -1; + } + // now the last touch of this and p_other is at the same side + if (last_touching_side == 0) + { + cmp_value = is1.corner(1).x - is2.corner(1).x; + } + else if (last_touching_side == 1) + { + cmp_value = is1.corner(2).x - is2.corner(2).x; + } + else if (last_touching_side == 2) + { + cmp_value = is1.corner(3).y - is2.corner(3).y; + } + else if (last_touching_side == 3) + { + cmp_value = is1.corner(4).y - is2.corner(4).y; + } + else if (last_touching_side == 4) + { + cmp_value = is2.corner(5).x - is1.corner(5).x; + } + else if (last_touching_side == 5) + { + cmp_value = is2.corner(6).x - is1.corner(6).x; + } + else if (last_touching_side == 6) + { + cmp_value = is2.corner(7).y - is1.corner(7).y; + } + else if (last_touching_side == 7) + { + cmp_value = is2.corner(0).y - is1.corner(0).y; + } + } + return cmp_value; + } + /** The shape of the neighbour room */ + public final IntOctagon shape; + + /** The intersection of tnis ExpansionRoom shape with the neighbour_shape */ + public final IntOctagon intersection; + + /** The first side of the room shape, where the neighbour_shape touches */ + public final int first_touching_side; + + /** The last side of the room shape, where the neighbour_shape touches */ + public final int last_touching_side; + } +} diff --git a/autoroute/SortedOrthogonalRoomNeighbours.java b/src/main/java/autoroute/SortedOrthogonalRoomNeighbours.java similarity index 97% rename from autoroute/SortedOrthogonalRoomNeighbours.java rename to src/main/java/autoroute/SortedOrthogonalRoomNeighbours.java index 80a83a5..be60df4 100644 --- a/autoroute/SortedOrthogonalRoomNeighbours.java +++ b/src/main/java/autoroute/SortedOrthogonalRoomNeighbours.java @@ -1,729 +1,738 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * OrthogonalAutorouteEngine.java - * - * Created on 24. Mai 2007, 07:51 - * - */ - -package autoroute; - -import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.SortedSet; -import java.util.TreeSet; - -import datastructures.ShapeTree; - -import geometry.planar.IntBox; -import geometry.planar.TileShape; -import geometry.planar.Limits; - -import board.SearchTreeObject; -import board.ShapeSearchTree; -import board.Item; - -/** - * - * @author Alfons Wirtz - */ -public class SortedOrthogonalRoomNeighbours -{ - - public static CompleteExpansionRoom calculate(ExpansionRoom p_room, AutorouteEngine p_autoroute_engine) - { - int net_no = p_autoroute_engine.get_net_no(); - SortedOrthogonalRoomNeighbours room_neighbours = SortedOrthogonalRoomNeighbours.calculate_neighbours(p_room, net_no, - p_autoroute_engine.autoroute_search_tree, p_autoroute_engine.generate_room_id_no()); - if (room_neighbours == null) - { - return null; - } - - // Check, that each side of the romm shape has at least one touching neighbour. - // Otherwise improve the room shape by enlarging. - boolean edge_removed = room_neighbours.try_remove_edge(net_no, p_autoroute_engine.autoroute_search_tree); - CompleteExpansionRoom result = room_neighbours.completed_room; - if (edge_removed) - { - p_autoroute_engine.remove_all_doors(result); - return calculate(p_room, p_autoroute_engine); - } - - // Now calculate the new incomplete rooms together with the doors - // between this room and the sorted neighbours. - - if (room_neighbours.sorted_neighbours.isEmpty()) - { - if (result instanceof ObstacleExpansionRoom) - { - calculate_incomplete_rooms_with_empty_neighbours((ObstacleExpansionRoom) p_room, p_autoroute_engine); - } - } - else - { - room_neighbours.calculate_new_incomplete_rooms(p_autoroute_engine); - } - return result; - } - - private static void calculate_incomplete_rooms_with_empty_neighbours(ObstacleExpansionRoom p_room, AutorouteEngine p_autoroute_engine) - { - TileShape room_shape = p_room.get_shape(); - if (!(room_shape instanceof IntBox)) - { - System.out.println("SortedOrthoganelRoomNeighbours.calculate_incomplete_rooms_with_empty_neighbours: IntBox expected for room_shape"); - return; - } - IntBox room_box = (IntBox) room_shape; - IntBox bounding_box = p_autoroute_engine.board.get_bounding_box(); - for (int i = 0; i < 4; ++i) - { - IntBox new_room_box; - if (i == 0) - { - new_room_box = new IntBox(bounding_box.ll.x, bounding_box.ll.y, bounding_box.ur.x, room_box.ll.y); - } - else if (i == 1) - { - new_room_box = new IntBox(room_box.ur.x, bounding_box.ll.y, bounding_box.ur.x, bounding_box.ur.y); - } - else if (i == 2) - { - new_room_box = new IntBox(bounding_box.ll.x, room_box.ur.y, bounding_box.ur.x, bounding_box.ur.y); - } - else if (i == 3) - { - new_room_box = new IntBox(bounding_box.ll.x, bounding_box.ll.y, room_box.ll.x, bounding_box.ur.y); - } - else - { - System.out.println("SortedOrthoganelRoomNeighbours.calculate_incomplete_rooms_with_empty_neighbours: illegal index i"); - return; - } - IntBox new_contained_box = room_box.intersection(new_room_box); - FreeSpaceExpansionRoom new_room = p_autoroute_engine.add_incomplete_expansion_room(new_room_box, p_room.get_layer(), new_contained_box); - ExpansionDoor new_door = new ExpansionDoor(p_room, new_room, 1); - p_room.add_door(new_door); - new_room.add_door(new_door); - } - } - - /** - * Calculates all touching neighbours of p_room and sorts them in - * counterclock sense around the boundary of the room shape. - */ - private static SortedOrthogonalRoomNeighbours calculate_neighbours(ExpansionRoom p_room, int p_net_no, - ShapeSearchTree p_autoroute_search_tree, int p_room_id_no) - { - TileShape room_shape = p_room.get_shape(); - if (!(room_shape instanceof IntBox)) - { - System.out.println("SortedOrthogonalRoomNeighbours.calculate: IntBox expected for room_shape"); - return null; - } - IntBox room_box = (IntBox) room_shape; - CompleteExpansionRoom completed_room; - if (p_room instanceof IncompleteFreeSpaceExpansionRoom) - { - completed_room = new CompleteFreeSpaceExpansionRoom(room_shape, p_room.get_layer(), p_room_id_no); - } - else if (p_room instanceof ObstacleExpansionRoom) - { - completed_room = (ObstacleExpansionRoom)p_room; - } - else - { - System.out.println("SortedOrthogonalRoomNeighbours.calculate: unexpected expansion room type"); - return null; - } - SortedOrthogonalRoomNeighbours result = new SortedOrthogonalRoomNeighbours(p_room, completed_room); - Collection overlapping_objects = new LinkedList(); - p_autoroute_search_tree.overlapping_tree_entries(room_shape, p_room.get_layer(), overlapping_objects); - // Calculate the touching neigbour objects and sort them in counterclock sence - // around the border of the room shape. - for (ShapeTree.TreeEntry curr_entry : overlapping_objects) - { - SearchTreeObject curr_object = (SearchTreeObject) curr_entry.object; - if (curr_object == p_room) - { - continue; - } - if ((completed_room instanceof CompleteFreeSpaceExpansionRoom) && !curr_object.is_trace_obstacle(p_net_no)) - { - ((CompleteFreeSpaceExpansionRoom) completed_room).calculate_target_doors(curr_entry, - p_net_no, p_autoroute_search_tree); - continue; - } - TileShape curr_shape = - curr_object.get_tree_shape(p_autoroute_search_tree, curr_entry.shape_index_in_object); - if (!(curr_shape instanceof IntBox)) - { - System.out.println("OrthogonalAutorouteEngine:calculate_sorted_neighbours: IntBox expected for curr_shape"); - return null; - } - IntBox curr_box = (IntBox) curr_shape; - IntBox intersection = room_box.intersection(curr_box); - int dimension = intersection.dimension(); - if (dimension > 1 && completed_room instanceof ObstacleExpansionRoom) - { - if (curr_object instanceof Item) - { - // only Obstacle expansion roos may have a 2-dim overlap - Item curr_item = (Item) curr_object; - if (curr_item.is_route()) - { - ItemAutorouteInfo item_info = curr_item.get_autoroute_info(); - ObstacleExpansionRoom curr_overlap_room = - item_info.get_expansion_room(curr_entry.shape_index_in_object, p_autoroute_search_tree); - ((ObstacleExpansionRoom) completed_room).create_overlap_door(curr_overlap_room); - } - - } - continue; - } - if (dimension < 0) - { - - System.out.println("AutorouteEngine.calculate_doors: dimension >= 0 expected"); - continue; - } - result.add_sorted_neighbour(curr_box, intersection); - if (dimension > 0) - { - // make shure, that there is a door to the neighbour room. - ExpansionRoom neighbour_room = null; - if (curr_object instanceof ExpansionRoom) - { - neighbour_room = (ExpansionRoom) curr_object; - } - else if (curr_object instanceof Item) - { - Item curr_item = (Item) curr_object; - if (curr_item.is_route()) - { - // expand the item for ripup and pushing purposes - ItemAutorouteInfo item_info = curr_item.get_autoroute_info(); - neighbour_room = - item_info.get_expansion_room(curr_entry.shape_index_in_object, p_autoroute_search_tree); - } - } - if (neighbour_room != null) - { - if (SortedRoomNeighbours.insert_door_ok(completed_room, neighbour_room, intersection)) - { - ExpansionDoor new_door = new ExpansionDoor(completed_room, neighbour_room); - neighbour_room.add_door(new_door); - completed_room.add_door(new_door); - } - } - } - } - return result; - } - - private void calculate_new_incomplete_rooms(AutorouteEngine p_autoroute_engine) - { - IntBox board_bounds = p_autoroute_engine.board.bounding_box; - SortedRoomNeighbour prev_neighbour = this.sorted_neighbours.last(); - Iterator it = this.sorted_neighbours.iterator(); - - while (it.hasNext()) - { - SortedRoomNeighbour next_neighbour = it.next(); - - if (!next_neighbour.intersection.intersects(prev_neighbour.intersection)) - { - // create a door to a new incomplete expansion room between - // the last corner of the previous neighbour and the first corner of the - // current neighbour. - if (next_neighbour.first_touching_side == 0) - { - if (prev_neighbour.last_touching_side == 0) - { - if (prev_neighbour.intersection.ur.x < next_neighbour.intersection.ll.x) - { - insert_incomplete_room(p_autoroute_engine, prev_neighbour.intersection.ur.x, board_bounds.ll.y, - next_neighbour.intersection.ll.x, this.room_shape.ll.y); - } - } - else - { - if (prev_neighbour.intersection.ll.y > this.room_shape.ll.y - || next_neighbour.intersection.ll.x > this.room_shape.ll.x) - { - if (is_obstacle_expansion_room) - { - // no 2-dim doors between obstacle_expansion_rooms and free space rooms allowed. - if (prev_neighbour.last_touching_side == 3) - { - insert_incomplete_room(p_autoroute_engine, board_bounds.ll.x, room_shape.ll.y, - room_shape.ll.x, prev_neighbour.intersection.ll.y); - } - insert_incomplete_room(p_autoroute_engine, room_shape.ll.x, board_bounds.ll.y, - next_neighbour.intersection.ll.x, room_shape.ll.y); - } - else - { - insert_incomplete_room(p_autoroute_engine, board_bounds.ll.x, board_bounds.ll.y, - next_neighbour.intersection.ll.x, prev_neighbour.intersection.ll.y); - } - } - } - } - else if (next_neighbour.first_touching_side == 1) - { - if (prev_neighbour.last_touching_side == 1) - { - if (prev_neighbour.intersection.ur.y < next_neighbour.intersection.ll.y) - { - insert_incomplete_room(p_autoroute_engine, this.room_shape.ur.x, prev_neighbour.intersection.ur.y, - board_bounds.ur.x, next_neighbour.intersection.ll.y ); - } - } - else - { - if (prev_neighbour.intersection.ur.x < this.room_shape.ur.x - || next_neighbour.intersection.ll.y > this.room_shape.ll.y) - { - if (is_obstacle_expansion_room) - { - // no 2-dim doors between obstacle_expansion_rooms and free space rooms allowed. - if (prev_neighbour.last_touching_side == 0) - { - insert_incomplete_room(p_autoroute_engine, prev_neighbour.intersection.ur.x, board_bounds.ll.y, - room_shape.ur.x, room_shape.ll.y); - } - insert_incomplete_room(p_autoroute_engine, room_shape.ur.x, room_shape.ll.y, - room_shape.ur.x, next_neighbour.intersection.ll.y ); - } - else - { - insert_incomplete_room(p_autoroute_engine, prev_neighbour.intersection.ur.x, board_bounds.ll.y, - board_bounds.ur.x, next_neighbour.intersection.ll.y); - } - } - } - } - else if (next_neighbour.first_touching_side == 2) - { - if (prev_neighbour.last_touching_side == 2) - { - if (prev_neighbour.intersection.ll.x > next_neighbour.intersection.ur.x) - { - insert_incomplete_room(p_autoroute_engine, next_neighbour.intersection.ur.x, this.room_shape.ur.y, - prev_neighbour.intersection.ll.x, board_bounds.ur.y); - } - } - else - { - if (prev_neighbour.intersection.ur.y < this.room_shape.ur.y - || next_neighbour.intersection.ur.x < this.room_shape.ur.x) - { - if (is_obstacle_expansion_room) - { - // no 2-dim doors between obstacle_expansion_rooms and free space rooms allowed. - if (prev_neighbour.last_touching_side == 1) - { - insert_incomplete_room(p_autoroute_engine, room_shape.ur.x, prev_neighbour.intersection.ur.y, - board_bounds.ur.x, room_shape.ur.y); - } - insert_incomplete_room(p_autoroute_engine, next_neighbour.intersection.ur.x, room_shape.ur.y, - room_shape.ur.x, board_bounds.ur.y ); - } - else - { - insert_incomplete_room(p_autoroute_engine, next_neighbour.intersection.ur.x, prev_neighbour.intersection.ur.y, - board_bounds.ur.x, board_bounds.ur.y); - } - } - } - } - else if (next_neighbour.first_touching_side == 3) - { - if (prev_neighbour.last_touching_side == 3) - { - if (prev_neighbour.intersection.ll.y > next_neighbour.intersection.ur.y) - { - insert_incomplete_room(p_autoroute_engine, board_bounds.ll.x, next_neighbour.intersection.ur.y, - this.room_shape.ll.x, prev_neighbour.intersection.ll.y); - } - } - else - { - if (next_neighbour.intersection.ur.y < this.room_shape.ur.y - || prev_neighbour.intersection.ll.x > this.room_shape.ll.x) - { - if (is_obstacle_expansion_room) - { - // no 2-dim doors between obstacle_expansion_rooms and free space rooms allowed. - if (prev_neighbour.last_touching_side == 2) - { - insert_incomplete_room(p_autoroute_engine, room_shape.ll.x, room_shape.ur.y, - prev_neighbour.intersection.ll.x, board_bounds.ur.y); - } - insert_incomplete_room(p_autoroute_engine, board_bounds.ll.x, next_neighbour.intersection.ur.y, - room_shape.ll.x, room_shape.ur.y); - } - else - { - insert_incomplete_room(p_autoroute_engine, board_bounds.ll.x, next_neighbour.intersection.ur.y, - prev_neighbour.intersection.ll.x, board_bounds.ur.y); - } - } - } - } - else - { - System.out.println("SortedOrthogonalRoomNeighbour.calculate_new_incomplete: illegal touching side"); - } - } - prev_neighbour = next_neighbour; - } - } - - private void insert_incomplete_room(AutorouteEngine p_autoroute_engine, int p_ll_x, int p_ll_y, int p_ur_x, int p_ur_y) - { - IntBox new_incomplete_room_shape = new IntBox(p_ll_x, p_ll_y, p_ur_x, p_ur_y); - if (new_incomplete_room_shape.dimension() == 2) - { - IntBox new_contained_shape = this.room_shape.intersection(new_incomplete_room_shape); - if (!new_contained_shape.is_empty()) - { - int door_dimension = new_incomplete_room_shape.intersection(this.room_shape).dimension(); - if (door_dimension > 0) - { - FreeSpaceExpansionRoom new_room = - p_autoroute_engine.add_incomplete_expansion_room(new_incomplete_room_shape, this.from_room.get_layer(), new_contained_shape); - ExpansionDoor new_door = new ExpansionDoor(this.completed_room, new_room, door_dimension); - this.completed_room.add_door(new_door); - new_room.add_door(new_door); - } - } - } - } - - /** Creates a new instance of SortedOrthogonalRoomNeighbours */ - private SortedOrthogonalRoomNeighbours(ExpansionRoom p_from_room, CompleteExpansionRoom p_completed_room) - { - from_room = p_from_room; - completed_room = p_completed_room; - is_obstacle_expansion_room = p_from_room instanceof ObstacleExpansionRoom; - room_shape = (IntBox) p_completed_room.get_shape(); - sorted_neighbours = new TreeSet(); - edge_interiour_touches_obstacle = new boolean[4]; - for (int i = 0; i < 4; ++i) - { - edge_interiour_touches_obstacle[i] = false; - } - } - - /** - * Check, that each side of the romm shape has at least one touching neighbour. - * Otherwise the room shape will be improved the by enlarging. - * Returns true, if the room shape was changed. - */ - private boolean try_remove_edge(int p_net_no, ShapeSearchTree p_autoroute_search_tree) - { - if (!(this.from_room instanceof IncompleteFreeSpaceExpansionRoom)) - { - return false; - } - IncompleteFreeSpaceExpansionRoom curr_incomplete_room = (IncompleteFreeSpaceExpansionRoom) this.from_room; - if (!(curr_incomplete_room.get_shape() instanceof IntBox)) - { - System.out.println("SortedOrthogonalRoomNeighbours.try_remove_edge: IntBox expected for room_shape type"); - return false; - } - IntBox room_box = (IntBox) curr_incomplete_room.get_shape(); - double room_area = room_box.area(); - - int remove_edge_no = -1; - for (int i = 0; i < 4; ++i) - { - if (!this.edge_interiour_touches_obstacle[i]) - { - remove_edge_no = i; - break; - } - } - - if (remove_edge_no >= 0) - { - // Touching neighbour missing at the edge side with index remove_edge_no - // Remove the edge line and restart the algorithm. - IntBox enlarged_box = remove_border_line( room_box, remove_edge_no); - Collection door_list = this.completed_room.get_doors(); - TileShape ignore_shape = null; - SearchTreeObject ignore_object = null; - double max_door_area = 0; - for (ExpansionDoor curr_door: door_list) - { - // insert the overlapping doors with CompleteFreeSpaceExpansionRooms - // for the information in complete_shape about the objects to ignore. - if (curr_door.dimension == 2) - { - CompleteExpansionRoom other_room = curr_door.other_room(this.completed_room); - { - if (other_room instanceof CompleteFreeSpaceExpansionRoom) - { - TileShape curr_door_shape = curr_door.get_shape(); - double curr_door_area = curr_door_shape.area(); - if (curr_door_area > max_door_area) - { - max_door_area = curr_door_area; - ignore_shape = curr_door_shape; - ignore_object = (CompleteFreeSpaceExpansionRoom) other_room; - } - } - } - } - } - IncompleteFreeSpaceExpansionRoom enlarged_room = - new IncompleteFreeSpaceExpansionRoom(enlarged_box, curr_incomplete_room.get_layer(), - curr_incomplete_room.get_contained_shape()); - Collection new_rooms = - p_autoroute_search_tree.complete_shape(enlarged_room, p_net_no, ignore_object, ignore_shape); - if (new_rooms.size() == 1) - { - // Check, that the area increases to prevent endless loop. - IncompleteFreeSpaceExpansionRoom new_room = new_rooms.iterator().next(); - if (new_room.get_shape().area() > room_area) - { - curr_incomplete_room.set_shape(new_room.get_shape()); - curr_incomplete_room.set_contained_shape(new_room.get_contained_shape()); - return true; - } - } - } - return false; - } - - private static IntBox remove_border_line( IntBox p_room_box, int p_remove_edge_no) - { - IntBox result; - if (p_remove_edge_no == 0) - { - result = new IntBox(p_room_box.ll.x, -Limits.CRIT_INT, p_room_box.ur.x, p_room_box.ur.y); - } - else if (p_remove_edge_no == 1) - { - result = new IntBox(p_room_box.ll.x, p_room_box.ll.y, Limits.CRIT_INT, p_room_box.ur.y); - } - else if (p_remove_edge_no == 2) - { - result = new IntBox(p_room_box.ll.x, p_room_box.ll.y, p_room_box.ur.x, Limits.CRIT_INT); - } - else if (p_remove_edge_no == 3) - { - result = new IntBox(-Limits.CRIT_INT, p_room_box.ll.y, p_room_box.ur.x, p_room_box.ur.y); - } - else - { - System.out.println("SortedOrthogonalRoomNeighbours.remove_border_line: illegal p_remove_edge_no"); - result = null; - } - return result; - } - - private void add_sorted_neighbour(IntBox p_neighbour_shape, IntBox p_intersection) - { - SortedRoomNeighbour new_neighbour = new SortedRoomNeighbour(p_neighbour_shape, p_intersection); - sorted_neighbours.add(new_neighbour); - } - - public final CompleteExpansionRoom completed_room; - public final SortedSet sorted_neighbours; - private final ExpansionRoom from_room; - private final boolean is_obstacle_expansion_room; - private final IntBox room_shape; - - private final boolean[] edge_interiour_touches_obstacle; - - /** - * Helper class to sort the doors of an expansion room counterclockwise - * arount the border of the room shape. - */ - - private class SortedRoomNeighbour implements Comparable - { - public SortedRoomNeighbour(IntBox p_neighbour_shape, IntBox p_intersection) - { - shape = p_neighbour_shape; - intersection = p_intersection; - - if( p_intersection.ll.y == room_shape.ll.y - && p_intersection.ur.x > room_shape.ll.x && p_intersection.ll.x < room_shape.ur.x) - { - edge_interiour_touches_obstacle[0] = true; - } - if( p_intersection.ur.x == room_shape.ur.x - && p_intersection.ur.y > room_shape.ll.y && p_intersection.ll.y < room_shape.ur.y) - { - edge_interiour_touches_obstacle[1] = true; - } - if( p_intersection.ur.y == room_shape.ur.y - && p_intersection.ur.x > room_shape.ll.x && p_intersection.ll.x < room_shape.ur.x) - { - edge_interiour_touches_obstacle[2] = true; - } - if( p_intersection.ll.x == room_shape.ll.x - && p_intersection.ur.y > room_shape.ll.y && p_intersection.ll.y < room_shape.ur.y) - { - edge_interiour_touches_obstacle[3] = true; - } - - if (p_intersection.ll.y == room_shape.ll.y && p_intersection.ll.x > room_shape.ll.x) - { - this.first_touching_side = 0; - } - else if (p_intersection.ur.x == room_shape.ur.x && p_intersection.ll.y > room_shape.ll.y) - { - this.first_touching_side = 1; - } - else if (p_intersection.ur.y == room_shape.ur.y ) - { - this.first_touching_side = 2; - } - else if (p_intersection.ll.x == room_shape.ll.x) - { - this.first_touching_side = 3; - } - else - { - System.out.println("SortedRoomNeighbour: case not expected"); - this.first_touching_side = -1; - } - - if (p_intersection.ll.x == room_shape.ll.x && p_intersection.ll.y > room_shape.ll.y) - { - this.last_touching_side = 3; - } - else if (p_intersection.ur.y == room_shape.ur.y && p_intersection.ll.x > room_shape.ll.x) - { - this.last_touching_side = 2; - } - else if (p_intersection.ur.x == room_shape.ur.x) - { - this.last_touching_side = 1; - } - else if (p_intersection.ll.y == room_shape.ll.y) - { - this.last_touching_side = 0; - } - else - { - System.out.println("SortedRoomNeighbour: case not expected"); - this.last_touching_side = -1; - } - } - - /** - * Compare function for or sorting the neighbours in counterclock sense - * around the border of the room shape in ascending order. - */ - public int compareTo(SortedRoomNeighbour p_other) - { - if (this.first_touching_side > p_other.first_touching_side) - { - return 1; - } - if (this.first_touching_side < p_other.first_touching_side) - { - return -1; - } - - // now the first touch of this and p_other is at the same side - IntBox is1 = this.intersection; - IntBox is2 = p_other.intersection; - int cmp_value; - - if (first_touching_side == 0) - { - cmp_value = is1.ll.x - is2.ll.x; - } - else if (first_touching_side == 1) - { - cmp_value = is1.ll.y - is2.ll.y; - } - else if (first_touching_side == 2) - { - cmp_value = is2.ur.x - is1.ur.x; - } - else if (first_touching_side == 3) - { - cmp_value = is2.ur.y - is1.ur.y; - } - else - { - System.out.println("SortedRoomNeighbour.compareTo: first_touching_side out of range "); - return 0; - } - if (cmp_value == 0) - { - // The first touching points of this neighbour and p_other with the room shape are equal. - // Compare the last touching points. - int this_touching_side_diff = (this.last_touching_side - this.first_touching_side + 4) % 4; - int other_touching_side_diff = (p_other.last_touching_side - p_other.first_touching_side + 4) % 4; - if (this_touching_side_diff > other_touching_side_diff) - { - return 1; - } - if (this_touching_side_diff < other_touching_side_diff) - { - return -1; - } - - // now the last touch of this and p_other is at the same side - if (last_touching_side == 0) - { - cmp_value = is1.ur.x - is2.ur.x; - } - else if (last_touching_side == 1) - { - cmp_value = is1.ur.y - is2.ur.y; - } - else if (last_touching_side == 2) - { - cmp_value = is2.ll.x - is1.ll.x; - } - else if (last_touching_side == 3) - { - cmp_value = is2.ll.y - is1.ll.y; - } - else - { - System.out.println("SortedRoomNeighbour.compareTo: first_touching_side out of range "); - return 0; - } - } - return cmp_value; - } - - /** The shape of the neighbour room */ - public final IntBox shape; - - /** The intersection of tnis ExpansionRoom shape with the neighbour_shape */ - public final IntBox intersection; - - /** The first side of the room shape, where the neighbour_shape touches */ - public final int first_touching_side; - - /** The last side of the room shape, where the neighbour_shape touches */ - public final int last_touching_side; - } -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * OrthogonalAutorouteEngine.java + * + * Created on 24. Mai 2007, 07:51 + * + */ + +package autoroute; + +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.SortedSet; +import java.util.TreeSet; + +import datastructures.ShapeTree; + +import geometry.planar.IntBox; +import geometry.planar.TileShape; +import geometry.planar.Limits; + +import board.SearchTreeObject; +import board.ShapeSearchTree; +import board.Item; + +/** + *

SortedOrthogonalRoomNeighbours class.

+ * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class SortedOrthogonalRoomNeighbours +{ + + /** + *

calculate.

+ * + * @param p_room a {@link autoroute.ExpansionRoom} object. + * @param p_autoroute_engine a {@link autoroute.AutorouteEngine} object. + * @return a {@link autoroute.CompleteExpansionRoom} object. + */ + public static CompleteExpansionRoom calculate(ExpansionRoom p_room, AutorouteEngine p_autoroute_engine) + { + int net_no = p_autoroute_engine.get_net_no(); + SortedOrthogonalRoomNeighbours room_neighbours = SortedOrthogonalRoomNeighbours.calculate_neighbours(p_room, net_no, + p_autoroute_engine.autoroute_search_tree, p_autoroute_engine.generate_room_id_no()); + if (room_neighbours == null) + { + return null; + } + + // Check, that each side of the romm shape has at least one touching neighbour. + // Otherwise improve the room shape by enlarging. + boolean edge_removed = room_neighbours.try_remove_edge(net_no, p_autoroute_engine.autoroute_search_tree); + CompleteExpansionRoom result = room_neighbours.completed_room; + if (edge_removed) + { + p_autoroute_engine.remove_all_doors(result); + return calculate(p_room, p_autoroute_engine); + } + + // Now calculate the new incomplete rooms together with the doors + // between this room and the sorted neighbours. + + if (room_neighbours.sorted_neighbours.isEmpty()) + { + if (result instanceof ObstacleExpansionRoom) + { + calculate_incomplete_rooms_with_empty_neighbours((ObstacleExpansionRoom) p_room, p_autoroute_engine); + } + } + else + { + room_neighbours.calculate_new_incomplete_rooms(p_autoroute_engine); + } + return result; + } + + private static void calculate_incomplete_rooms_with_empty_neighbours(ObstacleExpansionRoom p_room, AutorouteEngine p_autoroute_engine) + { + TileShape room_shape = p_room.get_shape(); + if (!(room_shape instanceof IntBox)) + { + System.out.println("SortedOrthoganelRoomNeighbours.calculate_incomplete_rooms_with_empty_neighbours: IntBox expected for room_shape"); + return; + } + IntBox room_box = (IntBox) room_shape; + IntBox bounding_box = p_autoroute_engine.board.get_bounding_box(); + for (int i = 0; i < 4; ++i) + { + IntBox new_room_box; + if (i == 0) + { + new_room_box = new IntBox(bounding_box.ll.x, bounding_box.ll.y, bounding_box.ur.x, room_box.ll.y); + } + else if (i == 1) + { + new_room_box = new IntBox(room_box.ur.x, bounding_box.ll.y, bounding_box.ur.x, bounding_box.ur.y); + } + else if (i == 2) + { + new_room_box = new IntBox(bounding_box.ll.x, room_box.ur.y, bounding_box.ur.x, bounding_box.ur.y); + } + else if (i == 3) + { + new_room_box = new IntBox(bounding_box.ll.x, bounding_box.ll.y, room_box.ll.x, bounding_box.ur.y); + } + else + { + System.out.println("SortedOrthoganelRoomNeighbours.calculate_incomplete_rooms_with_empty_neighbours: illegal index i"); + return; + } + IntBox new_contained_box = room_box.intersection(new_room_box); + FreeSpaceExpansionRoom new_room = p_autoroute_engine.add_incomplete_expansion_room(new_room_box, p_room.get_layer(), new_contained_box); + ExpansionDoor new_door = new ExpansionDoor(p_room, new_room, 1); + p_room.add_door(new_door); + new_room.add_door(new_door); + } + } + + /** + * Calculates all touching neighbours of p_room and sorts them in + * counterclock sense around the boundary of the room shape. + */ + private static SortedOrthogonalRoomNeighbours calculate_neighbours(ExpansionRoom p_room, int p_net_no, + ShapeSearchTree p_autoroute_search_tree, int p_room_id_no) + { + TileShape room_shape = p_room.get_shape(); + if (!(room_shape instanceof IntBox)) + { + System.out.println("SortedOrthogonalRoomNeighbours.calculate: IntBox expected for room_shape"); + return null; + } + IntBox room_box = (IntBox) room_shape; + CompleteExpansionRoom completed_room; + if (p_room instanceof IncompleteFreeSpaceExpansionRoom) + { + completed_room = new CompleteFreeSpaceExpansionRoom(room_shape, p_room.get_layer(), p_room_id_no); + } + else if (p_room instanceof ObstacleExpansionRoom) + { + completed_room = (ObstacleExpansionRoom)p_room; + } + else + { + System.out.println("SortedOrthogonalRoomNeighbours.calculate: unexpected expansion room type"); + return null; + } + SortedOrthogonalRoomNeighbours result = new SortedOrthogonalRoomNeighbours(p_room, completed_room); + Collection overlapping_objects = new LinkedList(); + p_autoroute_search_tree.overlapping_tree_entries(room_shape, p_room.get_layer(), overlapping_objects); + // Calculate the touching neigbour objects and sort them in counterclock sence + // around the border of the room shape. + for (ShapeTree.TreeEntry curr_entry : overlapping_objects) + { + SearchTreeObject curr_object = (SearchTreeObject) curr_entry.object; + if (curr_object == p_room) + { + continue; + } + if ((completed_room instanceof CompleteFreeSpaceExpansionRoom) && !curr_object.is_trace_obstacle(p_net_no)) + { + ((CompleteFreeSpaceExpansionRoom) completed_room).calculate_target_doors(curr_entry, + p_net_no, p_autoroute_search_tree); + continue; + } + TileShape curr_shape = + curr_object.get_tree_shape(p_autoroute_search_tree, curr_entry.shape_index_in_object); + if (!(curr_shape instanceof IntBox)) + { + System.out.println("OrthogonalAutorouteEngine:calculate_sorted_neighbours: IntBox expected for curr_shape"); + return null; + } + IntBox curr_box = (IntBox) curr_shape; + IntBox intersection = room_box.intersection(curr_box); + int dimension = intersection.dimension(); + if (dimension > 1 && completed_room instanceof ObstacleExpansionRoom) + { + if (curr_object instanceof Item) + { + // only Obstacle expansion roos may have a 2-dim overlap + Item curr_item = (Item) curr_object; + if (curr_item.is_route()) + { + ItemAutorouteInfo item_info = curr_item.get_autoroute_info(); + ObstacleExpansionRoom curr_overlap_room = + item_info.get_expansion_room(curr_entry.shape_index_in_object, p_autoroute_search_tree); + ((ObstacleExpansionRoom) completed_room).create_overlap_door(curr_overlap_room); + } + + } + continue; + } + if (dimension < 0) + { + + System.out.println("AutorouteEngine.calculate_doors: dimension >= 0 expected"); + continue; + } + result.add_sorted_neighbour(curr_box, intersection); + if (dimension > 0) + { + // make shure, that there is a door to the neighbour room. + ExpansionRoom neighbour_room = null; + if (curr_object instanceof ExpansionRoom) + { + neighbour_room = (ExpansionRoom) curr_object; + } + else if (curr_object instanceof Item) + { + Item curr_item = (Item) curr_object; + if (curr_item.is_route()) + { + // expand the item for ripup and pushing purposes + ItemAutorouteInfo item_info = curr_item.get_autoroute_info(); + neighbour_room = + item_info.get_expansion_room(curr_entry.shape_index_in_object, p_autoroute_search_tree); + } + } + if (neighbour_room != null) + { + if (SortedRoomNeighbours.insert_door_ok(completed_room, neighbour_room, intersection)) + { + ExpansionDoor new_door = new ExpansionDoor(completed_room, neighbour_room); + neighbour_room.add_door(new_door); + completed_room.add_door(new_door); + } + } + } + } + return result; + } + + private void calculate_new_incomplete_rooms(AutorouteEngine p_autoroute_engine) + { + IntBox board_bounds = p_autoroute_engine.board.bounding_box; + SortedRoomNeighbour prev_neighbour = this.sorted_neighbours.last(); + Iterator it = this.sorted_neighbours.iterator(); + + while (it.hasNext()) + { + SortedRoomNeighbour next_neighbour = it.next(); + + if (!next_neighbour.intersection.intersects(prev_neighbour.intersection)) + { + // create a door to a new incomplete expansion room between + // the last corner of the previous neighbour and the first corner of the + // current neighbour. + if (next_neighbour.first_touching_side == 0) + { + if (prev_neighbour.last_touching_side == 0) + { + if (prev_neighbour.intersection.ur.x < next_neighbour.intersection.ll.x) + { + insert_incomplete_room(p_autoroute_engine, prev_neighbour.intersection.ur.x, board_bounds.ll.y, + next_neighbour.intersection.ll.x, this.room_shape.ll.y); + } + } + else + { + if (prev_neighbour.intersection.ll.y > this.room_shape.ll.y + || next_neighbour.intersection.ll.x > this.room_shape.ll.x) + { + if (is_obstacle_expansion_room) + { + // no 2-dim doors between obstacle_expansion_rooms and free space rooms allowed. + if (prev_neighbour.last_touching_side == 3) + { + insert_incomplete_room(p_autoroute_engine, board_bounds.ll.x, room_shape.ll.y, + room_shape.ll.x, prev_neighbour.intersection.ll.y); + } + insert_incomplete_room(p_autoroute_engine, room_shape.ll.x, board_bounds.ll.y, + next_neighbour.intersection.ll.x, room_shape.ll.y); + } + else + { + insert_incomplete_room(p_autoroute_engine, board_bounds.ll.x, board_bounds.ll.y, + next_neighbour.intersection.ll.x, prev_neighbour.intersection.ll.y); + } + } + } + } + else if (next_neighbour.first_touching_side == 1) + { + if (prev_neighbour.last_touching_side == 1) + { + if (prev_neighbour.intersection.ur.y < next_neighbour.intersection.ll.y) + { + insert_incomplete_room(p_autoroute_engine, this.room_shape.ur.x, prev_neighbour.intersection.ur.y, + board_bounds.ur.x, next_neighbour.intersection.ll.y ); + } + } + else + { + if (prev_neighbour.intersection.ur.x < this.room_shape.ur.x + || next_neighbour.intersection.ll.y > this.room_shape.ll.y) + { + if (is_obstacle_expansion_room) + { + // no 2-dim doors between obstacle_expansion_rooms and free space rooms allowed. + if (prev_neighbour.last_touching_side == 0) + { + insert_incomplete_room(p_autoroute_engine, prev_neighbour.intersection.ur.x, board_bounds.ll.y, + room_shape.ur.x, room_shape.ll.y); + } + insert_incomplete_room(p_autoroute_engine, room_shape.ur.x, room_shape.ll.y, + room_shape.ur.x, next_neighbour.intersection.ll.y ); + } + else + { + insert_incomplete_room(p_autoroute_engine, prev_neighbour.intersection.ur.x, board_bounds.ll.y, + board_bounds.ur.x, next_neighbour.intersection.ll.y); + } + } + } + } + else if (next_neighbour.first_touching_side == 2) + { + if (prev_neighbour.last_touching_side == 2) + { + if (prev_neighbour.intersection.ll.x > next_neighbour.intersection.ur.x) + { + insert_incomplete_room(p_autoroute_engine, next_neighbour.intersection.ur.x, this.room_shape.ur.y, + prev_neighbour.intersection.ll.x, board_bounds.ur.y); + } + } + else + { + if (prev_neighbour.intersection.ur.y < this.room_shape.ur.y + || next_neighbour.intersection.ur.x < this.room_shape.ur.x) + { + if (is_obstacle_expansion_room) + { + // no 2-dim doors between obstacle_expansion_rooms and free space rooms allowed. + if (prev_neighbour.last_touching_side == 1) + { + insert_incomplete_room(p_autoroute_engine, room_shape.ur.x, prev_neighbour.intersection.ur.y, + board_bounds.ur.x, room_shape.ur.y); + } + insert_incomplete_room(p_autoroute_engine, next_neighbour.intersection.ur.x, room_shape.ur.y, + room_shape.ur.x, board_bounds.ur.y ); + } + else + { + insert_incomplete_room(p_autoroute_engine, next_neighbour.intersection.ur.x, prev_neighbour.intersection.ur.y, + board_bounds.ur.x, board_bounds.ur.y); + } + } + } + } + else if (next_neighbour.first_touching_side == 3) + { + if (prev_neighbour.last_touching_side == 3) + { + if (prev_neighbour.intersection.ll.y > next_neighbour.intersection.ur.y) + { + insert_incomplete_room(p_autoroute_engine, board_bounds.ll.x, next_neighbour.intersection.ur.y, + this.room_shape.ll.x, prev_neighbour.intersection.ll.y); + } + } + else + { + if (next_neighbour.intersection.ur.y < this.room_shape.ur.y + || prev_neighbour.intersection.ll.x > this.room_shape.ll.x) + { + if (is_obstacle_expansion_room) + { + // no 2-dim doors between obstacle_expansion_rooms and free space rooms allowed. + if (prev_neighbour.last_touching_side == 2) + { + insert_incomplete_room(p_autoroute_engine, room_shape.ll.x, room_shape.ur.y, + prev_neighbour.intersection.ll.x, board_bounds.ur.y); + } + insert_incomplete_room(p_autoroute_engine, board_bounds.ll.x, next_neighbour.intersection.ur.y, + room_shape.ll.x, room_shape.ur.y); + } + else + { + insert_incomplete_room(p_autoroute_engine, board_bounds.ll.x, next_neighbour.intersection.ur.y, + prev_neighbour.intersection.ll.x, board_bounds.ur.y); + } + } + } + } + else + { + System.out.println("SortedOrthogonalRoomNeighbour.calculate_new_incomplete: illegal touching side"); + } + } + prev_neighbour = next_neighbour; + } + } + + private void insert_incomplete_room(AutorouteEngine p_autoroute_engine, int p_ll_x, int p_ll_y, int p_ur_x, int p_ur_y) + { + IntBox new_incomplete_room_shape = new IntBox(p_ll_x, p_ll_y, p_ur_x, p_ur_y); + if (new_incomplete_room_shape.dimension() == 2) + { + IntBox new_contained_shape = this.room_shape.intersection(new_incomplete_room_shape); + if (!new_contained_shape.is_empty()) + { + int door_dimension = new_incomplete_room_shape.intersection(this.room_shape).dimension(); + if (door_dimension > 0) + { + FreeSpaceExpansionRoom new_room = + p_autoroute_engine.add_incomplete_expansion_room(new_incomplete_room_shape, this.from_room.get_layer(), new_contained_shape); + ExpansionDoor new_door = new ExpansionDoor(this.completed_room, new_room, door_dimension); + this.completed_room.add_door(new_door); + new_room.add_door(new_door); + } + } + } + } + + /** Creates a new instance of SortedOrthogonalRoomNeighbours */ + private SortedOrthogonalRoomNeighbours(ExpansionRoom p_from_room, CompleteExpansionRoom p_completed_room) + { + from_room = p_from_room; + completed_room = p_completed_room; + is_obstacle_expansion_room = p_from_room instanceof ObstacleExpansionRoom; + room_shape = (IntBox) p_completed_room.get_shape(); + sorted_neighbours = new TreeSet(); + edge_interiour_touches_obstacle = new boolean[4]; + for (int i = 0; i < 4; ++i) + { + edge_interiour_touches_obstacle[i] = false; + } + } + + /** + * Check, that each side of the romm shape has at least one touching neighbour. + * Otherwise the room shape will be improved the by enlarging. + * Returns true, if the room shape was changed. + */ + private boolean try_remove_edge(int p_net_no, ShapeSearchTree p_autoroute_search_tree) + { + if (!(this.from_room instanceof IncompleteFreeSpaceExpansionRoom)) + { + return false; + } + IncompleteFreeSpaceExpansionRoom curr_incomplete_room = (IncompleteFreeSpaceExpansionRoom) this.from_room; + if (!(curr_incomplete_room.get_shape() instanceof IntBox)) + { + System.out.println("SortedOrthogonalRoomNeighbours.try_remove_edge: IntBox expected for room_shape type"); + return false; + } + IntBox room_box = (IntBox) curr_incomplete_room.get_shape(); + double room_area = room_box.area(); + + int remove_edge_no = -1; + for (int i = 0; i < 4; ++i) + { + if (!this.edge_interiour_touches_obstacle[i]) + { + remove_edge_no = i; + break; + } + } + + if (remove_edge_no >= 0) + { + // Touching neighbour missing at the edge side with index remove_edge_no + // Remove the edge line and restart the algorithm. + IntBox enlarged_box = remove_border_line( room_box, remove_edge_no); + Collection door_list = this.completed_room.get_doors(); + TileShape ignore_shape = null; + SearchTreeObject ignore_object = null; + double max_door_area = 0; + for (ExpansionDoor curr_door: door_list) + { + // insert the overlapping doors with CompleteFreeSpaceExpansionRooms + // for the information in complete_shape about the objects to ignore. + if (curr_door.dimension == 2) + { + CompleteExpansionRoom other_room = curr_door.other_room(this.completed_room); + { + if (other_room instanceof CompleteFreeSpaceExpansionRoom) + { + TileShape curr_door_shape = curr_door.get_shape(); + double curr_door_area = curr_door_shape.area(); + if (curr_door_area > max_door_area) + { + max_door_area = curr_door_area; + ignore_shape = curr_door_shape; + ignore_object = (CompleteFreeSpaceExpansionRoom) other_room; + } + } + } + } + } + IncompleteFreeSpaceExpansionRoom enlarged_room = + new IncompleteFreeSpaceExpansionRoom(enlarged_box, curr_incomplete_room.get_layer(), + curr_incomplete_room.get_contained_shape()); + Collection new_rooms = + p_autoroute_search_tree.complete_shape(enlarged_room, p_net_no, ignore_object, ignore_shape); + if (new_rooms.size() == 1) + { + // Check, that the area increases to prevent endless loop. + IncompleteFreeSpaceExpansionRoom new_room = new_rooms.iterator().next(); + if (new_room.get_shape().area() > room_area) + { + curr_incomplete_room.set_shape(new_room.get_shape()); + curr_incomplete_room.set_contained_shape(new_room.get_contained_shape()); + return true; + } + } + } + return false; + } + + private static IntBox remove_border_line( IntBox p_room_box, int p_remove_edge_no) + { + IntBox result; + if (p_remove_edge_no == 0) + { + result = new IntBox(p_room_box.ll.x, -Limits.CRIT_INT, p_room_box.ur.x, p_room_box.ur.y); + } + else if (p_remove_edge_no == 1) + { + result = new IntBox(p_room_box.ll.x, p_room_box.ll.y, Limits.CRIT_INT, p_room_box.ur.y); + } + else if (p_remove_edge_no == 2) + { + result = new IntBox(p_room_box.ll.x, p_room_box.ll.y, p_room_box.ur.x, Limits.CRIT_INT); + } + else if (p_remove_edge_no == 3) + { + result = new IntBox(-Limits.CRIT_INT, p_room_box.ll.y, p_room_box.ur.x, p_room_box.ur.y); + } + else + { + System.out.println("SortedOrthogonalRoomNeighbours.remove_border_line: illegal p_remove_edge_no"); + result = null; + } + return result; + } + + private void add_sorted_neighbour(IntBox p_neighbour_shape, IntBox p_intersection) + { + SortedRoomNeighbour new_neighbour = new SortedRoomNeighbour(p_neighbour_shape, p_intersection); + sorted_neighbours.add(new_neighbour); + } + + public final CompleteExpansionRoom completed_room; + public final SortedSet sorted_neighbours; + private final ExpansionRoom from_room; + private final boolean is_obstacle_expansion_room; + private final IntBox room_shape; + + private final boolean[] edge_interiour_touches_obstacle; + + /** + * Helper class to sort the doors of an expansion room counterclockwise + * arount the border of the room shape. + */ + + private class SortedRoomNeighbour implements Comparable + { + public SortedRoomNeighbour(IntBox p_neighbour_shape, IntBox p_intersection) + { + shape = p_neighbour_shape; + intersection = p_intersection; + + if( p_intersection.ll.y == room_shape.ll.y + && p_intersection.ur.x > room_shape.ll.x && p_intersection.ll.x < room_shape.ur.x) + { + edge_interiour_touches_obstacle[0] = true; + } + if( p_intersection.ur.x == room_shape.ur.x + && p_intersection.ur.y > room_shape.ll.y && p_intersection.ll.y < room_shape.ur.y) + { + edge_interiour_touches_obstacle[1] = true; + } + if( p_intersection.ur.y == room_shape.ur.y + && p_intersection.ur.x > room_shape.ll.x && p_intersection.ll.x < room_shape.ur.x) + { + edge_interiour_touches_obstacle[2] = true; + } + if( p_intersection.ll.x == room_shape.ll.x + && p_intersection.ur.y > room_shape.ll.y && p_intersection.ll.y < room_shape.ur.y) + { + edge_interiour_touches_obstacle[3] = true; + } + + if (p_intersection.ll.y == room_shape.ll.y && p_intersection.ll.x > room_shape.ll.x) + { + this.first_touching_side = 0; + } + else if (p_intersection.ur.x == room_shape.ur.x && p_intersection.ll.y > room_shape.ll.y) + { + this.first_touching_side = 1; + } + else if (p_intersection.ur.y == room_shape.ur.y ) + { + this.first_touching_side = 2; + } + else if (p_intersection.ll.x == room_shape.ll.x) + { + this.first_touching_side = 3; + } + else + { + System.out.println("SortedRoomNeighbour: case not expected"); + this.first_touching_side = -1; + } + + if (p_intersection.ll.x == room_shape.ll.x && p_intersection.ll.y > room_shape.ll.y) + { + this.last_touching_side = 3; + } + else if (p_intersection.ur.y == room_shape.ur.y && p_intersection.ll.x > room_shape.ll.x) + { + this.last_touching_side = 2; + } + else if (p_intersection.ur.x == room_shape.ur.x) + { + this.last_touching_side = 1; + } + else if (p_intersection.ll.y == room_shape.ll.y) + { + this.last_touching_side = 0; + } + else + { + System.out.println("SortedRoomNeighbour: case not expected"); + this.last_touching_side = -1; + } + } + + /** + * Compare function for or sorting the neighbours in counterclock sense + * around the border of the room shape in ascending order. + */ + public int compareTo(SortedRoomNeighbour p_other) + { + if (this.first_touching_side > p_other.first_touching_side) + { + return 1; + } + if (this.first_touching_side < p_other.first_touching_side) + { + return -1; + } + + // now the first touch of this and p_other is at the same side + IntBox is1 = this.intersection; + IntBox is2 = p_other.intersection; + int cmp_value; + + if (first_touching_side == 0) + { + cmp_value = is1.ll.x - is2.ll.x; + } + else if (first_touching_side == 1) + { + cmp_value = is1.ll.y - is2.ll.y; + } + else if (first_touching_side == 2) + { + cmp_value = is2.ur.x - is1.ur.x; + } + else if (first_touching_side == 3) + { + cmp_value = is2.ur.y - is1.ur.y; + } + else + { + System.out.println("SortedRoomNeighbour.compareTo: first_touching_side out of range "); + return 0; + } + if (cmp_value == 0) + { + // The first touching points of this neighbour and p_other with the room shape are equal. + // Compare the last touching points. + int this_touching_side_diff = (this.last_touching_side - this.first_touching_side + 4) % 4; + int other_touching_side_diff = (p_other.last_touching_side - p_other.first_touching_side + 4) % 4; + if (this_touching_side_diff > other_touching_side_diff) + { + return 1; + } + if (this_touching_side_diff < other_touching_side_diff) + { + return -1; + } + + // now the last touch of this and p_other is at the same side + if (last_touching_side == 0) + { + cmp_value = is1.ur.x - is2.ur.x; + } + else if (last_touching_side == 1) + { + cmp_value = is1.ur.y - is2.ur.y; + } + else if (last_touching_side == 2) + { + cmp_value = is2.ll.x - is1.ll.x; + } + else if (last_touching_side == 3) + { + cmp_value = is2.ll.y - is1.ll.y; + } + else + { + System.out.println("SortedRoomNeighbour.compareTo: first_touching_side out of range "); + return 0; + } + } + return cmp_value; + } + + /** The shape of the neighbour room */ + public final IntBox shape; + + /** The intersection of tnis ExpansionRoom shape with the neighbour_shape */ + public final IntBox intersection; + + /** The first side of the room shape, where the neighbour_shape touches */ + public final int first_touching_side; + + /** The last side of the room shape, where the neighbour_shape touches */ + public final int last_touching_side; + } +} diff --git a/autoroute/SortedRoomNeighbours.java b/src/main/java/autoroute/SortedRoomNeighbours.java similarity index 97% rename from autoroute/SortedRoomNeighbours.java rename to src/main/java/autoroute/SortedRoomNeighbours.java index 15f29c2..6fef152 100644 --- a/autoroute/SortedRoomNeighbours.java +++ b/src/main/java/autoroute/SortedRoomNeighbours.java @@ -1,848 +1,855 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * SortedRoomNeighbours.java - * - * Created on 28. Mai 2007, 07:27 - * - */ - -package autoroute; - -import java.util.Collection; -import java.util.LinkedList; -import java.util.TreeSet; -import java.util.SortedSet; -import java.util.Iterator; - -import datastructures.Signum; -import datastructures.ShapeTree; - -import geometry.planar.Side; -import geometry.planar.Direction; -import geometry.planar.Point; -import geometry.planar.IntPoint; -import geometry.planar.FloatPoint; -import geometry.planar.Line; -import geometry.planar.TileShape; -import geometry.planar.Simplex; - -import board.ShapeSearchTree; -import board.SearchTreeObject; -import board.Connectable; -import board.Item; -import board.PolylineTrace; -import board.TestLevel; - -/** - * To calculate the neigbour rooms of an expansion room. - * The neighbour rooms will be sorted in counterclock sense around the border of the shape of p_room. - * Overlapping neighbours containing an item may be stored in an unordered list. - * - * @author Alfons Wirtz - */ -public class SortedRoomNeighbours -{ - /** - * To calculate the neigbour rooms of an expansion room. - * The neighbour rooms will be sorted in counterclock sense around the border of the shape of p_room. - * Overlapping neighbours containing an item may be stored in an unordered list. - */ - public static CompleteExpansionRoom calculate(ExpansionRoom p_room, AutorouteEngine p_autoroute_engine) - { - int net_no = p_autoroute_engine.get_net_no(); - TestLevel test_level = p_autoroute_engine.board.get_test_level(); - SortedRoomNeighbours room_neighbours = calculate_neighbours(p_room, net_no, p_autoroute_engine.autoroute_search_tree, - p_autoroute_engine.generate_room_id_no(), test_level); - - // Check, that each side of the romm shape has at least one touching neighbour. - // Otherwise improve the room shape by enlarging. - - boolean edge_removed = room_neighbours.try_remove_edge(net_no, - p_autoroute_engine.autoroute_search_tree, test_level); - CompleteExpansionRoom result = room_neighbours.completed_room; - if (edge_removed) - { - p_autoroute_engine.remove_all_doors(result); - return calculate(p_room, p_autoroute_engine); - } - - // Now calculate the new incomplete rooms together with the doors - // between this room and the sorted neighbours. - if (room_neighbours.sorted_neighbours.isEmpty()) - { - if (result instanceof ObstacleExpansionRoom) - { - calculate_incomplete_rooms_with_empty_neighbours((ObstacleExpansionRoom) p_room, p_autoroute_engine); - } - } - else - { - room_neighbours.calculate_new_incomplete_rooms(p_autoroute_engine); - if (test_level.ordinal() >= TestLevel.ALL_DEBUGGING_OUTPUT.ordinal() && result.get_shape().dimension() < 2) - { - System.out.println("AutorouteEngine.calculate_new_incomplete_rooms_with_mmore_than_1_neighbour: unexpected dimension for smoothened_shape"); - } - } - - if (result instanceof CompleteFreeSpaceExpansionRoom) - { - calculate_target_doors((CompleteFreeSpaceExpansionRoom) result, - room_neighbours.own_net_objects, p_autoroute_engine); - } - return result; - } - - private static void calculate_incomplete_rooms_with_empty_neighbours(ObstacleExpansionRoom p_room, AutorouteEngine p_autoroute_engine) - { - TileShape room_shape = p_room.get_shape(); - for (int i = 0; i < room_shape.border_line_count(); ++i) - { - Line curr_line = room_shape.border_line(i); - if (SortedRoomNeighbours.insert_door_ok(p_room, curr_line)) - { - Line[] shape_line = new Line[1]; - shape_line[0] = curr_line.opposite(); - TileShape new_room_shape = new Simplex(shape_line); - TileShape new_contained_shape = room_shape.intersection(new_room_shape); - FreeSpaceExpansionRoom new_room = p_autoroute_engine.add_incomplete_expansion_room(new_room_shape, p_room.get_layer(), new_contained_shape); - ExpansionDoor new_door = new ExpansionDoor(p_room, new_room, 1); - p_room.add_door(new_door); - new_room.add_door(new_door); - } - } - } - - - private static void calculate_target_doors(CompleteFreeSpaceExpansionRoom p_room, - Collection p_own_net_objects, AutorouteEngine p_autoroute_engine) - { - if (!p_own_net_objects.isEmpty()) - { - p_room.set_net_dependent(); - } - for (ShapeTree.TreeEntry curr_entry : p_own_net_objects) - { - if (curr_entry.object instanceof Connectable) - { - Connectable curr_object = (Connectable) curr_entry.object; - if (curr_object.contains_net(p_autoroute_engine.get_net_no())) - { - TileShape curr_connection_shape = - curr_object.get_trace_connection_shape(p_autoroute_engine.autoroute_search_tree, curr_entry.shape_index_in_object); - if (curr_connection_shape != null && p_room.get_shape().intersects(curr_connection_shape)) - { - Item curr_item = (Item) curr_object; - TargetItemExpansionDoor new_target_door = - new TargetItemExpansionDoor(curr_item, curr_entry.shape_index_in_object, p_room, - p_autoroute_engine.autoroute_search_tree); - p_room.add_target_door(new_target_door); - } - } - } - } - } - - private static SortedRoomNeighbours calculate_neighbours(ExpansionRoom p_room, int p_net_no, - ShapeSearchTree p_autoroute_search_tree, int p_room_id_no, TestLevel p_test_level) - { - TileShape room_shape = p_room.get_shape(); - CompleteExpansionRoom completed_room; - if (p_room instanceof IncompleteFreeSpaceExpansionRoom) - { - completed_room = new CompleteFreeSpaceExpansionRoom(room_shape, p_room.get_layer(), p_room_id_no); - } - else if (p_room instanceof ObstacleExpansionRoom) - { - completed_room = (ObstacleExpansionRoom)p_room; - } - else - { - System.out.println("SortedRoomNeighbours.calculate: unexpected expansion room type"); - return null; - } - SortedRoomNeighbours result = new SortedRoomNeighbours(p_room, completed_room); - Collection overlapping_objects = new LinkedList(); - p_autoroute_search_tree.overlapping_tree_entries(room_shape, p_room.get_layer(), overlapping_objects); - // Calculate the touching neigbour objects and sort them in counterclock sence - // around the border of the room shape. - for (ShapeTree.TreeEntry curr_entry : overlapping_objects) - { - SearchTreeObject curr_object = (SearchTreeObject) curr_entry.object; - if (curr_object == p_room) - { - continue; - } - if ((p_room instanceof IncompleteFreeSpaceExpansionRoom) && !curr_object.is_trace_obstacle(p_net_no)) - { - // delay processing the target doors until the room shape will not change any more - result.own_net_objects.add(curr_entry); - continue; - } - TileShape curr_shape = - curr_object.get_tree_shape(p_autoroute_search_tree, curr_entry.shape_index_in_object); - TileShape intersection = room_shape.intersection(curr_shape); - int dimension = intersection.dimension(); - if (dimension > 1) - { - if (completed_room instanceof ObstacleExpansionRoom && curr_object instanceof Item) - { - // only Obstacle expansion roos may have a 2-dim overlap - Item curr_item = (Item) curr_object; - if (curr_item.is_route()) - { - ItemAutorouteInfo item_info = curr_item.get_autoroute_info(); - ObstacleExpansionRoom curr_overlap_room = - item_info.get_expansion_room(curr_entry.shape_index_in_object, p_autoroute_search_tree); - ((ObstacleExpansionRoom) completed_room).create_overlap_door(curr_overlap_room); - } - } - else if (p_test_level.ordinal() >= TestLevel.ALL_DEBUGGING_OUTPUT.ordinal()) - { - System.out.println("SortedRoomNeighbours.calculate: unexpected area overlap of free space expansion room"); - } - continue; - } - if (dimension < 0) - { - if (p_test_level.ordinal() >= TestLevel.CRITICAL_DEBUGGING_OUTPUT.ordinal()) - { - System.out.println("SortedRoomNeighbours.calculate: dimension >= 0 expected"); - } - continue; - } - if (dimension == 1) - { - int[] touching_sides = room_shape.touching_sides(curr_shape); - if (touching_sides.length != 2) - { - if (p_test_level.ordinal() >= TestLevel.CRITICAL_DEBUGGING_OUTPUT.ordinal()) - { - System.out.println("SortedRoomNeighbours.calculate: touching_sides length 2 expected"); - } - continue; - } - result.add_sorted_neighbour(curr_shape, intersection, touching_sides[0], - touching_sides[1], false, false); - // make shure, that there is a door to the neighbour room. - ExpansionRoom neighbour_room = null; - if (curr_object instanceof ExpansionRoom) - { - neighbour_room = (ExpansionRoom) curr_object; - } - else if (curr_object instanceof Item) - { - Item curr_item = (Item) curr_object; - if (curr_item.is_route()) - { - // expand the item for ripup and pushing purposes - ItemAutorouteInfo item_info = curr_item.get_autoroute_info(); - neighbour_room = - item_info.get_expansion_room(curr_entry.shape_index_in_object, p_autoroute_search_tree); - } - } - if (neighbour_room != null) - { - if (SortedRoomNeighbours.insert_door_ok(completed_room, neighbour_room, intersection)) - { - ExpansionDoor new_door = new ExpansionDoor(completed_room, neighbour_room, 1); - neighbour_room.add_door(new_door); - completed_room.add_door(new_door); - } - } - } - else // dimensin = 0 - { - Point touching_point = intersection.corner(0); - int room_corner_no = room_shape.equals_corner(touching_point); - boolean room_touch_is_corner; - int touching_side_no_of_room; - if (room_corner_no >= 0) - { - room_touch_is_corner = true; - touching_side_no_of_room = room_corner_no; - } - else - { - room_touch_is_corner = false; - touching_side_no_of_room = room_shape.contains_on_border_line_no(touching_point); - if (touching_side_no_of_room < 0 && p_test_level.ordinal() >= TestLevel.CRITICAL_DEBUGGING_OUTPUT.ordinal()) - { - System.out.println("SortedRoomNeighbours.calculate: touching_side_no_of_room >= 0 expected"); - } - } - int neighbour_room_corner_no = curr_shape.equals_corner(touching_point); - boolean neighbour_room_touch_is_corner; - int touching_side_no_of_neighbour_room; - if (neighbour_room_corner_no >= 0) - { - neighbour_room_touch_is_corner = true; - // The previous border line is preferred to make the shape of the incomplete room as big as possible - touching_side_no_of_neighbour_room = curr_shape.prev_no(neighbour_room_corner_no); - } - else - { - neighbour_room_touch_is_corner = false; - touching_side_no_of_neighbour_room = curr_shape.contains_on_border_line_no(touching_point); - if (touching_side_no_of_neighbour_room < 0 && p_test_level.ordinal() >= TestLevel.CRITICAL_DEBUGGING_OUTPUT.ordinal()) - { - System.out.println("AutorouteEngine.SortedRoomNeighbours.calculate: touching_side_no_of_neighbour_room >= 0 expected"); - } - } - result.add_sorted_neighbour(curr_shape, intersection, - touching_side_no_of_room , touching_side_no_of_neighbour_room, - room_touch_is_corner , neighbour_room_touch_is_corner); - } - } - return result; - } - - - - /** Creates a new instance of SortedRoomNeighbours */ - private SortedRoomNeighbours(ExpansionRoom p_from_room, CompleteExpansionRoom p_completed_room) - { - from_room = p_from_room; - completed_room = p_completed_room; - room_shape = p_completed_room.get_shape(); - sorted_neighbours = new TreeSet(); - own_net_objects = new LinkedList(); - } - - private void add_sorted_neighbour(TileShape p_neighbour_shape, TileShape p_intersection, - int p_touching_side_no_of_room, int p_touching_side_no_of_neighbour_room, - boolean p_room_touch_is_corner, boolean p_neighbour_room_touch_is_corner) - { - SortedRoomNeighbour new_neighbour = new SortedRoomNeighbour(p_neighbour_shape, p_intersection, - p_touching_side_no_of_room, p_touching_side_no_of_neighbour_room, - p_room_touch_is_corner, p_neighbour_room_touch_is_corner); - sorted_neighbours.add(new_neighbour); - } - - /** - * Check, that each side of the romm shape has at least one touching neighbour. - * Otherwise the room shape will be improved the by enlarging. - * Returns true, if the room shape was changed. - */ - private boolean try_remove_edge(int p_net_no, ShapeSearchTree p_autoroute_search_tree, TestLevel p_test_level) - { - if (!(this.from_room instanceof IncompleteFreeSpaceExpansionRoom)) - { - return false; - } - IncompleteFreeSpaceExpansionRoom curr_incomplete_room = (IncompleteFreeSpaceExpansionRoom) this.from_room; - Iterator it = sorted_neighbours.iterator(); - int remove_edge_no = -1; - Simplex room_simplex = curr_incomplete_room.get_shape().to_Simplex(); - double room_shape_area = room_simplex.area(); - - int prev_edge_no = -1; - int curr_edge_no = 0; - while (it.hasNext()) - { - SortedRoomNeighbour next_neighbour = it.next(); - if (next_neighbour.touching_side_no_of_room == prev_edge_no) - { - continue; - } - if (next_neighbour.touching_side_no_of_room == curr_edge_no) - { - prev_edge_no = curr_edge_no; - ++curr_edge_no; - } - else - { - // On the edge side with index curr_edge_no is no touching - // neighbour. - remove_edge_no = curr_edge_no; - break; - } - } - - if (remove_edge_no < 0 && curr_edge_no < room_simplex.border_line_count()) - { - // missing touching neighbour at the last edge side. - remove_edge_no = curr_edge_no; - } - - - - if (remove_edge_no >= 0) - { - // Touching neighbour missing at the edge side with index remove_edge_no - // Remove the edge line and restart the algorithm. - Simplex enlarged_shape = room_simplex.remove_border_line(remove_edge_no); - IncompleteFreeSpaceExpansionRoom enlarged_room = - new IncompleteFreeSpaceExpansionRoom(enlarged_shape, curr_incomplete_room.get_layer(), - curr_incomplete_room.get_contained_shape()); - Collection new_rooms = - p_autoroute_search_tree.complete_shape(enlarged_room, p_net_no, null, null); - if (new_rooms.size() != 1) - { - if (p_test_level.ordinal() >= TestLevel.ALL_DEBUGGING_OUTPUT.ordinal()) - { - System.out.println("AutorouteEngine.calculate_doors: 1 completed shape expected"); - } - return false; - } - boolean remove_edge = false; - if (new_rooms.size() == 1) - { - // Check, that the area increases to prevent endless loop. - IncompleteFreeSpaceExpansionRoom new_shape = new_rooms.iterator().next(); - if (new_shape.get_shape().area() > room_shape_area) - { - remove_edge = true; - } - } - if (remove_edge) - { - Iterator it2 = new_rooms.iterator(); - IncompleteFreeSpaceExpansionRoom new_room = it2.next(); - curr_incomplete_room.set_shape(new_room.get_shape()); - curr_incomplete_room.set_contained_shape(new_room.get_contained_shape()); - return true; - } - } - return false; - } - - /** - * Called from calculate_doors(). - * The shape of the room p_result may change inside this function. - */ - public void calculate_new_incomplete_rooms(AutorouteEngine p_autoroute_engine) - { - SortedRoomNeighbour prev_neighbour = this.sorted_neighbours.last(); - Iterator it = this.sorted_neighbours.iterator(); - Simplex room_simplex = this.from_room.get_shape().to_Simplex(); - while (it.hasNext()) - { - SortedRoomNeighbour next_neighbour = it.next(); - int first_touching_side_no = prev_neighbour.touching_side_no_of_room; - int last_touching_side_no = next_neighbour.touching_side_no_of_room; - - int curr_next_no = room_simplex.next_no(first_touching_side_no); - boolean intersection_with_prev_neighbour_ends_at_corner = - (first_touching_side_no != last_touching_side_no || prev_neighbour == this.sorted_neighbours.last()) - && prev_neighbour.last_corner().equals(room_simplex.corner(curr_next_no)); - boolean intersection_with_next_neighbour_starts_at_corner = - (first_touching_side_no != last_touching_side_no || prev_neighbour == this.sorted_neighbours.last()) - && next_neighbour.first_corner().equals(room_simplex.corner(last_touching_side_no)); - - if (intersection_with_prev_neighbour_ends_at_corner) - { - first_touching_side_no = curr_next_no; - } - - if(intersection_with_next_neighbour_starts_at_corner) - { - last_touching_side_no = room_simplex.prev_no(last_touching_side_no); - } - boolean neighbours_touch = false; - - if (this.sorted_neighbours.size() > 1) - { - neighbours_touch = prev_neighbour.last_corner().equals(next_neighbour.first_corner()); - } - - if (!neighbours_touch) - { - // create a door to a new incomplete expansion room between - // the last corner of the previous neighbour and the first corner of the - // current neighbour. - int last_bounding_line_no = prev_neighbour.touching_side_no_of_neighbour_room; - if (!(intersection_with_prev_neighbour_ends_at_corner - || prev_neighbour.room_touch_is_corner)) - { - last_bounding_line_no = prev_neighbour.neighbour_shape.prev_no(last_bounding_line_no); - } - - - int first_bounding_line_no = next_neighbour.touching_side_no_of_neighbour_room; - if (!(intersection_with_next_neighbour_starts_at_corner - || next_neighbour.neighbour_room_touch_is_corner)) - { - first_bounding_line_no = next_neighbour.neighbour_shape.next_no(first_bounding_line_no); - } - Line start_edge_line = next_neighbour.neighbour_shape.border_line(first_bounding_line_no).opposite(); - // start_edge_line is only used for the first new incomplete room. - Line middle_edge_line = null; - int curr_touching_side_no = last_touching_side_no; - boolean first_time = true; - // The loop goes backwards fromm the edge line of next_neigbour to the edge line of prev_neigbour. - for (;;) - { - boolean corner_cut_off = false; - if (this.from_room instanceof IncompleteFreeSpaceExpansionRoom) - { - IncompleteFreeSpaceExpansionRoom incomplete_room = (IncompleteFreeSpaceExpansionRoom) this.from_room; - if (curr_touching_side_no == last_touching_side_no - && first_touching_side_no != last_touching_side_no) - { - // Create a new line approximately from the last corner of the previous - // neighbour to the first corner of the next neighbour to cut off - // the outstanding corners of the room shape in the empty space. - // That is only tried in the first pass of the loop. - IntPoint cut_line_start = prev_neighbour.last_corner().to_float().round(); - IntPoint cut_line_end = next_neighbour.first_corner().to_float().round(); - Line cut_line = new Line(cut_line_start, cut_line_end); - TileShape cut_half_plane = TileShape.get_instance(cut_line); - ((CompleteFreeSpaceExpansionRoom)this.completed_room).set_shape(this.completed_room.get_shape().intersection(cut_half_plane)); - corner_cut_off = true; - if (incomplete_room.get_contained_shape().side_of(cut_line) != Side.ON_THE_LEFT) - { - // Otherwise p_room.contained_shape would no longer be contained - // in the shape after cutting of the corner. - corner_cut_off = false; - } - if (corner_cut_off) - { - middle_edge_line = cut_line.opposite(); - } - } - } - int next_touching_side_no = room_simplex.prev_no(curr_touching_side_no); - - if (!corner_cut_off) - { - middle_edge_line = room_simplex.border_line(curr_touching_side_no).opposite(); - } - - Direction middle_line_dir = middle_edge_line.direction(); - - boolean last_time = - curr_touching_side_no == first_touching_side_no - && !(prev_neighbour == this.sorted_neighbours.last() && first_time) - // The expression above handles the case, when all neigbours are on 1 edge line. - || corner_cut_off; - - Line end_edge_line; - // end_edge_line is only used for the last new incomplete room. - if (last_time) - { - end_edge_line = prev_neighbour.neighbour_shape.border_line(last_bounding_line_no).opposite(); - if (end_edge_line.direction().side_of(middle_line_dir) != Side.ON_THE_LEFT) - { - // Concave corner between the middle and the last line. - // May be there is a 1 point touch. - end_edge_line = null; - } - } - else - { - end_edge_line = null; - } - - if (start_edge_line != null && middle_line_dir.side_of(start_edge_line.direction()) != Side.ON_THE_LEFT) - { - // concave corner between the first and the middle line - // May be there is a 1 point touch. - start_edge_line = null; - } - int new_edge_line_count = 1; - if (start_edge_line != null) - { - ++new_edge_line_count; - } - if (end_edge_line != null) - { - ++new_edge_line_count; - } - Line [] new_edge_lines = new Line[new_edge_line_count]; - int curr_index = 0; - if (start_edge_line != null) - { - new_edge_lines[curr_index] = start_edge_line; - ++curr_index; - } - new_edge_lines[curr_index] = middle_edge_line; - if (end_edge_line != null) - { - ++curr_index; - new_edge_lines[curr_index] = end_edge_line; - } - Simplex new_room_shape = Simplex.get_instance(new_edge_lines); - if (!new_room_shape.is_empty()) - { - - TileShape new_contained_shape = this.completed_room.get_shape().intersection(new_room_shape); - if (!new_contained_shape.is_empty()) - { - FreeSpaceExpansionRoom new_room = - p_autoroute_engine.add_incomplete_expansion_room(new_room_shape, this.from_room.get_layer(), new_contained_shape); - ExpansionDoor new_door = new ExpansionDoor(this.completed_room, new_room, 1); - this.completed_room.add_door(new_door); - new_room.add_door(new_door); - } - } - if (last_time) - { - break; - } - curr_touching_side_no = next_touching_side_no; - start_edge_line = null; - first_time = false; - } - } - prev_neighbour = next_neighbour; - } - } - - /** - * p_door_shape is expected to bave dimension 1. - */ - static boolean insert_door_ok(ExpansionRoom p_room_1, ExpansionRoom p_room_2, TileShape p_door_shape) - { - if (p_room_1.door_exists(p_room_2)) - { - return false; - } - if (p_room_1 instanceof ObstacleExpansionRoom && p_room_2 instanceof ObstacleExpansionRoom) - { - Item first_item = ((ObstacleExpansionRoom) p_room_1).get_item(); - Item second_item = ((ObstacleExpansionRoom) p_room_2).get_item(); - // insert only overlap_doors between items of the same net for performance reasons. - return (first_item.shares_net(second_item)); - } - if (!(p_room_1 instanceof ObstacleExpansionRoom) && !(p_room_2 instanceof ObstacleExpansionRoom)) - { - return true; - } - // Insert 1 dimensional doors of trace rooms only, if they are parallel to the trace line. - // Otherwise there may be check ripup problems with entering at the wrong side at a fork. - Line door_line = null; - Point prev_corner = p_door_shape.corner(0); - int corner_count = p_door_shape.border_line_count(); - for (int i = 1; i < corner_count; ++i) - { - Point curr_corner = p_door_shape.corner(i); - if (!curr_corner.equals(prev_corner)) - { - door_line = p_door_shape.border_line(i - 1); - break; - } - prev_corner = curr_corner; - } - if (p_room_1 instanceof ObstacleExpansionRoom) - { - if (!insert_door_ok((ObstacleExpansionRoom) p_room_1, door_line)) - { - return false; - } - } - if (p_room_2 instanceof ObstacleExpansionRoom) - { - if (!insert_door_ok((ObstacleExpansionRoom) p_room_2, door_line)) - { - return false; - } - } - return true; - } - /** - * Insert 1 dimensional doors for the first and the last room of a trace rooms only, - * if they are parallel to the trace line. - * Otherwise there may be check ripup problems with entering at the wrong side at a fork. - */ - private static boolean insert_door_ok(ObstacleExpansionRoom p_room, Line p_door_line) - { - if (p_door_line == null) - { - System.out.println("SortedRoomNeighbours.insert_door_ok: p_door_line is null"); - return false; - } - Item curr_item = p_room.get_item(); - if (curr_item instanceof PolylineTrace) - { - int room_index = p_room.get_index_in_item(); - PolylineTrace curr_trace = (PolylineTrace) curr_item; - if (room_index == 0 || room_index == curr_trace.tile_shape_count() - 1) - { - Line curr_trace_line = curr_trace.polyline().arr[room_index + 1]; - if (!curr_trace_line.is_parallel(p_door_line)) - { - return false; - } - } - } - return true; - } - - private final ExpansionRoom from_room; - private final CompleteExpansionRoom completed_room; - private final TileShape room_shape; - private final SortedSet sorted_neighbours; - private final Collection own_net_objects; - - /** - * Helper class to sort the doors of an expansion room counterclockwise - * arount the border of the room shape. - * - * @author Alfons Wirtz - */ - - private class SortedRoomNeighbour implements Comparable - { - public SortedRoomNeighbour(TileShape p_neighbour_shape, TileShape p_intersection, - int p_touching_side_no_of_room, int p_touching_side_no_of_neighbour_room, - boolean p_room_touch_is_corner, boolean p_neighbour_room_touch_is_corner) - { - neighbour_shape = p_neighbour_shape; - intersection = p_intersection; - touching_side_no_of_room = p_touching_side_no_of_room; - touching_side_no_of_neighbour_room = p_touching_side_no_of_neighbour_room; - room_touch_is_corner = p_room_touch_is_corner; - neighbour_room_touch_is_corner = p_neighbour_room_touch_is_corner; - } - - /** - * Compare function for or sorting the neighbours in counterclock sense - * around the border of the room shape in ascending order. - */ - public int compareTo(SortedRoomNeighbour p_other) - { - int compare_value = this.touching_side_no_of_room - p_other.touching_side_no_of_room; - if (compare_value != 0) - { - return compare_value; - } - FloatPoint compare_corner = room_shape.corner_approx(touching_side_no_of_room); - double this_distance = this.first_corner().to_float().distance(compare_corner); - double other_distance = p_other.first_corner().to_float().distance(compare_corner); - double delta_distance = this_distance - other_distance; - if (Math.abs(delta_distance) <= c_dist_tolerance) - { - // check corners for equality - if (this.first_corner().equals(p_other.first_corner())) - { - // in this case compare the last corners - double this_distance2 = this.last_corner().to_float().distance(compare_corner); - double other_distance2 = p_other.last_corner().to_float().distance(compare_corner); - delta_distance = this_distance2 - other_distance2; - if (Math.abs(delta_distance) <= c_dist_tolerance) - { - if (this.neighbour_room_touch_is_corner && p_other.neighbour_room_touch_is_corner) - // Otherwise there may be a short 1 dim. touch at a link between 2 trace lines. - // In this case equality is ok, because the 2 intersection pieces with - // the expansion room are identical, so that only 1 obstacle is needed. - { - int compare_line_no = touching_side_no_of_room; - if (room_touch_is_corner) - { - compare_line_no = room_shape.prev_no(compare_line_no); - } - Direction compare_dir = room_shape.border_line(compare_line_no).direction().opposite(); - Line this_compare_line = this.neighbour_shape.border_line(this.touching_side_no_of_neighbour_room); - Line other_compare_line = p_other.neighbour_shape.border_line(p_other.touching_side_no_of_neighbour_room); - delta_distance = compare_dir.compare_from(this_compare_line.direction(), other_compare_line.direction()); - } - } - } - } - int result = Signum.as_int(delta_distance); - return result; - } - - /** - * Returns the first corner of the intersection shape with the neighbour. - */ - public Point first_corner() - { - if (precalculated_first_corner == null) - { - if (room_touch_is_corner) - { - precalculated_first_corner = room_shape.corner(touching_side_no_of_room); - } - else if (neighbour_room_touch_is_corner) - { - precalculated_first_corner = neighbour_shape.corner(touching_side_no_of_neighbour_room); - } - else - { - Point curr_first_corner = neighbour_shape.corner(neighbour_shape.next_no(touching_side_no_of_neighbour_room)); - Line prev_line = room_shape.border_line(room_shape.prev_no(touching_side_no_of_room)); - if (prev_line.side_of(curr_first_corner) == Side.ON_THE_RIGHT) - { - precalculated_first_corner = curr_first_corner; - } - else // curr_first_corner is outside the door shape - { - precalculated_first_corner = room_shape.corner(touching_side_no_of_room); - } - } - } - return precalculated_first_corner; - } - - /** - * Returns the last corner of the intersection shape with the neighbour. - */ - public Point last_corner() - { - if (precalculated_last_corner == null) - { - if (room_touch_is_corner) - { - precalculated_last_corner = room_shape.corner(touching_side_no_of_room); - } - else if (neighbour_room_touch_is_corner) - { - precalculated_last_corner = neighbour_shape.corner(touching_side_no_of_neighbour_room); - } - else - { - Point curr_last_corner = neighbour_shape.corner(touching_side_no_of_neighbour_room); - Line next_line = room_shape.border_line(room_shape.next_no(touching_side_no_of_room)); - if (next_line.side_of(curr_last_corner) == Side.ON_THE_RIGHT) - { - precalculated_last_corner = curr_last_corner; - } - else // curr_last_corner is outside the door shape - { - precalculated_last_corner = room_shape.corner(room_shape.next_no(touching_side_no_of_room)); - } - } - } - return precalculated_last_corner; - } - - /** The shape of the neighbour room */ - public final TileShape neighbour_shape; - - /** The intersection of tnis ExpansionRoom shape with the neighbour_shape */ - public final TileShape intersection; - - /** The side number of this room, where it touches the neighbour */ - public final int touching_side_no_of_room ; - - /** The side number of the neighbour room, where it touches this room */ - public final int touching_side_no_of_neighbour_room ; - - /** True, if the intersection of this room and the neighbour is - * equal to a corner of this room */ - public final boolean room_touch_is_corner; - - /** True, if the intersection of this room and the neighbour is - * equal to a corner of the neighbour room */ - public final boolean neighbour_room_touch_is_corner; - - private Point precalculated_first_corner = null; - private Point precalculated_last_corner = null; - - static private final double c_dist_tolerance = 1; - } -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * SortedRoomNeighbours.java + * + * Created on 28. Mai 2007, 07:27 + * + */ + +package autoroute; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.TreeSet; +import java.util.SortedSet; +import java.util.Iterator; + +import datastructures.Signum; +import datastructures.ShapeTree; + +import geometry.planar.Side; +import geometry.planar.Direction; +import geometry.planar.Point; +import geometry.planar.IntPoint; +import geometry.planar.FloatPoint; +import geometry.planar.Line; +import geometry.planar.TileShape; +import geometry.planar.Simplex; + +import board.ShapeSearchTree; +import board.SearchTreeObject; +import board.Connectable; +import board.Item; +import board.PolylineTrace; +import board.TestLevel; + +/** + * To calculate the neigbour rooms of an expansion room. + * The neighbour rooms will be sorted in counterclock sense around the border of the shape of p_room. + * Overlapping neighbours containing an item may be stored in an unordered list. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class SortedRoomNeighbours +{ + /** + * To calculate the neigbour rooms of an expansion room. + * The neighbour rooms will be sorted in counterclock sense around the border of the shape of p_room. + * Overlapping neighbours containing an item may be stored in an unordered list. + * + * @param p_room a {@link autoroute.ExpansionRoom} object. + * @param p_autoroute_engine a {@link autoroute.AutorouteEngine} object. + * @return a {@link autoroute.CompleteExpansionRoom} object. + */ + public static CompleteExpansionRoom calculate(ExpansionRoom p_room, AutorouteEngine p_autoroute_engine) + { + int net_no = p_autoroute_engine.get_net_no(); + TestLevel test_level = p_autoroute_engine.board.get_test_level(); + SortedRoomNeighbours room_neighbours = calculate_neighbours(p_room, net_no, p_autoroute_engine.autoroute_search_tree, + p_autoroute_engine.generate_room_id_no(), test_level); + + // Check, that each side of the romm shape has at least one touching neighbour. + // Otherwise improve the room shape by enlarging. + + boolean edge_removed = room_neighbours.try_remove_edge(net_no, + p_autoroute_engine.autoroute_search_tree, test_level); + CompleteExpansionRoom result = room_neighbours.completed_room; + if (edge_removed) + { + p_autoroute_engine.remove_all_doors(result); + return calculate(p_room, p_autoroute_engine); + } + + // Now calculate the new incomplete rooms together with the doors + // between this room and the sorted neighbours. + if (room_neighbours.sorted_neighbours.isEmpty()) + { + if (result instanceof ObstacleExpansionRoom) + { + calculate_incomplete_rooms_with_empty_neighbours((ObstacleExpansionRoom) p_room, p_autoroute_engine); + } + } + else + { + room_neighbours.calculate_new_incomplete_rooms(p_autoroute_engine); + if (test_level.ordinal() >= TestLevel.ALL_DEBUGGING_OUTPUT.ordinal() && result.get_shape().dimension() < 2) + { + System.out.println("AutorouteEngine.calculate_new_incomplete_rooms_with_mmore_than_1_neighbour: unexpected dimension for smoothened_shape"); + } + } + + if (result instanceof CompleteFreeSpaceExpansionRoom) + { + calculate_target_doors((CompleteFreeSpaceExpansionRoom) result, + room_neighbours.own_net_objects, p_autoroute_engine); + } + return result; + } + + private static void calculate_incomplete_rooms_with_empty_neighbours(ObstacleExpansionRoom p_room, AutorouteEngine p_autoroute_engine) + { + TileShape room_shape = p_room.get_shape(); + for (int i = 0; i < room_shape.border_line_count(); ++i) + { + Line curr_line = room_shape.border_line(i); + if (SortedRoomNeighbours.insert_door_ok(p_room, curr_line)) + { + Line[] shape_line = new Line[1]; + shape_line[0] = curr_line.opposite(); + TileShape new_room_shape = new Simplex(shape_line); + TileShape new_contained_shape = room_shape.intersection(new_room_shape); + FreeSpaceExpansionRoom new_room = p_autoroute_engine.add_incomplete_expansion_room(new_room_shape, p_room.get_layer(), new_contained_shape); + ExpansionDoor new_door = new ExpansionDoor(p_room, new_room, 1); + p_room.add_door(new_door); + new_room.add_door(new_door); + } + } + } + + + private static void calculate_target_doors(CompleteFreeSpaceExpansionRoom p_room, + Collection p_own_net_objects, AutorouteEngine p_autoroute_engine) + { + if (!p_own_net_objects.isEmpty()) + { + p_room.set_net_dependent(); + } + for (ShapeTree.TreeEntry curr_entry : p_own_net_objects) + { + if (curr_entry.object instanceof Connectable) + { + Connectable curr_object = (Connectable) curr_entry.object; + if (curr_object.contains_net(p_autoroute_engine.get_net_no())) + { + TileShape curr_connection_shape = + curr_object.get_trace_connection_shape(p_autoroute_engine.autoroute_search_tree, curr_entry.shape_index_in_object); + if (curr_connection_shape != null && p_room.get_shape().intersects(curr_connection_shape)) + { + Item curr_item = (Item) curr_object; + TargetItemExpansionDoor new_target_door = + new TargetItemExpansionDoor(curr_item, curr_entry.shape_index_in_object, p_room, + p_autoroute_engine.autoroute_search_tree); + p_room.add_target_door(new_target_door); + } + } + } + } + } + + private static SortedRoomNeighbours calculate_neighbours(ExpansionRoom p_room, int p_net_no, + ShapeSearchTree p_autoroute_search_tree, int p_room_id_no, TestLevel p_test_level) + { + TileShape room_shape = p_room.get_shape(); + CompleteExpansionRoom completed_room; + if (p_room instanceof IncompleteFreeSpaceExpansionRoom) + { + completed_room = new CompleteFreeSpaceExpansionRoom(room_shape, p_room.get_layer(), p_room_id_no); + } + else if (p_room instanceof ObstacleExpansionRoom) + { + completed_room = (ObstacleExpansionRoom)p_room; + } + else + { + System.out.println("SortedRoomNeighbours.calculate: unexpected expansion room type"); + return null; + } + SortedRoomNeighbours result = new SortedRoomNeighbours(p_room, completed_room); + Collection overlapping_objects = new LinkedList(); + p_autoroute_search_tree.overlapping_tree_entries(room_shape, p_room.get_layer(), overlapping_objects); + // Calculate the touching neigbour objects and sort them in counterclock sence + // around the border of the room shape. + for (ShapeTree.TreeEntry curr_entry : overlapping_objects) + { + SearchTreeObject curr_object = (SearchTreeObject) curr_entry.object; + if (curr_object == p_room) + { + continue; + } + if ((p_room instanceof IncompleteFreeSpaceExpansionRoom) && !curr_object.is_trace_obstacle(p_net_no)) + { + // delay processing the target doors until the room shape will not change any more + result.own_net_objects.add(curr_entry); + continue; + } + TileShape curr_shape = + curr_object.get_tree_shape(p_autoroute_search_tree, curr_entry.shape_index_in_object); + TileShape intersection = room_shape.intersection(curr_shape); + int dimension = intersection.dimension(); + if (dimension > 1) + { + if (completed_room instanceof ObstacleExpansionRoom && curr_object instanceof Item) + { + // only Obstacle expansion roos may have a 2-dim overlap + Item curr_item = (Item) curr_object; + if (curr_item.is_route()) + { + ItemAutorouteInfo item_info = curr_item.get_autoroute_info(); + ObstacleExpansionRoom curr_overlap_room = + item_info.get_expansion_room(curr_entry.shape_index_in_object, p_autoroute_search_tree); + ((ObstacleExpansionRoom) completed_room).create_overlap_door(curr_overlap_room); + } + } + else if (p_test_level.ordinal() >= TestLevel.ALL_DEBUGGING_OUTPUT.ordinal()) + { + System.out.println("SortedRoomNeighbours.calculate: unexpected area overlap of free space expansion room"); + } + continue; + } + if (dimension < 0) + { + if (p_test_level.ordinal() >= TestLevel.CRITICAL_DEBUGGING_OUTPUT.ordinal()) + { + System.out.println("SortedRoomNeighbours.calculate: dimension >= 0 expected"); + } + continue; + } + if (dimension == 1) + { + int[] touching_sides = room_shape.touching_sides(curr_shape); + if (touching_sides.length != 2) + { + if (p_test_level.ordinal() >= TestLevel.CRITICAL_DEBUGGING_OUTPUT.ordinal()) + { + System.out.println("SortedRoomNeighbours.calculate: touching_sides length 2 expected"); + } + continue; + } + result.add_sorted_neighbour(curr_shape, intersection, touching_sides[0], + touching_sides[1], false, false); + // make shure, that there is a door to the neighbour room. + ExpansionRoom neighbour_room = null; + if (curr_object instanceof ExpansionRoom) + { + neighbour_room = (ExpansionRoom) curr_object; + } + else if (curr_object instanceof Item) + { + Item curr_item = (Item) curr_object; + if (curr_item.is_route()) + { + // expand the item for ripup and pushing purposes + ItemAutorouteInfo item_info = curr_item.get_autoroute_info(); + neighbour_room = + item_info.get_expansion_room(curr_entry.shape_index_in_object, p_autoroute_search_tree); + } + } + if (neighbour_room != null) + { + if (SortedRoomNeighbours.insert_door_ok(completed_room, neighbour_room, intersection)) + { + ExpansionDoor new_door = new ExpansionDoor(completed_room, neighbour_room, 1); + neighbour_room.add_door(new_door); + completed_room.add_door(new_door); + } + } + } + else // dimensin = 0 + { + Point touching_point = intersection.corner(0); + int room_corner_no = room_shape.equals_corner(touching_point); + boolean room_touch_is_corner; + int touching_side_no_of_room; + if (room_corner_no >= 0) + { + room_touch_is_corner = true; + touching_side_no_of_room = room_corner_no; + } + else + { + room_touch_is_corner = false; + touching_side_no_of_room = room_shape.contains_on_border_line_no(touching_point); + if (touching_side_no_of_room < 0 && p_test_level.ordinal() >= TestLevel.CRITICAL_DEBUGGING_OUTPUT.ordinal()) + { + System.out.println("SortedRoomNeighbours.calculate: touching_side_no_of_room >= 0 expected"); + } + } + int neighbour_room_corner_no = curr_shape.equals_corner(touching_point); + boolean neighbour_room_touch_is_corner; + int touching_side_no_of_neighbour_room; + if (neighbour_room_corner_no >= 0) + { + neighbour_room_touch_is_corner = true; + // The previous border line is preferred to make the shape of the incomplete room as big as possible + touching_side_no_of_neighbour_room = curr_shape.prev_no(neighbour_room_corner_no); + } + else + { + neighbour_room_touch_is_corner = false; + touching_side_no_of_neighbour_room = curr_shape.contains_on_border_line_no(touching_point); + if (touching_side_no_of_neighbour_room < 0 && p_test_level.ordinal() >= TestLevel.CRITICAL_DEBUGGING_OUTPUT.ordinal()) + { + System.out.println("AutorouteEngine.SortedRoomNeighbours.calculate: touching_side_no_of_neighbour_room >= 0 expected"); + } + } + result.add_sorted_neighbour(curr_shape, intersection, + touching_side_no_of_room , touching_side_no_of_neighbour_room, + room_touch_is_corner , neighbour_room_touch_is_corner); + } + } + return result; + } + + + + /** Creates a new instance of SortedRoomNeighbours */ + private SortedRoomNeighbours(ExpansionRoom p_from_room, CompleteExpansionRoom p_completed_room) + { + from_room = p_from_room; + completed_room = p_completed_room; + room_shape = p_completed_room.get_shape(); + sorted_neighbours = new TreeSet(); + own_net_objects = new LinkedList(); + } + + private void add_sorted_neighbour(TileShape p_neighbour_shape, TileShape p_intersection, + int p_touching_side_no_of_room, int p_touching_side_no_of_neighbour_room, + boolean p_room_touch_is_corner, boolean p_neighbour_room_touch_is_corner) + { + SortedRoomNeighbour new_neighbour = new SortedRoomNeighbour(p_neighbour_shape, p_intersection, + p_touching_side_no_of_room, p_touching_side_no_of_neighbour_room, + p_room_touch_is_corner, p_neighbour_room_touch_is_corner); + sorted_neighbours.add(new_neighbour); + } + + /** + * Check, that each side of the romm shape has at least one touching neighbour. + * Otherwise the room shape will be improved the by enlarging. + * Returns true, if the room shape was changed. + */ + private boolean try_remove_edge(int p_net_no, ShapeSearchTree p_autoroute_search_tree, TestLevel p_test_level) + { + if (!(this.from_room instanceof IncompleteFreeSpaceExpansionRoom)) + { + return false; + } + IncompleteFreeSpaceExpansionRoom curr_incomplete_room = (IncompleteFreeSpaceExpansionRoom) this.from_room; + Iterator it = sorted_neighbours.iterator(); + int remove_edge_no = -1; + Simplex room_simplex = curr_incomplete_room.get_shape().to_Simplex(); + double room_shape_area = room_simplex.area(); + + int prev_edge_no = -1; + int curr_edge_no = 0; + while (it.hasNext()) + { + SortedRoomNeighbour next_neighbour = it.next(); + if (next_neighbour.touching_side_no_of_room == prev_edge_no) + { + continue; + } + if (next_neighbour.touching_side_no_of_room == curr_edge_no) + { + prev_edge_no = curr_edge_no; + ++curr_edge_no; + } + else + { + // On the edge side with index curr_edge_no is no touching + // neighbour. + remove_edge_no = curr_edge_no; + break; + } + } + + if (remove_edge_no < 0 && curr_edge_no < room_simplex.border_line_count()) + { + // missing touching neighbour at the last edge side. + remove_edge_no = curr_edge_no; + } + + + + if (remove_edge_no >= 0) + { + // Touching neighbour missing at the edge side with index remove_edge_no + // Remove the edge line and restart the algorithm. + Simplex enlarged_shape = room_simplex.remove_border_line(remove_edge_no); + IncompleteFreeSpaceExpansionRoom enlarged_room = + new IncompleteFreeSpaceExpansionRoom(enlarged_shape, curr_incomplete_room.get_layer(), + curr_incomplete_room.get_contained_shape()); + Collection new_rooms = + p_autoroute_search_tree.complete_shape(enlarged_room, p_net_no, null, null); + if (new_rooms.size() != 1) + { + if (p_test_level.ordinal() >= TestLevel.ALL_DEBUGGING_OUTPUT.ordinal()) + { + System.out.println("AutorouteEngine.calculate_doors: 1 completed shape expected"); + } + return false; + } + boolean remove_edge = false; + if (new_rooms.size() == 1) + { + // Check, that the area increases to prevent endless loop. + IncompleteFreeSpaceExpansionRoom new_shape = new_rooms.iterator().next(); + if (new_shape.get_shape().area() > room_shape_area) + { + remove_edge = true; + } + } + if (remove_edge) + { + Iterator it2 = new_rooms.iterator(); + IncompleteFreeSpaceExpansionRoom new_room = it2.next(); + curr_incomplete_room.set_shape(new_room.get_shape()); + curr_incomplete_room.set_contained_shape(new_room.get_contained_shape()); + return true; + } + } + return false; + } + + /** + * Called from calculate_doors(). + * The shape of the room p_result may change inside this function. + * + * @param p_autoroute_engine a {@link autoroute.AutorouteEngine} object. + */ + public void calculate_new_incomplete_rooms(AutorouteEngine p_autoroute_engine) + { + SortedRoomNeighbour prev_neighbour = this.sorted_neighbours.last(); + Iterator it = this.sorted_neighbours.iterator(); + Simplex room_simplex = this.from_room.get_shape().to_Simplex(); + while (it.hasNext()) + { + SortedRoomNeighbour next_neighbour = it.next(); + int first_touching_side_no = prev_neighbour.touching_side_no_of_room; + int last_touching_side_no = next_neighbour.touching_side_no_of_room; + + int curr_next_no = room_simplex.next_no(first_touching_side_no); + boolean intersection_with_prev_neighbour_ends_at_corner = + (first_touching_side_no != last_touching_side_no || prev_neighbour == this.sorted_neighbours.last()) + && prev_neighbour.last_corner().equals(room_simplex.corner(curr_next_no)); + boolean intersection_with_next_neighbour_starts_at_corner = + (first_touching_side_no != last_touching_side_no || prev_neighbour == this.sorted_neighbours.last()) + && next_neighbour.first_corner().equals(room_simplex.corner(last_touching_side_no)); + + if (intersection_with_prev_neighbour_ends_at_corner) + { + first_touching_side_no = curr_next_no; + } + + if(intersection_with_next_neighbour_starts_at_corner) + { + last_touching_side_no = room_simplex.prev_no(last_touching_side_no); + } + boolean neighbours_touch = false; + + if (this.sorted_neighbours.size() > 1) + { + neighbours_touch = prev_neighbour.last_corner().equals(next_neighbour.first_corner()); + } + + if (!neighbours_touch) + { + // create a door to a new incomplete expansion room between + // the last corner of the previous neighbour and the first corner of the + // current neighbour. + int last_bounding_line_no = prev_neighbour.touching_side_no_of_neighbour_room; + if (!(intersection_with_prev_neighbour_ends_at_corner + || prev_neighbour.room_touch_is_corner)) + { + last_bounding_line_no = prev_neighbour.neighbour_shape.prev_no(last_bounding_line_no); + } + + + int first_bounding_line_no = next_neighbour.touching_side_no_of_neighbour_room; + if (!(intersection_with_next_neighbour_starts_at_corner + || next_neighbour.neighbour_room_touch_is_corner)) + { + first_bounding_line_no = next_neighbour.neighbour_shape.next_no(first_bounding_line_no); + } + Line start_edge_line = next_neighbour.neighbour_shape.border_line(first_bounding_line_no).opposite(); + // start_edge_line is only used for the first new incomplete room. + Line middle_edge_line = null; + int curr_touching_side_no = last_touching_side_no; + boolean first_time = true; + // The loop goes backwards fromm the edge line of next_neigbour to the edge line of prev_neigbour. + for (;;) + { + boolean corner_cut_off = false; + if (this.from_room instanceof IncompleteFreeSpaceExpansionRoom) + { + IncompleteFreeSpaceExpansionRoom incomplete_room = (IncompleteFreeSpaceExpansionRoom) this.from_room; + if (curr_touching_side_no == last_touching_side_no + && first_touching_side_no != last_touching_side_no) + { + // Create a new line approximately from the last corner of the previous + // neighbour to the first corner of the next neighbour to cut off + // the outstanding corners of the room shape in the empty space. + // That is only tried in the first pass of the loop. + IntPoint cut_line_start = prev_neighbour.last_corner().to_float().round(); + IntPoint cut_line_end = next_neighbour.first_corner().to_float().round(); + Line cut_line = new Line(cut_line_start, cut_line_end); + TileShape cut_half_plane = TileShape.get_instance(cut_line); + ((CompleteFreeSpaceExpansionRoom)this.completed_room).set_shape(this.completed_room.get_shape().intersection(cut_half_plane)); + corner_cut_off = true; + if (incomplete_room.get_contained_shape().side_of(cut_line) != Side.ON_THE_LEFT) + { + // Otherwise p_room.contained_shape would no longer be contained + // in the shape after cutting of the corner. + corner_cut_off = false; + } + if (corner_cut_off) + { + middle_edge_line = cut_line.opposite(); + } + } + } + int next_touching_side_no = room_simplex.prev_no(curr_touching_side_no); + + if (!corner_cut_off) + { + middle_edge_line = room_simplex.border_line(curr_touching_side_no).opposite(); + } + + Direction middle_line_dir = middle_edge_line.direction(); + + boolean last_time = + curr_touching_side_no == first_touching_side_no + && !(prev_neighbour == this.sorted_neighbours.last() && first_time) + // The expression above handles the case, when all neigbours are on 1 edge line. + || corner_cut_off; + + Line end_edge_line; + // end_edge_line is only used for the last new incomplete room. + if (last_time) + { + end_edge_line = prev_neighbour.neighbour_shape.border_line(last_bounding_line_no).opposite(); + if (end_edge_line.direction().side_of(middle_line_dir) != Side.ON_THE_LEFT) + { + // Concave corner between the middle and the last line. + // May be there is a 1 point touch. + end_edge_line = null; + } + } + else + { + end_edge_line = null; + } + + if (start_edge_line != null && middle_line_dir.side_of(start_edge_line.direction()) != Side.ON_THE_LEFT) + { + // concave corner between the first and the middle line + // May be there is a 1 point touch. + start_edge_line = null; + } + int new_edge_line_count = 1; + if (start_edge_line != null) + { + ++new_edge_line_count; + } + if (end_edge_line != null) + { + ++new_edge_line_count; + } + Line [] new_edge_lines = new Line[new_edge_line_count]; + int curr_index = 0; + if (start_edge_line != null) + { + new_edge_lines[curr_index] = start_edge_line; + ++curr_index; + } + new_edge_lines[curr_index] = middle_edge_line; + if (end_edge_line != null) + { + ++curr_index; + new_edge_lines[curr_index] = end_edge_line; + } + Simplex new_room_shape = Simplex.get_instance(new_edge_lines); + if (!new_room_shape.is_empty()) + { + + TileShape new_contained_shape = this.completed_room.get_shape().intersection(new_room_shape); + if (!new_contained_shape.is_empty()) + { + FreeSpaceExpansionRoom new_room = + p_autoroute_engine.add_incomplete_expansion_room(new_room_shape, this.from_room.get_layer(), new_contained_shape); + ExpansionDoor new_door = new ExpansionDoor(this.completed_room, new_room, 1); + this.completed_room.add_door(new_door); + new_room.add_door(new_door); + } + } + if (last_time) + { + break; + } + curr_touching_side_no = next_touching_side_no; + start_edge_line = null; + first_time = false; + } + } + prev_neighbour = next_neighbour; + } + } + + /** + * p_door_shape is expected to bave dimension 1. + */ + static boolean insert_door_ok(ExpansionRoom p_room_1, ExpansionRoom p_room_2, TileShape p_door_shape) + { + if (p_room_1.door_exists(p_room_2)) + { + return false; + } + if (p_room_1 instanceof ObstacleExpansionRoom && p_room_2 instanceof ObstacleExpansionRoom) + { + Item first_item = ((ObstacleExpansionRoom) p_room_1).get_item(); + Item second_item = ((ObstacleExpansionRoom) p_room_2).get_item(); + // insert only overlap_doors between items of the same net for performance reasons. + return (first_item.shares_net(second_item)); + } + if (!(p_room_1 instanceof ObstacleExpansionRoom) && !(p_room_2 instanceof ObstacleExpansionRoom)) + { + return true; + } + // Insert 1 dimensional doors of trace rooms only, if they are parallel to the trace line. + // Otherwise there may be check ripup problems with entering at the wrong side at a fork. + Line door_line = null; + Point prev_corner = p_door_shape.corner(0); + int corner_count = p_door_shape.border_line_count(); + for (int i = 1; i < corner_count; ++i) + { + Point curr_corner = p_door_shape.corner(i); + if (!curr_corner.equals(prev_corner)) + { + door_line = p_door_shape.border_line(i - 1); + break; + } + prev_corner = curr_corner; + } + if (p_room_1 instanceof ObstacleExpansionRoom) + { + if (!insert_door_ok((ObstacleExpansionRoom) p_room_1, door_line)) + { + return false; + } + } + if (p_room_2 instanceof ObstacleExpansionRoom) + { + if (!insert_door_ok((ObstacleExpansionRoom) p_room_2, door_line)) + { + return false; + } + } + return true; + } + /** + * Insert 1 dimensional doors for the first and the last room of a trace rooms only, + * if they are parallel to the trace line. + * Otherwise there may be check ripup problems with entering at the wrong side at a fork. + */ + private static boolean insert_door_ok(ObstacleExpansionRoom p_room, Line p_door_line) + { + if (p_door_line == null) + { + System.out.println("SortedRoomNeighbours.insert_door_ok: p_door_line is null"); + return false; + } + Item curr_item = p_room.get_item(); + if (curr_item instanceof PolylineTrace) + { + int room_index = p_room.get_index_in_item(); + PolylineTrace curr_trace = (PolylineTrace) curr_item; + if (room_index == 0 || room_index == curr_trace.tile_shape_count() - 1) + { + Line curr_trace_line = curr_trace.polyline().arr[room_index + 1]; + if (!curr_trace_line.is_parallel(p_door_line)) + { + return false; + } + } + } + return true; + } + + private final ExpansionRoom from_room; + private final CompleteExpansionRoom completed_room; + private final TileShape room_shape; + private final SortedSet sorted_neighbours; + private final Collection own_net_objects; + + /** + * Helper class to sort the doors of an expansion room counterclockwise + * arount the border of the room shape. + * + * @author Alfons Wirtz + */ + + private class SortedRoomNeighbour implements Comparable + { + public SortedRoomNeighbour(TileShape p_neighbour_shape, TileShape p_intersection, + int p_touching_side_no_of_room, int p_touching_side_no_of_neighbour_room, + boolean p_room_touch_is_corner, boolean p_neighbour_room_touch_is_corner) + { + neighbour_shape = p_neighbour_shape; + intersection = p_intersection; + touching_side_no_of_room = p_touching_side_no_of_room; + touching_side_no_of_neighbour_room = p_touching_side_no_of_neighbour_room; + room_touch_is_corner = p_room_touch_is_corner; + neighbour_room_touch_is_corner = p_neighbour_room_touch_is_corner; + } + + /** + * Compare function for or sorting the neighbours in counterclock sense + * around the border of the room shape in ascending order. + */ + public int compareTo(SortedRoomNeighbour p_other) + { + int compare_value = this.touching_side_no_of_room - p_other.touching_side_no_of_room; + if (compare_value != 0) + { + return compare_value; + } + FloatPoint compare_corner = room_shape.corner_approx(touching_side_no_of_room); + double this_distance = this.first_corner().to_float().distance(compare_corner); + double other_distance = p_other.first_corner().to_float().distance(compare_corner); + double delta_distance = this_distance - other_distance; + if (Math.abs(delta_distance) <= c_dist_tolerance) + { + // check corners for equality + if (this.first_corner().equals(p_other.first_corner())) + { + // in this case compare the last corners + double this_distance2 = this.last_corner().to_float().distance(compare_corner); + double other_distance2 = p_other.last_corner().to_float().distance(compare_corner); + delta_distance = this_distance2 - other_distance2; + if (Math.abs(delta_distance) <= c_dist_tolerance) + { + if (this.neighbour_room_touch_is_corner && p_other.neighbour_room_touch_is_corner) + // Otherwise there may be a short 1 dim. touch at a link between 2 trace lines. + // In this case equality is ok, because the 2 intersection pieces with + // the expansion room are identical, so that only 1 obstacle is needed. + { + int compare_line_no = touching_side_no_of_room; + if (room_touch_is_corner) + { + compare_line_no = room_shape.prev_no(compare_line_no); + } + Direction compare_dir = room_shape.border_line(compare_line_no).direction().opposite(); + Line this_compare_line = this.neighbour_shape.border_line(this.touching_side_no_of_neighbour_room); + Line other_compare_line = p_other.neighbour_shape.border_line(p_other.touching_side_no_of_neighbour_room); + delta_distance = compare_dir.compare_from(this_compare_line.direction(), other_compare_line.direction()); + } + } + } + } + int result = Signum.as_int(delta_distance); + return result; + } + + /** + * Returns the first corner of the intersection shape with the neighbour. + */ + public Point first_corner() + { + if (precalculated_first_corner == null) + { + if (room_touch_is_corner) + { + precalculated_first_corner = room_shape.corner(touching_side_no_of_room); + } + else if (neighbour_room_touch_is_corner) + { + precalculated_first_corner = neighbour_shape.corner(touching_side_no_of_neighbour_room); + } + else + { + Point curr_first_corner = neighbour_shape.corner(neighbour_shape.next_no(touching_side_no_of_neighbour_room)); + Line prev_line = room_shape.border_line(room_shape.prev_no(touching_side_no_of_room)); + if (prev_line.side_of(curr_first_corner) == Side.ON_THE_RIGHT) + { + precalculated_first_corner = curr_first_corner; + } + else // curr_first_corner is outside the door shape + { + precalculated_first_corner = room_shape.corner(touching_side_no_of_room); + } + } + } + return precalculated_first_corner; + } + + /** + * Returns the last corner of the intersection shape with the neighbour. + */ + public Point last_corner() + { + if (precalculated_last_corner == null) + { + if (room_touch_is_corner) + { + precalculated_last_corner = room_shape.corner(touching_side_no_of_room); + } + else if (neighbour_room_touch_is_corner) + { + precalculated_last_corner = neighbour_shape.corner(touching_side_no_of_neighbour_room); + } + else + { + Point curr_last_corner = neighbour_shape.corner(touching_side_no_of_neighbour_room); + Line next_line = room_shape.border_line(room_shape.next_no(touching_side_no_of_room)); + if (next_line.side_of(curr_last_corner) == Side.ON_THE_RIGHT) + { + precalculated_last_corner = curr_last_corner; + } + else // curr_last_corner is outside the door shape + { + precalculated_last_corner = room_shape.corner(room_shape.next_no(touching_side_no_of_room)); + } + } + } + return precalculated_last_corner; + } + + /** The shape of the neighbour room */ + public final TileShape neighbour_shape; + + /** The intersection of tnis ExpansionRoom shape with the neighbour_shape */ + public final TileShape intersection; + + /** The side number of this room, where it touches the neighbour */ + public final int touching_side_no_of_room ; + + /** The side number of the neighbour room, where it touches this room */ + public final int touching_side_no_of_neighbour_room ; + + /** True, if the intersection of this room and the neighbour is + * equal to a corner of this room */ + public final boolean room_touch_is_corner; + + /** True, if the intersection of this room and the neighbour is + * equal to a corner of the neighbour room */ + public final boolean neighbour_room_touch_is_corner; + + private Point precalculated_first_corner = null; + private Point precalculated_last_corner = null; + + static private final double c_dist_tolerance = 1; + } +} diff --git a/autoroute/TargetItemExpansionDoor.java b/src/main/java/autoroute/TargetItemExpansionDoor.java similarity index 76% rename from autoroute/TargetItemExpansionDoor.java rename to src/main/java/autoroute/TargetItemExpansionDoor.java index 536e833..eefe9b5 100644 --- a/autoroute/TargetItemExpansionDoor.java +++ b/src/main/java/autoroute/TargetItemExpansionDoor.java @@ -28,11 +28,19 @@ * An expansion door leading to a start or destination item of the autoroute algorithm. * * @author Alfons Wirtz + * @version $Id: $Id */ public class TargetItemExpansionDoor implements ExpandableObject { - /** Creates a new instance of ItemExpansionInfo */ + /** + * Creates a new instance of ItemExpansionInfo + * + * @param p_item a {@link board.Item} object. + * @param p_tree_entry_no a int. + * @param p_room a {@link autoroute.CompleteExpansionRoom} object. + * @param p_search_tree a {@link board.ShapeSearchTree} object. + */ public TargetItemExpansionDoor(Item p_item, int p_tree_entry_no, CompleteExpansionRoom p_room, ShapeSearchTree p_search_tree) { item = p_item; @@ -50,37 +58,62 @@ public TargetItemExpansionDoor(Item p_item, int p_tree_entry_no, CompleteExpansi maze_search_info = new MazeSearchElement(); } + /** + *

get_shape.

+ * + * @return a {@link geometry.planar.TileShape} object. + */ public TileShape get_shape() { return this.shape; } + /** + *

get_dimension.

+ * + * @return a int. + */ public int get_dimension() { return 2; } + /** + *

is_destination_door.

+ * + * @return a boolean. + */ public boolean is_destination_door() { ItemAutorouteInfo item_info = this.item.get_autoroute_info(); return !item_info.is_start_info(); } + /** {@inheritDoc} */ public CompleteExpansionRoom other_room(CompleteExpansionRoom p_room) { return null; } + /** {@inheritDoc} */ public MazeSearchElement get_maze_search_element(int p_no) { return maze_search_info; } + /** + *

maze_search_element_count.

+ * + * @return a int. + */ public int maze_search_element_count() { return 1; } + /** + *

reset.

+ */ public void reset() { maze_search_info.reset(); diff --git a/autoroute/package.html b/src/main/java/autoroute/package.html similarity index 100% rename from autoroute/package.html rename to src/main/java/autoroute/package.html diff --git a/board/AngleRestriction.java b/src/main/java/board/AngleRestriction.java similarity index 85% rename from board/AngleRestriction.java rename to src/main/java/board/AngleRestriction.java index afd770f..b798a40 100644 --- a/board/AngleRestriction.java +++ b/src/main/java/board/AngleRestriction.java @@ -24,13 +24,18 @@ * Enum for angle restrictions none, fortyfive degree and ninety degree. * * @author Alfons Wirtz + * @version $Id: $Id */ public class AngleRestriction { + /** Constant NONE */ public static final AngleRestriction NONE = new AngleRestriction("none", 0); + /** Constant FORTYFIVE_DEGREE */ public static final AngleRestriction FORTYFIVE_DEGREE = new AngleRestriction("45 degree", 1); + /** Constant NINETY_DEGREE */ public static final AngleRestriction NINETY_DEGREE = new AngleRestriction("90 degree", 2); + /** Constant arr */ public static final AngleRestriction[] arr = { NONE, FORTYFIVE_DEGREE, NINETY_DEGREE @@ -38,6 +43,8 @@ public class AngleRestriction /** * Returns the string of this instance + * + * @return a {@link java.lang.String} object. */ public String to_string() { @@ -46,6 +53,8 @@ public String to_string() /** * Returns the number of this instance + * + * @return a int. */ public int get_no() { @@ -60,4 +69,4 @@ private AngleRestriction(String p_name, int p_no) private final String name; private final int no; -} \ No newline at end of file +} diff --git a/board/BasicBoard.java b/src/main/java/board/BasicBoard.java similarity index 83% rename from board/BasicBoard.java rename to src/main/java/board/BasicBoard.java index b0e084e..5880ab6 100644 --- a/board/BasicBoard.java +++ b/src/main/java/board/BasicBoard.java @@ -1,1568 +1,1837 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - */ -package board; - -import geometry.planar.Area; -import geometry.planar.ConvexShape; -import geometry.planar.IntBox; -import geometry.planar.IntOctagon; -import geometry.planar.Point; -import geometry.planar.Vector; -import geometry.planar.Polyline; -import geometry.planar.PolylineShape; -import geometry.planar.TileShape; - -import java.awt.Graphics; - -import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.Set; -import java.util.SortedSet; -import java.util.TreeSet; - -import datastructures.ShapeTree.TreeEntry; - -import library.BoardLibrary; -import library.Padstack; -import rules.BoardRules; -import boardgraphics.GraphicsContext; -import boardgraphics.Drawable; -import datastructures.UndoableObjects; - -/** - * - * Provides basic functionality of a board with geometric items. - * Contains functions such as inserting, deleting, modifying - * and picking items and elementary checking functions. - * A board may have 1 or several layers. - * - * @author Alfons Wirtz - */ -public class BasicBoard implements java.io.Serializable -{ - - /** - * Creates a new instance of a routing Board with surrrounding box - * p_bounding_box - * Rules contains the restrictions to obey when inserting items. - * Among other things it may contain a clearance matrix. - * p_observers is used for syncronisation, if the board is generated - * by a host database. Otherwise it is null. - * If p_test_level != RELEASE_VERSION,, some features may be used, which are still in experimental state. - * Also warnings for debugging may be printed depending on the size of p_test_level. - */ - public BasicBoard(IntBox p_bounding_box, LayerStructure p_layer_structure, PolylineShape[] p_outline_shapes, - int p_outline_cl_class_no, BoardRules p_rules, Communication p_communication, TestLevel p_test_level) - { - layer_structure = p_layer_structure; - rules = p_rules; - library = new BoardLibrary(); - item_list = new UndoableObjects(); - components = new Components(); - communication = p_communication; - bounding_box = p_bounding_box; - this.test_level = p_test_level; - search_tree_manager = new SearchTreeManager(this); - p_rules.nets.set_board(this); - insert_outline(p_outline_shapes, p_outline_cl_class_no); - } - - /** - * Inserts a trace into the board, whose geometry is described by - * a Polyline. p_clearance_class is the index in the clearance_matix, - * which describes the required clearance restrictions to other items. - * Because no internal cleaning of items is done, the new inserted - * item can be returned. - */ - public PolylineTrace insert_trace_without_cleaning(Polyline p_polyline, int p_layer, - int p_half_width, int[] p_net_no_arr, int p_clearance_class, FixedState p_fixed_state) - { - if (p_polyline.corner_count() < 2) - { - return null; - } - PolylineTrace new_trace = new PolylineTrace(p_polyline, p_layer, p_half_width, p_net_no_arr, - p_clearance_class, 0, 0, p_fixed_state, this); - if (new_trace.first_corner().equals(new_trace.last_corner())) - { - if (p_fixed_state.ordinal() < FixedState.USER_FIXED.ordinal()) - { - return null; - } - } - insert_item(new_trace); - if (new_trace.nets_normal()) - { - max_trace_half_width = Math.max(max_trace_half_width, p_half_width); - min_trace_half_width = Math.min(min_trace_half_width, p_half_width); - } - return new_trace; - } - - /** - * Inserts a trace into the board, whose geometry is described by - * a Polyline. p_clearance_class is the index in the clearance_matix, - * which describes the required clearance restrictions to other items. - */ - public void insert_trace(Polyline p_polyline, int p_layer, - int p_half_width, int[] p_net_no_arr, int p_clearance_class, FixedState p_fixed_state) - { - PolylineTrace new_trace = - insert_trace_without_cleaning(p_polyline, p_layer, p_half_width, - p_net_no_arr, p_clearance_class, p_fixed_state); - if (new_trace == null) - { - return; - } - IntOctagon clip_shape = null; - if (this instanceof RoutingBoard) - { - ChangedArea changed_area = ((RoutingBoard) this).changed_area; - if (changed_area != null) - { - clip_shape = changed_area.get_area(p_layer); - } - } - new_trace.normalize(clip_shape); - } - - /** - * Inserts a trace into the board, whose geometry is described by - * an array of points, and cleans up the net. - */ - public void insert_trace(Point[] p_points, int p_layer, - int p_half_width, int[] p_net_no_arr, int p_clearance_class, FixedState p_fixed_state) - { - for (int i = 0; i < p_points.length; ++i) - { - if (!this.bounding_box.contains(p_points[i])) - { - System.out.println("LayeredBoard.insert_trace: input point out of range"); - } - } - Polyline poly = new Polyline(p_points); - insert_trace(poly, p_layer, p_half_width, p_net_no_arr, p_clearance_class, p_fixed_state); - } - - /** - * Inserts a via into the board. p_attach_allowed indicates, if the via may overlap with smd pins - * of the same net. - */ - public Via insert_via(Padstack p_padstack, Point p_center, int[] p_net_no_arr, int p_clearance_class, - FixedState p_fixed_state, boolean p_attach_allowed) - { - Via new_via = new Via(p_padstack, p_center, p_net_no_arr, p_clearance_class, 0, 0, p_fixed_state, - p_attach_allowed, this); - insert_item(new_via); - int from_layer = p_padstack.from_layer(); - int to_layer = p_padstack.to_layer(); - for (int i = from_layer; i < to_layer; ++i) - { - for (int curr_net_no : p_net_no_arr) - { - split_traces(p_center, i, curr_net_no); - } - } - return new_via; - } - - /** - * Inserts a pin into the board. - * p_pin_no is the number of this pin in the library package of its component (starting with 0). - */ - public Pin insert_pin(int p_component_no, int p_pin_no, int[] p_net_no_arr, int p_clearance_class, FixedState p_fixed_state) - { - Pin new_pin = new Pin(p_component_no, p_pin_no, p_net_no_arr, p_clearance_class, 0, p_fixed_state, this); - insert_item(new_pin); - return new_pin; - } - - /** - * Inserts an obstacle into the board , whose geometry is described - * by a polygonyal shape, which may have holes. - * If p_component_no != 0, the obstacle belongs to a component. - */ - public ObstacleArea insert_obstacle(Area p_area, int p_layer, int p_clearance_class, FixedState p_fixed_state) - { - if (p_area == null) - { - System.out.println("BasicBoard.insert_obstacle: p_area is null"); - return null; - } - ObstacleArea obs = new ObstacleArea(p_area, p_layer, Vector.ZERO, 0, false, p_clearance_class, 0, 0, null, p_fixed_state, this); - insert_item(obs); - return obs; - } - - /** - * Inserts an obstacle belonging to a component into the board - * p_name is to identify the corresponding ObstacstacleArea in the component package. - */ - public ObstacleArea insert_obstacle(Area p_area, int p_layer, Vector p_translation, double p_rotation_in_degree, - boolean p_side_changed, int p_clearance_class, int p_component_no, String p_name, FixedState p_fixed_state) - { - if (p_area == null) - { - System.out.println("BasicBoard.insert_obstacle: p_area is null"); - return null; - } - ObstacleArea obs = new ObstacleArea(p_area, p_layer, p_translation, p_rotation_in_degree, p_side_changed, - p_clearance_class, 0, p_component_no, p_name, p_fixed_state, this); - insert_item(obs); - return obs; - } - - /** - * Inserts an via obstacle area into the board , whose geometry is described - * by a polygonyal shape, which may have holes. - */ - public ViaObstacleArea insert_via_obstacle(Area p_area, int p_layer, int p_clearance_class, - FixedState p_fixed_state) - { - if (p_area == null) - { - System.out.println("BasicBoard.insert_via_obstacle: p_area is null"); - return null; - } - ViaObstacleArea obs = new ViaObstacleArea(p_area, p_layer, Vector.ZERO, 0, false, - p_clearance_class, 0, 0, null, p_fixed_state, this); - insert_item(obs); - return obs; - } - - /** - * Inserts an via obstacle belonging to a component into the board - * p_name is to identify the corresponding ObstacstacleArea in the component package. - */ - public ViaObstacleArea insert_via_obstacle(Area p_area, int p_layer, Vector p_translation, double p_rotation_in_degree, - boolean p_side_changed, int p_clearance_class, int p_component_no, String p_name, - FixedState p_fixed_state) - { - if (p_area == null) - { - System.out.println("BasicBoard.insert_via_obstacle: p_area is null"); - return null; - } - ViaObstacleArea obs = new ViaObstacleArea(p_area, p_layer, p_translation, p_rotation_in_degree, p_side_changed, - p_clearance_class, 0, p_component_no, p_name, p_fixed_state, this); - insert_item(obs); - return obs; - } - - /** - * Inserts a component obstacle area into the board , whose geometry is described - * by a polygonyal shape, which may have holes. - */ - public ComponentObstacleArea insert_component_obstacle(Area p_area, int p_layer, - int p_clearance_class, FixedState p_fixed_state) - { - if (p_area == null) - { - System.out.println("BasicBoard.insert_component_obstacle: p_area is null"); - return null; - } - ComponentObstacleArea obs = new ComponentObstacleArea(p_area, p_layer, Vector.ZERO, 0, false, - p_clearance_class, 0, 0, null, p_fixed_state, this); - insert_item(obs); - return obs; - } - - /** - * Inserts a component obstacle belonging to a component into the board. - * p_name is to identify the corresponding ObstacstacleArea in the component package. - */ - public ComponentObstacleArea insert_component_obstacle(Area p_area, int p_layer, Vector p_translation, double p_rotation_in_degree, - boolean p_side_changed, int p_clearance_class, int p_component_no, String p_name, FixedState p_fixed_state) - { - if (p_area == null) - { - System.out.println("BasicBoard.insert_component_obstacle: p_area is null"); - return null; - } - ComponentObstacleArea obs = new ComponentObstacleArea(p_area, p_layer, p_translation, p_rotation_in_degree, p_side_changed, - p_clearance_class, 0, p_component_no, p_name, p_fixed_state, this); - insert_item(obs); - return obs; - } - - /** - * Inserts a component ouline into the board. - */ - public ComponentOutline insert_component_outline(Area p_area, boolean p_is_front, Vector p_translation, double p_rotation_in_degree, - int p_component_no, FixedState p_fixed_state) - { - if (p_area == null) - { - System.out.println("BasicBoard.insert_component_outline: p_area is null"); - return null; - } - if (!p_area.is_bounded()) - { - System.out.println("BasicBoard.insert_component_outline: p_area is not bounded"); - return null; - } - ComponentOutline outline = new ComponentOutline(p_area, p_is_front, p_translation, p_rotation_in_degree, - p_component_no, p_fixed_state, this); - insert_item(outline); - return outline; - } - - /** - * Inserts a condution area into the board , whose geometry is described - * by a polygonyal shape, which may have holes. - * If p_is_obstacle is false, it is possible to route through the conduction area - * with traces and vias of foreign nets. - */ - public ConductionArea insert_conduction_area(Area p_area, int p_layer, - int[] p_net_no_arr, int p_clearance_class, boolean p_is_obstacle, FixedState p_fixed_state) - { - if (p_area == null) - { - System.out.println("BasicBoard.insert_conduction_area: p_area is null"); - return null; - } - ConductionArea c = new ConductionArea(p_area, p_layer, Vector.ZERO, 0, false, p_net_no_arr, p_clearance_class, - 0, 0, null, p_is_obstacle, p_fixed_state, this); - insert_item(c); - return c; - } - - /** - * Inserts an Outline into the board. - */ - public BoardOutline insert_outline(PolylineShape[] p_outline_shapes, int p_clearance_class_no) - { - BoardOutline result = new BoardOutline(p_outline_shapes, p_clearance_class_no, 0, this); - insert_item(result); - return result; - } - - /** - * Returns the outline of the board. - */ - public BoardOutline get_outline() - { - Iterator it = item_list.start_read_object(); - for (;;) - { - UndoableObjects.Storable curr_item = item_list.read_object(it); - if (curr_item == null) - { - break; - } - if (curr_item instanceof BoardOutline) - { - return (BoardOutline) curr_item; - } - } - return null; - } - - /** - * Removes an item from the board - */ - public void remove_item(Item p_item) - { - if (p_item == null) - { - return; - } - additional_update_after_change(p_item); // must be called before p_item is deleted. - search_tree_manager.remove(p_item); - item_list.delete(p_item); - - // let the observers syncronize the deletion - communication.observers.notify_deleted(p_item); - } - - /** - * looks, if an item with id_no p_id_no is on the board. - * Returns the found item or null, if no such item is found. - */ - public Item get_item(int p_id_no) - { - Iterator it = item_list.start_read_object(); - for (;;) - { - Item curr_item = (Item) item_list.read_object(it); - if (curr_item == null) - { - break; - } - if (curr_item.get_id_no() == p_id_no) - { - return curr_item; - } - } - return null; - } - - /** - * Returns the list of all items on the board - */ - public Collection get_items() - { - Collection result = new LinkedList(); - Iterator it = item_list.start_read_object(); - for (;;) - { - Item curr_item = (Item) item_list.read_object(it); - if (curr_item == null) - { - break; - } - result.add(curr_item); - } - return result; - } - - /** - * Returns all connectable items on the board containing p_net_no - */ - public Collection get_connectable_items(int p_net_no) - { - Collection result = new LinkedList(); - Iterator it = item_list.start_read_object(); - for (;;) - { - Item curr_item = (Item) item_list.read_object(it); - if (curr_item == null) - { - break; - } - if (curr_item instanceof Connectable && curr_item.contains_net(p_net_no)) - { - result.add(curr_item); - } - } - return result; - } - - /** - * Returns the count of connectable items of the net with number p_net_no - */ - public int connectable_item_count(int p_net_no) - { - int result = 0; - Iterator it = item_list.start_read_object(); - for (;;) - { - Item curr_item = (Item) item_list.read_object(it); - if (curr_item == null) - { - break; - } - if (curr_item instanceof Connectable && curr_item.contains_net(p_net_no)) - { - ++result; - } - } - return result; - } - - /** - * Returns all items with the input component number - */ - public Collection get_component_items(int p_component_no) - { - Collection result = new LinkedList(); - Iterator it = item_list.start_read_object(); - for (;;) - { - Item curr_item = (Item) item_list.read_object(it); - if (curr_item == null) - { - break; - } - if (curr_item.get_component_no() == p_component_no) - { - result.add(curr_item); - } - } - return result; - } - - /** - * Returns all pins with the input component number - */ - public Collection get_component_pins(int p_component_no) - { - Collection result = new LinkedList(); - Iterator it = item_list.start_read_object(); - for (;;) - { - Item curr_item = (Item) item_list.read_object(it); - if (curr_item == null) - { - break; - } - if (curr_item.get_component_no() == p_component_no && curr_item instanceof Pin) - { - result.add((Pin) curr_item); - } - } - return result; - } - - /** - * Returns the pin with the input component number and pin number, or null, if no such pinn exists. - */ - public Pin get_pin(int p_component_no, int p_pin_no) - { - Iterator it = item_list.start_read_object(); - for (;;) - { - Item curr_item = (Item) item_list.read_object(it); - if (curr_item == null) - { - break; - } - if (curr_item.get_component_no() == p_component_no && curr_item instanceof Pin) - { - Pin curr_pin = (Pin) curr_item; - if (curr_pin.pin_no == p_pin_no) - { - return curr_pin; - } - } - } - return null; - } - - /** - * Removes the items in p_item_list. - * Returns false, if some items could not be removed, bcause they are fixed. - */ - public boolean remove_items(Collection p_item_list, boolean p_with_delete_fixed) - { - boolean result = true; - Iterator it = p_item_list.iterator(); - while (it.hasNext()) - { - Item curr_item = it.next(); - if (!p_with_delete_fixed && curr_item.is_delete_fixed() || curr_item.is_user_fixed()) - { - result = false; - } - else - { - remove_item(curr_item); - } - } - return result; - } - - /** - * Returns the list of all conduction areas on the board - */ - public Collection get_conduction_areas() - { - Collection result = new LinkedList(); - Iterator it = item_list.start_read_object(); - for (;;) - { - UndoableObjects.Storable curr_item = item_list.read_object(it); - if (curr_item == null) - { - break; - } - if (curr_item instanceof ConductionArea) - { - result.add((ConductionArea) curr_item); - } - } - return result; - } - - /** - * Returns the list of all pins on the board - */ - public Collection get_pins() - { - Collection result = new LinkedList(); - Iterator it = item_list.start_read_object(); - for (;;) - { - UndoableObjects.Storable curr_item = item_list.read_object(it); - if (curr_item == null) - { - break; - } - if (curr_item instanceof Pin) - { - result.add((Pin) curr_item); - } - } - return result; - } - - /** - * Returns the list of all pins on the board with only 1 layer - */ - public Collection get_smd_pins() - { - Collection result = new LinkedList(); - Iterator it = item_list.start_read_object(); - for (;;) - { - UndoableObjects.Storable curr_item = item_list.read_object(it); - if (curr_item == null) - { - break; - } - if (curr_item instanceof Pin) - { - Pin curr_pin = (Pin) curr_item; - if (curr_pin.first_layer() == curr_pin.last_layer()) - { - result.add(curr_pin); - } - } - } - return result; - } - - /** - * Returns the list of all vias on the board - */ - public Collection get_vias() - { - Collection result = new LinkedList(); - Iterator it = item_list.start_read_object(); - for (;;) - { - UndoableObjects.Storable curr_item = item_list.read_object(it); - if (curr_item == null) - { - break; - } - if (curr_item instanceof Via) - { - result.add((Via) curr_item); - } - } - return result; - } - - /** - * Returns the list of all traces on the board - */ - public Collection get_traces() - { - Collection result = new LinkedList(); - Iterator it = item_list.start_read_object(); - for (;;) - { - UndoableObjects.Storable curr_item = item_list.read_object(it); - if (curr_item == null) - { - break; - } - if (curr_item instanceof Trace) - { - result.add((Trace) curr_item); - } - } - return result; - } - - /** - * Returns the cumulative length of all traces on the board - */ - public double cumulative_trace_length() - { - double result = 0; - Iterator it = item_list.start_read_object(); - for (;;) - { - UndoableObjects.Storable curr_item = item_list.read_object(it); - if (curr_item == null) - { - break; - } - if (curr_item instanceof Trace) - { - result += ((Trace) curr_item).get_length(); - } - } - return result; - } - - /** - * Combines the connected traces of this net, which have only 1 contact - * at the connection point. - * if p_net_no < 0 traces of all nets are combined. - */ - public boolean combine_traces(int p_net_no) - { - boolean result = false; - boolean something_changed = true; - while (something_changed) - { - something_changed = false; - Iterator it = item_list.start_read_object(); - for (;;) - { - Item curr_item = (Item) item_list.read_object(it); - if (curr_item == null) - { - break; - } - if ((p_net_no < 0 || curr_item.contains_net(p_net_no)) && curr_item instanceof Trace && curr_item.is_on_the_board()) - { - if (((Trace) curr_item).combine()) - { - something_changed = true; - result = true; - break; - } - } - } - } - return result; - } - - /** - * Normalizes the traces of this net - */ - public boolean normalize_traces(int p_net_no) - { - boolean result = false; - boolean something_changed = true; - Item curr_item = null; - while (something_changed) - { - something_changed = false; - Iterator it = item_list.start_read_object(); - for (;;) - { - try - { - curr_item = (Item) item_list.read_object(it); - } - catch (java.util.ConcurrentModificationException e) - { - something_changed = true; - break; - } - if (curr_item == null) - { - break; - } - if (curr_item.contains_net(p_net_no) && curr_item instanceof PolylineTrace && curr_item.is_on_the_board()) - { - PolylineTrace curr_trace = (PolylineTrace) curr_item; - if (curr_trace.normalize(null)) - { - something_changed = true; - result = true; - } - else if (!curr_trace.is_user_fixed() && this.remove_if_cycle(curr_trace)) - { - something_changed = true; - result = true; - } - } - } - } - return result; - } - - /** - * Looks for traces of the input net on the input layer, so that p_location is on the trace polygon, - * and splits these traces. Returns false, if no trace was split. - */ - public boolean split_traces(Point p_location, int p_layer, int p_net_no) - { - ItemSelectionFilter filter = new ItemSelectionFilter(ItemSelectionFilter.SelectableChoices.TRACES); - Collection picked_items = this.pick_items(p_location, p_layer, filter); - IntOctagon location_shape = TileShape.get_instance(p_location).bounding_octagon(); - boolean trace_split = false; - for (Item curr_item : picked_items) - { - Trace curr_trace = (Trace) curr_item; - if (curr_trace.contains_net(p_net_no)) - { - Collection split_pieces = curr_trace.split(location_shape); - if (split_pieces.size() != 1) - { - trace_split = true; - } - } - } - return trace_split; - } - - /** - * Returs a Collection of Collections of items forming a connected set. - */ - public Collection> get_connected_sets(int p_net_no) - { - Collection> result = new LinkedList>(); - if (p_net_no <= 0) - { - return result; - } - SortedSet items_to_handle = new TreeSet(); - Iterator it = this.item_list.start_read_object(); - for (;;) - { - Item curr_item = (Item) item_list.read_object(it); - if (curr_item == null) - { - break; - } - if (curr_item instanceof Connectable && curr_item.contains_net(p_net_no)) - { - items_to_handle.add(curr_item); - } - } - Iterator it2 = items_to_handle.iterator(); - while (it2.hasNext()) - { - Item curr_item = it2.next(); - Collection next_connected_set = curr_item.get_connected_set(p_net_no); - result.add(next_connected_set); - items_to_handle.removeAll(next_connected_set); - it2 = items_to_handle.iterator(); - } - return result; - } - - /** - * Returns all SearchTreeObjects on layer p_layer, which overlap with p_shape. - * If p_layer < 0, the layer is ignored - */ - public Set overlapping_objects(ConvexShape p_shape, int p_layer) - { - return this.search_tree_manager.get_default_tree().overlapping_objects(p_shape, p_layer); - } - - /** - * Returns items, which overlap with p_shape on layer p_layer - * inclusive clearance. - * p_clearance_class is the index in the clearance matrix, - * which describes the required clearance restrictions to other items. - * The function may also return items, which are nearly overlapping, - * but do not overlap with exact calculation. - * If p_layer < 0, the layer is ignored. - */ - public Set overlapping_items_with_clearance(ConvexShape p_shape, int p_layer, int[] p_ignore_net_nos, - int p_clearance_class) - { - ShapeSearchTree default_tree = this.search_tree_manager.get_default_tree(); - return default_tree.overlapping_items_with_clearance(p_shape, p_layer, p_ignore_net_nos, p_clearance_class); - } - - /** - * Returns all items on layer p_layer, which overlap with p_area. - * If p_layer < 0, the layer is ignored - */ - public Set overlapping_items(Area p_area, int p_layer) - { - Set result = new TreeSet(); - TileShape[] tile_shapes = p_area.split_to_convex(); - for (int i = 0; i < tile_shapes.length; ++i) - { - Set curr_overlaps = overlapping_objects(tile_shapes[i], p_layer); - for (SearchTreeObject curr_overlap : curr_overlaps) - { - if (curr_overlap instanceof Item) - { - result.add((Item) curr_overlap); - } - } - } - return result; - } - - /** - * Checks, if the an object with shape p_shape and net nos p_net_no_arr - * and clearance class p_cl_class can be inserted on layer p_layer - * without clearance violation. - */ - public boolean check_shape(Area p_shape, int p_layer, int[] p_net_no_arr, int p_cl_class) - { - TileShape[] tiles = p_shape.split_to_convex(); - ShapeSearchTree default_tree = this.search_tree_manager.get_default_tree(); - for (int i = 0; i < tiles.length; ++i) - { - TileShape curr_shape = tiles[i]; - if (!curr_shape.is_contained_in(bounding_box)) - { - return false; - } - Set obstacles = new TreeSet(); - default_tree.overlapping_objects_with_clearance(curr_shape, p_layer, - p_net_no_arr, p_cl_class, obstacles); - for (SearchTreeObject curr_ob : obstacles) - { - boolean is_obstacle = true; - for (int j = 0; j < p_net_no_arr.length; ++j) - { - if (!curr_ob.is_obstacle(p_net_no_arr[j])) - { - is_obstacle = false; - } - } - if (is_obstacle) - { - return false; - } - } - } - return true; - } - - /** - * Checks, if the a trace line with shape p_shape and net numbers p_net_no_arr - * and clearance class p_cl_class can be inserted on layer p_layer - * without clearance violation. - * If p_contact_pins != null, all pins not contained in p_contact_pins are - * regarded as obstacles, even if they are of the own net. - */ - public boolean check_trace_shape(TileShape p_shape, int p_layer, int[] p_net_no_arr, - int p_cl_class, Set p_contact_pins) - { - if (!p_shape.is_contained_in(bounding_box)) - { - return false; - } - ShapeSearchTree default_tree = this.search_tree_manager.get_default_tree(); - Collection tree_entries = new LinkedList(); - int[] ignore_net_nos = new int[0]; - if (default_tree.is_clearance_compensation_used()) - { - default_tree.overlapping_tree_entries(p_shape, p_layer, ignore_net_nos, tree_entries); - } - else - { - default_tree.overlapping_tree_entries_with_clearance(p_shape, p_layer, ignore_net_nos, p_cl_class, tree_entries); - } - for (TreeEntry curr_tree_entry : tree_entries) - { - if (!(curr_tree_entry.object instanceof Item)) - { - continue; - } - Item curr_item = (Item) curr_tree_entry.object; - if (p_contact_pins != null) - { - if (p_contact_pins.contains(curr_item)) - { - continue; - } - if (curr_item instanceof Pin) - { - // The contact pins of the trace should be contained in p_ignore_items. - // Other pins are handled as obstacles to avoid acid traps. - return false; - } - } - boolean is_obstacle = true; - for (int i = 0; i < p_net_no_arr.length; ++i) - { - if (!curr_item.is_trace_obstacle(p_net_no_arr[i])) - { - is_obstacle = false; - } - } - if (is_obstacle && (curr_item instanceof PolylineTrace) && p_contact_pins != null) - { - // check for traces of foreign nets at tie pins, which will be ignored inside the pin shape - TileShape intersection = null; - for (Pin curr_contact_pin : p_contact_pins) - { - if (curr_contact_pin.net_count() <= 1 || !curr_contact_pin.shares_net(curr_item)) - { - continue; - } - if (intersection == null) - { - TileShape obstacle_trace_shape = curr_item.get_tile_shape(curr_tree_entry.shape_index_in_object); - intersection = p_shape.intersection(obstacle_trace_shape); - } - TileShape pin_shape = curr_contact_pin.get_tile_shape_on_layer(p_layer); - if (pin_shape.contains_approx(intersection)) - { - is_obstacle = false; - break; - } - } - } - if (is_obstacle) - { - return false; - } - } - return true; - } - - /** - * Checks, if a polyline trace with the input parameters can be inserted - * without clearance violations - */ - public boolean check_polyline_trace(Polyline p_polyline, int p_layer, int p_pen_half_width, - int[] p_net_no_arr, int p_clearance_class) - { - Trace tmp_trace = - new PolylineTrace(p_polyline, p_layer, p_pen_half_width, p_net_no_arr, p_clearance_class, 0, 0, FixedState.UNFIXED, this); - Set contact_pins = tmp_trace.touching_pins_at_end_corners(); - for (int i = 0; i < tmp_trace.tile_shape_count(); ++i) - { - if (!this.check_trace_shape(tmp_trace.get_tile_shape(i), p_layer, p_net_no_arr, - p_clearance_class, contact_pins)) - { - return false; - } - } - return true; - } - - /** - * Returns the layer count of this board. - */ - public int get_layer_count() - { - return layer_structure.arr.length; - } - - /** - * Draws all items of the board on their visible layers. Called in the overwritten - * paintComponent method of a class derived from JPanel. - * The value of p_layer_visibility is expected between 0 and 1 for each layer. - */ - public void draw(Graphics p_graphics, GraphicsContext p_graphics_context) - { - if (p_graphics_context == null) - { - return; - } - - // draw all items on the board - for (int curr_priority = Drawable.MIN_DRAW_PRIORITY; curr_priority <= Drawable.MIDDLE_DRAW_PRIORITY; ++curr_priority) - { - Iterator it = item_list.start_read_object(); - for (;;) - { - try - { - Item curr_item = (Item) item_list.read_object(it); - if (curr_item == null) - { - break; - } - if (curr_item.get_draw_priority() == curr_priority) - { - curr_item.draw(p_graphics, p_graphics_context); - } - } - catch (java.util.ConcurrentModificationException e) - { - // may happen when window are changed interactively while running a logfile - return; - } - } - } - } - - /** - * Returns the list of items on the board, whose shape on layer p_layer contains the point at p_location. - * If p_layer < 0, the layer is ignored. - * If p_item_selection_filter != null, only items of types selected by the filter are picked. - */ - public Set pick_items(Point p_location, int p_layer, ItemSelectionFilter p_filter) - { - TileShape point_shape = TileShape.get_instance(p_location); - Collection overlaps = overlapping_objects(point_shape, p_layer); - Set result = new TreeSet(); - for (SearchTreeObject curr_object : overlaps) - { - if (curr_object instanceof Item) - { - result.add((Item) curr_object); - } - } - if (p_filter != null) - { - result = p_filter.filter(result); - } - return result; - } - - /** - * checks, if p_point is contained in the bounding box of this board. - */ - public boolean contains(Point p_point) - { - return p_point.is_contained_in(bounding_box); - } - - /** - * Returns the minimum clearance requested between items of - * clearance class p_class_1 and p_class_2. - * p_class_1 and p_class_2 are indices in the clearance matrix. - */ - public int clearance_value(int p_class_1, int p_class_2, int p_layer) - { - if (rules == null || rules.clearance_matrix == null) - { - return 0; - } - return rules.clearance_matrix.value(p_class_1, p_class_2, p_layer); - } - - /** - * returns the biggest half width of all traces on the board. - */ - public int get_max_trace_half_width() - { - return max_trace_half_width; - } - - /** - * returns the smallest half width of all traces on the board. - */ - public int get_min_trace_half_width() - { - return min_trace_half_width; - } - - /** - * Returns a surrounding box of the geometry of this board - */ - public IntBox get_bounding_box() - { - return bounding_box; - } - - /** - * Returns a box containing all items in p_item_list. - */ - public IntBox get_bounding_box(Collection p_item_list) - { - IntBox result = IntBox.EMPTY; - for (Item curr_item : p_item_list) - { - result = result.union(curr_item.bounding_box()); - } - return result; - } - - /** - * Resets the rectangle, where a graphics update is needed. - */ - public void reset_graphics_update_box() - { - update_box = IntBox.EMPTY; - } - - /** - * Gets the rectancle, where a graphics update is needed on the screen. - */ - public IntBox get_graphics_update_box() - { - return update_box; - } - - /** - * enlarges the graphics update box, so that it contains p_box - */ - public void join_graphics_update_box(IntBox p_box) - { - if (update_box == null) - { - reset_graphics_update_box(); - } - update_box = update_box.union(p_box); - } - - /** - * starts notifying the observers of any change in the objects list - */ - public void start_notify_observers() - { - if (this.communication.observers != null) - { - communication.observers.activate(); - } - } - - /** - * ends notifying the observers of changes in the objects list - */ - public void end_notify_observers() - { - if (this.communication.observers != null) - { - communication.observers.deactivate(); - } - } - - /** - * Returns, if the observer of the board items is activated. - */ - public boolean observers_active() - { - boolean result; - if (this.communication.observers != null) - { - result = communication.observers.is_active(); - } - else - { - result = false; - } - return result; - } - - /** - * Turns an obstacle area into a conduction area with net number p_net_no - * If it is convex and has no holes, it is turned into a Pin, - * alse into a conduction area. - */ - public Connectable make_conductive(ObstacleArea p_area, int p_net_no) - { - Item new_item; - Area curr_area = p_area.get_relative_area(); - int layer = p_area.get_layer(); - FixedState fixed_state = p_area.get_fixed_state(); - Vector translation = p_area.get_translation(); - double rotation = p_area.get_rotation_in_degree(); - boolean side_changed = p_area.get_side_changed(); - int[] net_no_arr = new int[1]; - net_no_arr[0] = p_net_no; - new_item = new ConductionArea(curr_area, layer, translation, rotation, side_changed, net_no_arr, - p_area.clearance_class_no(), 0, p_area.get_component_no(), p_area.name, true, fixed_state, this); - remove_item(p_area); - insert_item(new_item); - return (Connectable) new_item; - } - - /** - * Inserts an item into the board data base - */ - public void insert_item(Item p_item) - { - if (p_item == null) - { - return; - } - - if (rules == null || rules.clearance_matrix == null || p_item.clearance_class_no() < 0 || - p_item.clearance_class_no() >= rules.clearance_matrix.get_class_count()) - { - System.out.println("LayeredBoard.insert_item: clearance_class no out of range"); - p_item.set_clearance_class_no(0); - } - p_item.board = this; - item_list.insert(p_item); - search_tree_manager.insert(p_item); - communication.observers.notify_new(p_item); - additional_update_after_change(p_item); - } - - /** - * Stub function overwritten in class RoutingBoard to maintain the autorouter database if necessesary. - */ - public void additional_update_after_change(Item p_item) - { - } - - /** - * Restores the sitiation at the previous snapshot. - * Returns false, if no more undo is possible. - * Puts the numbers of the changed nets into the set p_changed_nets, if p_changed_nets != null - */ - public boolean undo(Set p_changed_nets) - { - this.components.undo(this.communication.observers); - Collection cancelled_objects = new LinkedList(); - Collection restored_objects = new LinkedList(); - boolean result = item_list.undo(cancelled_objects, restored_objects); - // update the search trees - Iterator it = cancelled_objects.iterator(); - while (it.hasNext()) - { - Item curr_item = (Item) it.next(); - search_tree_manager.remove(curr_item); - - // let the observers syncronize the deletion - communication.observers.notify_deleted(curr_item); - if (p_changed_nets != null) - { - for (int i = 0; i < curr_item.net_count(); ++i) - { - p_changed_nets.add(new Integer(curr_item.get_net_no(i))); - } - } - } - it = restored_objects.iterator(); - while (it.hasNext()) - { - Item curr_item = (Item) it.next(); - curr_item.board = this; - search_tree_manager.insert(curr_item); - curr_item.clear_autoroute_info(); - // let the observers know the insertion - communication.observers.notify_new(curr_item); - if (p_changed_nets != null) - { - for (int i = 0; i < curr_item.net_count(); ++i) - { - p_changed_nets.add(new Integer(curr_item.get_net_no(i))); - } - } - } - return result; - } - - /** - * Restores the sitiation before the last undo. - * Returns false, if no more redo is possible. - * Puts the numbers of the changed nets into the set p_changed_nets, if p_changed_nets != null - */ - public boolean redo(Set p_changed_nets) - { - this.components.redo(this.communication.observers); - Collection cancelled_objects = new LinkedList(); - Collection restored_objects = new LinkedList(); - boolean result = item_list.redo(cancelled_objects, restored_objects); - // update the search trees - Iterator it = cancelled_objects.iterator(); - while (it.hasNext()) - { - Item curr_item = (Item) it.next(); - search_tree_manager.remove(curr_item); - // let the observers syncronize the deletion - communication.observers.notify_deleted(curr_item); - if (p_changed_nets != null) - { - for (int i = 0; i < curr_item.net_count(); ++i) - { - p_changed_nets.add(curr_item.get_net_no(i)); - } - } - } - it = restored_objects.iterator(); - while (it.hasNext()) - { - Item curr_item = (Item) it.next(); - curr_item.board = this; - search_tree_manager.insert(curr_item); - curr_item.clear_autoroute_info(); - // let the observers know the insertion - communication.observers.notify_new(curr_item); - if (p_changed_nets != null) - { - for (int i = 0; i < curr_item.net_count(); ++i) - { - p_changed_nets.add(curr_item.get_net_no(i)); - } - } - } - return result; - } - - /** - * Makes the current board situation restorable by undo. - */ - public void generate_snapshot() - { - item_list.generate_snapshot(); - components.generate_snapshot(); - } - - /** - * Removes the top snapshot from the undo stack, so that its situation cannot be - * restored any more. - * Returns false, if no more snapshot could be popped. - */ - public boolean pop_snapshot() - { - return item_list.pop_snapshot(); - } - - /** - * Looks if at the input position ends a trace with the input net number, - * which has no normal contact at that position. - * Returns null, if no tail is found. - */ - public Trace get_trace_tail(Point p_location, int p_layer, int[] p_net_no_arr) - { - TileShape point_shape = TileShape.get_instance(p_location); - Collection found_items = overlapping_objects(point_shape, p_layer); - Iterator it = found_items.iterator(); - while (it.hasNext()) - { - SearchTreeObject curr_ob = it.next(); - if (curr_ob instanceof Trace) - { - Trace curr_trace = (Trace) curr_ob; - if (!curr_trace.nets_equal(p_net_no_arr)) - { - continue; - } - if (curr_trace.first_corner().equals(p_location)) - { - Collection contacts = curr_trace.get_start_contacts(); - if (contacts.size() == 0) - { - return curr_trace; - } - } - if (curr_trace.last_corner().equals(p_location)) - { - Collection contacts = curr_trace.get_end_contacts(); - if (contacts.size() == 0) - { - return curr_trace; - } - } - } - } - return null; - } - - /** - * Checks, if p_item item is part of a cycle and remuve it - * together with its connection in this case. - */ - public boolean remove_if_cycle(Trace p_trace) - { - if (!p_trace.is_on_the_board()) - { - return false; - } - if (!p_trace.is_cycle()) - { - return false; - } - // Remove tails at the endpoints after removing the cycle, - // if there was no tail before. - boolean[] tail_at_endpoint_before = null; - Point[] end_corners = null; - int curr_layer = p_trace.get_layer(); - int[] curr_net_no_arr = p_trace.net_no_arr; - end_corners = new Point[2]; - end_corners[0] = p_trace.first_corner(); - end_corners[1] = p_trace.last_corner(); - tail_at_endpoint_before = new boolean[2]; - for (int i = 0; i < 2; ++i) - { - Trace tail = - get_trace_tail(end_corners[i], curr_layer, curr_net_no_arr); - tail_at_endpoint_before[i] = (tail != null); - } - Set connection_items = p_trace.get_connection_items(); - this.remove_items(connection_items, false); - for (int i = 0; i < 2; ++i) - { - if (!tail_at_endpoint_before[i]) - { - Trace tail = get_trace_tail(end_corners[i], curr_layer, curr_net_no_arr); - if (tail != null) - { - remove_items(tail.get_connection_items(), false); - } - } - } - return true; - } - - /** - * If != RELEASE_VERSION,, some features may be used, which are still in experimental state. - * Also warnings for debugging may be printed depending on the test_level. - */ - public TestLevel get_test_level() - { - return this.test_level; - } - - /** - * Only to be used in BoardHandling.read_design. - */ - public void set_test_level(TestLevel p_value) - { - this.test_level = p_value; - } - - private void readObject(java.io.ObjectInputStream p_stream) - throws java.io.IOException, java.lang.ClassNotFoundException - { - p_stream.defaultReadObject(); - // insert the items on the board into the search trees - search_tree_manager = new SearchTreeManager(this); - Iterator it = this.get_items().iterator(); - while (it.hasNext()) - { - Item curr_item = it.next(); - curr_item.board = this; - search_tree_manager.insert(curr_item); - } - } - /** - * List of items inserted into this board - */ - public final UndoableObjects item_list; - /** List of placed components on the board. */ - public final Components components; - /** - * Class defining the rules for items to be inserted into this board. - * Contains for example the clearance matrix. - */ - public final BoardRules rules; - /** - * The library containing pastack masks, packagages and other - * templates used on the board. - */ - public final BoardLibrary library; - /** - * The layer structure of this board. - */ - public final LayerStructure layer_structure; - /** - * Handels the search trees pointing into the items of this board - */ - public transient SearchTreeManager search_tree_manager; - /** - * For communication with a host system or host design file formats. - */ - public final Communication communication; - /** - * bounding orthogonal rectangle of this board - */ - public final IntBox bounding_box; - /** - * If test_level != RELEASE_VERSION, some features may be used, which are still in experimental state. - * Also warnings for debugging may be printed depending on the size of test_level. - */ - transient private TestLevel test_level; - /** the rectangle, where the graphics may be not uptodate */ - transient private IntBox update_box = IntBox.EMPTY; - /** - * the biggest half width of all traces on the board - */ - private int max_trace_half_width = 1000; - /** - * the smallest half width of all traces on the board - */ - private int min_trace_half_width = 10000; - /** - * Limits the maximum width of a shape in the search tree. - */ -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + */ +package board; + +import geometry.planar.Area; +import geometry.planar.ConvexShape; +import geometry.planar.IntBox; +import geometry.planar.IntOctagon; +import geometry.planar.Point; +import geometry.planar.Vector; +import geometry.planar.Polyline; +import geometry.planar.PolylineShape; +import geometry.planar.TileShape; + +import java.awt.Graphics; + +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; + +import datastructures.ShapeTree.TreeEntry; + +import library.BoardLibrary; +import library.Padstack; +import rules.BoardRules; +import boardgraphics.GraphicsContext; +import boardgraphics.Drawable; +import datastructures.UndoableObjects; + +/** + * + * Provides basic functionality of a board with geometric items. + * Contains functions such as inserting, deleting, modifying + * and picking items and elementary checking functions. + * A board may have 1 or several layers. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class BasicBoard implements java.io.Serializable +{ + + /** + * Creates a new instance of a routing Board with surrrounding box + * p_bounding_box + * Rules contains the restrictions to obey when inserting items. + * Among other things it may contain a clearance matrix. + * p_observers is used for syncronisation, if the board is generated + * by a host database. Otherwise it is null. + * If p_test_level != RELEASE_VERSION,, some features may be used, which are still in experimental state. + * Also warnings for debugging may be printed depending on the size of p_test_level. + * + * @param p_bounding_box a {@link geometry.planar.IntBox} object. + * @param p_layer_structure a {@link board.LayerStructure} object. + * @param p_outline_shapes an array of {@link geometry.planar.PolylineShape} objects. + * @param p_outline_cl_class_no a int. + * @param p_rules a rules$BoardRules object. + * @param p_communication a {@link board.Communication} object. + * @param p_test_level a {@link board.TestLevel} object. + */ + public BasicBoard(IntBox p_bounding_box, LayerStructure p_layer_structure, PolylineShape[] p_outline_shapes, + int p_outline_cl_class_no, BoardRules p_rules, Communication p_communication, TestLevel p_test_level) + { + layer_structure = p_layer_structure; + rules = p_rules; + library = new BoardLibrary(); + item_list = new UndoableObjects(); + components = new Components(); + communication = p_communication; + bounding_box = p_bounding_box; + this.test_level = p_test_level; + search_tree_manager = new SearchTreeManager(this); + p_rules.nets.set_board(this); + insert_outline(p_outline_shapes, p_outline_cl_class_no); + } + + /** + * Inserts a trace into the board, whose geometry is described by + * a Polyline. p_clearance_class is the index in the clearance_matix, + * which describes the required clearance restrictions to other items. + * Because no internal cleaning of items is done, the new inserted + * item can be returned. + * + * @param p_polyline a {@link geometry.planar.Polyline} object. + * @param p_layer a int. + * @param p_half_width a int. + * @param p_net_no_arr an array of int. + * @param p_clearance_class a int. + * @param p_fixed_state a {@link board.FixedState} object. + * @return a {@link board.PolylineTrace} object. + */ + public PolylineTrace insert_trace_without_cleaning(Polyline p_polyline, int p_layer, + int p_half_width, int[] p_net_no_arr, int p_clearance_class, FixedState p_fixed_state) + { + if (p_polyline.corner_count() < 2) + { + return null; + } + PolylineTrace new_trace = new PolylineTrace(p_polyline, p_layer, p_half_width, p_net_no_arr, + p_clearance_class, 0, 0, p_fixed_state, this); + if (new_trace.first_corner().equals(new_trace.last_corner())) + { + if (p_fixed_state.ordinal() < FixedState.USER_FIXED.ordinal()) + { + return null; + } + } + insert_item(new_trace); + if (new_trace.nets_normal()) + { + max_trace_half_width = Math.max(max_trace_half_width, p_half_width); + min_trace_half_width = Math.min(min_trace_half_width, p_half_width); + } + return new_trace; + } + + /** + * Inserts a trace into the board, whose geometry is described by + * a Polyline. p_clearance_class is the index in the clearance_matix, + * which describes the required clearance restrictions to other items. + * + * @param p_polyline a {@link geometry.planar.Polyline} object. + * @param p_layer a int. + * @param p_half_width a int. + * @param p_net_no_arr an array of int. + * @param p_clearance_class a int. + * @param p_fixed_state a {@link board.FixedState} object. + */ + public void insert_trace(Polyline p_polyline, int p_layer, + int p_half_width, int[] p_net_no_arr, int p_clearance_class, FixedState p_fixed_state) + { + PolylineTrace new_trace = + insert_trace_without_cleaning(p_polyline, p_layer, p_half_width, + p_net_no_arr, p_clearance_class, p_fixed_state); + if (new_trace == null) + { + return; + } + IntOctagon clip_shape = null; + if (this instanceof RoutingBoard) + { + ChangedArea changed_area = ((RoutingBoard) this).changed_area; + if (changed_area != null) + { + clip_shape = changed_area.get_area(p_layer); + } + } + new_trace.normalize(clip_shape); + } + + /** + * Inserts a trace into the board, whose geometry is described by + * an array of points, and cleans up the net. + * + * @param p_points an array of {@link geometry.planar.Point} objects. + * @param p_layer a int. + * @param p_half_width a int. + * @param p_net_no_arr an array of int. + * @param p_clearance_class a int. + * @param p_fixed_state a {@link board.FixedState} object. + */ + public void insert_trace(Point[] p_points, int p_layer, + int p_half_width, int[] p_net_no_arr, int p_clearance_class, FixedState p_fixed_state) + { + for (int i = 0; i < p_points.length; ++i) + { + if (!this.bounding_box.contains(p_points[i])) + { + System.out.println("LayeredBoard.insert_trace: input point out of range"); + } + } + Polyline poly = new Polyline(p_points); + insert_trace(poly, p_layer, p_half_width, p_net_no_arr, p_clearance_class, p_fixed_state); + } + + /** + * Inserts a via into the board. p_attach_allowed indicates, if the via may overlap with smd pins + * of the same net. + * + * @param p_padstack a {@link library.Padstack} object. + * @param p_center a {@link geometry.planar.Point} object. + * @param p_net_no_arr an array of int. + * @param p_clearance_class a int. + * @param p_fixed_state a {@link board.FixedState} object. + * @param p_attach_allowed a boolean. + * @return a {@link board.Via} object. + */ + public Via insert_via(Padstack p_padstack, Point p_center, int[] p_net_no_arr, int p_clearance_class, + FixedState p_fixed_state, boolean p_attach_allowed) + { + Via new_via = new Via(p_padstack, p_center, p_net_no_arr, p_clearance_class, 0, 0, p_fixed_state, + p_attach_allowed, this); + insert_item(new_via); + int from_layer = p_padstack.from_layer(); + int to_layer = p_padstack.to_layer(); + for (int i = from_layer; i < to_layer; ++i) + { + for (int curr_net_no : p_net_no_arr) + { + split_traces(p_center, i, curr_net_no); + } + } + return new_via; + } + + /** + * Inserts a pin into the board. + * p_pin_no is the number of this pin in the library package of its component (starting with 0). + * + * @param p_component_no a int. + * @param p_pin_no a int. + * @param p_net_no_arr an array of int. + * @param p_clearance_class a int. + * @param p_fixed_state a {@link board.FixedState} object. + * @return a {@link board.Pin} object. + */ + public Pin insert_pin(int p_component_no, int p_pin_no, int[] p_net_no_arr, int p_clearance_class, FixedState p_fixed_state) + { + Pin new_pin = new Pin(p_component_no, p_pin_no, p_net_no_arr, p_clearance_class, 0, p_fixed_state, this); + insert_item(new_pin); + return new_pin; + } + + /** + * Inserts an obstacle into the board , whose geometry is described + * by a polygonyal shape, which may have holes. + * If p_component_no != 0, the obstacle belongs to a component. + * + * @param p_area a {@link geometry.planar.Area} object. + * @param p_layer a int. + * @param p_clearance_class a int. + * @param p_fixed_state a {@link board.FixedState} object. + * @return a {@link board.ObstacleArea} object. + */ + public ObstacleArea insert_obstacle(Area p_area, int p_layer, int p_clearance_class, FixedState p_fixed_state) + { + if (p_area == null) + { + System.out.println("BasicBoard.insert_obstacle: p_area is null"); + return null; + } + ObstacleArea obs = new ObstacleArea(p_area, p_layer, Vector.ZERO, 0, false, p_clearance_class, 0, 0, null, p_fixed_state, this); + insert_item(obs); + return obs; + } + + /** + * Inserts an obstacle belonging to a component into the board + * p_name is to identify the corresponding ObstacstacleArea in the component package. + * + * @param p_area a {@link geometry.planar.Area} object. + * @param p_layer a int. + * @param p_translation a {@link geometry.planar.Vector} object. + * @param p_rotation_in_degree a double. + * @param p_side_changed a boolean. + * @param p_clearance_class a int. + * @param p_component_no a int. + * @param p_name a {@link java.lang.String} object. + * @param p_fixed_state a {@link board.FixedState} object. + * @return a {@link board.ObstacleArea} object. + */ + public ObstacleArea insert_obstacle(Area p_area, int p_layer, Vector p_translation, double p_rotation_in_degree, + boolean p_side_changed, int p_clearance_class, int p_component_no, String p_name, FixedState p_fixed_state) + { + if (p_area == null) + { + System.out.println("BasicBoard.insert_obstacle: p_area is null"); + return null; + } + ObstacleArea obs = new ObstacleArea(p_area, p_layer, p_translation, p_rotation_in_degree, p_side_changed, + p_clearance_class, 0, p_component_no, p_name, p_fixed_state, this); + insert_item(obs); + return obs; + } + + /** + * Inserts an via obstacle area into the board , whose geometry is described + * by a polygonyal shape, which may have holes. + * + * @param p_area a {@link geometry.planar.Area} object. + * @param p_layer a int. + * @param p_clearance_class a int. + * @param p_fixed_state a {@link board.FixedState} object. + * @return a {@link board.ViaObstacleArea} object. + */ + public ViaObstacleArea insert_via_obstacle(Area p_area, int p_layer, int p_clearance_class, + FixedState p_fixed_state) + { + if (p_area == null) + { + System.out.println("BasicBoard.insert_via_obstacle: p_area is null"); + return null; + } + ViaObstacleArea obs = new ViaObstacleArea(p_area, p_layer, Vector.ZERO, 0, false, + p_clearance_class, 0, 0, null, p_fixed_state, this); + insert_item(obs); + return obs; + } + + /** + * Inserts an via obstacle belonging to a component into the board + * p_name is to identify the corresponding ObstacstacleArea in the component package. + * + * @param p_area a {@link geometry.planar.Area} object. + * @param p_layer a int. + * @param p_translation a {@link geometry.planar.Vector} object. + * @param p_rotation_in_degree a double. + * @param p_side_changed a boolean. + * @param p_clearance_class a int. + * @param p_component_no a int. + * @param p_name a {@link java.lang.String} object. + * @param p_fixed_state a {@link board.FixedState} object. + * @return a {@link board.ViaObstacleArea} object. + */ + public ViaObstacleArea insert_via_obstacle(Area p_area, int p_layer, Vector p_translation, double p_rotation_in_degree, + boolean p_side_changed, int p_clearance_class, int p_component_no, String p_name, + FixedState p_fixed_state) + { + if (p_area == null) + { + System.out.println("BasicBoard.insert_via_obstacle: p_area is null"); + return null; + } + ViaObstacleArea obs = new ViaObstacleArea(p_area, p_layer, p_translation, p_rotation_in_degree, p_side_changed, + p_clearance_class, 0, p_component_no, p_name, p_fixed_state, this); + insert_item(obs); + return obs; + } + + /** + * Inserts a component obstacle area into the board , whose geometry is described + * by a polygonyal shape, which may have holes. + * + * @param p_area a {@link geometry.planar.Area} object. + * @param p_layer a int. + * @param p_clearance_class a int. + * @param p_fixed_state a {@link board.FixedState} object. + * @return a {@link board.ComponentObstacleArea} object. + */ + public ComponentObstacleArea insert_component_obstacle(Area p_area, int p_layer, + int p_clearance_class, FixedState p_fixed_state) + { + if (p_area == null) + { + System.out.println("BasicBoard.insert_component_obstacle: p_area is null"); + return null; + } + ComponentObstacleArea obs = new ComponentObstacleArea(p_area, p_layer, Vector.ZERO, 0, false, + p_clearance_class, 0, 0, null, p_fixed_state, this); + insert_item(obs); + return obs; + } + + /** + * Inserts a component obstacle belonging to a component into the board. + * p_name is to identify the corresponding ObstacstacleArea in the component package. + * + * @param p_area a {@link geometry.planar.Area} object. + * @param p_layer a int. + * @param p_translation a {@link geometry.planar.Vector} object. + * @param p_rotation_in_degree a double. + * @param p_side_changed a boolean. + * @param p_clearance_class a int. + * @param p_component_no a int. + * @param p_name a {@link java.lang.String} object. + * @param p_fixed_state a {@link board.FixedState} object. + * @return a {@link board.ComponentObstacleArea} object. + */ + public ComponentObstacleArea insert_component_obstacle(Area p_area, int p_layer, Vector p_translation, double p_rotation_in_degree, + boolean p_side_changed, int p_clearance_class, int p_component_no, String p_name, FixedState p_fixed_state) + { + if (p_area == null) + { + System.out.println("BasicBoard.insert_component_obstacle: p_area is null"); + return null; + } + ComponentObstacleArea obs = new ComponentObstacleArea(p_area, p_layer, p_translation, p_rotation_in_degree, p_side_changed, + p_clearance_class, 0, p_component_no, p_name, p_fixed_state, this); + insert_item(obs); + return obs; + } + + /** + * Inserts a component ouline into the board. + * + * @param p_area a {@link geometry.planar.Area} object. + * @param p_is_front a boolean. + * @param p_translation a {@link geometry.planar.Vector} object. + * @param p_rotation_in_degree a double. + * @param p_component_no a int. + * @param p_fixed_state a {@link board.FixedState} object. + * @return a {@link board.ComponentOutline} object. + */ + public ComponentOutline insert_component_outline(Area p_area, boolean p_is_front, Vector p_translation, double p_rotation_in_degree, + int p_component_no, FixedState p_fixed_state) + { + if (p_area == null) + { + System.out.println("BasicBoard.insert_component_outline: p_area is null"); + return null; + } + if (!p_area.is_bounded()) + { + System.out.println("BasicBoard.insert_component_outline: p_area is not bounded"); + return null; + } + ComponentOutline outline = new ComponentOutline(p_area, p_is_front, p_translation, p_rotation_in_degree, + p_component_no, p_fixed_state, this); + insert_item(outline); + return outline; + } + + /** + * Inserts a condution area into the board , whose geometry is described + * by a polygonyal shape, which may have holes. + * If p_is_obstacle is false, it is possible to route through the conduction area + * with traces and vias of foreign nets. + * + * @param p_area a {@link geometry.planar.Area} object. + * @param p_layer a int. + * @param p_net_no_arr an array of int. + * @param p_clearance_class a int. + * @param p_is_obstacle a boolean. + * @param p_fixed_state a {@link board.FixedState} object. + * @return a {@link board.ConductionArea} object. + */ + public ConductionArea insert_conduction_area(Area p_area, int p_layer, + int[] p_net_no_arr, int p_clearance_class, boolean p_is_obstacle, FixedState p_fixed_state) + { + if (p_area == null) + { + System.out.println("BasicBoard.insert_conduction_area: p_area is null"); + return null; + } + ConductionArea c = new ConductionArea(p_area, p_layer, Vector.ZERO, 0, false, p_net_no_arr, p_clearance_class, + 0, 0, null, p_is_obstacle, p_fixed_state, this); + insert_item(c); + return c; + } + + /** + * Inserts an Outline into the board. + * + * @param p_outline_shapes an array of {@link geometry.planar.PolylineShape} objects. + * @param p_clearance_class_no a int. + * @return a {@link board.BoardOutline} object. + */ + public BoardOutline insert_outline(PolylineShape[] p_outline_shapes, int p_clearance_class_no) + { + BoardOutline result = new BoardOutline(p_outline_shapes, p_clearance_class_no, 0, this); + insert_item(result); + return result; + } + + /** + * Returns the outline of the board. + * + * @return a {@link board.BoardOutline} object. + */ + public BoardOutline get_outline() + { + Iterator it = item_list.start_read_object(); + for (;;) + { + UndoableObjects.Storable curr_item = item_list.read_object(it); + if (curr_item == null) + { + break; + } + if (curr_item instanceof BoardOutline) + { + return (BoardOutline) curr_item; + } + } + return null; + } + + /** + * Removes an item from the board + * + * @param p_item a {@link board.Item} object. + */ + public void remove_item(Item p_item) + { + if (p_item == null) + { + return; + } + additional_update_after_change(p_item); // must be called before p_item is deleted. + search_tree_manager.remove(p_item); + item_list.delete(p_item); + + // let the observers syncronize the deletion + communication.observers.notify_deleted(p_item); + } + + /** + * looks, if an item with id_no p_id_no is on the board. + * Returns the found item or null, if no such item is found. + * + * @param p_id_no a int. + * @return a {@link board.Item} object. + */ + public Item get_item(int p_id_no) + { + Iterator it = item_list.start_read_object(); + for (;;) + { + Item curr_item = (Item) item_list.read_object(it); + if (curr_item == null) + { + break; + } + if (curr_item.get_id_no() == p_id_no) + { + return curr_item; + } + } + return null; + } + + /** + * Returns the list of all items on the board + * + * @return a {@link java.util.Collection} object. + */ + public Collection get_items() + { + Collection result = new LinkedList(); + Iterator it = item_list.start_read_object(); + for (;;) + { + Item curr_item = (Item) item_list.read_object(it); + if (curr_item == null) + { + break; + } + result.add(curr_item); + } + return result; + } + + /** + * Returns all connectable items on the board containing p_net_no + * + * @param p_net_no a int. + * @return a {@link java.util.Collection} object. + */ + public Collection get_connectable_items(int p_net_no) + { + Collection result = new LinkedList(); + Iterator it = item_list.start_read_object(); + for (;;) + { + Item curr_item = (Item) item_list.read_object(it); + if (curr_item == null) + { + break; + } + if (curr_item instanceof Connectable && curr_item.contains_net(p_net_no)) + { + result.add(curr_item); + } + } + return result; + } + + /** + * Returns the count of connectable items of the net with number p_net_no + * + * @param p_net_no a int. + * @return a int. + */ + public int connectable_item_count(int p_net_no) + { + int result = 0; + Iterator it = item_list.start_read_object(); + for (;;) + { + Item curr_item = (Item) item_list.read_object(it); + if (curr_item == null) + { + break; + } + if (curr_item instanceof Connectable && curr_item.contains_net(p_net_no)) + { + ++result; + } + } + return result; + } + + /** + * Returns all items with the input component number + * + * @param p_component_no a int. + * @return a {@link java.util.Collection} object. + */ + public Collection get_component_items(int p_component_no) + { + Collection result = new LinkedList(); + Iterator it = item_list.start_read_object(); + for (;;) + { + Item curr_item = (Item) item_list.read_object(it); + if (curr_item == null) + { + break; + } + if (curr_item.get_component_no() == p_component_no) + { + result.add(curr_item); + } + } + return result; + } + + /** + * Returns all pins with the input component number + * + * @param p_component_no a int. + * @return a {@link java.util.Collection} object. + */ + public Collection get_component_pins(int p_component_no) + { + Collection result = new LinkedList(); + Iterator it = item_list.start_read_object(); + for (;;) + { + Item curr_item = (Item) item_list.read_object(it); + if (curr_item == null) + { + break; + } + if (curr_item.get_component_no() == p_component_no && curr_item instanceof Pin) + { + result.add((Pin) curr_item); + } + } + return result; + } + + /** + * Returns the pin with the input component number and pin number, or null, if no such pinn exists. + * + * @param p_component_no a int. + * @param p_pin_no a int. + * @return a {@link board.Pin} object. + */ + public Pin get_pin(int p_component_no, int p_pin_no) + { + Iterator it = item_list.start_read_object(); + for (;;) + { + Item curr_item = (Item) item_list.read_object(it); + if (curr_item == null) + { + break; + } + if (curr_item.get_component_no() == p_component_no && curr_item instanceof Pin) + { + Pin curr_pin = (Pin) curr_item; + if (curr_pin.pin_no == p_pin_no) + { + return curr_pin; + } + } + } + return null; + } + + /** + * Removes the items in p_item_list. + * Returns false, if some items could not be removed, bcause they are fixed. + * + * @param p_item_list a {@link java.util.Collection} object. + * @param p_with_delete_fixed a boolean. + * @return a boolean. + */ + public boolean remove_items(Collection p_item_list, boolean p_with_delete_fixed) + { + boolean result = true; + Iterator it = p_item_list.iterator(); + while (it.hasNext()) + { + Item curr_item = it.next(); + if (!p_with_delete_fixed && curr_item.is_delete_fixed() || curr_item.is_user_fixed()) + { + result = false; + } + else + { + remove_item(curr_item); + } + } + return result; + } + + /** + * Returns the list of all conduction areas on the board + * + * @return a {@link java.util.Collection} object. + */ + public Collection get_conduction_areas() + { + Collection result = new LinkedList(); + Iterator it = item_list.start_read_object(); + for (;;) + { + UndoableObjects.Storable curr_item = item_list.read_object(it); + if (curr_item == null) + { + break; + } + if (curr_item instanceof ConductionArea) + { + result.add((ConductionArea) curr_item); + } + } + return result; + } + + /** + * Returns the list of all pins on the board + * + * @return a {@link java.util.Collection} object. + */ + public Collection get_pins() + { + Collection result = new LinkedList(); + Iterator it = item_list.start_read_object(); + for (;;) + { + UndoableObjects.Storable curr_item = item_list.read_object(it); + if (curr_item == null) + { + break; + } + if (curr_item instanceof Pin) + { + result.add((Pin) curr_item); + } + } + return result; + } + + /** + * Returns the list of all pins on the board with only 1 layer + * + * @return a {@link java.util.Collection} object. + */ + public Collection get_smd_pins() + { + Collection result = new LinkedList(); + Iterator it = item_list.start_read_object(); + for (;;) + { + UndoableObjects.Storable curr_item = item_list.read_object(it); + if (curr_item == null) + { + break; + } + if (curr_item instanceof Pin) + { + Pin curr_pin = (Pin) curr_item; + if (curr_pin.first_layer() == curr_pin.last_layer()) + { + result.add(curr_pin); + } + } + } + return result; + } + + /** + * Returns the list of all vias on the board + * + * @return a {@link java.util.Collection} object. + */ + public Collection get_vias() + { + Collection result = new LinkedList(); + Iterator it = item_list.start_read_object(); + for (;;) + { + UndoableObjects.Storable curr_item = item_list.read_object(it); + if (curr_item == null) + { + break; + } + if (curr_item instanceof Via) + { + result.add((Via) curr_item); + } + } + return result; + } + + /** + * Returns the list of all traces on the board + * + * @return a {@link java.util.Collection} object. + */ + public Collection get_traces() + { + Collection result = new LinkedList(); + Iterator it = item_list.start_read_object(); + for (;;) + { + UndoableObjects.Storable curr_item = item_list.read_object(it); + if (curr_item == null) + { + break; + } + if (curr_item instanceof Trace) + { + result.add((Trace) curr_item); + } + } + return result; + } + + /** + * Returns the cumulative length of all traces on the board + * + * @return a double. + */ + public double cumulative_trace_length() + { + double result = 0; + Iterator it = item_list.start_read_object(); + for (;;) + { + UndoableObjects.Storable curr_item = item_list.read_object(it); + if (curr_item == null) + { + break; + } + if (curr_item instanceof Trace) + { + result += ((Trace) curr_item).get_length(); + } + } + return result; + } + + /** + * Combines the connected traces of this net, which have only 1 contact + * at the connection point. + * + * {@code if p_net_no < 0 traces of all nets are combined.} + * + * @param p_net_no a int. + * @return a boolean. + */ + public boolean combine_traces(int p_net_no) + { + boolean result = false; + boolean something_changed = true; + while (something_changed) + { + something_changed = false; + Iterator it = item_list.start_read_object(); + for (;;) + { + Item curr_item = (Item) item_list.read_object(it); + if (curr_item == null) + { + break; + } + if ((p_net_no < 0 || curr_item.contains_net(p_net_no)) && curr_item instanceof Trace && curr_item.is_on_the_board()) + { + if (((Trace) curr_item).combine()) + { + something_changed = true; + result = true; + break; + } + } + } + } + return result; + } + + /** + * Normalizes the traces of this net + * + * @param p_net_no a int. + * @return a boolean. + */ + public boolean normalize_traces(int p_net_no) + { + boolean result = false; + boolean something_changed = true; + Item curr_item = null; + while (something_changed) + { + something_changed = false; + Iterator it = item_list.start_read_object(); + for (;;) + { + try + { + curr_item = (Item) item_list.read_object(it); + } + catch (java.util.ConcurrentModificationException e) + { + something_changed = true; + break; + } + if (curr_item == null) + { + break; + } + if (curr_item.contains_net(p_net_no) && curr_item instanceof PolylineTrace && curr_item.is_on_the_board()) + { + PolylineTrace curr_trace = (PolylineTrace) curr_item; + if (curr_trace.normalize(null)) + { + something_changed = true; + result = true; + } + else if (!curr_trace.is_user_fixed() && this.remove_if_cycle(curr_trace)) + { + something_changed = true; + result = true; + } + } + } + } + return result; + } + + /** + * Looks for traces of the input net on the input layer, so that p_location is on the trace polygon, + * and splits these traces. Returns false, if no trace was split. + * + * @param p_location a {@link geometry.planar.Point} object. + * @param p_layer a int. + * @param p_net_no a int. + * @return a boolean. + */ + public boolean split_traces(Point p_location, int p_layer, int p_net_no) + { + ItemSelectionFilter filter = new ItemSelectionFilter(ItemSelectionFilter.SelectableChoices.TRACES); + Collection picked_items = this.pick_items(p_location, p_layer, filter); + IntOctagon location_shape = TileShape.get_instance(p_location).bounding_octagon(); + boolean trace_split = false; + for (Item curr_item : picked_items) + { + Trace curr_trace = (Trace) curr_item; + if (curr_trace.contains_net(p_net_no)) + { + Collection split_pieces = curr_trace.split(location_shape); + if (split_pieces.size() != 1) + { + trace_split = true; + } + } + } + return trace_split; + } + + /** + * Returs a Collection of Collections of items forming a connected set. + * + * @param p_net_no a int. + * @return a {@link java.util.Collection} object. + */ + public Collection> get_connected_sets(int p_net_no) + { + Collection> result = new LinkedList>(); + if (p_net_no <= 0) + { + return result; + } + SortedSet items_to_handle = new TreeSet(); + Iterator it = this.item_list.start_read_object(); + for (;;) + { + Item curr_item = (Item) item_list.read_object(it); + if (curr_item == null) + { + break; + } + if (curr_item instanceof Connectable && curr_item.contains_net(p_net_no)) + { + items_to_handle.add(curr_item); + } + } + Iterator it2 = items_to_handle.iterator(); + while (it2.hasNext()) + { + Item curr_item = it2.next(); + Collection next_connected_set = curr_item.get_connected_set(p_net_no); + result.add(next_connected_set); + items_to_handle.removeAll(next_connected_set); + it2 = items_to_handle.iterator(); + } + return result; + } + + /** + * Returns all SearchTreeObjects on layer p_layer, which overlap with p_shape. + * {@code If p_layer < 0, the layer is ignored} + * + * @param p_shape a {@link geometry.planar.ConvexShape} object. + * @param p_layer a int. + * @return a {@link java.util.Set} object. + */ + public Set overlapping_objects(ConvexShape p_shape, int p_layer) + { + return this.search_tree_manager.get_default_tree().overlapping_objects(p_shape, p_layer); + } + + /** + * Returns items, which overlap with p_shape on layer p_layer + * inclusive clearance. + * p_clearance_class is the index in the clearance matrix, + * which describes the required clearance restrictions to other items. + * The function may also return items, which are nearly overlapping, + * but do not overlap with exact calculation. + * {@code If p_layer < 0, the layer is ignored.} + * + * @param p_shape a {@link geometry.planar.ConvexShape} object. + * @param p_layer a int. + * @param p_ignore_net_nos an array of int. + * @param p_clearance_class a int. + * @return a {@link java.util.Set} object. + */ + public Set overlapping_items_with_clearance(ConvexShape p_shape, int p_layer, int[] p_ignore_net_nos, + int p_clearance_class) + { + ShapeSearchTree default_tree = this.search_tree_manager.get_default_tree(); + return default_tree.overlapping_items_with_clearance(p_shape, p_layer, p_ignore_net_nos, p_clearance_class); + } + + /** + * Returns all items on layer p_layer, which overlap with p_area. + * {@code If p_layer < 0, the layer is ignored} + * + * @param p_area a {@link geometry.planar.Area} object. + * @param p_layer a int. + * @return a {@link java.util.Set} object. + */ + public Set overlapping_items(Area p_area, int p_layer) + { + Set result = new TreeSet(); + TileShape[] tile_shapes = p_area.split_to_convex(); + for (int i = 0; i < tile_shapes.length; ++i) + { + Set curr_overlaps = overlapping_objects(tile_shapes[i], p_layer); + for (SearchTreeObject curr_overlap : curr_overlaps) + { + if (curr_overlap instanceof Item) + { + result.add((Item) curr_overlap); + } + } + } + return result; + } + + /** + * Checks, if the an object with shape p_shape and net nos p_net_no_arr + * and clearance class p_cl_class can be inserted on layer p_layer + * without clearance violation. + * + * @param p_shape a {@link geometry.planar.Area} object. + * @param p_layer a int. + * @param p_net_no_arr an array of int. + * @param p_cl_class a int. + * @return a boolean. + */ + public boolean check_shape(Area p_shape, int p_layer, int[] p_net_no_arr, int p_cl_class) + { + TileShape[] tiles = p_shape.split_to_convex(); + ShapeSearchTree default_tree = this.search_tree_manager.get_default_tree(); + for (int i = 0; i < tiles.length; ++i) + { + TileShape curr_shape = tiles[i]; + if (!curr_shape.is_contained_in(bounding_box)) + { + return false; + } + Set obstacles = new TreeSet(); + default_tree.overlapping_objects_with_clearance(curr_shape, p_layer, + p_net_no_arr, p_cl_class, obstacles); + for (SearchTreeObject curr_ob : obstacles) + { + boolean is_obstacle = true; + for (int j = 0; j < p_net_no_arr.length; ++j) + { + if (!curr_ob.is_obstacle(p_net_no_arr[j])) + { + is_obstacle = false; + } + } + if (is_obstacle) + { + return false; + } + } + } + return true; + } + + /** + * Checks, if the a trace line with shape p_shape and net numbers p_net_no_arr + * and clearance class p_cl_class can be inserted on layer p_layer + * without clearance violation. + * If p_contact_pins != null, all pins not contained in p_contact_pins are + * regarded as obstacles, even if they are of the own net. + * + * @param p_shape a {@link geometry.planar.TileShape} object. + * @param p_layer a int. + * @param p_net_no_arr an array of int. + * @param p_cl_class a int. + * @param p_contact_pins a {@link java.util.Set} object. + * @return a boolean. + */ + public boolean check_trace_shape(TileShape p_shape, int p_layer, int[] p_net_no_arr, + int p_cl_class, Set p_contact_pins) + { + if (!p_shape.is_contained_in(bounding_box)) + { + return false; + } + ShapeSearchTree default_tree = this.search_tree_manager.get_default_tree(); + Collection tree_entries = new LinkedList(); + int[] ignore_net_nos = new int[0]; + if (default_tree.is_clearance_compensation_used()) + { + default_tree.overlapping_tree_entries(p_shape, p_layer, ignore_net_nos, tree_entries); + } + else + { + default_tree.overlapping_tree_entries_with_clearance(p_shape, p_layer, ignore_net_nos, p_cl_class, tree_entries); + } + for (TreeEntry curr_tree_entry : tree_entries) + { + if (!(curr_tree_entry.object instanceof Item)) + { + continue; + } + Item curr_item = (Item) curr_tree_entry.object; + if (p_contact_pins != null) + { + if (p_contact_pins.contains(curr_item)) + { + continue; + } + if (curr_item instanceof Pin) + { + // The contact pins of the trace should be contained in p_ignore_items. + // Other pins are handled as obstacles to avoid acid traps. + return false; + } + } + boolean is_obstacle = true; + for (int i = 0; i < p_net_no_arr.length; ++i) + { + if (!curr_item.is_trace_obstacle(p_net_no_arr[i])) + { + is_obstacle = false; + } + } + if (is_obstacle && (curr_item instanceof PolylineTrace) && p_contact_pins != null) + { + // check for traces of foreign nets at tie pins, which will be ignored inside the pin shape + TileShape intersection = null; + for (Pin curr_contact_pin : p_contact_pins) + { + if (curr_contact_pin.net_count() <= 1 || !curr_contact_pin.shares_net(curr_item)) + { + continue; + } + if (intersection == null) + { + TileShape obstacle_trace_shape = curr_item.get_tile_shape(curr_tree_entry.shape_index_in_object); + intersection = p_shape.intersection(obstacle_trace_shape); + } + TileShape pin_shape = curr_contact_pin.get_tile_shape_on_layer(p_layer); + if (pin_shape.contains_approx(intersection)) + { + is_obstacle = false; + break; + } + } + } + if (is_obstacle) + { + return false; + } + } + return true; + } + + /** + * Checks, if a polyline trace with the input parameters can be inserted + * without clearance violations + * + * @param p_polyline a {@link geometry.planar.Polyline} object. + * @param p_layer a int. + * @param p_pen_half_width a int. + * @param p_net_no_arr an array of int. + * @param p_clearance_class a int. + * @return a boolean. + */ + public boolean check_polyline_trace(Polyline p_polyline, int p_layer, int p_pen_half_width, + int[] p_net_no_arr, int p_clearance_class) + { + Trace tmp_trace = + new PolylineTrace(p_polyline, p_layer, p_pen_half_width, p_net_no_arr, p_clearance_class, 0, 0, FixedState.UNFIXED, this); + Set contact_pins = tmp_trace.touching_pins_at_end_corners(); + for (int i = 0; i < tmp_trace.tile_shape_count(); ++i) + { + if (!this.check_trace_shape(tmp_trace.get_tile_shape(i), p_layer, p_net_no_arr, + p_clearance_class, contact_pins)) + { + return false; + } + } + return true; + } + + /** + * Returns the layer count of this board. + * + * @return a int. + */ + public int get_layer_count() + { + return layer_structure.arr.length; + } + + /** + * Draws all items of the board on their visible layers. Called in the overwritten + * paintComponent method of a class derived from JPanel. + * The value of p_layer_visibility is expected between 0 and 1 for each layer. + * + * @param p_graphics a {@link java.awt.Graphics} object. + * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object. + * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object. + */ + public void draw(Graphics p_graphics, GraphicsContext p_graphics_context) + { + if (p_graphics_context == null) + { + return; + } + + // draw all items on the board + for (int curr_priority = Drawable.MIN_DRAW_PRIORITY; curr_priority <= Drawable.MIDDLE_DRAW_PRIORITY; ++curr_priority) + { + Iterator it = item_list.start_read_object(); + for (;;) + { + try + { + Item curr_item = (Item) item_list.read_object(it); + if (curr_item == null) + { + break; + } + if (curr_item.get_draw_priority() == curr_priority) + { + curr_item.draw(p_graphics, p_graphics_context); + } + } + catch (java.util.ConcurrentModificationException e) + { + // may happen when window are changed interactively while running a logfile + return; + } + } + } + } + + /** + * Returns the list of items on the board, whose shape on layer p_layer contains the point at p_location. + * {@code If p_layer < 0, the layer is ignored. + * If p_item_selection_filter != null, only items of types selected by the filter are picked.} + * + * @param p_location a {@link geometry.planar.Point} object. + * @param p_layer a int. + * @param p_filter a {@link board.ItemSelectionFilter} object. + * @return a {@link java.util.Set} object. + */ + public Set pick_items(Point p_location, int p_layer, ItemSelectionFilter p_filter) + { + TileShape point_shape = TileShape.get_instance(p_location); + Collection overlaps = overlapping_objects(point_shape, p_layer); + Set result = new TreeSet(); + for (SearchTreeObject curr_object : overlaps) + { + if (curr_object instanceof Item) + { + result.add((Item) curr_object); + } + } + if (p_filter != null) + { + result = p_filter.filter(result); + } + return result; + } + + /** + * checks, if p_point is contained in the bounding box of this board. + * + * @param p_point a {@link geometry.planar.Point} object. + * @return a boolean. + */ + public boolean contains(Point p_point) + { + return p_point.is_contained_in(bounding_box); + } + + /** + * Returns the minimum clearance requested between items of + * clearance class p_class_1 and p_class_2. + * p_class_1 and p_class_2 are indices in the clearance matrix. + * + * @param p_class_1 a int. + * @param p_class_2 a int. + * @param p_layer a int. + * @return a int. + */ + public int clearance_value(int p_class_1, int p_class_2, int p_layer) + { + if (rules == null || rules.clearance_matrix == null) + { + return 0; + } + return rules.clearance_matrix.value(p_class_1, p_class_2, p_layer); + } + + /** + * returns the biggest half width of all traces on the board. + * + * @return a int. + */ + public int get_max_trace_half_width() + { + return max_trace_half_width; + } + + /** + * returns the smallest half width of all traces on the board. + * + * @return a int. + */ + public int get_min_trace_half_width() + { + return min_trace_half_width; + } + + /** + * Returns a surrounding box of the geometry of this board + * + * @return a {@link geometry.planar.IntBox} object. + */ + public IntBox get_bounding_box() + { + return bounding_box; + } + + /** + * Returns a box containing all items in p_item_list. + * + * @param p_item_list a {@link java.util.Collection} object. + * @return a {@link geometry.planar.IntBox} object. + */ + public IntBox get_bounding_box(Collection p_item_list) + { + IntBox result = IntBox.EMPTY; + for (Item curr_item : p_item_list) + { + result = result.union(curr_item.bounding_box()); + } + return result; + } + + /** + * Resets the rectangle, where a graphics update is needed. + */ + public void reset_graphics_update_box() + { + update_box = IntBox.EMPTY; + } + + /** + * Gets the rectancle, where a graphics update is needed on the screen. + * + * @return a {@link geometry.planar.IntBox} object. + */ + public IntBox get_graphics_update_box() + { + return update_box; + } + + /** + * enlarges the graphics update box, so that it contains p_box + * + * @param p_box a {@link geometry.planar.IntBox} object. + */ + public void join_graphics_update_box(IntBox p_box) + { + if (update_box == null) + { + reset_graphics_update_box(); + } + update_box = update_box.union(p_box); + } + + /** + * starts notifying the observers of any change in the objects list + */ + public void start_notify_observers() + { + if (this.communication.observers != null) + { + communication.observers.activate(); + } + } + + /** + * ends notifying the observers of changes in the objects list + */ + public void end_notify_observers() + { + if (this.communication.observers != null) + { + communication.observers.deactivate(); + } + } + + /** + * Returns, if the observer of the board items is activated. + * + * @return a boolean. + */ + public boolean observers_active() + { + boolean result; + if (this.communication.observers != null) + { + result = communication.observers.is_active(); + } + else + { + result = false; + } + return result; + } + + /** + * Turns an obstacle area into a conduction area with net number p_net_no + * If it is convex and has no holes, it is turned into a Pin, + * alse into a conduction area. + * + * @param p_area a {@link board.ObstacleArea} object. + * @param p_net_no a int. + * @return a {@link board.Connectable} object. + */ + public Connectable make_conductive(ObstacleArea p_area, int p_net_no) + { + Item new_item; + Area curr_area = p_area.get_relative_area(); + int layer = p_area.get_layer(); + FixedState fixed_state = p_area.get_fixed_state(); + Vector translation = p_area.get_translation(); + double rotation = p_area.get_rotation_in_degree(); + boolean side_changed = p_area.get_side_changed(); + int[] net_no_arr = new int[1]; + net_no_arr[0] = p_net_no; + new_item = new ConductionArea(curr_area, layer, translation, rotation, side_changed, net_no_arr, + p_area.clearance_class_no(), 0, p_area.get_component_no(), p_area.name, true, fixed_state, this); + remove_item(p_area); + insert_item(new_item); + return (Connectable) new_item; + } + + /** + * Inserts an item into the board data base + * + * @param p_item a {@link board.Item} object. + */ + public void insert_item(Item p_item) + { + if (p_item == null) + { + return; + } + + if (rules == null || rules.clearance_matrix == null || p_item.clearance_class_no() < 0 || + p_item.clearance_class_no() >= rules.clearance_matrix.get_class_count()) + { + System.out.println("LayeredBoard.insert_item: clearance_class no out of range"); + p_item.set_clearance_class_no(0); + } + p_item.board = this; + item_list.insert(p_item); + search_tree_manager.insert(p_item); + communication.observers.notify_new(p_item); + additional_update_after_change(p_item); + } + + /** + * Stub function overwritten in class RoutingBoard to maintain the autorouter database if necessesary. + * + * @param p_item a {@link board.Item} object. + */ + public void additional_update_after_change(Item p_item) + { + } + + /** + * Restores the sitiation at the previous snapshot. + * Returns false, if no more undo is possible. + * Puts the numbers of the changed nets into the set p_changed_nets, if p_changed_nets != null + * + * @param p_changed_nets a {@link java.util.Set} object. + * @return a boolean. + */ + public boolean undo(Set p_changed_nets) + { + this.components.undo(this.communication.observers); + Collection cancelled_objects = new LinkedList(); + Collection restored_objects = new LinkedList(); + boolean result = item_list.undo(cancelled_objects, restored_objects); + // update the search trees + Iterator it = cancelled_objects.iterator(); + while (it.hasNext()) + { + Item curr_item = (Item) it.next(); + search_tree_manager.remove(curr_item); + + // let the observers syncronize the deletion + communication.observers.notify_deleted(curr_item); + if (p_changed_nets != null) + { + for (int i = 0; i < curr_item.net_count(); ++i) + { + p_changed_nets.add(new Integer(curr_item.get_net_no(i))); + } + } + } + it = restored_objects.iterator(); + while (it.hasNext()) + { + Item curr_item = (Item) it.next(); + curr_item.board = this; + search_tree_manager.insert(curr_item); + curr_item.clear_autoroute_info(); + // let the observers know the insertion + communication.observers.notify_new(curr_item); + if (p_changed_nets != null) + { + for (int i = 0; i < curr_item.net_count(); ++i) + { + p_changed_nets.add(new Integer(curr_item.get_net_no(i))); + } + } + } + return result; + } + + /** + * Restores the sitiation before the last undo. + * Returns false, if no more redo is possible. + * Puts the numbers of the changed nets into the set p_changed_nets, if p_changed_nets != null + * + * @param p_changed_nets a {@link java.util.Set} object. + * @return a boolean. + */ + public boolean redo(Set p_changed_nets) + { + this.components.redo(this.communication.observers); + Collection cancelled_objects = new LinkedList(); + Collection restored_objects = new LinkedList(); + boolean result = item_list.redo(cancelled_objects, restored_objects); + // update the search trees + Iterator it = cancelled_objects.iterator(); + while (it.hasNext()) + { + Item curr_item = (Item) it.next(); + search_tree_manager.remove(curr_item); + // let the observers syncronize the deletion + communication.observers.notify_deleted(curr_item); + if (p_changed_nets != null) + { + for (int i = 0; i < curr_item.net_count(); ++i) + { + p_changed_nets.add(curr_item.get_net_no(i)); + } + } + } + it = restored_objects.iterator(); + while (it.hasNext()) + { + Item curr_item = (Item) it.next(); + curr_item.board = this; + search_tree_manager.insert(curr_item); + curr_item.clear_autoroute_info(); + // let the observers know the insertion + communication.observers.notify_new(curr_item); + if (p_changed_nets != null) + { + for (int i = 0; i < curr_item.net_count(); ++i) + { + p_changed_nets.add(curr_item.get_net_no(i)); + } + } + } + return result; + } + + /** + * Makes the current board situation restorable by undo. + */ + public void generate_snapshot() + { + item_list.generate_snapshot(); + components.generate_snapshot(); + } + + /** + * Removes the top snapshot from the undo stack, so that its situation cannot be + * restored any more. + * Returns false, if no more snapshot could be popped. + * + * @return a boolean. + */ + public boolean pop_snapshot() + { + return item_list.pop_snapshot(); + } + + /** + * Looks if at the input position ends a trace with the input net number, + * which has no normal contact at that position. + * Returns null, if no tail is found. + * + * @param p_location a {@link geometry.planar.Point} object. + * @param p_layer a int. + * @param p_net_no_arr an array of int. + * @return a {@link board.Trace} object. + */ + public Trace get_trace_tail(Point p_location, int p_layer, int[] p_net_no_arr) + { + TileShape point_shape = TileShape.get_instance(p_location); + Collection found_items = overlapping_objects(point_shape, p_layer); + Iterator it = found_items.iterator(); + while (it.hasNext()) + { + SearchTreeObject curr_ob = it.next(); + if (curr_ob instanceof Trace) + { + Trace curr_trace = (Trace) curr_ob; + if (!curr_trace.nets_equal(p_net_no_arr)) + { + continue; + } + if (curr_trace.first_corner().equals(p_location)) + { + Collection contacts = curr_trace.get_start_contacts(); + if (contacts.size() == 0) + { + return curr_trace; + } + } + if (curr_trace.last_corner().equals(p_location)) + { + Collection contacts = curr_trace.get_end_contacts(); + if (contacts.size() == 0) + { + return curr_trace; + } + } + } + } + return null; + } + + /** + * Checks, if p_item item is part of a cycle and remuve it + * together with its connection in this case. + * + * @param p_trace a {@link board.Trace} object. + * @return a boolean. + */ + public boolean remove_if_cycle(Trace p_trace) + { + if (!p_trace.is_on_the_board()) + { + return false; + } + if (!p_trace.is_cycle()) + { + return false; + } + // Remove tails at the endpoints after removing the cycle, + // if there was no tail before. + boolean[] tail_at_endpoint_before = null; + Point[] end_corners = null; + int curr_layer = p_trace.get_layer(); + int[] curr_net_no_arr = p_trace.net_no_arr; + end_corners = new Point[2]; + end_corners[0] = p_trace.first_corner(); + end_corners[1] = p_trace.last_corner(); + tail_at_endpoint_before = new boolean[2]; + for (int i = 0; i < 2; ++i) + { + Trace tail = + get_trace_tail(end_corners[i], curr_layer, curr_net_no_arr); + tail_at_endpoint_before[i] = (tail != null); + } + Set connection_items = p_trace.get_connection_items(); + this.remove_items(connection_items, false); + for (int i = 0; i < 2; ++i) + { + if (!tail_at_endpoint_before[i]) + { + Trace tail = get_trace_tail(end_corners[i], curr_layer, curr_net_no_arr); + if (tail != null) + { + remove_items(tail.get_connection_items(), false); + } + } + } + return true; + } + + /** + * If != RELEASE_VERSION,, some features may be used, which are still in experimental state. + * Also warnings for debugging may be printed depending on the test_level. + * + * @return a {@link board.TestLevel} object. + */ + public TestLevel get_test_level() + { + return this.test_level; + } + + /** + * Only to be used in BoardHandling.read_design. + * + * @param p_value a {@link board.TestLevel} object. + */ + public void set_test_level(TestLevel p_value) + { + this.test_level = p_value; + } + + private void readObject(java.io.ObjectInputStream p_stream) + throws java.io.IOException, java.lang.ClassNotFoundException + { + p_stream.defaultReadObject(); + // insert the items on the board into the search trees + search_tree_manager = new SearchTreeManager(this); + Iterator it = this.get_items().iterator(); + while (it.hasNext()) + { + Item curr_item = it.next(); + curr_item.board = this; + search_tree_manager.insert(curr_item); + } + } + /** + * List of items inserted into this board + */ + public final UndoableObjects item_list; + /** List of placed components on the board. */ + public final Components components; + /** + * Class defining the rules for items to be inserted into this board. + * Contains for example the clearance matrix. + */ + public final BoardRules rules; + /** + * The library containing pastack masks, packagages and other + * templates used on the board. + */ + public final BoardLibrary library; + /** + * The layer structure of this board. + */ + public final LayerStructure layer_structure; + /** + * Handels the search trees pointing into the items of this board + */ + public transient SearchTreeManager search_tree_manager; + /** + * For communication with a host system or host design file formats. + */ + public final Communication communication; + /** + * bounding orthogonal rectangle of this board + */ + public final IntBox bounding_box; + /** + * If test_level != RELEASE_VERSION, some features may be used, which are still in experimental state. + * Also warnings for debugging may be printed depending on the size of test_level. + */ + transient private TestLevel test_level; + /** the rectangle, where the graphics may be not uptodate */ + transient private IntBox update_box = IntBox.EMPTY; + /** + * the biggest half width of all traces on the board + */ + private int max_trace_half_width = 1000; + /** + * the smallest half width of all traces on the board + */ + private int min_trace_half_width = 10000; + /** + * Limits the maximum width of a shape in the search tree. + */ +} diff --git a/board/BoardObserverAdaptor.java b/src/main/java/board/BoardObserverAdaptor.java similarity index 87% rename from board/BoardObserverAdaptor.java rename to src/main/java/board/BoardObserverAdaptor.java index ac5740b..d9c183a 100644 --- a/board/BoardObserverAdaptor.java +++ b/src/main/java/board/BoardObserverAdaptor.java @@ -1,89 +1,100 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * BoardObserverAdaptor.java - * - * Created on 20. September 2007, 07:44 - * - */ - -package board; - -/** - * Empty adaptor implementing the BoardObservers interface. - * - * @author Alfons Wirtz - */ -public class BoardObserverAdaptor implements BoardObservers -{ - /** - * Tell the observers the deletion p_object. - */ - public void notify_deleted(Item p_item) - { - - } - - /** - * Notify the observers, that they can syncronize the changes on p_object. - */ - public void notify_changed(Item p_item) - { - - } - - /** - * Enable the observers to syncronize the new created item. - */ - public void notify_new(Item p_item) - { - - } - - /** - * Enable the observers to syncronize the moved component. - */ - public void notify_moved(Component p_component) - { - - } - - /** - * activate the observers - */ - public void activate() - { - active = true; - } - - /** - * Deactivate the observers. - **/ - public void deactivate() - { - active = false; - } - - /** - * Returns, if the observer is activated. - */ - public boolean is_active() - { - return active; - } - - private boolean active = false; - -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * BoardObserverAdaptor.java + * + * Created on 20. September 2007, 07:44 + * + */ + +package board; + +/** + * Empty adaptor implementing the BoardObservers interface. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class BoardObserverAdaptor implements BoardObservers +{ + /** + * Tell the observers the deletion p_object. + * + * @param p_item a {@link board.Item} object. + */ + public void notify_deleted(Item p_item) + { + + } + + /** + * Notify the observers, that they can syncronize the changes on p_object. + * + * @param p_item a {@link board.Item} object. + */ + public void notify_changed(Item p_item) + { + + } + + /** + * Enable the observers to syncronize the new created item. + * + * @param p_item a {@link board.Item} object. + */ + public void notify_new(Item p_item) + { + + } + + /** + * {@inheritDoc} + * + * Enable the observers to syncronize the moved component. + */ + public void notify_moved(Component p_component) + { + + } + + /** + * activate the observers + */ + public void activate() + { + active = true; + } + + /** + * Deactivate the observers. + */ + public void deactivate() + { + active = false; + } + + /** + * Returns, if the observer is activated. + * + * @return a boolean. + */ + public boolean is_active() + { + return active; + } + + private boolean active = false; + +} diff --git a/board/BoardObservers.java b/src/main/java/board/BoardObservers.java similarity index 88% rename from board/BoardObservers.java rename to src/main/java/board/BoardObservers.java index 6ab4896..c6a5f97 100644 --- a/board/BoardObservers.java +++ b/src/main/java/board/BoardObservers.java @@ -1,36 +1,40 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * BoardObservers.java - * - * Created on 20. September 2007, 07:39 - * - */ - -package board; - -import datastructures.Observers; - -/** - * - * @author alfons - */ -public interface BoardObservers extends Observers -{ - /** - * Enable the observers to syncronize the moved component. - */ - public void notify_moved(Component p_component); -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * BoardObservers.java + * + * Created on 20. September 2007, 07:39 + * + */ + +package board; + +import datastructures.Observers; + +/** + *

BoardObservers interface.

+ * + * @author alfons + * @version $Id: $Id + */ +public interface BoardObservers extends Observers +{ + /** + * Enable the observers to syncronize the moved component. + * + * @param p_component a {@link board.Component} object. + */ + public void notify_moved(Component p_component); +} diff --git a/board/BoardOutline.java b/src/main/java/board/BoardOutline.java similarity index 87% rename from board/BoardOutline.java rename to src/main/java/board/BoardOutline.java index 5b91901..14bdff7 100644 --- a/board/BoardOutline.java +++ b/src/main/java/board/BoardOutline.java @@ -35,17 +35,30 @@ * Class describing a board outline. * * @author alfons + * @version $Id: $Id */ public class BoardOutline extends Item implements java.io.Serializable { - /** Creates a new instance of BoardOutline */ + /** + * Creates a new instance of BoardOutline + * + * @param p_shapes an array of {@link geometry.planar.PolylineShape} objects. + * @param p_clearance_class_no a int. + * @param p_id_no a int. + * @param p_board a {@link board.BasicBoard} object. + */ public BoardOutline(PolylineShape[] p_shapes, int p_clearance_class_no, int p_id_no, BasicBoard p_board) { super(new int[0], p_clearance_class_no, p_id_no, 0, FixedState.SYSTEM_FIXED, p_board); shapes = p_shapes; } + /** + *

tile_shape_count.

+ * + * @return a int. + */ public int tile_shape_count() { int result; @@ -69,6 +82,7 @@ public int tile_shape_count() return result; } + /** {@inheritDoc} */ public int shape_layer(int p_index) { int shape_count = this.tile_shape_count(); @@ -88,11 +102,22 @@ public int shape_layer(int p_index) return result; } + /** + *

is_obstacle.

+ * + * @param p_other a {@link board.Item} object. + * @return a boolean. + */ public boolean is_obstacle(Item p_other) { return !(p_other instanceof BoardOutline || p_other instanceof ObstacleArea); } + /** + *

bounding_box.

+ * + * @return a {@link geometry.planar.IntBox} object. + */ public IntBox bounding_box() { IntBox result = IntBox.EMPTY; @@ -103,21 +128,33 @@ public IntBox bounding_box() return result; } + /** + *

first_layer.

+ * + * @return a int. + */ public int first_layer() { return 0; } + /** + *

last_layer.

+ * + * @return a int. + */ public int last_layer() { return this.board.layer_structure.arr.length - 1; } + /** {@inheritDoc} */ public boolean is_on_layer(int p_layer) { return true; } + /** {@inheritDoc} */ public void translate_by(Vector p_vector) { for (PolylineShape curr_shape : this.shapes) @@ -131,6 +168,7 @@ public void translate_by(Vector p_vector) keepout_lines = null; } + /** {@inheritDoc} */ public void turn_90_degree(int p_factor, IntPoint p_pole) { for (PolylineShape curr_shape : this.shapes) @@ -144,6 +182,7 @@ public void turn_90_degree(int p_factor, IntPoint p_pole) keepout_lines = null; } + /** {@inheritDoc} */ public void rotate_approx(double p_angle_in_degree, FloatPoint p_pole) { double angle = Math.toRadians(p_angle_in_degree); @@ -159,6 +198,7 @@ public void rotate_approx(double p_angle_in_degree, FloatPoint p_pole) keepout_lines = null; } + /** {@inheritDoc} */ public void change_placement_side(IntPoint p_pole) { for (PolylineShape curr_shape : this.shapes) @@ -172,21 +212,38 @@ public void change_placement_side(IntPoint p_pole) keepout_lines = null; } + /** {@inheritDoc} */ public double get_draw_intensity(GraphicsContext p_graphics_context) { return 1; } + /** + *

get_draw_priority.

+ * + * @return a int. + */ public int get_draw_priority() { return boardgraphics.Drawable.MAX_DRAW_PRIORITY; } + /** + *

shape_count.

+ * + * @return a int. + */ public int shape_count() { return this.shapes.length; } + /** + *

get_shape.

+ * + * @param p_index a int. + * @return a {@link geometry.planar.PolylineShape} object. + */ public PolylineShape get_shape(int p_index) { if (p_index < 0 || p_index >= this.shapes.length) @@ -197,6 +254,7 @@ public PolylineShape get_shape(int p_index) return this.shapes[p_index]; } + /** {@inheritDoc} */ public boolean is_selected_by_filter(ItemSelectionFilter p_filter) { if (!this.is_selected_by_fixed_filter(p_filter)) @@ -206,6 +264,7 @@ public boolean is_selected_by_filter(ItemSelectionFilter p_filter) return p_filter.is_selected(ItemSelectionFilter.SelectableChoices.BOARD_OUTLINE); } + /** {@inheritDoc} */ public java.awt.Color[] get_draw_colors(GraphicsContext p_graphics_context) { java.awt.Color[] color_arr = new java.awt.Color[this.board.layer_structure.arr.length]; @@ -244,6 +303,7 @@ TileShape[] get_keepout_lines() return this.keepout_lines; } + /** {@inheritDoc} */ public void draw(java.awt.Graphics p_g, GraphicsContext p_graphics_context, java.awt.Color[] p_color_arr, double p_intensity) { if (p_graphics_context == null || p_intensity <= 0) @@ -260,11 +320,13 @@ public void draw(java.awt.Graphics p_g, GraphicsContext p_graphics_context, java } } + /** {@inheritDoc} */ public Item copy(int p_id_no) { return new BoardOutline(this.shapes, this.clearance_class_no(), p_id_no, this.board); } + /** {@inheritDoc} */ public void print_info(ObjectInfoPanel p_window, java.util.Locale p_locale) { java.util.ResourceBundle resources = @@ -274,6 +336,7 @@ public void print_info(ObjectInfoPanel p_window, java.util.Locale p_locale) p_window.newline(); } + /** {@inheritDoc} */ public boolean write(java.io.ObjectOutputStream p_stream) { try @@ -289,6 +352,8 @@ public boolean write(java.io.ObjectOutputStream p_stream) /** * Returns, if keepout is generated outside the board outline. * Otherwise only the line shapes of the outlines are inserted as keepout. + * + * @return a boolean. */ public boolean keepout_outside_outline_generated() { @@ -298,6 +363,8 @@ public boolean keepout_outside_outline_generated() /** * Makes the area outside this Outline to Keepout, if p_valus = true. * Reinserts this Outline into the search trees, if the value changes. + * + * @param p_value a boolean. */ public void generate_keepout_outside(boolean p_value) { @@ -317,6 +384,8 @@ public void generate_keepout_outside(boolean p_value) /** * Returns the sum of the lines of all outline poligons. + * + * @return a int. */ public int line_count() { @@ -330,12 +399,15 @@ public int line_count() /** * Returns the half width of the lines of this outline. + * + * @return a int. */ public int get_half_width() { return HALF_WIDTH; } + /** {@inheritDoc} */ protected TileShape[] calculate_tree_shapes(ShapeSearchTree p_search_tree) { return p_search_tree.calculate_tree_shapes(this); diff --git a/board/CalcFromSide.java b/src/main/java/board/CalcFromSide.java similarity index 98% rename from board/CalcFromSide.java rename to src/main/java/board/CalcFromSide.java index 25953ee..7633be0 100644 --- a/board/CalcFromSide.java +++ b/src/main/java/board/CalcFromSide.java @@ -29,11 +29,14 @@ import geometry.planar.Side; /** + *

CalcFromSide class.

* * @author Alfons Wirtz + * @version $Id: $Id */ public class CalcFromSide { + /** Constant NOT_CALCULATED */ public static final CalcFromSide NOT_CALCULATED = new CalcFromSide(-1, null); /** diff --git a/board/CalcShapeAndFromSide.java b/src/main/java/board/CalcShapeAndFromSide.java similarity index 100% rename from board/CalcShapeAndFromSide.java rename to src/main/java/board/CalcShapeAndFromSide.java diff --git a/board/ChangedArea.java b/src/main/java/board/ChangedArea.java similarity index 89% rename from board/ChangedArea.java rename to src/main/java/board/ChangedArea.java index 18e6145..37d851a 100644 --- a/board/ChangedArea.java +++ b/src/main/java/board/ChangedArea.java @@ -1,163 +1,182 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - */ - -package board; -import geometry.planar.FloatPoint; -import geometry.planar.IntBox; -import geometry.planar.IntOctagon; - -/** - * - * Used internally for marking changed areas on the board - * after shoving and optimizing items. - * - - * @author Alfons Wirtz - */ - -class ChangedArea -{ - - public ChangedArea(int p_layer_count) - { - layer_count = p_layer_count; - arr = new MutableOctagon [layer_count]; - // initialise all octagons to empty - for (int i = 0; i < layer_count; ++i) - { - arr[i] = new MutableOctagon(); - arr[i].set_empty(); - } - } - - /** - * enlarges the octagon on p_layer, so that it contains p_point - */ - public void join (FloatPoint p_point, int p_layer) - { - MutableOctagon curr = arr[p_layer]; - curr.lx = Math.min(p_point.x, curr.lx); - curr.ly = Math.min(p_point.y, curr.ly); - curr.rx = Math.max(curr.rx, p_point.x); - curr.uy = Math.max(curr.uy, p_point.y); - - double tmp = p_point.x - p_point.y; - curr.ulx = Math.min(curr.ulx, tmp); - curr.lrx = Math.max(curr.lrx, tmp); - - tmp = p_point.x + p_point.y; - curr.llx = Math.min(curr.llx, tmp); - curr.urx = Math.max(curr.urx, tmp); - } - - /** - * enlarges the octagon on p_layer, so that it contains p_shape - */ - public void join (geometry.planar.TileShape p_shape, int p_layer) - { - if (p_shape == null) - { - return; - } - int corner_count = p_shape.border_line_count(); - for (int i = 0; i < corner_count; ++i) - { - join(p_shape.corner_approx(i), p_layer); - } - } - - /** - * get the marking octagon on layer p_layer - */ - public IntOctagon get_area (int p_layer) - { - - return arr[p_layer].to_int(); - } - - public IntBox surrounding_box() - { - int llx = Integer.MAX_VALUE; - int lly = Integer.MAX_VALUE; - int urx = Integer.MIN_VALUE; - int ury = Integer.MIN_VALUE; - for (int i = 0; i < layer_count; ++i) - { - MutableOctagon curr = arr[i]; - llx = Math.min (llx, (int)Math.floor(curr.lx)); - lly = Math.min (lly, (int)Math.floor(curr.ly)); - urx = Math.max (urx, (int)Math.ceil(curr.rx)); - ury = Math.max (ury, (int)Math.ceil(curr.uy)); - } - if (llx > urx || lly > ury) - { - return IntBox.EMPTY; - } - return new IntBox(llx, lly, urx, ury); - } - - /** - * inizialises the marking octagon on p_layer to empty - */ - void set_empty(int p_layer) - { - arr[p_layer].set_empty(); - } - - final int layer_count; - MutableOctagon [] arr; - - /** - * mutable octagon with double coordinates (see geometry.planar.IntOctagon) - */ - private static class MutableOctagon - { - double lx; - double ly; - double rx; - double uy; - double ulx; - double lrx; - double llx; - double urx; - - void set_empty() - { - lx = Integer.MAX_VALUE; - ly = Integer.MAX_VALUE; - rx = Integer.MIN_VALUE; - uy = Integer.MIN_VALUE; - ulx = Integer.MAX_VALUE; - lrx = Integer.MIN_VALUE; - llx = Integer.MAX_VALUE; - urx = Integer.MIN_VALUE; - } - /** - * calculates the smallest IntOctagon containing this octagon. - */ - IntOctagon to_int() - { - if (rx < lx || uy < ly || lrx < ulx || urx < llx) - { - return IntOctagon.EMPTY; - } - return new IntOctagon ((int)Math.floor(lx), (int)Math.floor(ly), - (int)Math.ceil(rx), (int)Math.ceil(uy), - (int)Math.floor(ulx), (int)Math.ceil(lrx), - (int)Math.floor(llx), (int)Math.ceil(urx)); - } - } -} \ No newline at end of file +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + */ + +package board; +import geometry.planar.FloatPoint; +import geometry.planar.IntBox; +import geometry.planar.IntOctagon; + +/** + * + * Used internally for marking changed areas on the board + * after shoving and optimizing items. + * + + * @author Alfons Wirtz + */ + +class ChangedArea +{ + + /** + *

Constructor for ChangedArea.

+ * + * @param p_layer_count a int. + */ + public ChangedArea(int p_layer_count) + { + layer_count = p_layer_count; + arr = new MutableOctagon [layer_count]; + // initialise all octagons to empty + for (int i = 0; i < layer_count; ++i) + { + arr[i] = new MutableOctagon(); + arr[i].set_empty(); + } + } + + /** + * enlarges the octagon on p_layer, so that it contains p_point + * + * @param p_point a {@link geometry.planar.FloatPoint} object. + * @param p_layer a int. + */ + public void join (FloatPoint p_point, int p_layer) + { + MutableOctagon curr = arr[p_layer]; + curr.lx = Math.min(p_point.x, curr.lx); + curr.ly = Math.min(p_point.y, curr.ly); + curr.rx = Math.max(curr.rx, p_point.x); + curr.uy = Math.max(curr.uy, p_point.y); + + double tmp = p_point.x - p_point.y; + curr.ulx = Math.min(curr.ulx, tmp); + curr.lrx = Math.max(curr.lrx, tmp); + + tmp = p_point.x + p_point.y; + curr.llx = Math.min(curr.llx, tmp); + curr.urx = Math.max(curr.urx, tmp); + } + + /** + * enlarges the octagon on p_layer, so that it contains p_shape + * + * @param p_shape a {@link geometry.planar.TileShape} object. + * @param p_layer a int. + */ + public void join (geometry.planar.TileShape p_shape, int p_layer) + { + if (p_shape == null) + { + return; + } + int corner_count = p_shape.border_line_count(); + for (int i = 0; i < corner_count; ++i) + { + join(p_shape.corner_approx(i), p_layer); + } + } + + /** + * get the marking octagon on layer p_layer + * + * @param p_layer a int. + * @return a {@link geometry.planar.IntOctagon} object. + */ + public IntOctagon get_area (int p_layer) + { + + return arr[p_layer].to_int(); + } + + /** + *

surrounding_box.

+ * + * @return a {@link geometry.planar.IntBox} object. + */ + public IntBox surrounding_box() + { + int llx = Integer.MAX_VALUE; + int lly = Integer.MAX_VALUE; + int urx = Integer.MIN_VALUE; + int ury = Integer.MIN_VALUE; + for (int i = 0; i < layer_count; ++i) + { + MutableOctagon curr = arr[i]; + llx = Math.min (llx, (int)Math.floor(curr.lx)); + lly = Math.min (lly, (int)Math.floor(curr.ly)); + urx = Math.max (urx, (int)Math.ceil(curr.rx)); + ury = Math.max (ury, (int)Math.ceil(curr.uy)); + } + if (llx > urx || lly > ury) + { + return IntBox.EMPTY; + } + return new IntBox(llx, lly, urx, ury); + } + + /** + * inizialises the marking octagon on p_layer to empty + */ + void set_empty(int p_layer) + { + arr[p_layer].set_empty(); + } + + final int layer_count; + MutableOctagon [] arr; + + /** + * mutable octagon with double coordinates (see geometry.planar.IntOctagon) + */ + private static class MutableOctagon + { + double lx; + double ly; + double rx; + double uy; + double ulx; + double lrx; + double llx; + double urx; + + void set_empty() + { + lx = Integer.MAX_VALUE; + ly = Integer.MAX_VALUE; + rx = Integer.MIN_VALUE; + uy = Integer.MIN_VALUE; + ulx = Integer.MAX_VALUE; + lrx = Integer.MIN_VALUE; + llx = Integer.MAX_VALUE; + urx = Integer.MIN_VALUE; + } + /** + * calculates the smallest IntOctagon containing this octagon. + */ + IntOctagon to_int() + { + if (rx < lx || uy < ly || lrx < ulx || urx < llx) + { + return IntOctagon.EMPTY; + } + return new IntOctagon ((int)Math.floor(lx), (int)Math.floor(ly), + (int)Math.ceil(rx), (int)Math.ceil(uy), + (int)Math.floor(ulx), (int)Math.ceil(lrx), + (int)Math.floor(llx), (int)Math.ceil(urx)); + } + } +} diff --git a/board/ClearanceViolation.java b/src/main/java/board/ClearanceViolation.java similarity index 88% rename from board/ClearanceViolation.java rename to src/main/java/board/ClearanceViolation.java index d463d4f..50a8810 100644 --- a/board/ClearanceViolation.java +++ b/src/main/java/board/ClearanceViolation.java @@ -27,11 +27,19 @@ * Information of a clearance violation between 2 items. * * @author alfons + * @version $Id: $Id */ public class ClearanceViolation implements ObjectInfoPanel.Printable { - /** Creates a new instance of ClearanceViolation */ + /** + * Creates a new instance of ClearanceViolation + * + * @param p_first_item a {@link board.Item} object. + * @param p_second_item a {@link board.Item} object. + * @param p_shape a {@link geometry.planar.ConvexShape} object. + * @param p_layer a int. + */ public ClearanceViolation(Item p_first_item, Item p_second_item, ConvexShape p_shape, int p_layer) { first_item = p_first_item; @@ -40,6 +48,7 @@ public ClearanceViolation(Item p_first_item, Item p_second_item, ConvexShape p_s layer = p_layer; } + /** {@inheritDoc} */ public void print_info(ObjectInfoPanel p_window, java.util.Locale p_locale) { java.util.ResourceBundle resources = diff --git a/board/Communication.java b/src/main/java/board/Communication.java similarity index 84% rename from board/Communication.java rename to src/main/java/board/Communication.java index 781e11e..54c4bab 100644 --- a/board/Communication.java +++ b/src/main/java/board/Communication.java @@ -27,11 +27,21 @@ * Communication information to host systems or host design formats. * * @author alfons + * @version $Id: $Id */ public class Communication implements java.io.Serializable { - /** Creates a new instance of BoardCommunication */ + /** + * Creates a new instance of BoardCommunication + * + * @param p_unit a {@link board.Unit} object. + * @param p_resolution a int. + * @param p_specctra_parser_info a {@link board.Communication.SpecctraParserInfo} object. + * @param p_coordinate_transform a {@link designformats.specctra.CoordinateTransform} object. + * @param p_id_no_generator a {@link datastructures.IdNoGenerator} object. + * @param p_observers a {@link board.BoardObservers} object. + */ public Communication(Unit p_unit, int p_resolution, SpecctraParserInfo p_specctra_parser_info, CoordinateTransform p_coordinate_transform, IdNoGenerator p_id_no_generator, BoardObservers p_observers) @@ -44,19 +54,31 @@ public Communication(Unit p_unit, int p_resolution, observers = p_observers; } - /** Creates a new instance of BoardCommunication */ + /** + * Creates a new instance of BoardCommunication + */ public Communication() { this(Unit.MIL, 1, new SpecctraParserInfo("\"", null, null, null, null, false), new CoordinateTransform(1, 0, 0), new board.ItemIdNoGenerator(), new BoardObserverAdaptor()); } + /** + *

host_cad_is_eagle.

+ * + * @return a boolean. + */ public boolean host_cad_is_eagle() { return specctra_parser_info != null && specctra_parser_info.host_cad != null && specctra_parser_info.host_cad.equalsIgnoreCase("CadSoft"); } + /** + *

host_cad_exists.

+ * + * @return a boolean. + */ public boolean host_cad_exists() { return specctra_parser_info != null && specctra_parser_info.host_cad != null; @@ -65,6 +87,9 @@ public boolean host_cad_exists() /** * Returns the resolution scaled to the input unit + * + * @param p_unit a {@link board.Unit} object. + * @return a double. */ public double get_resolution (Unit p_unit) { diff --git a/board/Component.java b/src/main/java/board/Component.java similarity index 89% rename from board/Component.java rename to src/main/java/board/Component.java index c67ba63..6faf33e 100644 --- a/board/Component.java +++ b/src/main/java/board/Component.java @@ -35,6 +35,7 @@ * und other stuff like component keepouts. * * @author Alfons Wirtz + * @version $Id: $Id */ public class Component implements UndoableObjects.Storable, ObjectInfoPanel.Printable, java.io.Serializable { @@ -65,6 +66,8 @@ public class Component implements UndoableObjects.Storable, ObjectInfoPanel.Prin /** * Returns the location of this component. + * + * @return a {@link geometry.planar.Point} object. */ public Point get_location() { @@ -73,12 +76,19 @@ public Point get_location() /** * Returns the rotation of this component in degree. + * + * @return a double. */ public double get_rotation_in_degree() { return rotation_in_degree; } + /** + *

is_placed.

+ * + * @return a boolean. + */ public boolean is_placed() { return location != null; @@ -86,6 +96,8 @@ public boolean is_placed() /** * If false, the component will be placed on the back side of the board. + * + * @return a boolean. */ public boolean placed_on_front() { @@ -95,6 +107,8 @@ public boolean placed_on_front() /** * Translates the location of this Component by p_p_vector. * The Pins in the board must be moved seperately. + * + * @param p_vector a {@link geometry.planar.Vector} object. */ public void translate_by(Vector p_vector) { @@ -106,6 +120,9 @@ public void translate_by(Vector p_vector) /** * Turns this component by p_factor times 90 degree around p_pole. + * + * @param p_factor a int. + * @param p_pole a {@link geometry.planar.IntPoint} object. */ public void turn_90_degree(int p_factor, IntPoint p_pole) { @@ -129,6 +146,10 @@ public void turn_90_degree(int p_factor, IntPoint p_pole) } /** * Rotates this component by p_angle_in_degree around p_pole. + * + * @param p_angle_in_degree a double. + * @param p_pole a {@link geometry.planar.IntPoint} object. + * @param p_flip_style_rotate_first a boolean. */ public void rotate(double p_angle_in_degree, IntPoint p_pole, boolean p_flip_style_rotate_first) { @@ -160,6 +181,8 @@ public void rotate(double p_angle_in_degree, IntPoint p_pole, boolean p_flip_sty /** * Changes the placement side of this component and mirrors it at the * vertical line through p_pole. + * + * @param p_pole a {@link geometry.planar.IntPoint} object. */ public void change_side(IntPoint p_pole) { @@ -168,6 +191,8 @@ public void change_side(IntPoint p_pole) } /** + * {@inheritDoc} + * * Compares 2 components by name. * Useful for example to display components in alphabetic order. */ @@ -182,6 +207,8 @@ public int compareTo(Object p_other) /** * Creates a copy of this component. + * + * @return a {@link board.Component} object. */ public Component clone() { @@ -191,6 +218,11 @@ public Component clone() return result; } + /** + *

toString.

+ * + * @return a {@link java.lang.String} object. + */ public String toString() { return this.name; @@ -198,6 +230,8 @@ public String toString() /** * Returns information for pin swap and gate swap, if != null. + * + * @return a {@link library.LogicalPart} object. */ public library.LogicalPart get_logical_part() { @@ -206,12 +240,15 @@ public library.LogicalPart get_logical_part() /** * Sets the infomation for pin swap and gate swap. + * + * @param p_logical_part a {@link library.LogicalPart} object. */ public void set_logical_part(library.LogicalPart p_logical_part) { this.logical_part = p_logical_part; } + /** {@inheritDoc} */ public void print_info(ObjectInfoPanel p_window, java.util.Locale p_locale) { java.util.ResourceBundle resources = @@ -252,6 +289,8 @@ public void print_info(ObjectInfoPanel p_window, java.util.Locale p_locale) /** * Returns the library package of this component. + * + * @return a {@link library.Package} object. */ public Package get_package() { diff --git a/board/ComponentObstacleArea.java b/src/main/java/board/ComponentObstacleArea.java similarity index 91% rename from board/ComponentObstacleArea.java rename to src/main/java/board/ComponentObstacleArea.java index 006ad91..e99fcb9 100644 --- a/board/ComponentObstacleArea.java +++ b/src/main/java/board/ComponentObstacleArea.java @@ -28,6 +28,7 @@ * Describes areas of the board, where components arre not allowed. * * @author alfons + * @version $Id: $Id */ public class ComponentObstacleArea extends ObstacleArea { @@ -43,6 +44,7 @@ public class ComponentObstacleArea extends ObstacleArea p_clearance_type, p_id_no, p_component_no, p_name, p_fixed_state, p_board); } + /** {@inheritDoc} */ public Item copy(int p_id_no) { return new ComponentObstacleArea(get_relative_area(), get_layer(), get_translation(), @@ -50,17 +52,20 @@ public Item copy(int p_id_no) get_component_no(), this.name, get_fixed_state(), board); } + /** {@inheritDoc} */ public boolean is_obstacle(Item p_other) { return p_other != this && p_other instanceof ComponentObstacleArea && p_other.get_component_no() != this.get_component_no(); } + /** {@inheritDoc} */ public boolean is_trace_obstacle(int p_net_no) { return false; } + /** {@inheritDoc} */ public boolean is_selected_by_filter(ItemSelectionFilter p_filter) { if (!this.is_selected_by_fixed_filter(p_filter)) @@ -71,16 +76,24 @@ public boolean is_selected_by_filter(ItemSelectionFilter p_filter) } + /** {@inheritDoc} */ public java.awt.Color[] get_draw_colors(boardgraphics.GraphicsContext p_graphics_context) { return p_graphics_context.get_place_obstacle_colors(); } + /** {@inheritDoc} */ public double get_draw_intensity(boardgraphics.GraphicsContext p_graphics_context) { return p_graphics_context.get_place_obstacle_color_intensity(); } + /** + *

is_selectrd_by_filter.

+ * + * @param p_filter a {@link board.ItemSelectionFilter} object. + * @return a boolean. + */ public boolean is_selectrd_by_filter(ItemSelectionFilter p_filter) { if (!this.is_selected_by_fixed_filter(p_filter)) @@ -90,6 +103,7 @@ public boolean is_selectrd_by_filter(ItemSelectionFilter p_filter) return p_filter.is_selected(ItemSelectionFilter.SelectableChoices.COMPONENT_KEEPOUT); } + /** {@inheritDoc} */ public void print_info(ObjectInfoPanel p_window, java.util.Locale p_locale) { java.util.ResourceBundle resources = diff --git a/board/ComponentOutline.java b/src/main/java/board/ComponentOutline.java similarity index 83% rename from board/ComponentOutline.java rename to src/main/java/board/ComponentOutline.java index 66460e7..1ef91d1 100644 --- a/board/ComponentOutline.java +++ b/src/main/java/board/ComponentOutline.java @@ -31,13 +31,25 @@ import boardgraphics.GraphicsContext; /** + *

ComponentOutline class.

* * @author Alfons Wirtz + * @version $Id: $Id */ public class ComponentOutline extends Item implements java.io.Serializable { - /** Creates a new instance of ComponentOutline */ + /** + * Creates a new instance of ComponentOutline + * + * @param p_area a {@link geometry.planar.Area} object. + * @param p_is_front a boolean. + * @param p_translation a {@link geometry.planar.Vector} object. + * @param p_rotation_in_degree a double. + * @param p_component_no a int. + * @param p_fixed_state a {@link board.FixedState} object. + * @param p_board a {@link board.BasicBoard} object. + */ public ComponentOutline(Area p_area, boolean p_is_front, Vector p_translation, double p_rotation_in_degree, int p_component_no, FixedState p_fixed_state, BasicBoard p_board) { @@ -48,17 +60,24 @@ public ComponentOutline(Area p_area, boolean p_is_front, Vector p_translation, d this.rotation_in_degree = p_rotation_in_degree; } + /** {@inheritDoc} */ public Item copy(int p_id_no) { return new ComponentOutline(this.relative_area, this.is_front, this.translation, this.rotation_in_degree, this.get_component_no(), this.get_fixed_state(), this.board); } + /** {@inheritDoc} */ public boolean is_selected_by_filter(ItemSelectionFilter p_filter) { return false; } + /** + *

get_layer.

+ * + * @return a int. + */ public int get_layer() { int result; @@ -73,46 +92,72 @@ public int get_layer() return result; } + /** + *

first_layer.

+ * + * @return a int. + */ public int first_layer() { return get_layer(); } + /** + *

last_layer.

+ * + * @return a int. + */ public int last_layer() { return get_layer(); } + /** {@inheritDoc} */ public boolean is_on_layer(int p_layer) { return get_layer() == p_layer; } + /** + *

is_obstacle.

+ * + * @param p_item a {@link board.Item} object. + * @return a boolean. + */ public boolean is_obstacle(Item p_item) { return false; } + /** {@inheritDoc} */ public int shape_layer(int p_index) { return get_layer(); } + /** + *

tile_shape_count.

+ * + * @return a int. + */ public int tile_shape_count() { return 0; } + /** {@inheritDoc} */ protected geometry.planar.TileShape[] calculate_tree_shapes(ShapeSearchTree p_search_tree) { return new geometry.planar.TileShape[0]; } + /** {@inheritDoc} */ public double get_draw_intensity(GraphicsContext p_graphics_context) { return p_graphics_context.get_component_outline_color_intensity(); } + /** {@inheritDoc} */ public Color[] get_draw_colors(GraphicsContext p_graphics_context) { Color[] color_arr = new java.awt.Color[this.board.layer_structure.arr.length]; @@ -128,11 +173,17 @@ public Color[] get_draw_colors(GraphicsContext p_graphics_context) return color_arr; } + /** + *

get_draw_priority.

+ * + * @return a int. + */ public int get_draw_priority() { return boardgraphics.Drawable.MIDDLE_DRAW_PRIORITY; } + /** {@inheritDoc} */ public void draw(java.awt.Graphics p_g, GraphicsContext p_graphics_context, Color[] p_color_arr, double p_intensity) { if (p_graphics_context == null || p_intensity <= 0) @@ -146,17 +197,24 @@ public void draw(java.awt.Graphics p_g, GraphicsContext p_graphics_context, Colo p_graphics_context.draw_boundary(this.get_area(), draw_width, color, p_g, intensity); } + /** + *

bounding_box.

+ * + * @return a {@link geometry.planar.IntBox} object. + */ public geometry.planar.IntBox bounding_box() { return get_area().bounding_box(); } + /** {@inheritDoc} */ public void translate_by(Vector p_vector) { this.translation = this.translation.add(p_vector); clear_derived_data(); } + /** {@inheritDoc} */ public void change_placement_side(IntPoint p_pole) { this.is_front = !this.is_front; @@ -165,6 +223,7 @@ public void change_placement_side(IntPoint p_pole) clear_derived_data(); } + /** {@inheritDoc} */ public void rotate_approx(double p_angle_in_degree, FloatPoint p_pole) { double turn_angle = p_angle_in_degree; @@ -186,6 +245,7 @@ public void rotate_approx(double p_angle_in_degree, FloatPoint p_pole) clear_derived_data(); } + /** {@inheritDoc} */ public void turn_90_degree(int p_factor, IntPoint p_pole) { this.rotation_in_degree += p_factor * 90; @@ -202,6 +262,11 @@ public void turn_90_degree(int p_factor, IntPoint p_pole) clear_derived_data(); } + /** + *

get_area.

+ * + * @return a {@link geometry.planar.Area} object. + */ public Area get_area() { if (this.precalculated_absolute_area == null) @@ -238,15 +303,20 @@ public Area get_area() return this.precalculated_absolute_area; } + /** + *

clear_derived_data.

+ */ public void clear_derived_data() { precalculated_absolute_area = null; } + /** {@inheritDoc} */ public void print_info(ObjectInfoPanel p_window, java.util.Locale p_locale) { } + /** {@inheritDoc} */ public boolean write(java.io.ObjectOutputStream p_stream) { try diff --git a/board/Components.java b/src/main/java/board/Components.java similarity index 81% rename from board/Components.java rename to src/main/java/board/Components.java index 3859f58..3f97c81 100644 --- a/board/Components.java +++ b/src/main/java/board/Components.java @@ -36,6 +36,7 @@ * Contains the lists of components on the board. * * @author Alfons Wirtz + * @version $Id: $Id */ public class Components implements java.io.Serializable { @@ -44,6 +45,15 @@ public class Components implements java.io.Serializable * The items of the component have to be inserted seperately into the board. * If p_on_front is false, the component will be placed on the back side, * and p_package_back is used instead of p_package_front. + * + * @param p_name a {@link java.lang.String} object. + * @param p_location a {@link geometry.planar.Point} object. + * @param p_rotation_in_degree a double. + * @param p_on_front a boolean. + * @param p_package_front a {@link library.Package} object. + * @param p_package_back a {@link library.Package} object. + * @param p_position_fixed a boolean. + * @return a {@link board.Component} object. */ public Component add(String p_name, Point p_location, double p_rotation_in_degree, boolean p_on_front, Package p_package_front, Package p_package_back, boolean p_position_fixed) @@ -62,6 +72,12 @@ public Component add(String p_name, Point p_location, double p_rotation_in_degre * The items of the component have to be inserted seperately into the board. * If p_on_front is false, the component will be placed on the back side. * The component name is generated internally. + * + * @param p_location a {@link geometry.planar.Point} object. + * @param p_rotation a double. + * @param p_on_front a boolean. + * @param p_package a {@link library.Package} object. + * @return a {@link board.Component} object. */ public Component add(Point p_location, double p_rotation, boolean p_on_front, Package p_package) { @@ -72,6 +88,9 @@ public Component add(Point p_location, double p_rotation, boolean p_on_front, Pa /** * Returns the component with the input name or null, * if no such component exists. + * + * @param p_name a {@link java.lang.String} object. + * @return a {@link board.Component} object. */ public Component get(String p_name) { @@ -91,6 +110,9 @@ public Component get(String p_name) * Returns the component with the input component number or null, * if no such component exists. * Component numbers are from 1 to component count + * + * @param p_component_no a int. + * @return a {@link board.Component} object. */ public Component get(int p_component_no) { @@ -104,6 +126,8 @@ public Component get(int p_component_no) /** * Returns the number of components on the board. + * + * @return a int. */ public int count() { @@ -121,6 +145,9 @@ public void generate_snapshot() /** * Restores the sitiation at the previous snapshot. * Returns false, if no more undo is possible. + * + * @param p_observers a {@link board.BoardObservers} object. + * @return a boolean. */ public boolean undo(BoardObservers p_observers) { @@ -135,6 +162,9 @@ public boolean undo(BoardObservers p_observers) /** * Restores the sitiation before the last undo. * Returns false, if no more redo is possible. + * + * @param p_observers a {@link board.BoardObservers} object. + * @return a boolean. */ public boolean redo(BoardObservers p_observers) { @@ -167,6 +197,9 @@ private void restore_component_arr_from_undo_list(BoardObservers p_observers) /** * Moves the component with number p_component_no. * Works contrary to Component.translate_by with the undo algorithm of the board. + * + * @param p_component_no a int. + * @param p_vector a {@link geometry.planar.Vector} object. */ public void move(int p_component_no, geometry.planar.Vector p_vector ) { @@ -178,6 +211,10 @@ public void move(int p_component_no, geometry.planar.Vector p_vector ) /** * Turns the component with number p_component_no by p_factor times 90 degree around p_pole. * Works contrary to Component.turn_90_degree with the undo algorithm of the board. + * + * @param p_component_no a int. + * @param p_factor a int. + * @param p_pole a {@link geometry.planar.IntPoint} object. */ public void turn_90_degree(int p_component_no, int p_factor, IntPoint p_pole) { @@ -186,9 +223,13 @@ public void turn_90_degree(int p_component_no, int p_factor, IntPoint p_pole) curr_component.turn_90_degree(p_factor, p_pole); } - /** + /** * Rotates the component with number p_component_no by p_rotation_in_degree around p_pole. * Works contrary to Component.rotate with the undo algorithm of the board. + * + * @param p_component_no a int. + * @param p_rotation_in_degree a double. + * @param p_pole a {@link geometry.planar.IntPoint} object. */ public void rotate (int p_component_no, double p_rotation_in_degree, IntPoint p_pole) { @@ -201,6 +242,9 @@ public void rotate (int p_component_no, double p_rotation_in_degree, IntPoint p_ * Changes the placement side of the component the component with numberp_component_no and * mirrors it at the vertical line through p_pole. * Works contrary to Component.change_side the undo algorithm of the board. + * + * @param p_component_no a int. + * @param p_pole a {@link geometry.planar.IntPoint} object. */ public void change_side(int p_component_no, IntPoint p_pole) { @@ -212,6 +256,8 @@ public void change_side(int p_component_no, IntPoint p_pole) /** * If true, components on the back side are rotated before mirroring, * else they are mirrored before rotating. + * + * @param p_value a boolean. */ public void set_flip_style_rotate_first(boolean p_value) { @@ -221,6 +267,8 @@ public void set_flip_style_rotate_first(boolean p_value) /** * If true, components on the back side are rotated before mirroring, * else they are mirrored before rotating. + * + * @return a boolean. */ public boolean get_flip_style_rotate_first() { diff --git a/board/ConductionArea.java b/src/main/java/board/ConductionArea.java similarity index 92% rename from board/ConductionArea.java rename to src/main/java/board/ConductionArea.java index 6ad8363..981cd6c 100644 --- a/board/ConductionArea.java +++ b/src/main/java/board/ConductionArea.java @@ -35,6 +35,7 @@ * A ObstacleArea, which can be electrically conected to other items. * * @author Alfons Wirtz + * @version $Id: $Id */ public class ConductionArea extends ObstacleArea implements Connectable { @@ -49,6 +50,7 @@ public class ConductionArea extends ObstacleArea implements Connectable is_obstacle = p_is_obstacle; } + /** {@inheritDoc} */ public Item copy(int p_id_no) { if (this.net_count() != 1) @@ -61,6 +63,11 @@ public Item copy(int p_id_no) this.name, is_obstacle, get_fixed_state(), board); } + /** + *

get_normal_contacts.

+ * + * @return a {@link java.util.Set} object. + */ public Set get_normal_contacts() { Set result = new TreeSet(); @@ -102,6 +109,7 @@ else if (curr_item instanceof DrillItem) return result; } + /** {@inheritDoc} */ public TileShape get_trace_connection_shape(ShapeSearchTree p_search_tree, int p_index) { if (p_index < 0 || p_index >= this.tree_shape_count(p_search_tree)) @@ -112,6 +120,11 @@ public TileShape get_trace_connection_shape(ShapeSearchTree p_search_tree, int p return this.get_tree_shape(p_search_tree, p_index); } + /** + *

get_ratsnest_corners.

+ * + * @return an array of {@link geometry.planar.Point} objects. + */ public Point[] get_ratsnest_corners() { Point [] result; @@ -125,6 +138,7 @@ public Point[] get_ratsnest_corners() return result; } + /** {@inheritDoc} */ public boolean is_obstacle(Item p_other) { if (this.is_obstacle) @@ -136,6 +150,8 @@ public boolean is_obstacle(Item p_other) /** * Returns if this conduction area is regarded as obstacle to traces of foreign nets. + * + * @return a boolean. */ public boolean get_is_obstacle() { @@ -145,22 +161,27 @@ public boolean get_is_obstacle() /** * Sets, if this conduction area is regarded as obstacle to traces and vias of foreign nets. + * + * @param p_value a boolean. */ public void set_is_obstacle(boolean p_value) { this.is_obstacle = p_value; } + /** {@inheritDoc} */ public boolean is_trace_obstacle(int p_net_no) { return this.is_obstacle && !this.contains_net(p_net_no); } + /** {@inheritDoc} */ public boolean is_drillable(int p_net_no) { return !this.is_obstacle || this.contains_net(p_net_no); } + /** {@inheritDoc} */ public boolean is_selected_by_filter(ItemSelectionFilter p_filter) { if (!this.is_selected_by_fixed_filter(p_filter)) @@ -170,16 +191,19 @@ public boolean is_selected_by_filter(ItemSelectionFilter p_filter) return p_filter.is_selected(ItemSelectionFilter.SelectableChoices.CONDUCTION); } + /** {@inheritDoc} */ public java.awt.Color[] get_draw_colors(boardgraphics.GraphicsContext p_graphics_context) { return p_graphics_context.get_conduction_colors(); } + /** {@inheritDoc} */ public double get_draw_intensity(boardgraphics.GraphicsContext p_graphics_context) { return p_graphics_context.get_conduction_color_intensity(); } + /** {@inheritDoc} */ public void print_info(ObjectInfoPanel p_window, java.util.Locale p_locale) { java.util.ResourceBundle resources = diff --git a/board/Connectable.java b/src/main/java/board/Connectable.java similarity index 78% rename from board/Connectable.java rename to src/main/java/board/Connectable.java index 21ef07d..b4e6e04 100644 --- a/board/Connectable.java +++ b/src/main/java/board/Connectable.java @@ -1,77 +1,97 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - */ - -package board; - -import geometry.planar.TileShape; - -import java.util.Set; - -/** - * - * Functionality required for items, which can be - * electrical connected to other items. - * - * @author Alfons Wirtz - */ - -public interface Connectable -{ - /** - * Returns true if this item belongs to the net with number p_net_no. - */ - public boolean contains_net(int p_net_no); - - /** - * Returns true if the net number array of this and p_net_no_arr have a common - * number. - */ - public boolean shares_net_no(int [] p_net_no_arr); - - /** - * Returns a list of all connectable items overlapping - * and sharing a net with this item. - */ - Set get_all_contacts(); - - /** - * Returns a list of all connectable items overlapping with - * this item on the input layer and sharing a net with this item. - */ - Set get_all_contacts(int p_layer ); - - /** - * Returns the list of all contacts of a connectable item - * located at defined connection points. - * Connection points of traces are there endpoints, connection - * points of drill_items there center points, and connection - * points of conduction areas are points on there border. - */ - Set get_normal_contacts(); - - /** - * Returns all connectable items of the net with number p_net_no, which can be reached recursively - * from this item via normal contacts. - * if (p_net_no <= 0, the net number is ignored. - */ - Set get_connected_set(int p_net_no); - - /** - * Returns for each convex shape of a connectable item - * the subshape of points, where traces can be connected to that item. - */ - TileShape get_trace_connection_shape(ShapeSearchTree p_tree, int p_index); -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + */ + +package board; + +import geometry.planar.TileShape; + +import java.util.Set; + +/** + * + * Functionality required for items, which can be + * electrical connected to other items. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public interface Connectable +{ + /** + * Returns true if this item belongs to the net with number p_net_no. + * + * @param p_net_no a int. + * @return a boolean. + */ + public boolean contains_net(int p_net_no); + + /** + * Returns true if the net number array of this and p_net_no_arr have a common + * number. + * + * @param p_net_no_arr an array of int. + * @return a boolean. + */ + public boolean shares_net_no(int [] p_net_no_arr); + + /** + * Returns a list of all connectable items overlapping + * and sharing a net with this item. + * + * @return a {@link java.util.Set} object. + */ + Set get_all_contacts(); + + /** + * Returns a list of all connectable items overlapping with + * this item on the input layer and sharing a net with this item. + * + * @param p_layer a int. + * @return a {@link java.util.Set} object. + */ + Set get_all_contacts(int p_layer ); + + /** + * Returns the list of all contacts of a connectable item + * located at defined connection points. + * Connection points of traces are there endpoints, connection + * points of drill_items there center points, and connection + * points of conduction areas are points on there border. + * + * @return a {@link java.util.Set} object. + */ + Set get_normal_contacts(); + + /** + * Returns all connectable items of the net with number p_net_no, which can be reached recursively + * from this item via normal contacts. + * if {@code p_net_no <= 0}, the net number is ignored. + * + * @param p_net_no a int. + * @return a {@link java.util.Set} object. + */ + Set get_connected_set(int p_net_no); + + /** + * Returns for each convex shape of a connectable item + * the subshape of points, where traces can be connected to that item. + * + * @param p_tree a {@link board.ShapeSearchTree} object. + * @param p_index a int. + * @return a {@link geometry.planar.TileShape} object. + */ + TileShape get_trace_connection_shape(ShapeSearchTree p_tree, int p_index); +} diff --git a/board/CoordinateTransform.java b/src/main/java/board/CoordinateTransform.java similarity index 73% rename from board/CoordinateTransform.java rename to src/main/java/board/CoordinateTransform.java index c1c30a5..7bbae17 100644 --- a/board/CoordinateTransform.java +++ b/src/main/java/board/CoordinateTransform.java @@ -26,11 +26,21 @@ * Class for transforming objects between user coordinate space and board coordinate space. * * @author Alfons Wirtz + * @version $Id: $Id */ public class CoordinateTransform implements java.io.Serializable { - /** Creates a new instance of CoordinateTransform */ + /** + * Creates a new instance of CoordinateTransform + * + * @param p_user_unit_factor a double. + * @param p_user_unit_factor a double. + * @param p_user_unit a {@link board.Unit} object. + * @param p_board_unit_factor a double. + * @param p_board_unit_factor a double. + * @param p_board_unit a {@link board.Unit} object. + */ public CoordinateTransform(double p_user_unit_factor, Unit p_user_unit, double p_board_unit_factor, Unit p_board_unit) { @@ -43,6 +53,9 @@ public CoordinateTransform(double p_user_unit_factor, Unit p_user_unit, /** * Scale a value from the board to the user coordinate system. + * + * @param p_value a double. + * @return a double. */ public double board_to_user(double p_value) { @@ -51,6 +64,9 @@ public double board_to_user(double p_value) /** * Scale a value from the user to the board coordinate system. + * + * @param p_value a double. + * @return a double. */ public double user_to_board(double p_value) { @@ -61,6 +77,9 @@ public double user_to_board(double p_value) /** * Transforms a geometry.planar.FloatPoint from the board coordinate space * to the user coordinate space. + * + * @param p_point a {@link geometry.planar.FloatPoint} object. + * @return a {@link geometry.planar.FloatPoint} object. */ public FloatPoint board_to_user(FloatPoint p_point) { @@ -70,12 +89,22 @@ public FloatPoint board_to_user(FloatPoint p_point) /** * Transforms a geometry.planar.FloatPoint from the user coordinate space. * to the board coordinate space. + * + * @param p_point a {@link geometry.planar.FloatPoint} object. + * @return a {@link geometry.planar.FloatPoint} object. */ public FloatPoint user_to_board(FloatPoint p_point) { return new FloatPoint(user_to_board(p_point.x), user_to_board(p_point.y)); } + /** + *

board_to_user.

+ * + * @param p_shape a {@link geometry.planar.Shape} object. + * @param p_locale a {@link java.util.Locale} object. + * @return a {@link board.PrintableShape} object. + */ public PrintableShape board_to_user(geometry.planar.Shape p_shape, java.util.Locale p_locale) { PrintableShape result; @@ -99,18 +128,39 @@ else if (p_shape instanceof geometry.planar.PolylineShape) return result; } + /** + *

board_to_user.

+ * + * @param p_circle a {@link geometry.planar.Circle} object. + * @param p_locale a {@link java.util.Locale} object. + * @return a {@link board.PrintableShape.Circle} object. + */ public PrintableShape.Circle board_to_user(geometry.planar.Circle p_circle, java.util.Locale p_locale) { return new PrintableShape.Circle(board_to_user(p_circle.center.to_float()), board_to_user(p_circle.radius), p_locale); } + /** + *

board_to_user.

+ * + * @param p_box a {@link geometry.planar.IntBox} object. + * @param p_locale a {@link java.util.Locale} object. + * @return a {@link board.PrintableShape.Rectangle} object. + */ public PrintableShape.Rectangle board_to_user(geometry.planar.IntBox p_box, java.util.Locale p_locale) { return new PrintableShape.Rectangle(board_to_user(p_box.ll.to_float()), board_to_user(p_box.ur.to_float()), p_locale); } + /** + *

board_to_user.

+ * + * @param p_shape a {@link geometry.planar.PolylineShape} object. + * @param p_locale a {@link java.util.Locale} object. + * @return a {@link board.PrintableShape.Polygon} object. + */ public PrintableShape.Polygon board_to_user(geometry.planar.PolylineShape p_shape, java.util.Locale p_locale) { FloatPoint[] corners = p_shape.corner_approx_arr(); diff --git a/board/DrillItem.java b/src/main/java/board/DrillItem.java similarity index 85% rename from board/DrillItem.java rename to src/main/java/board/DrillItem.java index 185a14a..735fd1a 100644 --- a/board/DrillItem.java +++ b/src/main/java/board/DrillItem.java @@ -40,10 +40,22 @@ * Common superclass for Pins and Vias * * @author Alfons Wirtz + * @version $Id: $Id */ public abstract class DrillItem extends Item implements Connectable, java.io.Serializable { + /** + *

Constructor for DrillItem.

+ * + * @param p_center a {@link geometry.planar.Point} object. + * @param p_net_no_arr an array of int. + * @param p_clearance_type a int. + * @param p_id_no a int. + * @param p_group_no a int. + * @param p_fixed_state a {@link board.FixedState} object. + * @param p_board a {@link board.BasicBoard} object. + */ public DrillItem( Point p_center, int[] p_net_no_arr, int p_clearance_type, int p_id_no, int p_group_no, FixedState p_fixed_state, BasicBoard p_board) { @@ -52,6 +64,8 @@ public DrillItem( Point p_center, int[] p_net_no_arr, int p_clearance_type, int } /** + * {@inheritDoc} + * * Works only for symmettric DrillItems */ public void translate_by(Vector p_vector) @@ -64,6 +78,7 @@ public void translate_by(Vector p_vector) } + /** {@inheritDoc} */ public void turn_90_degree(int p_factor, IntPoint p_pole) { if (center != null) @@ -73,6 +88,7 @@ public void turn_90_degree(int p_factor, IntPoint p_pole) this.clear_derived_data(); } + /** {@inheritDoc} */ public void rotate_approx(double p_angle_in_degree, FloatPoint p_pole) { if (center != null) @@ -83,6 +99,7 @@ public void rotate_approx(double p_angle_in_degree, FloatPoint p_pole) this.clear_derived_data(); } + /** {@inheritDoc} */ public void change_placement_side(IntPoint p_pole) { if (center != null) @@ -92,6 +109,7 @@ public void change_placement_side(IntPoint p_pole) this.clear_derived_data(); } + /** {@inheritDoc} */ public void move_by(Vector p_vector) { Point old_center = this.get_center(); @@ -150,6 +168,7 @@ else if (board.rules.get_trace_angle_restriction() == AngleRestriction.FORTYFIVE } } + /** {@inheritDoc} */ public int shape_layer(int p_index) { int index = Math.max( p_index, 0); @@ -159,12 +178,18 @@ public int shape_layer(int p_index) return from_layer + index; } + /** {@inheritDoc} */ public boolean is_on_layer(int p_layer) { return p_layer >= first_layer() && p_layer <= last_layer(); } + /** + *

first_layer.

+ * + * @return a int. + */ public int first_layer() { if (this.precalculated_first_layer < 0) @@ -182,6 +207,11 @@ public int first_layer() return this.precalculated_first_layer; } + /** + *

last_layer.

+ * + * @return a int. + */ public int last_layer() { if (this.precalculated_last_layer < 0) @@ -199,8 +229,19 @@ public int last_layer() return this.precalculated_last_layer; } + /** + *

get_shape.

+ * + * @param p_index a int. + * @return a {@link geometry.planar.Shape} object. + */ public abstract Shape get_shape(int p_index); + /** + *

bounding_box.

+ * + * @return a {@link geometry.planar.IntBox} object. + */ public IntBox bounding_box() { IntBox result = IntBox.EMPTY; @@ -215,6 +256,11 @@ public IntBox bounding_box() return result; } + /** + *

tile_shape_count.

+ * + * @return a int. + */ public int tile_shape_count() { Padstack padstack = get_padstack(); @@ -223,6 +269,7 @@ public int tile_shape_count() return to_layer - from_layer + 1; } + /** {@inheritDoc} */ protected TileShape[] calculate_tree_shapes(ShapeSearchTree p_search_tree) { return p_search_tree.calculate_tree_shapes(this); @@ -231,6 +278,8 @@ protected TileShape[] calculate_tree_shapes(ShapeSearchTree p_search_tree) /** * Returns the smallest distance from the center to the border of * the shape on any layer. + * + * @return a double. */ public double smallest_radius() { @@ -248,12 +297,21 @@ public double smallest_radius() } - /** Returns the center point of this DrillItem. */ + /** + * Returns the center point of this DrillItem. + * + * @return a {@link geometry.planar.Point} object. + */ public Point get_center() { return center; } + /** + *

set_center.

+ * + * @param p_center a {@link geometry.planar.Point} object. + */ protected void set_center(Point p_center) { center = p_center; @@ -261,9 +319,18 @@ protected void set_center(Point p_center) /** * Returns the padstack of this drillitem. + * + * @return a {@link library.Padstack} object. */ public abstract Padstack get_padstack(); + /** + *

get_tree_shape_on_layer.

+ * + * @param p_tree a {@link board.ShapeSearchTree} object. + * @param p_layer a int. + * @return a {@link geometry.planar.TileShape} object. + */ public TileShape get_tree_shape_on_layer(ShapeSearchTree p_tree, int p_layer) { int from_layer = first_layer(); @@ -276,6 +343,12 @@ public TileShape get_tree_shape_on_layer(ShapeSearchTree p_tree, int p_layer) return get_tree_shape(p_tree, p_layer - from_layer); } + /** + *

get_tile_shape_on_layer.

+ * + * @param p_layer a int. + * @return a {@link geometry.planar.TileShape} object. + */ public TileShape get_tile_shape_on_layer(int p_layer) { int from_layer = first_layer(); @@ -288,6 +361,12 @@ public TileShape get_tile_shape_on_layer(int p_layer) return get_tile_shape(p_layer - from_layer); } + /** + *

get_shape_on_layer.

+ * + * @param p_layer a int. + * @return a {@link geometry.planar.Shape} object. + */ public Shape get_shape_on_layer(int p_layer) { int from_layer = first_layer(); @@ -300,6 +379,11 @@ public Shape get_shape_on_layer(int p_layer) return get_shape(p_layer - from_layer); } + /** + *

get_normal_contacts.

+ * + * @return a {@link java.util.Set} object. + */ public Set get_normal_contacts() { Point drill_center = this.get_center(); @@ -347,6 +431,12 @@ else if (curr_item instanceof ConductionArea) return result; } + /** + *

normal_contact_point.

+ * + * @param p_other a {@link board.Item} object. + * @return a {@link geometry.planar.Point} object. + */ public Point normal_contact_point(Item p_other) { return p_other.normal_contact_point(this); @@ -375,6 +465,11 @@ Point normal_contact_point(Trace p_trace) return null; } + /** + *

get_ratsnest_corners.

+ * + * @return an array of {@link geometry.planar.Point} objects. + */ public Point[] get_ratsnest_corners() { Point[] result = new Point[1]; @@ -382,12 +477,17 @@ public Point[] get_ratsnest_corners() return result; } + /** {@inheritDoc} */ public TileShape get_trace_connection_shape(ShapeSearchTree p_search_tree, int p_index) { return TileShape.get_instance(this.get_center()); } - /** False, if this drillitem is places on the back side of the board */ + /** + * False, if this drillitem is places on the back side of the board + * + * @return a boolean. + */ public boolean is_placed_on_front() { return true; @@ -395,6 +495,8 @@ public boolean is_placed_on_front() /** * Return the mininal width of the shapes of this DrillItem on all signal layers. + * + * @return a double. */ public double min_width() { @@ -422,6 +524,9 @@ public double min_width() return this.precalculated_min_width; } + /** + *

clear_derived_data.

+ */ public void clear_derived_data() { super.clear_derived_data(); @@ -429,11 +534,17 @@ public void clear_derived_data() this.precalculated_last_layer = -1; } + /** + *

get_draw_priority.

+ * + * @return a int. + */ public int get_draw_priority() { return boardgraphics.Drawable.MIDDLE_DRAW_PRIORITY; } + /** {@inheritDoc} */ public void draw(java.awt.Graphics p_g, boardgraphics.GraphicsContext p_graphics_context, java.awt.Color[] p_color_arr, double p_intensity) { @@ -473,19 +584,19 @@ public void draw(java.awt.Graphics p_g, boardgraphics.GraphicsContext p_graphics /** * Contains the precalculated mininal width of the shapes of this DrillItem on all layers. - * If < 0, the value is not yet calculated + * {@code If < 0} , the value is not yet calculated */ private double precalculated_min_width = -1; /** * Contains the precalculated first layer, where this DrillItem contains a pad shape. - * If < 0, the value is not yet calculated + * {@code If < 0}, the value is not yet calculated */ private int precalculated_first_layer = -1; /** * Contains the precalculated last layer, where this DrillItem contains a pad shape. - * If < 0, the value is not yet calculated + * {@code If < 0}, the value is not yet calculated */ private int precalculated_last_layer = -1; diff --git a/board/FixedState.java b/src/main/java/board/FixedState.java similarity index 97% rename from board/FixedState.java rename to src/main/java/board/FixedState.java index 3b4fe0f..8733795 100644 --- a/board/FixedState.java +++ b/src/main/java/board/FixedState.java @@ -24,6 +24,7 @@ * Sorted fixed states of board items. The strongest fixed states came last. * * @author alfons + * @version $Id: $Id */ public enum FixedState { diff --git a/board/ForcedPadAlgo.java b/src/main/java/board/ForcedPadAlgo.java similarity index 96% rename from board/ForcedPadAlgo.java rename to src/main/java/board/ForcedPadAlgo.java index fb17151..a1b16c1 100644 --- a/board/ForcedPadAlgo.java +++ b/src/main/java/board/ForcedPadAlgo.java @@ -40,11 +40,16 @@ * shoving aside obstacle traces. * * @author Alfons Wirtz + * @version $Id: $Id */ public class ForcedPadAlgo { - /** Creates a new instance of ForcedPadAlgo */ + /** + * Creates a new instance of ForcedPadAlgo + * + * @param p_board a {@link board.RoutingBoard} object. + */ public ForcedPadAlgo(RoutingBoard p_board) { board = p_board; @@ -57,6 +62,19 @@ public ForcedPadAlgo(RoutingBoard p_board) * If p_ignore_items != null, items in this list are not checked, * If p_check_only_front only trace obstacles in the direction from p_from_side are checked * for performance reasons. This is the cave when moving drill_items + * + * @param p_pad_shape a {@link geometry.planar.TileShape} object. + * @param p_from_side a {@link board.CalcFromSide} object. + * @param p_layer a int. + * @param p_net_no_arr an array of int. + * @param p_cl_type a int. + * @param p_copper_sharing_allowed a boolean. + * @param p_ignore_items a {@link java.util.Collection} object. + * @param p_max_recursion_depth a int. + * @param p_max_via_recursion_depth a int. + * @param p_check_only_front a boolean. + * @param p_time_limit a {@link datastructures.TimeLimit} object. + * @return a {@link board.ForcedPadAlgo.CheckDrillResult} object. */ public CheckDrillResult check_forced_pad(TileShape p_pad_shape, CalcFromSide p_from_side, int p_layer, int[] p_net_no_arr, int p_cl_type, boolean p_copper_sharing_allowed, Collection p_ignore_items, int p_max_recursion_depth, int p_max_via_recursion_depth, diff --git a/board/ForcedViaAlgo.java b/src/main/java/board/ForcedViaAlgo.java similarity index 89% rename from board/ForcedViaAlgo.java rename to src/main/java/board/ForcedViaAlgo.java index 9ff43ad..c8d1dc1 100644 --- a/board/ForcedViaAlgo.java +++ b/src/main/java/board/ForcedViaAlgo.java @@ -39,12 +39,25 @@ * Class with static functions for checking and inserting forced vias. * * @author alfons + * @version $Id: $Id */ public class ForcedViaAlgo { /** * Checks, if a Via is possible at the input layer after evtl. shoving aside obstacle traces. * p_room_shape is used for calculating the from_side. + * + * @param p_via_radius a double. + * @param p_cl_class a int. + * @param p_attach_smd_allowed a boolean. + * @param p_room_shape a {@link geometry.planar.TileShape} object. + * @param p_location a {@link geometry.planar.Point} object. + * @param p_layer a int. + * @param p_net_no_arr an array of int. + * @param p_max_recursion_depth a int. + * @param p_max_via_recursion_depth a int. + * @param p_board a {@link board.RoutingBoard} object. + * @return a {@link board.ForcedPadAlgo.CheckDrillResult} object. */ public static ForcedPadAlgo.CheckDrillResult check_layer(double p_via_radius, int p_cl_class, boolean p_attach_smd_allowed, TileShape p_room_shape, Point p_location, int p_layer, @@ -92,6 +105,14 @@ public static ForcedPadAlgo.CheckDrillResult check_layer(double p_via_radius, in /** * Checks, if a Via is possible with the input parameter after evtl. shoving aside obstacle traces. + * + * @param p_via_info a {@link rules.ViaInfo} object. + * @param p_location a {@link geometry.planar.Point} object. + * @param p_net_no_arr an array of int. + * @param p_max_recursion_depth a int. + * @param p_max_via_recursion_depth a int. + * @param p_board a {@link board.RoutingBoard} object. + * @return a boolean. */ public static boolean check(ViaInfo p_via_info, Point p_location, int[] p_net_no_arr, int p_max_recursion_depth, int p_max_via_recursion_depth, RoutingBoard p_board) @@ -137,6 +158,16 @@ public static boolean check(ViaInfo p_via_info, Point p_location, int[] p_net_no * p_trace_clearance_class_no and p_trace_pen_halfwidth_arr is provided to make space for starting a trace * in case the trace width is bigger than the via shape. * Returns false, if the forced via failed. + * + * @param p_via_info a {@link rules.ViaInfo} object. + * @param p_location a {@link geometry.planar.Point} object. + * @param p_net_no_arr an array of int. + * @param p_trace_clearance_class_no a int. + * @param p_trace_pen_halfwidth_arr an array of int. + * @param p_max_recursion_depth a int. + * @param p_max_via_recursion_depth a int. + * @param p_board a {@link board.RoutingBoard} object. + * @return a boolean. */ public static boolean insert( ViaInfo p_via_info, Point p_location, int[] p_net_no_arr, int p_trace_clearance_class_no, int [] p_trace_pen_halfwidth_arr, int p_max_recursion_depth, diff --git a/board/Item.java b/src/main/java/board/Item.java similarity index 88% rename from board/Item.java rename to src/main/java/board/Item.java index 52f2bb7..4abca36 100644 --- a/board/Item.java +++ b/src/main/java/board/Item.java @@ -1,1480 +1,1685 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - */ -package board; - -import java.util.Collection; -import java.util.LinkedList; - -import geometry.planar.Point; -import geometry.planar.IntPoint; -import geometry.planar.FloatPoint; -import geometry.planar.TileShape; -import geometry.planar.Vector; -import geometry.planar.IntBox; - -import java.awt.Color; -import java.awt.Graphics; -import java.io.Serializable; -import java.util.Iterator; -import java.util.Set; -import java.util.TreeSet; - -import rules.Nets; -import boardgraphics.Drawable; -import boardgraphics.GraphicsContext; - -import datastructures.UndoableObjects; -import datastructures.ShapeTree; -import datastructures.ShapeTree.TreeEntry; - -/** - * Basic class of the items on a board. - * - * @author Alfons Wirtz - */ -public abstract class Item implements Drawable, SearchTreeObject, ObjectInfoPanel.Printable, UndoableObjects.Storable, Serializable -{ - - /** - * Implements the comparable interface. - */ - public int compareTo(Object p_other) - { - int result; - if (p_other instanceof Item) - { - result = ((Item) p_other).id_no - id_no; - } - else - { - result = 1; - } - return result; - } - - /** - * returns the unique idcentification number of this item - */ - public int get_id_no() - { - return id_no; - } - - /** - * Returns true if the net number array of this item contains p_net_no. - */ - public boolean contains_net(int p_net_no) - { - if (p_net_no <= 0) - { - return false; - } - for (int i = 0; i < net_no_arr.length; ++i) - { - if (net_no_arr[i] == p_net_no) - { - return true; - } - } - return false; - } - - public boolean is_obstacle(int p_net_no) - { - return !contains_net(p_net_no); - } - - public boolean is_trace_obstacle(int p_net_no) - { - return !contains_net(p_net_no); - } - - /** - * Returns, if this item in not allowed to overlap with p_other. - */ - public abstract boolean is_obstacle(Item p_other); - - /** - * Returns true if the net number arrays of this and p_other have a common - * number. - */ - public boolean shares_net(Item p_other) - { - return this.shares_net_no(p_other.net_no_arr); - } - - /** - * Returns true if the net number array of this and p_net_no_arr have a common - * number. - */ - public boolean shares_net_no(int[] p_net_no_arr) - { - for (int i = 0; i < net_no_arr.length; ++i) - { - for (int j = 0; j < p_net_no_arr.length; ++j) - { - if (net_no_arr[i] == p_net_no_arr[j]) - { - return true; - } - } - } - return false; - } - - /** - * Returns the number of shapes of this item after decomposition into convex polygonal shapes - */ - public abstract int tile_shape_count(); - - /** - * Returns the p_index-throws shape of this item after decomposition into convex polygonal shapes - */ - public TileShape get_tile_shape(int p_index) - { - if (this.board == null) - { - System.out.println("Item.get_tile_shape: board is null"); - return null; - } - return get_tree_shape(this.board.search_tree_manager.get_default_tree(), p_index); - } - - public int tree_shape_count(ShapeTree p_tree) - { - if (this.board == null) - { - return 0; - } - TileShape[] precalculated_tree_shapes = this.get_precalculated_tree_shapes(p_tree); - return precalculated_tree_shapes.length; - } - - public TileShape get_tree_shape(ShapeTree p_tree, int p_index) - { - if (this.board == null) - { - return null; - } - TileShape[] precalculated_tree_shapes = this.get_precalculated_tree_shapes(p_tree); - return precalculated_tree_shapes[p_index]; - } - - private TileShape[] get_precalculated_tree_shapes(ShapeTree p_tree) - { - if (this.search_trees_info == null) - { - this.search_trees_info = new ItemSearchTreesInfo(); - } - TileShape[] precalculated_tree_shapes = this.search_trees_info.get_precalculated_tree_shapes(p_tree); - if (precalculated_tree_shapes == null) - { - precalculated_tree_shapes = this.calculate_tree_shapes((ShapeSearchTree) p_tree); - this.search_trees_info.set_precalculated_tree_shapes(precalculated_tree_shapes, p_tree); - } - return precalculated_tree_shapes; - } - - /** - * Caculates the tree shapes for this item for p_search_tree. - */ - protected abstract TileShape[] calculate_tree_shapes(ShapeSearchTree p_search_tree); - - /** - * Returns false, if this item is deleted oor not inserted into - * the board. - */ - public boolean is_on_the_board() - { - return this.on_the_board; - } - - void set_on_the_board(boolean p_value) - { - this.on_the_board = p_value; - } - - /** - * Creates a copy of this item with id number p_id_no. - * If p_id_no <= 0, the id_no of the new item is generated internally - */ - public abstract Item copy(int p_id_no); - - public Object clone() - { - return copy(this.get_id_no()); - } - - /** - * returns true, if the layer range of this item contains p_layer - */ - public abstract boolean is_on_layer(int p_layer); - - /** - * Returns the number of the first layer containing geometry of this item. - */ - public abstract int first_layer(); - - /** - * Returns the number of the last layer containing geometry of this item. - */ - public abstract int last_layer(); - - /** - * write this item to an output stream - */ - public abstract boolean write(java.io.ObjectOutputStream p_stream); - - /** - * Translates the shapes of this item by p_vector. - * Does not move the item in the board. - */ - public abstract void translate_by(Vector p_vector); - - /** - * Turns this Item by p_factor times 90 degree around p_pole. - * Does not update the item in the board. - */ - public abstract void turn_90_degree(int p_factor, IntPoint p_pole); - - /** - * Rotates this Item by p_angle_in_degree around p_pole. - * Does not update the item in the board. - */ - public abstract void rotate_approx(double p_angle_in_degree, FloatPoint p_pole); - - /** - * Changes the placement side of this Item and mirrors it at the vertical line through p_pole. - * Does not update the item in the board. - */ - public abstract void change_placement_side(IntPoint p_pole); - - /** - * Returns a box containing the geometry of this item. - */ - public abstract IntBox bounding_box(); - - /** - * Translates this item by p_vector in the board. - */ - public void move_by(Vector p_vector) - { - board.item_list.save_for_undo(this); - board.search_tree_manager.remove(this); - this.translate_by(p_vector); - board.search_tree_manager.insert(this); - // let the observers syncronize the changes - board.communication.observers.notify_changed(this); - } - - /** - * Returns true, if some shapes of this item and p_other are - * on the same layer. - */ - public boolean shares_layer(Item p_other) - { - int max_first_layer = Math.max(this.first_layer(), p_other.first_layer()); - int min_last_layer = Math.min(this.last_layer(), p_other.last_layer()); - return max_first_layer <= min_last_layer; - } - - /** - * Returns the first layer, where both this item and p_other have a shape. - * Returns -1, if such a layer does not exisr. - */ - public int first_common_layer(Item p_other) - { - int max_first_layer = Math.max(this.first_layer(), p_other.first_layer()); - int min_last_layer = Math.min(this.last_layer(), p_other.last_layer()); - if (max_first_layer > min_last_layer) - { - return -1; - } - return max_first_layer; - } - - /** - * Returns the last layer, where both this item and p_other have a shape. - * Returns -1, if such a layer does not exisr. - */ - public int last_common_layer(Item p_other) - { - int max_first_layer = Math.max(this.first_layer(), p_other.first_layer()); - int min_last_layer = Math.min(this.last_layer(), p_other.last_layer()); - if (max_first_layer > min_last_layer) - { - return -1; - } - return min_last_layer; - } - - /** - * Return the name of the component of this item or null, if this item does not belong to a component. - */ - public String component_name() - { - if (component_no <= 0) - { - return null; - } - return board.components.get(component_no).name; - } - - /** - * Returns the count of clearance violations of this item with - * other items. - */ - public int clearance_violation_count() - { - Collection violations = this.clearance_violations(); - return violations.size(); - } - - /** - * Returns a list of all clearance violations of this item with other items. - * The objects in the list are of type ClearanceViolations. - * The first_item in such an object is always this item. - */ - public Collection clearance_violations() - { - Collection result = new LinkedList(); - if (this.board == null) - { - return result; - } - ShapeSearchTree default_tree = board.search_tree_manager.get_default_tree(); - for (int i = 0; i < tile_shape_count(); ++i) - { - TileShape curr_tile_shape = get_tile_shape(i); - Collection curr_overlapping_items = - default_tree.overlapping_tree_entries_with_clearance(curr_tile_shape, shape_layer(i), new int[0], clearance_class); - Iterator it = curr_overlapping_items.iterator(); - while (it.hasNext()) - { - TreeEntry curr_entry = it.next(); - if (!(curr_entry.object instanceof Item) || curr_entry.object == this) - { - continue; - } - Item curr_item = (Item) curr_entry.object; - boolean is_obstacle = curr_item.is_obstacle(this); - if (is_obstacle && this instanceof Trace && curr_item instanceof Trace) - { - // Look, if both traces are connected to the same tie pin. - // In this case they are allowed to overlap without sharing a net. - Trace this_trace = (Trace) this; - Point contact_point = this_trace.first_corner(); - boolean contact_found = false; - Collection curr_contacts = this_trace.get_normal_contacts(contact_point, true); - { - if (curr_contacts.contains(curr_item)) - { - contact_found = true; - } - } - if (!contact_found) - { - contact_point = this_trace.last_corner(); - curr_contacts = this_trace.get_normal_contacts(contact_point, true); - { - if (curr_contacts.contains(curr_item)) - { - contact_found = true; - } - } - } - if (contact_found) - { - for (Item curr_contact : curr_contacts) - { - if (curr_contact instanceof Pin) - { - if (curr_contact.shares_net(this) && curr_contact.shares_net(curr_item)) - { - is_obstacle = false; - break; - } - } - } - } - } - - if (is_obstacle) - { - TileShape shape_1 = curr_tile_shape; - TileShape shape_2 = curr_item.get_tree_shape(default_tree, curr_entry.shape_index_in_object); - if (shape_1 == null || shape_2 == null) - { - System.out.println("Item.clearance_violations: unexpected null shape"); - continue; - } - if (!this.board.search_tree_manager.is_clearance_compensation_used()) - { - double cl_offset = 0.5 * - board.rules.clearance_matrix.value(curr_item.clearance_class, this.clearance_class, shape_layer(i)); - shape_1 = (TileShape) shape_1.enlarge(cl_offset); - shape_2 = (TileShape) shape_2.enlarge(cl_offset); - } - - TileShape intersection = shape_1.intersection(shape_2); - if (intersection.dimension() == 2) - { - ClearanceViolation curr_violation = - new ClearanceViolation(this, curr_item, intersection, shape_layer(i)); - result.add(curr_violation); - } - } - } - } - return result; - } - - /** - * Returns all connectable Items with a direct contacts to this item. - * The result will be empty, if this item is not connectable. - */ - public Set get_all_contacts() - { - Set result = new TreeSet(); - if (!(this instanceof Connectable)) - { - return result; - } - for (int i = 0; i < this.tile_shape_count(); ++i) - { - Collection overlapping_items = board.overlapping_objects(get_tile_shape(i), shape_layer(i)); - Iterator it = overlapping_items.iterator(); - while (it.hasNext()) - { - SearchTreeObject curr_ob = it.next(); - if (!(curr_ob instanceof Item)) - { - continue; - } - Item curr_item = (Item) curr_ob; - if (curr_item != this && curr_item instanceof Connectable && curr_item.shares_net(this)) - { - result.add(curr_item); - } - } - } - return result; - } - - /** - * Returns all connectable Items with a direct contacts to this item on the input layer. - * The result will be empty, if this item is not connectable. - */ - public Set get_all_contacts(int p_layer) - { - Set result = new TreeSet(); - if (!(this instanceof Connectable)) - { - return result; - } - for (int i = 0; i < this.tile_shape_count(); ++i) - { - if (this.shape_layer(i) != p_layer) - { - continue; - } - Collection overlapping_items = board.overlapping_objects(get_tile_shape(i), p_layer); - Iterator it = overlapping_items.iterator(); - while (it.hasNext()) - { - SearchTreeObject curr_ob = it.next(); - if (!(curr_ob instanceof Item)) - { - continue; - } - Item curr_item = (Item) curr_ob; - if (curr_item != this && curr_item instanceof Connectable && curr_item.shares_net(this)) - { - result.add(curr_item); - } - } - } - return result; - } - - /** - * Checks, if this item is electrically connected to another connectable - * item. Returns false for items, which are not connectable. - */ - public boolean is_connected() - { - Collection contacts = this.get_all_contacts(); - return (contacts.size() > 0); - } - - /** - * Checks, if this item is electrically connected to another connectable - * item on the input layer. Returns false for items, which are not connectable. - */ - public boolean is_connected_on_layer(int p_layer) - { - Collection contacts_on_layer = this.get_all_contacts(p_layer); - return (contacts_on_layer.size() > 0); - } - - /** - * default implementation to be overwritten in the Connectable subclasses - */ - public Set get_normal_contacts() - { - return new TreeSet(); - } - - /** - * Returns the contact point, if this item and p_other are Connectable - * and have a unique normal contact. - * Returns null otherwise - */ - public Point normal_contact_point(Item p_other) - { - return null; - } - - /** - * auxiliary function - */ - Point normal_contact_point(Trace p_other) - { - return null; - } - - /** - * auxiliary function - */ - Point normal_contact_point(DrillItem p_other) - { - return null; - } - - /** - * Returns the set of all Connectable items of the net with number p_net_no which can be reached recursively - * via normal contacts from this item. - * If p_net_no <= 0, the net number is ignored. - */ - public Set get_connected_set(int p_net_no) - { - return get_connected_set(p_net_no, false); - } - - /** - * Returns the set of all Connectable items of the net with number p_net_no which can be reached recursively - * via normal contacts from this item. - * If p_net_no <= 0, the net number is ignored. - * If p_stop_at_plane, the recursive algorithm stops, when a conduction area is reached, - * which does not belong to a component. - */ - public Set get_connected_set(int p_net_no, boolean p_stop_at_plane) - { - Set result = new TreeSet(); - if (p_net_no > 0 && !this.contains_net(p_net_no)) - { - return result; - } - result.add(this); - get_connected_set_recu(result, p_net_no, p_stop_at_plane); - return result; - } - - /** - * recursive part of get_connected_set - */ - private void get_connected_set_recu(Set p_result, int p_net_no, boolean p_stop_at_plane) - { - Collection contact_list = get_normal_contacts(); - if (contact_list == null) - { - return; - } - for (Item curr_contact : contact_list) - { - if (p_stop_at_plane && curr_contact instanceof ConductionArea && curr_contact.get_component_no() <= 0) - { - continue; - } - if (p_net_no > 0 && !curr_contact.contains_net(p_net_no)) - { - continue; - } - if (p_result.add(curr_contact)) - { - curr_contact.get_connected_set_recu(p_result, p_net_no, p_stop_at_plane); - } - } - } - - /** - * Returns true, if this item contains some overlap to be cleaned. - */ - public boolean is_overlap() - { - return false; - } - - /** - * Recursive part of Trace.is_cycle. - * If p_ignore_areas is true, cycles where conduction areas are involved are ignored. - */ - boolean is_cycle_recu(Set p_visited_items, Item p_search_item, Item p_come_from_item, - boolean p_ignore_areas) - { - if (p_ignore_areas && this instanceof ConductionArea) - { - return false; - } - Collection contact_list = get_normal_contacts(); - if (contact_list == null) - { - return false; - } - Iterator it = contact_list.iterator(); - while (it.hasNext()) - { - Item curr_contact = it.next(); - if (curr_contact == p_come_from_item) - { - continue; - } - if (curr_contact == p_search_item) - { - return true; - } - if (p_visited_items.add(curr_contact)) - { - if (curr_contact.is_cycle_recu(p_visited_items, p_search_item, this, p_ignore_areas)) - { - return true; - } - } - } - return false; - } - - /** - * Returns the set of all Connectable items belonging to the net with number p_net_no, - * which are not in the connected set of this item. - * If p_net_no <= 0, the net numbers contained in this items are used instead of p_net_no. - */ - public Set get_unconnected_set(int p_net_no) - { - Set result = new TreeSet(); - if (p_net_no > 0 && !this.contains_net(p_net_no)) - { - return result; - } - if (p_net_no > 0) - { - result.addAll(board.get_connectable_items(p_net_no)); - } - else - { - for (int curr_net_no : this.net_no_arr) - { - result.addAll(board.get_connectable_items(curr_net_no)); - } - } - result.removeAll(this.get_connected_set(p_net_no)); - return result; - } - - /** - * Returns all traces and vias from this item until the next fork or terminal item. - */ - public Set get_connection_items() - { - return get_connection_items(StopConnectionOption.NONE); - } - - /** - * Returns all traces and vias from this item until the next fork or terminal item. - * If p_stop_option == StopConnectionOption.FANOUT_VIA, the algorithm will stop at the next fanout via, - * If p_stop_option == StopConnectionOption.VIA, the algorithm will stop at any via. - */ - public Set get_connection_items(StopConnectionOption p_stop_option) - { - Set contacts = this.get_normal_contacts(); - Set result = new TreeSet(); - if (this.is_route()) - { - result.add(this); - } - Iterator it = contacts.iterator(); - while (it.hasNext()) - { - Item curr_item = it.next(); - Point prev_contact_point = this.normal_contact_point(curr_item); - if (prev_contact_point == null) - { - // no unique contact point - continue; - } - int prev_contact_layer = this.first_common_layer(curr_item); - if (this instanceof Trace) - { - // Check, that there is only 1 contact at this location. - // Only for pins and vias items of more than 1 connection - // are collected - Trace start_trace = (Trace) this; - Collection check_contacts = start_trace.get_normal_contacts(prev_contact_point, false); - if (check_contacts.size() != 1) - { - continue; - } - } - // Search from curr_item along the contacts - // until the next fork or nonroute item. - for (;;) - { - if (!curr_item.is_route()) - { - // connection ends - break; - } - if (curr_item instanceof Via) - { - if (p_stop_option == StopConnectionOption.VIA) - { - break; - } - if (p_stop_option == StopConnectionOption.FANOUT_VIA) - { - if (curr_item.is_fanout_via(result)) - { - break; - } - } - } - result.add(curr_item); - Collection curr_ob_contacts = curr_item.get_normal_contacts(); - // filter the contacts at the previous contact point, - // because we were already there. - // If then there is not exactly 1 new contact left, there is - // a stub or a fork. - Point next_contact_point = null; - int next_contact_layer = -1; - Item next_contact = null; - boolean fork_found = false; - Iterator curr_it = curr_ob_contacts.iterator(); - while (curr_it.hasNext()) - { - Item tmp_contact = curr_it.next(); - int tmp_contact_layer = curr_item.first_common_layer(tmp_contact); - if (tmp_contact_layer >= 0) - { - Point tmp_contact_point = curr_item.normal_contact_point(tmp_contact); - if (tmp_contact_point == null) - { - // no unique contact point - fork_found = true; - break; - } - if (prev_contact_layer != tmp_contact_layer || - !prev_contact_point.equals(tmp_contact_point)) - { - if (next_contact != null) - { - // second new contact found - fork_found = true; - break; - } - next_contact = tmp_contact; - next_contact_point = tmp_contact_point; - next_contact_layer = tmp_contact_layer; - } - } - } - if (next_contact == null || fork_found) - { - break; - } - curr_item = next_contact; - prev_contact_point = next_contact_point; - prev_contact_layer = next_contact_layer; - } - } - return result; - } - - /** - * Function o be overwritten by classes Trace ans Via - */ - public boolean is_tail() - { - return false; - } - - /** - * Returns all corners of this item, which are used for displaying the ratsnest. - * To be overwritten in derived classes implementing the Connectable interface. - */ - public Point[] get_ratsnest_corners() - { - return new Point[0]; - } - - public void draw(Graphics p_g, GraphicsContext p_graphics_context, Color p_color, double p_intensity) - { - Color[] color_arr = new Color[board.get_layer_count()]; - for (int i = 0; i < color_arr.length; ++i) - { - color_arr[i] = p_color; - } - draw(p_g, p_graphics_context, color_arr, p_intensity); - } - - /** - * Draws this item whith its draw colors from p_graphics_context. - * p_layer_visibility[i] is expected between 0 and 1 for each layer i. - */ - public void draw(Graphics p_g, GraphicsContext p_graphics_context) - { - Color[] layer_colors = get_draw_colors(p_graphics_context); - draw(p_g, p_graphics_context, layer_colors, get_draw_intensity(p_graphics_context)); - } - - /** - * Test function checking the item for inconsitencies. - */ - public boolean validate() - { - boolean result = true; - if (!board.search_tree_manager.validate_entries(this)) - { - result = false; - } - for (int i = 0; i < this.tile_shape_count(); ++i) - { - TileShape curr_shape = this.get_tile_shape(i); - if (curr_shape.is_empty()) - { - System.out.println("Item.validate: shape is empty"); - result = false; - } - } - return result; - } - - /** - * Returns for this item the layer of the shape with index p_index. - * If p_id_no <= 0, it w2ill be generated internally. - */ - public abstract int shape_layer(int p_index); - - Item(int[] p_net_no_arr, int p_clearance_type, int p_id_no, - int p_component_no, FixedState p_fixed_state, BasicBoard p_board) - { - if (p_net_no_arr == null) - { - net_no_arr = new int[0]; - } - else - { - net_no_arr = new int[p_net_no_arr.length]; - System.arraycopy(p_net_no_arr, 0, net_no_arr, 0, p_net_no_arr.length); - } - clearance_class = p_clearance_type; - component_no = p_component_no; - fixed_state = p_fixed_state; - board = p_board; - if (p_id_no <= 0) - { - id_no = board.communication.id_no_generator.new_no(); - } - else - { - id_no = p_id_no; - } - } - - /** - * Returns true, if it is not allowed to change this item except evtl. shoving the item - */ - public boolean is_user_fixed() - { - return (fixed_state.ordinal() >= FixedState.USER_FIXED.ordinal()); - } - - /** - * Returns true, if it is not allowed to delete this item. - */ - boolean is_delete_fixed() - { - // Items belonging to a component are delete_fixed. - if (this.component_no > 0 || is_user_fixed()) - { - return true; - } - // Also power planes are delete_fixed. - if (this instanceof ConductionArea) - { - if (!this.board.layer_structure.arr[((ConductionArea) this).get_layer()].is_signal) - { - return true; - } - } - return false; - } - - /** - * Returns true, if it is not allowed to change the location of this item by the push algorithm. - */ - public boolean is_shove_fixed() - { - return (this.fixed_state.ordinal() >= FixedState.SHOVE_FIXED.ordinal()); - } - - /** - * Returns the fixed state of this Item. - */ - public FixedState get_fixed_state() - { - return this.fixed_state; - } - - /** - * Returns false, if this item is an obstacle for vias with the input net number. - */ - public boolean is_drillable(int p_net_no) - { - return false; - } - - /** - * Fixes the item. - */ - public void set_fixed_state(FixedState p_fixed_state) - { - fixed_state = p_fixed_state; - } - - /** - * Unfixes the item, if it is not fixed by the system. - */ - public void unfix() - { - if (fixed_state != FixedState.SYSTEM_FIXED) - { - fixed_state = FixedState.UNFIXED; - } - - } - - /** - * returns true, if this item is an unfixed trace or via - */ - public boolean is_route() - { - return false; - } - - /** - * Returns, if this item can be routed to. - */ - public boolean is_connectable() - { - return ((this instanceof Connectable) && this.net_count() > 0); - } - - /** - * Returns the count of nets this item belongs to. - */ - public int net_count() - { - return net_no_arr.length; - } - - /** - * gets the p_no-th net number of this item for 0 <= p_no < this.net_count(). - */ - public int get_net_no(int p_no) - { - return net_no_arr[p_no]; - } - - /** - * Return the component number of this item or 0, if it does not belong to a component. - */ - public int get_component_no() - { - return component_no; - } - - /** - * Removes p_net_no from the net number array. - * Returns false, if p_net_no was not contained in this array. - */ - public boolean remove_from_net(int p_net_no) - { - int found_index = -1; - for (int i = 0; i < this.net_no_arr.length; ++i) - { - if (this.net_no_arr[i] == p_net_no) - { - found_index = i; - } - } - if (found_index < 0) - { - return false; - } - int[] new_net_no_arr = new int[this.net_no_arr.length - 1]; - for (int i = 0; i < found_index; ++i) - { - new_net_no_arr[i] = this.net_no_arr[i]; - } - for (int i = found_index; i < new_net_no_arr.length; ++i) - { - new_net_no_arr[i] = this.net_no_arr[i + 1]; - } - this.net_no_arr = new_net_no_arr; - return true; - } - - /** - * Returns the index in the clearance matrix describing the required spacing - * of this item to other items - */ - public int clearance_class_no() - { - return clearance_class; - } - - /** - * Sets the index in the clearance matrix describing the required spacing - * of this item to other items. - */ - public void set_clearance_class_no(int p_index) - { - if (p_index < 0 || p_index >= this.board.rules.clearance_matrix.get_class_count()) - { - System.out.println("Item.set_clearance_class_no: p_index out of range"); - return; - } - clearance_class = p_index; - } - - /** - * Changes the clearance class of this item and updates the search tree. - */ - public void change_clearance_class(int p_index) - { - if (p_index < 0 || p_index >= this.board.rules.clearance_matrix.get_class_count()) - { - System.out.println("Item.set_clearance_class_no: p_index out of range"); - return; - } - clearance_class = p_index; - this.clear_derived_data(); - if (this.board != null && this.board.search_tree_manager.is_clearance_compensation_used()) - { - // reinsert the item into the search tree, because the compensated shape has changed. - this.board.search_tree_manager.remove(this); - this.board.search_tree_manager.insert(this); - } - } - - /** - * Assigns this item to the component with the input component number. - */ - public void assign_component_no(int p_no) - { - component_no = p_no; - } - - /** - * Makes this item connectable and assigns it to the input net. - * If p_net_no < 0, the net items net number will be removed and the item will no longer be connectable. - */ - public void assign_net_no(int p_net_no) - { - if (!Nets.is_normal_net_no(p_net_no)) - { - return; - } - if (p_net_no > board.rules.nets.max_net_no()) - { - System.out.println("Item.assign_net_no: p_net_no to big"); - return; - } - board.item_list.save_for_undo(this); - if (p_net_no <= 0) - { - net_no_arr = new int[0]; - } - else - { - if (net_no_arr.length == 0) - { - net_no_arr = new int[1]; - } - else if (net_no_arr.length > 1) - { - System.out.println("Item.assign_net_no: unexpected net_count > 1"); - } - net_no_arr[0] = p_net_no; - } - } - - /** - * Returns true, if p_item is contained in the input filter. - */ - public abstract boolean is_selected_by_filter(ItemSelectionFilter p_filter); - - /** - * Internally used for implementing the function is_selectrd_by_filter - */ - protected boolean is_selected_by_fixed_filter(ItemSelectionFilter p_filter) - { - boolean result; - if (this.is_user_fixed()) - { - result = p_filter.is_selected(ItemSelectionFilter.SelectableChoices.FIXED); - } - else - { - result = p_filter.is_selected(ItemSelectionFilter.SelectableChoices.UNFIXED); - } - return result; - } - - /** - * Sets the item tree entries for the tree with identification number p_tree_no. - */ - public void set_search_tree_entries(ShapeTree.Leaf[] p_tree_entries, ShapeTree p_tree) - { - if (this.board == null) - { - return; - } - if (this.search_trees_info == null) - { - this.search_trees_info = new ItemSearchTreesInfo(); - } - this.search_trees_info.set_tree_entries(p_tree_entries, p_tree); - } - - /** - * Returns the tree entries for the tree with identification number p_tree_no, - * or null, if for this tree no entries of this item are inserted. - */ - public ShapeTree.Leaf[] get_search_tree_entries(ShapeSearchTree p_tree) - { - if (this.search_trees_info == null) - { - return null; - } - return this.search_trees_info.get_tree_entries(p_tree); - } - - /** - * Sets the precalculated tree shapes tree entries for the tree with identification number p_tree_no. - */ - protected void set_precalculated_tree_shapes(TileShape[] p_shapes, ShapeSearchTree p_tree) - { - if (this.board == null) - { - return; - } - if (this.search_trees_info == null) - { - System.out.println("Item.set_precalculated_tree_shapes search_trees_info not allocated"); - return; - } - this.search_trees_info.set_precalculated_tree_shapes(p_shapes, p_tree); - } - - /** - * Sets the searh tree entries of this item to null. - */ - public void clear_search_tree_entries() - { - this.search_trees_info = null; - } - - /** - * Gets the information for the autoroute algorithm. - * Creates it, if it does not yet exist. - */ - public autoroute.ItemAutorouteInfo get_autoroute_info() - { - if (autoroute_info == null) - { - autoroute_info = new autoroute.ItemAutorouteInfo(this); - } - return autoroute_info; - } - - /** - * Gets the information for the autoroute algorithm. - */ - public autoroute.ItemAutorouteInfo get_autoroute_info_pur() - { - return autoroute_info; - } - - /** - * Clears the data allocated for the autoroute algorithm. - */ - public void clear_autoroute_info() - { - autoroute_info = null; - } - - /** - * Clear all cached or derived data. so that they have to be recalculated, - * when they are used next time. - */ - public void clear_derived_data() - { - if (this.search_trees_info != null) - { - this.search_trees_info.clear_precalculated_tree_shapes(); - } - autoroute_info = null; - } - - /** - * Internal funktion used in the implementation of print_info - */ - protected void print_net_info(ObjectInfoPanel p_window, java.util.Locale p_locale) - { - java.util.ResourceBundle resources = - java.util.ResourceBundle.getBundle("board.resources.ObjectInfoPanel", p_locale); - for (int i = 0; i < this.net_count(); ++i) - { - p_window.append(", " + resources.getString("net") + " "); - rules.Net curr_net = board.rules.nets.get(this.get_net_no(i)); - p_window.append(curr_net.name, resources.getString("net_info"), curr_net); - } - } - - /** - * Internal funktion used in the implementation of print_info - */ - protected void print_clearance_info(ObjectInfoPanel p_window, java.util.Locale p_locale) - { - if (this.clearance_class > 0) - { - java.util.ResourceBundle resources = - java.util.ResourceBundle.getBundle("board.resources.ObjectInfoPanel", p_locale); - p_window.append(", " + resources.getString("clearance_class") + " "); - String name = board.rules.clearance_matrix.get_name(this.clearance_class); - p_window.append(name, resources.getString("clearance_info"), board.rules.clearance_matrix.get_row(this.clearance_class)); - } - } - - /** - * Internal funktion used in the implementation of print_info - */ - protected void print_fixed_info(ObjectInfoPanel p_window, java.util.Locale p_locale) - { - if (this.fixed_state != FixedState.UNFIXED) - { - java.util.ResourceBundle resources = - java.util.ResourceBundle.getBundle("board.resources.FixedState", p_locale); - p_window.append(", "); - p_window.append(resources.getString(this.fixed_state.toString())); - } - } - - /** - * Internal funktion used in the implementation of print_info - */ - protected void print_contact_info(ObjectInfoPanel p_window, java.util.Locale p_locale) - { - Collection contacts = this.get_normal_contacts(); - if (!contacts.isEmpty()) - { - java.util.ResourceBundle resources = - java.util.ResourceBundle.getBundle("board.resources.ObjectInfoPanel", p_locale); - p_window.append(", " + resources.getString("contacts") + " "); - Integer contact_count = contacts.size(); - p_window.append_items(contact_count.toString(), resources.getString("contact_info"), contacts); - } - } - - /** - * Internal funktion used in the implementation of print_info - */ - protected void print_clearance_violation_info(ObjectInfoPanel p_window, java.util.Locale p_locale) - { - Collection clearance_violations = this.clearance_violations(); - if (!clearance_violations.isEmpty()) - { - java.util.ResourceBundle resources = - java.util.ResourceBundle.getBundle("board.resources.ObjectInfoPanel", p_locale); - p_window.append(", "); - Integer violation_count = clearance_violations.size(); - Collection violations = new java.util.LinkedList(); - violations.addAll(clearance_violations); - p_window.append_objects(violation_count.toString(), resources.getString("violation_info"), violations); - if (violation_count == 1) - { - p_window.append(" " + resources.getString("clearance_violation")); - } - else - { - p_window.append(" " + resources.getString("clearance_violations")); - } - } - } - - /** - * Internal funktion used in the implementation of print_info - */ - protected void print_connectable_item_info(ObjectInfoPanel p_window, java.util.Locale p_locale) - { - this.print_clearance_info(p_window, p_locale); - this.print_fixed_info(p_window, p_locale); - this.print_net_info(p_window, p_locale); - this.print_contact_info(p_window, p_locale); - this.print_clearance_violation_info(p_window, p_locale); - } - - /** - * Internal funktion used in the implementation of print_info - */ - protected void print_item_info(ObjectInfoPanel p_window, java.util.Locale p_locale) - { - this.print_clearance_info(p_window, p_locale); - this.print_fixed_info(p_window, p_locale); - this.print_clearance_violation_info(p_window, p_locale); - } - - /** - * Checks, if all nets of this items are normal. - */ - public boolean nets_normal() - { - for (int i = 0; i < this.net_no_arr.length; ++i) - { - if (!Nets.is_normal_net_no(this.net_no_arr[i])) - { - return false; - } - } - return true; - } - - /** - * Checks, if this item and p_other contain exactly the same net numbers. - */ - public boolean nets_equal(Item p_other) - { - return nets_equal(p_other.net_no_arr); - } - - /** - * Checks, if this item contains exacly the nets in p_net_no_arr - */ - public boolean nets_equal(int[] p_net_no_arr) - { - if (this.net_no_arr.length != p_net_no_arr.length) - { - return false; - } - for (int curr_net_no : p_net_no_arr) - { - if (!this.contains_net(curr_net_no)) - { - return false; - } - } - return true; - } - - /** - * Returns true, if the via is directly ob by a trace connected to a nearby SMD-pin. - * If p_ignore_items != null, contact traces in P-ignore_items are ignored. - */ - boolean is_fanout_via(Set p_ignore_items) - { - Collection contact_list = this.get_normal_contacts(); - for (Item curr_contact : contact_list) - { - if (curr_contact instanceof Pin && curr_contact.first_layer() == curr_contact.last_layer() && curr_contact.get_normal_contacts().size() <= 1) - { - return true; - } - if (curr_contact instanceof Trace) - { - if (p_ignore_items != null && p_ignore_items.contains(curr_contact)) - { - continue; - } - Trace curr_trace = (Trace) curr_contact; - if (curr_trace.get_length() >= PROTECT_FANOUT_LENGTH * curr_trace.get_half_width()) - { - continue; - } - Collection trace_contact_list = curr_trace.get_normal_contacts(); - for (Item tmp_contact : trace_contact_list) - { - if (tmp_contact instanceof Pin && curr_contact.first_layer() == curr_contact.last_layer() && tmp_contact.get_normal_contacts().size() <= 1) - { - return true; - } - if (tmp_contact instanceof PolylineTrace && tmp_contact.get_fixed_state() == FixedState.SHOVE_FIXED) - { - // look for shove fixed exit traces of SMD-pins - PolylineTrace contact_trace = (PolylineTrace) tmp_contact; - if (contact_trace.corner_count() == 2) - { - return true; - } - } - } - } - } - return false; - } - /** - * the index in the clearance matrix describing the required spacing - * to other items - */ - private int clearance_class; - /** The board this Itewm is on */ - transient public BasicBoard board; - /** The nets, to which this item belongs */ - int[] net_no_arr; - /** points to the entries of this item in the ShapeSearchTrees */ - transient private ItemSearchTreesInfo search_trees_info = null; - private FixedState fixed_state; - /** not 0, if this item belongs to a component */ - private int component_no = 0; - private final int id_no; - /** - * Folse, if the item is deleted or not inserted into the board - */ - private boolean on_the_board = false; - /** Temporary data used in the autoroute algorithm. */ - transient private autoroute.ItemAutorouteInfo autoroute_info = null; - private static double PROTECT_FANOUT_LENGTH = 400; - - /** - * Used as parameter of get_connection to control, that the connection - * stops at the next fanout via or at any via. - */ - public enum StopConnectionOption - { - - NONE, FANOUT_VIA, VIA - } -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + */ +package board; + +import java.util.Collection; +import java.util.LinkedList; + +import geometry.planar.Point; +import geometry.planar.IntPoint; +import geometry.planar.FloatPoint; +import geometry.planar.TileShape; +import geometry.planar.Vector; +import geometry.planar.IntBox; + +import java.awt.Color; +import java.awt.Graphics; +import java.io.Serializable; +import java.util.Iterator; +import java.util.Set; +import java.util.TreeSet; + +import rules.Nets; +import boardgraphics.Drawable; +import boardgraphics.GraphicsContext; + +import datastructures.UndoableObjects; +import datastructures.ShapeTree; +import datastructures.ShapeTree.TreeEntry; + +/** + * Basic class of the items on a board. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public abstract class Item implements Drawable, SearchTreeObject, ObjectInfoPanel.Printable, UndoableObjects.Storable, Serializable +{ + + /** + * {@inheritDoc} + * + * Implements the comparable interface. + */ + public int compareTo(Object p_other) + { + int result; + if (p_other instanceof Item) + { + result = ((Item) p_other).id_no - id_no; + } + else + { + result = 1; + } + return result; + } + + /** + * returns the unique idcentification number of this item + * + * @return a int. + */ + public int get_id_no() + { + return id_no; + } + + /** + * Returns true if the net number array of this item contains p_net_no. + * + * @param p_net_no a int. + * @return a boolean. + */ + public boolean contains_net(int p_net_no) + { + if (p_net_no <= 0) + { + return false; + } + for (int i = 0; i < net_no_arr.length; ++i) + { + if (net_no_arr[i] == p_net_no) + { + return true; + } + } + return false; + } + + /** {@inheritDoc} */ + public boolean is_obstacle(int p_net_no) + { + return !contains_net(p_net_no); + } + + /** {@inheritDoc} */ + public boolean is_trace_obstacle(int p_net_no) + { + return !contains_net(p_net_no); + } + + /** + * Returns, if this item in not allowed to overlap with p_other. + * + * @param p_other a {@link board.Item} object. + * @return a boolean. + */ + public abstract boolean is_obstacle(Item p_other); + + /** + * Returns true if the net number arrays of this and p_other have a common + * number. + * + * @param p_other a {@link board.Item} object. + * @return a boolean. + */ + public boolean shares_net(Item p_other) + { + return this.shares_net_no(p_other.net_no_arr); + } + + /** + * Returns true if the net number array of this and p_net_no_arr have a common + * number. + * + * @param p_net_no_arr an array of int. + * @return a boolean. + */ + public boolean shares_net_no(int[] p_net_no_arr) + { + for (int i = 0; i < net_no_arr.length; ++i) + { + for (int j = 0; j < p_net_no_arr.length; ++j) + { + if (net_no_arr[i] == p_net_no_arr[j]) + { + return true; + } + } + } + return false; + } + + /** + * Returns the number of shapes of this item after decomposition into convex polygonal shapes + * + * @return a int. + */ + public abstract int tile_shape_count(); + + /** + * Returns the p_index-throws shape of this item after decomposition into convex polygonal shapes + * + * @param p_index a int. + * @return a {@link geometry.planar.TileShape} object. + */ + public TileShape get_tile_shape(int p_index) + { + if (this.board == null) + { + System.out.println("Item.get_tile_shape: board is null"); + return null; + } + return get_tree_shape(this.board.search_tree_manager.get_default_tree(), p_index); + } + + /** {@inheritDoc} */ + public int tree_shape_count(ShapeTree p_tree) + { + if (this.board == null) + { + return 0; + } + TileShape[] precalculated_tree_shapes = this.get_precalculated_tree_shapes(p_tree); + return precalculated_tree_shapes.length; + } + + /** {@inheritDoc} */ + public TileShape get_tree_shape(ShapeTree p_tree, int p_index) + { + if (this.board == null) + { + return null; + } + TileShape[] precalculated_tree_shapes = this.get_precalculated_tree_shapes(p_tree); + return precalculated_tree_shapes[p_index]; + } + + private TileShape[] get_precalculated_tree_shapes(ShapeTree p_tree) + { + if (this.search_trees_info == null) + { + this.search_trees_info = new ItemSearchTreesInfo(); + } + TileShape[] precalculated_tree_shapes = this.search_trees_info.get_precalculated_tree_shapes(p_tree); + if (precalculated_tree_shapes == null) + { + precalculated_tree_shapes = this.calculate_tree_shapes((ShapeSearchTree) p_tree); + this.search_trees_info.set_precalculated_tree_shapes(precalculated_tree_shapes, p_tree); + } + return precalculated_tree_shapes; + } + + /** + * Caculates the tree shapes for this item for p_search_tree. + * + * @param p_search_tree a {@link board.ShapeSearchTree} object. + * @return an array of {@link geometry.planar.TileShape} objects. + */ + protected abstract TileShape[] calculate_tree_shapes(ShapeSearchTree p_search_tree); + + /** + * Returns false, if this item is deleted oor not inserted into + * the board. + * + * @return a boolean. + */ + public boolean is_on_the_board() + { + return this.on_the_board; + } + + void set_on_the_board(boolean p_value) + { + this.on_the_board = p_value; + } + + /** + * Creates a copy of this item with id number p_id_no. + * If {@code p_id_no <= 0}, the id_no of the new item is generated internally + * + * @param p_id_no a int. + * @return a {@link board.Item} object. + */ + public abstract Item copy(int p_id_no); + + /** + *

clone.

+ * + * @return a {@link java.lang.Object} object. + */ + public Object clone() + { + return copy(this.get_id_no()); + } + + /** + * returns true, if the layer range of this item contains p_layer + * + * @param p_layer a int. + * @return a boolean. + */ + public abstract boolean is_on_layer(int p_layer); + + /** + * Returns the number of the first layer containing geometry of this item. + * + * @return a int. + */ + public abstract int first_layer(); + + /** + * Returns the number of the last layer containing geometry of this item. + * + * @return a int. + */ + public abstract int last_layer(); + + /** + * write this item to an output stream + * + * @param p_stream a {@link java.io.ObjectOutputStream} object. + * @return a boolean. + */ + public abstract boolean write(java.io.ObjectOutputStream p_stream); + + /** + * Translates the shapes of this item by p_vector. + * Does not move the item in the board. + * + * @param p_vector a {@link geometry.planar.Vector} object. + */ + public abstract void translate_by(Vector p_vector); + + /** + * Turns this Item by p_factor times 90 degree around p_pole. + * Does not update the item in the board. + * + * @param p_factor a int. + * @param p_pole a {@link geometry.planar.IntPoint} object. + */ + public abstract void turn_90_degree(int p_factor, IntPoint p_pole); + + /** + * Rotates this Item by p_angle_in_degree around p_pole. + * Does not update the item in the board. + * + * @param p_angle_in_degree a double. + * @param p_pole a {@link geometry.planar.FloatPoint} object. + */ + public abstract void rotate_approx(double p_angle_in_degree, FloatPoint p_pole); + + /** + * Changes the placement side of this Item and mirrors it at the vertical line through p_pole. + * Does not update the item in the board. + * + * @param p_pole a {@link geometry.planar.IntPoint} object. + */ + public abstract void change_placement_side(IntPoint p_pole); + + /** + * Returns a box containing the geometry of this item. + * + * @return a {@link geometry.planar.IntBox} object. + */ + public abstract IntBox bounding_box(); + + /** + * Translates this item by p_vector in the board. + * + * @param p_vector a {@link geometry.planar.Vector} object. + */ + public void move_by(Vector p_vector) + { + board.item_list.save_for_undo(this); + board.search_tree_manager.remove(this); + this.translate_by(p_vector); + board.search_tree_manager.insert(this); + // let the observers syncronize the changes + board.communication.observers.notify_changed(this); + } + + /** + * Returns true, if some shapes of this item and p_other are + * on the same layer. + * + * @param p_other a {@link board.Item} object. + * @return a boolean. + */ + public boolean shares_layer(Item p_other) + { + int max_first_layer = Math.max(this.first_layer(), p_other.first_layer()); + int min_last_layer = Math.min(this.last_layer(), p_other.last_layer()); + return max_first_layer <= min_last_layer; + } + + /** + * Returns the first layer, where both this item and p_other have a shape. + * Returns -1, if such a layer does not exisr. + * + * @param p_other a {@link board.Item} object. + * @return a int. + */ + public int first_common_layer(Item p_other) + { + int max_first_layer = Math.max(this.first_layer(), p_other.first_layer()); + int min_last_layer = Math.min(this.last_layer(), p_other.last_layer()); + if (max_first_layer > min_last_layer) + { + return -1; + } + return max_first_layer; + } + + /** + * Returns the last layer, where both this item and p_other have a shape. + * Returns -1, if such a layer does not exisr. + * + * @param p_other a {@link board.Item} object. + * @return a int. + */ + public int last_common_layer(Item p_other) + { + int max_first_layer = Math.max(this.first_layer(), p_other.first_layer()); + int min_last_layer = Math.min(this.last_layer(), p_other.last_layer()); + if (max_first_layer > min_last_layer) + { + return -1; + } + return min_last_layer; + } + + /** + * Return the name of the component of this item or null, if this item does not belong to a component. + * + * @return a {@link java.lang.String} object. + */ + public String component_name() + { + if (component_no <= 0) + { + return null; + } + return board.components.get(component_no).name; + } + + /** + * Returns the count of clearance violations of this item with + * other items. + * + * @return a int. + */ + public int clearance_violation_count() + { + Collection violations = this.clearance_violations(); + return violations.size(); + } + + /** + * Returns a list of all clearance violations of this item with other items. + * The objects in the list are of type ClearanceViolations. + * The first_item in such an object is always this item. + * + * @return a java$util$Collection object. + */ + public Collection clearance_violations() + { + Collection result = new LinkedList(); + if (this.board == null) + { + return result; + } + ShapeSearchTree default_tree = board.search_tree_manager.get_default_tree(); + for (int i = 0; i < tile_shape_count(); ++i) + { + TileShape curr_tile_shape = get_tile_shape(i); + Collection curr_overlapping_items = + default_tree.overlapping_tree_entries_with_clearance(curr_tile_shape, shape_layer(i), new int[0], clearance_class); + Iterator it = curr_overlapping_items.iterator(); + while (it.hasNext()) + { + TreeEntry curr_entry = it.next(); + if (!(curr_entry.object instanceof Item) || curr_entry.object == this) + { + continue; + } + Item curr_item = (Item) curr_entry.object; + boolean is_obstacle = curr_item.is_obstacle(this); + if (is_obstacle && this instanceof Trace && curr_item instanceof Trace) + { + // Look, if both traces are connected to the same tie pin. + // In this case they are allowed to overlap without sharing a net. + Trace this_trace = (Trace) this; + Point contact_point = this_trace.first_corner(); + boolean contact_found = false; + Collection curr_contacts = this_trace.get_normal_contacts(contact_point, true); + { + if (curr_contacts.contains(curr_item)) + { + contact_found = true; + } + } + if (!contact_found) + { + contact_point = this_trace.last_corner(); + curr_contacts = this_trace.get_normal_contacts(contact_point, true); + { + if (curr_contacts.contains(curr_item)) + { + contact_found = true; + } + } + } + if (contact_found) + { + for (Item curr_contact : curr_contacts) + { + if (curr_contact instanceof Pin) + { + if (curr_contact.shares_net(this) && curr_contact.shares_net(curr_item)) + { + is_obstacle = false; + break; + } + } + } + } + } + + if (is_obstacle) + { + TileShape shape_1 = curr_tile_shape; + TileShape shape_2 = curr_item.get_tree_shape(default_tree, curr_entry.shape_index_in_object); + if (shape_1 == null || shape_2 == null) + { + System.out.println("Item.clearance_violations: unexpected null shape"); + continue; + } + if (!this.board.search_tree_manager.is_clearance_compensation_used()) + { + double cl_offset = 0.5 * + board.rules.clearance_matrix.value(curr_item.clearance_class, this.clearance_class, shape_layer(i)); + shape_1 = (TileShape) shape_1.enlarge(cl_offset); + shape_2 = (TileShape) shape_2.enlarge(cl_offset); + } + + TileShape intersection = shape_1.intersection(shape_2); + if (intersection.dimension() == 2) + { + ClearanceViolation curr_violation = + new ClearanceViolation(this, curr_item, intersection, shape_layer(i)); + result.add(curr_violation); + } + } + } + } + return result; + } + + /** + * Returns all connectable Items with a direct contacts to this item. + * The result will be empty, if this item is not connectable. + * + * @return a java$util$Set object. + */ + public Set get_all_contacts() + { + Set result = new TreeSet(); + if (!(this instanceof Connectable)) + { + return result; + } + for (int i = 0; i < this.tile_shape_count(); ++i) + { + Collection overlapping_items = board.overlapping_objects(get_tile_shape(i), shape_layer(i)); + Iterator it = overlapping_items.iterator(); + while (it.hasNext()) + { + SearchTreeObject curr_ob = it.next(); + if (!(curr_ob instanceof Item)) + { + continue; + } + Item curr_item = (Item) curr_ob; + if (curr_item != this && curr_item instanceof Connectable && curr_item.shares_net(this)) + { + result.add(curr_item); + } + } + } + return result; + } + + /** + * Returns all connectable Items with a direct contacts to this item on the input layer. + * The result will be empty, if this item is not connectable. + * + * @param p_layer a int. + * @return a java$util$Set object. + */ + public Set get_all_contacts(int p_layer) + { + Set result = new TreeSet(); + if (!(this instanceof Connectable)) + { + return result; + } + for (int i = 0; i < this.tile_shape_count(); ++i) + { + if (this.shape_layer(i) != p_layer) + { + continue; + } + Collection overlapping_items = board.overlapping_objects(get_tile_shape(i), p_layer); + Iterator it = overlapping_items.iterator(); + while (it.hasNext()) + { + SearchTreeObject curr_ob = it.next(); + if (!(curr_ob instanceof Item)) + { + continue; + } + Item curr_item = (Item) curr_ob; + if (curr_item != this && curr_item instanceof Connectable && curr_item.shares_net(this)) + { + result.add(curr_item); + } + } + } + return result; + } + + /** + * Checks, if this item is electrically connected to another connectable + * item. Returns false for items, which are not connectable. + * + * @return a boolean. + */ + public boolean is_connected() + { + Collection contacts = this.get_all_contacts(); + return (contacts.size() > 0); + } + + /** + * Checks, if this item is electrically connected to another connectable + * item on the input layer. Returns false for items, which are not connectable. + * + * @param p_layer a int. + * @return a boolean. + */ + public boolean is_connected_on_layer(int p_layer) + { + Collection contacts_on_layer = this.get_all_contacts(p_layer); + return (contacts_on_layer.size() > 0); + } + + /** + * default implementation to be overwritten in the Connectable subclasses + * + * @return a java$util$Set object. + */ + public Set get_normal_contacts() + { + return new TreeSet(); + } + + /** + * Returns the contact point, if this item and p_other are Connectable + * and have a unique normal contact. + * Returns null otherwise + * + * @param p_other a {@link board.Item} object. + * @return a {@link geometry.planar.Point} object. + */ + public Point normal_contact_point(Item p_other) + { + return null; + } + + /** + * auxiliary function + */ + Point normal_contact_point(Trace p_other) + { + return null; + } + + /** + * auxiliary function + */ + Point normal_contact_point(DrillItem p_other) + { + return null; + } + + /** + * Returns the set of all Connectable items of the net with number p_net_no which can be reached recursively + * via normal contacts from this item. + * If {@code p_net_no <= 0}, the net number is ignored. + * + * @param p_net_no a int. + * @return a java$util$Set object. + */ + public Set get_connected_set(int p_net_no) + { + return get_connected_set(p_net_no, false); + } + + /** + * Returns the set of all Connectable items of the net with number p_net_no which can be reached recursively + * via normal contacts from this item. + * If {@code p_net_no <= 0}, the net number is ignored. + * If p_stop_at_plane, the recursive algorithm stops, when a conduction area is reached, + * which does not belong to a component. + * + * @param p_net_no a int. + * @param p_stop_at_plane a boolean. + * @return a java$util$Set object. + */ + public Set get_connected_set(int p_net_no, boolean p_stop_at_plane) + { + Set result = new TreeSet(); + if (p_net_no > 0 && !this.contains_net(p_net_no)) + { + return result; + } + result.add(this); + get_connected_set_recu(result, p_net_no, p_stop_at_plane); + return result; + } + + /** + * recursive part of get_connected_set + */ + private void get_connected_set_recu(Set p_result, int p_net_no, boolean p_stop_at_plane) + { + Collection contact_list = get_normal_contacts(); + if (contact_list == null) + { + return; + } + for (Item curr_contact : contact_list) + { + if (p_stop_at_plane && curr_contact instanceof ConductionArea && curr_contact.get_component_no() <= 0) + { + continue; + } + if (p_net_no > 0 && !curr_contact.contains_net(p_net_no)) + { + continue; + } + if (p_result.add(curr_contact)) + { + curr_contact.get_connected_set_recu(p_result, p_net_no, p_stop_at_plane); + } + } + } + + /** + * Returns true, if this item contains some overlap to be cleaned. + * + * @return a boolean. + */ + public boolean is_overlap() + { + return false; + } + + /** + * Recursive part of Trace.is_cycle. + * If p_ignore_areas is true, cycles where conduction areas are involved are ignored. + */ + boolean is_cycle_recu(Set p_visited_items, Item p_search_item, Item p_come_from_item, + boolean p_ignore_areas) + { + if (p_ignore_areas && this instanceof ConductionArea) + { + return false; + } + Collection contact_list = get_normal_contacts(); + if (contact_list == null) + { + return false; + } + Iterator it = contact_list.iterator(); + while (it.hasNext()) + { + Item curr_contact = it.next(); + if (curr_contact == p_come_from_item) + { + continue; + } + if (curr_contact == p_search_item) + { + return true; + } + if (p_visited_items.add(curr_contact)) + { + if (curr_contact.is_cycle_recu(p_visited_items, p_search_item, this, p_ignore_areas)) + { + return true; + } + } + } + return false; + } + + /** + * Returns the set of all Connectable items belonging to the net with number p_net_no, + * which are not in the connected set of this item. + * If {@code p_net_no <= 0}, the net numbers contained in this items are used instead of p_net_no. + * + * @param p_net_no a int. + * @return a java$util$Set object. + */ + public Set get_unconnected_set(int p_net_no) + { + Set result = new TreeSet(); + if (p_net_no > 0 && !this.contains_net(p_net_no)) + { + return result; + } + if (p_net_no > 0) + { + result.addAll(board.get_connectable_items(p_net_no)); + } + else + { + for (int curr_net_no : this.net_no_arr) + { + result.addAll(board.get_connectable_items(curr_net_no)); + } + } + result.removeAll(this.get_connected_set(p_net_no)); + return result; + } + + /** + * Returns all traces and vias from this item until the next fork or terminal item. + * + * @return a java.util.Set object. + */ + public Set get_connection_items() + { + return get_connection_items(StopConnectionOption.NONE); + } + + /** + * Returns all traces and vias from this item until the next fork or terminal item. + * If p_stop_option == StopConnectionOption.FANOUT_VIA, the algorithm will stop at the next fanout via, + * If p_stop_option == StopConnectionOption.VIA, the algorithm will stop at any via. + * + * @param p_stop_option a {@link board.Item.StopConnectionOption} object. + * @return a java.util.Set object. + */ + public Set get_connection_items(StopConnectionOption p_stop_option) + { + Set contacts = this.get_normal_contacts(); + Set result = new TreeSet(); + if (this.is_route()) + { + result.add(this); + } + Iterator it = contacts.iterator(); + while (it.hasNext()) + { + Item curr_item = it.next(); + Point prev_contact_point = this.normal_contact_point(curr_item); + if (prev_contact_point == null) + { + // no unique contact point + continue; + } + int prev_contact_layer = this.first_common_layer(curr_item); + if (this instanceof Trace) + { + // Check, that there is only 1 contact at this location. + // Only for pins and vias items of more than 1 connection + // are collected + Trace start_trace = (Trace) this; + Collection check_contacts = start_trace.get_normal_contacts(prev_contact_point, false); + if (check_contacts.size() != 1) + { + continue; + } + } + // Search from curr_item along the contacts + // until the next fork or nonroute item. + for (;;) + { + if (!curr_item.is_route()) + { + // connection ends + break; + } + if (curr_item instanceof Via) + { + if (p_stop_option == StopConnectionOption.VIA) + { + break; + } + if (p_stop_option == StopConnectionOption.FANOUT_VIA) + { + if (curr_item.is_fanout_via(result)) + { + break; + } + } + } + result.add(curr_item); + Collection curr_ob_contacts = curr_item.get_normal_contacts(); + // filter the contacts at the previous contact point, + // because we were already there. + // If then there is not exactly 1 new contact left, there is + // a stub or a fork. + Point next_contact_point = null; + int next_contact_layer = -1; + Item next_contact = null; + boolean fork_found = false; + Iterator curr_it = curr_ob_contacts.iterator(); + while (curr_it.hasNext()) + { + Item tmp_contact = curr_it.next(); + int tmp_contact_layer = curr_item.first_common_layer(tmp_contact); + if (tmp_contact_layer >= 0) + { + Point tmp_contact_point = curr_item.normal_contact_point(tmp_contact); + if (tmp_contact_point == null) + { + // no unique contact point + fork_found = true; + break; + } + if (prev_contact_layer != tmp_contact_layer || + !prev_contact_point.equals(tmp_contact_point)) + { + if (next_contact != null) + { + // second new contact found + fork_found = true; + break; + } + next_contact = tmp_contact; + next_contact_point = tmp_contact_point; + next_contact_layer = tmp_contact_layer; + } + } + } + if (next_contact == null || fork_found) + { + break; + } + curr_item = next_contact; + prev_contact_point = next_contact_point; + prev_contact_layer = next_contact_layer; + } + } + return result; + } + + /** + * Function o be overwritten by classes Trace ans Via + * + * @return a boolean. + */ + public boolean is_tail() + { + return false; + } + + /** + * Returns all corners of this item, which are used for displaying the ratsnest. + * To be overwritten in derived classes implementing the Connectable interface. + * + * @return an array of {@link geometry.planar.Point} objects. + */ + public Point[] get_ratsnest_corners() + { + return new Point[0]; + } + + /** {@inheritDoc} */ + public void draw(Graphics p_g, GraphicsContext p_graphics_context, Color p_color, double p_intensity) + { + Color[] color_arr = new Color[board.get_layer_count()]; + for (int i = 0; i < color_arr.length; ++i) + { + color_arr[i] = p_color; + } + draw(p_g, p_graphics_context, color_arr, p_intensity); + } + + /** + * Draws this item whith its draw colors from p_graphics_context. + * p_layer_visibility[i] is expected between 0 and 1 for each layer i. + * + * @param p_g a {@link java.awt.Graphics} object. + * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object. + * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object. + */ + public void draw(Graphics p_g, GraphicsContext p_graphics_context) + { + Color[] layer_colors = get_draw_colors(p_graphics_context); + draw(p_g, p_graphics_context, layer_colors, get_draw_intensity(p_graphics_context)); + } + + /** + * Test function checking the item for inconsitencies. + * + * @return a boolean. + */ + public boolean validate() + { + boolean result = true; + if (!board.search_tree_manager.validate_entries(this)) + { + result = false; + } + for (int i = 0; i < this.tile_shape_count(); ++i) + { + TileShape curr_shape = this.get_tile_shape(i); + if (curr_shape.is_empty()) + { + System.out.println("Item.validate: shape is empty"); + result = false; + } + } + return result; + } + + /** + * {@inheritDoc} + * + * Returns for this item the layer of the shape with index p_index. + * If {@code p_id_no <= 0}, it w2ill be generated internally. + */ + public abstract int shape_layer(int p_index); + + Item(int[] p_net_no_arr, int p_clearance_type, int p_id_no, + int p_component_no, FixedState p_fixed_state, BasicBoard p_board) + { + if (p_net_no_arr == null) + { + net_no_arr = new int[0]; + } + else + { + net_no_arr = new int[p_net_no_arr.length]; + System.arraycopy(p_net_no_arr, 0, net_no_arr, 0, p_net_no_arr.length); + } + clearance_class = p_clearance_type; + component_no = p_component_no; + fixed_state = p_fixed_state; + board = p_board; + if (p_id_no <= 0) + { + id_no = board.communication.id_no_generator.new_no(); + } + else + { + id_no = p_id_no; + } + } + + /** + * Returns true, if it is not allowed to change this item except evtl. shoving the item + * + * @return a boolean. + */ + public boolean is_user_fixed() + { + return (fixed_state.ordinal() >= FixedState.USER_FIXED.ordinal()); + } + + /** + * Returns true, if it is not allowed to delete this item. + */ + boolean is_delete_fixed() + { + // Items belonging to a component are delete_fixed. + if (this.component_no > 0 || is_user_fixed()) + { + return true; + } + // Also power planes are delete_fixed. + if (this instanceof ConductionArea) + { + if (!this.board.layer_structure.arr[((ConductionArea) this).get_layer()].is_signal) + { + return true; + } + } + return false; + } + + /** + * Returns true, if it is not allowed to change the location of this item by the push algorithm. + * + * @return a boolean. + */ + public boolean is_shove_fixed() + { + return (this.fixed_state.ordinal() >= FixedState.SHOVE_FIXED.ordinal()); + } + + /** + * Returns the fixed state of this Item. + * + * @return a {@link board.FixedState} object. + */ + public FixedState get_fixed_state() + { + return this.fixed_state; + } + + /** + * Returns false, if this item is an obstacle for vias with the input net number. + * + * @param p_net_no a int. + * @return a boolean. + */ + public boolean is_drillable(int p_net_no) + { + return false; + } + + /** + * Fixes the item. + * + * @param p_fixed_state a {@link board.FixedState} object. + */ + public void set_fixed_state(FixedState p_fixed_state) + { + fixed_state = p_fixed_state; + } + + /** + * Unfixes the item, if it is not fixed by the system. + */ + public void unfix() + { + if (fixed_state != FixedState.SYSTEM_FIXED) + { + fixed_state = FixedState.UNFIXED; + } + + } + + /** + * returns true, if this item is an unfixed trace or via + * + * @return a boolean. + */ + public boolean is_route() + { + return false; + } + + /** + * Returns, if this item can be routed to. + * + * @return a boolean. + */ + public boolean is_connectable() + { + return ((this instanceof Connectable) && this.net_count() > 0); + } + + /** + * Returns the count of nets this item belongs to. + * + * @return a int. + */ + public int net_count() + { + return net_no_arr.length; + } + + /** + * gets the p_no-th net number of this item for {@code 0 <= p_no < this.net_count()}. + * + * @param p_no a int. + * @return a int. + */ + public int get_net_no(int p_no) + { + return net_no_arr[p_no]; + } + + /** + * Return the component number of this item or 0, if it does not belong to a component. + * + * @return a int. + */ + public int get_component_no() + { + return component_no; + } + + /** + * Removes p_net_no from the net number array. + * Returns false, if p_net_no was not contained in this array. + * + * @param p_net_no a int. + * @return a boolean. + */ + public boolean remove_from_net(int p_net_no) + { + int found_index = -1; + for (int i = 0; i < this.net_no_arr.length; ++i) + { + if (this.net_no_arr[i] == p_net_no) + { + found_index = i; + } + } + if (found_index < 0) + { + return false; + } + int[] new_net_no_arr = new int[this.net_no_arr.length - 1]; + for (int i = 0; i < found_index; ++i) + { + new_net_no_arr[i] = this.net_no_arr[i]; + } + for (int i = found_index; i < new_net_no_arr.length; ++i) + { + new_net_no_arr[i] = this.net_no_arr[i + 1]; + } + this.net_no_arr = new_net_no_arr; + return true; + } + + /** + * Returns the index in the clearance matrix describing the required spacing + * of this item to other items + * + * @return a int. + */ + public int clearance_class_no() + { + return clearance_class; + } + + /** + * Sets the index in the clearance matrix describing the required spacing + * of this item to other items. + * + * @param p_index a int. + */ + public void set_clearance_class_no(int p_index) + { + if (p_index < 0 || p_index >= this.board.rules.clearance_matrix.get_class_count()) + { + System.out.println("Item.set_clearance_class_no: p_index out of range"); + return; + } + clearance_class = p_index; + } + + /** + * Changes the clearance class of this item and updates the search tree. + * + * @param p_index a int. + */ + public void change_clearance_class(int p_index) + { + if (p_index < 0 || p_index >= this.board.rules.clearance_matrix.get_class_count()) + { + System.out.println("Item.set_clearance_class_no: p_index out of range"); + return; + } + clearance_class = p_index; + this.clear_derived_data(); + if (this.board != null && this.board.search_tree_manager.is_clearance_compensation_used()) + { + // reinsert the item into the search tree, because the compensated shape has changed. + this.board.search_tree_manager.remove(this); + this.board.search_tree_manager.insert(this); + } + } + + /** + * Assigns this item to the component with the input component number. + * + * @param p_no a int. + */ + public void assign_component_no(int p_no) + { + component_no = p_no; + } + + /** + * Makes this item connectable and assigns it to the input net. + * If {@code p_net_no < 0}, the net items net number will be removed and the item will no longer be connectable. + * + * @param p_net_no a int. + */ + public void assign_net_no(int p_net_no) + { + if (!Nets.is_normal_net_no(p_net_no)) + { + return; + } + if (p_net_no > board.rules.nets.max_net_no()) + { + System.out.println("Item.assign_net_no: p_net_no to big"); + return; + } + board.item_list.save_for_undo(this); + if (p_net_no <= 0) + { + net_no_arr = new int[0]; + } + else + { + if (net_no_arr.length == 0) + { + net_no_arr = new int[1]; + } + else if (net_no_arr.length > 1) + { + System.out.println("Item.assign_net_no: unexpected net_count > 1"); + } + net_no_arr[0] = p_net_no; + } + } + + /** + * Returns true, if p_item is contained in the input filter. + * + * @param p_filter a {@link board.ItemSelectionFilter} object. + * @return a boolean. + */ + public abstract boolean is_selected_by_filter(ItemSelectionFilter p_filter); + + /** + * Internally used for implementing the function is_selectrd_by_filter + * + * @param p_filter a {@link board.ItemSelectionFilter} object. + * @return a boolean. + */ + protected boolean is_selected_by_fixed_filter(ItemSelectionFilter p_filter) + { + boolean result; + if (this.is_user_fixed()) + { + result = p_filter.is_selected(ItemSelectionFilter.SelectableChoices.FIXED); + } + else + { + result = p_filter.is_selected(ItemSelectionFilter.SelectableChoices.UNFIXED); + } + return result; + } + + /** + * {@inheritDoc} + * + * Sets the item tree entries for the tree with identification number p_tree_no. + */ + public void set_search_tree_entries(ShapeTree.Leaf[] p_tree_entries, ShapeTree p_tree) + { + if (this.board == null) + { + return; + } + if (this.search_trees_info == null) + { + this.search_trees_info = new ItemSearchTreesInfo(); + } + this.search_trees_info.set_tree_entries(p_tree_entries, p_tree); + } + + /** + * Returns the tree entries for the tree with identification number p_tree_no, + * or null, if for this tree no entries of this item are inserted. + * + * @param p_tree a {@link board.ShapeSearchTree} object. + * @return an array of {@link datastructures.ShapeTree.Leaf} objects. + */ + public ShapeTree.Leaf[] get_search_tree_entries(ShapeSearchTree p_tree) + { + if (this.search_trees_info == null) + { + return null; + } + return this.search_trees_info.get_tree_entries(p_tree); + } + + /** + * Sets the precalculated tree shapes tree entries for the tree with identification number p_tree_no. + * + * @param p_shapes an array of {@link geometry.planar.TileShape} objects. + * @param p_tree a {@link board.ShapeSearchTree} object. + */ + protected void set_precalculated_tree_shapes(TileShape[] p_shapes, ShapeSearchTree p_tree) + { + if (this.board == null) + { + return; + } + if (this.search_trees_info == null) + { + System.out.println("Item.set_precalculated_tree_shapes search_trees_info not allocated"); + return; + } + this.search_trees_info.set_precalculated_tree_shapes(p_shapes, p_tree); + } + + /** + * Sets the searh tree entries of this item to null. + */ + public void clear_search_tree_entries() + { + this.search_trees_info = null; + } + + /** + * Gets the information for the autoroute algorithm. + * Creates it, if it does not yet exist. + * + * @return a {@link autoroute.ItemAutorouteInfo} object. + */ + public autoroute.ItemAutorouteInfo get_autoroute_info() + { + if (autoroute_info == null) + { + autoroute_info = new autoroute.ItemAutorouteInfo(this); + } + return autoroute_info; + } + + /** + * Gets the information for the autoroute algorithm. + * + * @return a {@link autoroute.ItemAutorouteInfo} object. + */ + public autoroute.ItemAutorouteInfo get_autoroute_info_pur() + { + return autoroute_info; + } + + /** + * Clears the data allocated for the autoroute algorithm. + */ + public void clear_autoroute_info() + { + autoroute_info = null; + } + + /** + * Clear all cached or derived data. so that they have to be recalculated, + * when they are used next time. + */ + public void clear_derived_data() + { + if (this.search_trees_info != null) + { + this.search_trees_info.clear_precalculated_tree_shapes(); + } + autoroute_info = null; + } + + /** + * Internal funktion used in the implementation of print_info + * + * @param p_window a {@link board.ObjectInfoPanel} object. + * @param p_locale a {@link java.util.Locale} object. + */ + protected void print_net_info(ObjectInfoPanel p_window, java.util.Locale p_locale) + { + java.util.ResourceBundle resources = + java.util.ResourceBundle.getBundle("board.resources.ObjectInfoPanel", p_locale); + for (int i = 0; i < this.net_count(); ++i) + { + p_window.append(", " + resources.getString("net") + " "); + rules.Net curr_net = board.rules.nets.get(this.get_net_no(i)); + p_window.append(curr_net.name, resources.getString("net_info"), curr_net); + } + } + + /** + * Internal funktion used in the implementation of print_info + * + * @param p_window a {@link board.ObjectInfoPanel} object. + * @param p_locale a {@link java.util.Locale} object. + */ + protected void print_clearance_info(ObjectInfoPanel p_window, java.util.Locale p_locale) + { + if (this.clearance_class > 0) + { + java.util.ResourceBundle resources = + java.util.ResourceBundle.getBundle("board.resources.ObjectInfoPanel", p_locale); + p_window.append(", " + resources.getString("clearance_class") + " "); + String name = board.rules.clearance_matrix.get_name(this.clearance_class); + p_window.append(name, resources.getString("clearance_info"), board.rules.clearance_matrix.get_row(this.clearance_class)); + } + } + + /** + * Internal funktion used in the implementation of print_info + * + * @param p_window a {@link board.ObjectInfoPanel} object. + * @param p_locale a {@link java.util.Locale} object. + */ + protected void print_fixed_info(ObjectInfoPanel p_window, java.util.Locale p_locale) + { + if (this.fixed_state != FixedState.UNFIXED) + { + java.util.ResourceBundle resources = + java.util.ResourceBundle.getBundle("board.resources.FixedState", p_locale); + p_window.append(", "); + p_window.append(resources.getString(this.fixed_state.toString())); + } + } + + /** + * Internal funktion used in the implementation of print_info + * + * @param p_window a {@link board.ObjectInfoPanel} object. + * @param p_locale a {@link java.util.Locale} object. + */ + protected void print_contact_info(ObjectInfoPanel p_window, java.util.Locale p_locale) + { + Collection contacts = this.get_normal_contacts(); + if (!contacts.isEmpty()) + { + java.util.ResourceBundle resources = + java.util.ResourceBundle.getBundle("board.resources.ObjectInfoPanel", p_locale); + p_window.append(", " + resources.getString("contacts") + " "); + Integer contact_count = contacts.size(); + p_window.append_items(contact_count.toString(), resources.getString("contact_info"), contacts); + } + } + + /** + * Internal funktion used in the implementation of print_info + * + * @param p_window a {@link board.ObjectInfoPanel} object. + * @param p_locale a {@link java.util.Locale} object. + */ + protected void print_clearance_violation_info(ObjectInfoPanel p_window, java.util.Locale p_locale) + { + Collection clearance_violations = this.clearance_violations(); + if (!clearance_violations.isEmpty()) + { + java.util.ResourceBundle resources = + java.util.ResourceBundle.getBundle("board.resources.ObjectInfoPanel", p_locale); + p_window.append(", "); + Integer violation_count = clearance_violations.size(); + Collection violations = new java.util.LinkedList(); + violations.addAll(clearance_violations); + p_window.append_objects(violation_count.toString(), resources.getString("violation_info"), violations); + if (violation_count == 1) + { + p_window.append(" " + resources.getString("clearance_violation")); + } + else + { + p_window.append(" " + resources.getString("clearance_violations")); + } + } + } + + /** + * Internal funktion used in the implementation of print_info + * + * @param p_window a {@link board.ObjectInfoPanel} object. + * @param p_locale a {@link java.util.Locale} object. + */ + protected void print_connectable_item_info(ObjectInfoPanel p_window, java.util.Locale p_locale) + { + this.print_clearance_info(p_window, p_locale); + this.print_fixed_info(p_window, p_locale); + this.print_net_info(p_window, p_locale); + this.print_contact_info(p_window, p_locale); + this.print_clearance_violation_info(p_window, p_locale); + } + + /** + * Internal funktion used in the implementation of print_info + * + * @param p_window a {@link board.ObjectInfoPanel} object. + * @param p_locale a {@link java.util.Locale} object. + */ + protected void print_item_info(ObjectInfoPanel p_window, java.util.Locale p_locale) + { + this.print_clearance_info(p_window, p_locale); + this.print_fixed_info(p_window, p_locale); + this.print_clearance_violation_info(p_window, p_locale); + } + + /** + * Checks, if all nets of this items are normal. + * + * @return a boolean. + */ + public boolean nets_normal() + { + for (int i = 0; i < this.net_no_arr.length; ++i) + { + if (!Nets.is_normal_net_no(this.net_no_arr[i])) + { + return false; + } + } + return true; + } + + /** + * Checks, if this item and p_other contain exactly the same net numbers. + * + * @param p_other a {@link board.Item} object. + * @return a boolean. + */ + public boolean nets_equal(Item p_other) + { + return nets_equal(p_other.net_no_arr); + } + + /** + * Checks, if this item contains exacly the nets in p_net_no_arr + * + * @param p_net_no_arr an array of int. + * @return a boolean. + */ + public boolean nets_equal(int[] p_net_no_arr) + { + if (this.net_no_arr.length != p_net_no_arr.length) + { + return false; + } + for (int curr_net_no : p_net_no_arr) + { + if (!this.contains_net(curr_net_no)) + { + return false; + } + } + return true; + } + + /** + * Returns true, if the via is directly ob by a trace connected to a nearby SMD-pin. + * If p_ignore_items != null, contact traces in P-ignore_items are ignored. + */ + boolean is_fanout_via(Set p_ignore_items) + { + Collection contact_list = this.get_normal_contacts(); + for (Item curr_contact : contact_list) + { + if (curr_contact instanceof Pin && curr_contact.first_layer() == curr_contact.last_layer() && curr_contact.get_normal_contacts().size() <= 1) + { + return true; + } + if (curr_contact instanceof Trace) + { + if (p_ignore_items != null && p_ignore_items.contains(curr_contact)) + { + continue; + } + Trace curr_trace = (Trace) curr_contact; + if (curr_trace.get_length() >= PROTECT_FANOUT_LENGTH * curr_trace.get_half_width()) + { + continue; + } + Collection trace_contact_list = curr_trace.get_normal_contacts(); + for (Item tmp_contact : trace_contact_list) + { + if (tmp_contact instanceof Pin && curr_contact.first_layer() == curr_contact.last_layer() && tmp_contact.get_normal_contacts().size() <= 1) + { + return true; + } + if (tmp_contact instanceof PolylineTrace && tmp_contact.get_fixed_state() == FixedState.SHOVE_FIXED) + { + // look for shove fixed exit traces of SMD-pins + PolylineTrace contact_trace = (PolylineTrace) tmp_contact; + if (contact_trace.corner_count() == 2) + { + return true; + } + } + } + } + } + return false; + } + /** + * the index in the clearance matrix describing the required spacing + * to other items + */ + private int clearance_class; + /** The board this Itewm is on */ + transient public BasicBoard board; + /** The nets, to which this item belongs */ + int[] net_no_arr; + /** points to the entries of this item in the ShapeSearchTrees */ + transient private ItemSearchTreesInfo search_trees_info = null; + private FixedState fixed_state; + /** not 0, if this item belongs to a component */ + private int component_no = 0; + private final int id_no; + /** + * Folse, if the item is deleted or not inserted into the board + */ + private boolean on_the_board = false; + /** Temporary data used in the autoroute algorithm. */ + transient private autoroute.ItemAutorouteInfo autoroute_info = null; + private static double PROTECT_FANOUT_LENGTH = 400; + + /** + * Used as parameter of get_connection to control, that the connection + * stops at the next fanout via or at any via. + */ + public enum StopConnectionOption + { + + NONE, FANOUT_VIA, VIA + } +} diff --git a/board/ItemIdNoGenerator.java b/src/main/java/board/ItemIdNoGenerator.java similarity index 95% rename from board/ItemIdNoGenerator.java rename to src/main/java/board/ItemIdNoGenerator.java index 57e41b3..98f4713 100644 --- a/board/ItemIdNoGenerator.java +++ b/src/main/java/board/ItemIdNoGenerator.java @@ -24,6 +24,7 @@ * Creates unique Item identication nunbers. * * @author Alfons Wirtz + * @version $Id: $Id */ public class ItemIdNoGenerator implements datastructures.IdNoGenerator, java.io.Serializable { @@ -39,6 +40,8 @@ public ItemIdNoGenerator() * Create a new unique identification number. * Use eventually the id_no generater from the host system * for syncronisation + * + * @return a int. */ public int new_no() { @@ -52,6 +55,8 @@ public int new_no() /** * Return the maximum generated id number so far. + * + * @return a int. */ public int max_generated_no() { diff --git a/board/ItemSearchTreesInfo.java b/src/main/java/board/ItemSearchTreesInfo.java similarity index 84% rename from board/ItemSearchTreesInfo.java rename to src/main/java/board/ItemSearchTreesInfo.java index 28def97..2a28f25 100644 --- a/board/ItemSearchTreesInfo.java +++ b/src/main/java/board/ItemSearchTreesInfo.java @@ -37,7 +37,9 @@ class ItemSearchTreesInfo { - /** Creates a new instance of ItemSearchTreeEntries */ + /** + * Creates a new instance of ItemSearchTreeEntries + */ public ItemSearchTreesInfo() { this.tree_list = new LinkedList(); @@ -46,6 +48,9 @@ public ItemSearchTreesInfo() /** * Returns the tree entries for the tree with identification number p_tree_no, * or null, if for this tree no entries of this item are inserted. + * + * @param p_tree a {@link datastructures.ShapeTree} object. + * @return an array of {@link datastructures.ShapeTree.Leaf} objects. */ public ShapeTree.Leaf[] get_tree_entries(ShapeTree p_tree) { @@ -61,6 +66,10 @@ public ShapeTree.Leaf[] get_tree_entries(ShapeTree p_tree) /** * Sets the item tree entries for the tree with identification number p_tree_no. + * + * @param p_tree_entries an array of {@link datastructures.ShapeTree.Leaf} objects. + * @param p_tree_entries an array of {@link datastructures.ShapeTree.Leaf} objects. + * @param p_tree a {@link datastructures.ShapeTree} object. */ public void set_tree_entries(ShapeTree.Leaf[] p_tree_entries, ShapeTree p_tree) { @@ -80,6 +89,9 @@ public void set_tree_entries(ShapeTree.Leaf[] p_tree_entries, ShapeTree p_tree) /** * Returns the precalculated tiles hapes for the tree with identification number p_tree_no, * or null, if the tile shapes of this tree are nnot yet precalculated. + * + * @param p_tree a {@link datastructures.ShapeTree} object. + * @return an array of {@link geometry.planar.TileShape} objects. */ public TileShape[] get_precalculated_tree_shapes(ShapeTree p_tree) { @@ -95,6 +107,9 @@ public TileShape[] get_precalculated_tree_shapes(ShapeTree p_tree) /** * Sets the item tree entries for the tree with identification number p_tree_no. + * + * @param p_tile_shapes an array of {@link geometry.planar.TileShape} objects. + * @param p_tree a {@link datastructures.ShapeTree} object. */ public void set_precalculated_tree_shapes(TileShape[] p_tile_shapes, ShapeTree p_tree) { diff --git a/board/ItemSelectionFilter.java b/src/main/java/board/ItemSelectionFilter.java similarity index 86% rename from board/ItemSelectionFilter.java rename to src/main/java/board/ItemSelectionFilter.java index e64378a..3546e65 100644 --- a/board/ItemSelectionFilter.java +++ b/src/main/java/board/ItemSelectionFilter.java @@ -27,6 +27,7 @@ * Filter for selecting items on the board. * * @author Alfons Wirtz + * @version $Id: $Id */ public class ItemSelectionFilter implements java.io.Serializable { @@ -54,6 +55,8 @@ public ItemSelectionFilter() /** * Creates a new filter with only p_item_type selected. + * + * @param p_item_type a {@link board.ItemSelectionFilter.SelectableChoices} object. */ public ItemSelectionFilter(SelectableChoices p_item_type) { @@ -66,6 +69,8 @@ public ItemSelectionFilter(SelectableChoices p_item_type) /** * Creates a new filter with only p_item_types selected. + * + * @param p_item_types an array of {@link board.ItemSelectionFilter.SelectableChoices} objects. */ public ItemSelectionFilter(SelectableChoices[] p_item_types) { @@ -81,6 +86,8 @@ public ItemSelectionFilter(SelectableChoices[] p_item_types) /** * Copy constructor + * + * @param p_item_selection_filter a {@link board.ItemSelectionFilter} object. */ public ItemSelectionFilter(ItemSelectionFilter p_item_selection_filter) { @@ -93,6 +100,9 @@ public ItemSelectionFilter(ItemSelectionFilter p_item_selection_filter) /** * Selects or deselects an item type + * + * @param p_choice a {@link board.ItemSelectionFilter.SelectableChoices} object. + * @param p_value a boolean. */ public void set_selected(SelectableChoices p_choice, boolean p_value) { @@ -117,6 +127,9 @@ public void deselect_all() /** * Filters a collection of items with this filter. + * + * @param p_items a java$util$Set object. + * @return a java$util$Set object. */ public Set filter(java.util.Set p_items) { @@ -133,6 +146,9 @@ public Set filter(java.util.Set p_items) /** * Looks, if the input item type is selected. + * + * @param p_choice a {@link board.ItemSelectionFilter.SelectableChoices} object. + * @return a boolean. */ public boolean is_selected(SelectableChoices p_choice) { diff --git a/board/Layer.java b/src/main/java/board/Layer.java similarity index 82% rename from board/Layer.java rename to src/main/java/board/Layer.java index 22d53a2..eba2e3b 100644 --- a/board/Layer.java +++ b/src/main/java/board/Layer.java @@ -24,17 +24,28 @@ * Describes the structure of a board layer. * * @author alfons + * @version $Id: $Id */ public class Layer implements java.io.Serializable { - /** Creates a new instance of Layer */ + /** + * Creates a new instance of Layer + * + * @param p_name a {@link java.lang.String} object. + * @param p_is_signal a boolean. + */ public Layer(String p_name, boolean p_is_signal) { name = p_name; is_signal = p_is_signal; } + /** + *

toString.

+ * + * @return a {@link java.lang.String} object. + */ public String toString() { return name; diff --git a/board/LayerStructure.java b/src/main/java/board/LayerStructure.java similarity index 85% rename from board/LayerStructure.java rename to src/main/java/board/LayerStructure.java index 7fe1f3e..6b289b1 100644 --- a/board/LayerStructure.java +++ b/src/main/java/board/LayerStructure.java @@ -24,11 +24,16 @@ * Describes the layer structure of the board. * * @author alfons + * @version $Id: $Id */ public class LayerStructure implements java.io.Serializable { - /** Creates a new instance of LayerStructure */ + /** + * Creates a new instance of LayerStructure + * + * @param p_layer_arr an array of {@link board.Layer} objects. + */ public LayerStructure(Layer [] p_layer_arr) { arr = p_layer_arr; @@ -37,6 +42,9 @@ public LayerStructure(Layer [] p_layer_arr) /** * Returns the index of the layer with the name p_name in the array arr, * -1, if arr contains no layer with name p_name. + * + * @param p_name a {@link java.lang.String} object. + * @return a int. */ public int get_no(String p_name) { @@ -53,6 +61,9 @@ public int get_no(String p_name) /** * Returns the index of p_layer in the array arr, * or -1, if arr does not contain p_layer. + * + * @param p_layer a {@link board.Layer} object. + * @return a int. */ public int get_no(Layer p_layer) { @@ -68,6 +79,8 @@ public int get_no(Layer p_layer) /** * Returns the count of signal layers of this layer_structure. + * + * @return a int. */ public int signal_layer_count() { @@ -84,6 +97,9 @@ public int signal_layer_count() /** * Gets the p_no-th signal layer of this layer structure. + * + * @param p_no a int. + * @return a {@link board.Layer} object. */ public Layer get_signal_layer(int p_no) { @@ -104,6 +120,9 @@ public Layer get_signal_layer(int p_no) /** * Returns the count of signal layers with a smaller number than p_layer + * + * @param p_layer a {@link board.Layer} object. + * @return a int. */ public int get_signal_layer_no(Layer p_layer) { @@ -124,6 +143,9 @@ public int get_signal_layer_no(Layer p_layer) /** * Gets the layer number of the p_signal_layer_no-th signal layer in this layer structure + * + * @param p_signal_layer_no a int. + * @return a int. */ public int get_layer_no (int p_signal_layer_no) { diff --git a/board/MoveComponent.java b/src/main/java/board/MoveComponent.java similarity index 94% rename from board/MoveComponent.java rename to src/main/java/board/MoveComponent.java index b8c8197..1e4b70f 100644 --- a/board/MoveComponent.java +++ b/src/main/java/board/MoveComponent.java @@ -34,12 +34,21 @@ /** * Class for moving a group of items on the board + * * @author Alfons Wirtz + * @version $Id: $Id */ public class MoveComponent { - /** Creates a new instance of MoveItemGroup */ + /** + * Creates a new instance of MoveItemGroup + * + * @param p_item a {@link board.Item} object. + * @param p_translate_vector a {@link geometry.planar.Vector} object. + * @param p_max_recursion_depth a int. + * @param p_max_via_recursion_depth a int. + */ public MoveComponent(Item p_item, Vector p_translate_vector, int p_max_recursion_depth, int p_max_via_recursion_depth) { translate_vector = p_translate_vector; @@ -119,6 +128,8 @@ public MoveComponent(Item p_item, Vector p_translate_vector, int p_max_recursion /** * Checks, if all items in the group can be moved by shoving obstacle trace aside * without creating clearance violations. + * + * @return a boolean. */ public boolean check() { @@ -162,6 +173,10 @@ public boolean check() * Moves all items in the group by this.translate_vector and shoves aside * obstacle traces. Returns false, if that was not possible without * creating clearance violations. In this case an undo may be necessary. + * + * @param p_tidy_width a int. + * @param p_pull_tight_accuracy a int. + * @return a boolean. */ public boolean insert(int p_tidy_width, int p_pull_tight_accuracy) { diff --git a/board/MoveDrillItemAlgo.java b/src/main/java/board/MoveDrillItemAlgo.java similarity index 96% rename from board/MoveDrillItemAlgo.java rename to src/main/java/board/MoveDrillItemAlgo.java index 0c68310..04917f3 100644 --- a/board/MoveDrillItemAlgo.java +++ b/src/main/java/board/MoveDrillItemAlgo.java @@ -41,6 +41,7 @@ * for shoving vias and pins * * @author Alfons Wirtz + * @version $Id: $Id */ public class MoveDrillItemAlgo { @@ -48,6 +49,15 @@ public class MoveDrillItemAlgo /** * checks, if p_drill_item can be translated by p_vector by shoving obstacle * traces and vias aside, so that no clearance violations occur. + * + * @param p_drill_item a {@link board.DrillItem} object. + * @param p_vector a {@link geometry.planar.Vector} object. + * @param p_max_recursion_depth a int. + * @param p_max_via_recursion_depth a int. + * @param p_ignore_items a java$util$Collection object. + * @param p_board a {@link board.RoutingBoard} object. + * @param p_time_limit a {@link datastructures.TimeLimit} object. + * @return a boolean. */ public static boolean check(DrillItem p_drill_item, Vector p_vector, int p_max_recursion_depth, int p_max_via_recursion_depth, Collection p_ignore_items, diff --git a/board/ObjectInfoPanel.java b/src/main/java/board/ObjectInfoPanel.java similarity index 72% rename from board/ObjectInfoPanel.java rename to src/main/java/board/ObjectInfoPanel.java index 408d9a6..5a8726c 100644 --- a/board/ObjectInfoPanel.java +++ b/src/main/java/board/ObjectInfoPanel.java @@ -24,18 +24,25 @@ * Output window for printing information about board objects. * * @author Alfons Wirtz + * @version $Id: $Id */ public interface ObjectInfoPanel { /** * Appends p_string to the window. * Returns false, if that was not possible. + * + * @param p_string a {@link java.lang.String} object. + * @return a boolean. */ boolean append(String p_string); /** * Appends p_string in bold styleto the window. * Returns false, if that was not possible. + * + * @param p_string a {@link java.lang.String} object. + * @return a boolean. */ boolean append_bold(String p_string); @@ -43,6 +50,9 @@ public interface ObjectInfoPanel * Appends p_value to the window after * transforming it to the user coordinate sytem. * Returns false, if that was not possible. + * + * @param p_value a double. + * @return a boolean. */ boolean append(double p_value); @@ -50,6 +60,9 @@ public interface ObjectInfoPanel * Appends p_value to the window without * transforming it to the user coordinate sytem. * Returns false, if that was not possible. + * + * @param p_value a double. + * @return a boolean. */ boolean append_without_transforming(double p_value); @@ -57,6 +70,9 @@ public interface ObjectInfoPanel * Appends p_point to the window * after transforming to the user coordinate sytem. * Returns false, if that was not possible. + * + * @param p_point a {@link geometry.planar.FloatPoint} object. + * @return a boolean. */ boolean append(geometry.planar.FloatPoint p_point); @@ -64,22 +80,35 @@ public interface ObjectInfoPanel * Appends p_shape to the window * after transforming to the user coordinate sytem. * Returns false, if that was not possible. + * + * @param p_shape a {@link geometry.planar.Shape} object. + * @param p_locale a {@link java.util.Locale} object. + * @return a boolean. */ boolean append(geometry.planar.Shape p_shape, java.util.Locale p_locale); /** * Begins a new line in the window. + * + * @return a boolean. */ boolean newline(); /** * Appends a fixed number of spaces to the window. + * + * @return a boolean. */ boolean indent(); /** * Appends a link for creating a new PrintInfoWindow with the information * of p_object to the window. Returns false, if that was not possible. + * + * @param p_link_name a {@link java.lang.String} object. + * @param p_window_title a {@link java.lang.String} object. + * @param p_object a {@link board.ObjectInfoPanel.Printable} object. + * @return a boolean. */ boolean append( String p_link_name, String p_window_title, ObjectInfoPanel.Printable p_object); @@ -87,12 +116,22 @@ public interface ObjectInfoPanel /** * Appends a link for creating a new PrintInfoWindow with the information * of p_items to the window. Returns false, if that was not possible. + * + * @param p_link_name a {@link java.lang.String} object. + * @param p_window_title a {@link java.lang.String} object. + * @param p_items a {@link java.util.Collection} object. + * @return a boolean. */ boolean append_items( String p_link_name, String p_window_title, java.util.Collection p_items); /** * Appends a link for creating a new PrintInfoWindow with the information * of p_objects to the window. Returns false, if that was not possible. + * + * @param p_button_name a {@link java.lang.String} object. + * @param p_window_title a {@link java.lang.String} object. + * @param p_objects a {@link java.util.Collection} object. + * @return a boolean. */ boolean append_objects( String p_button_name, String p_window_title, java.util.Collection p_objects); diff --git a/board/ObstacleArea.java b/src/main/java/board/ObstacleArea.java similarity index 88% rename from board/ObstacleArea.java rename to src/main/java/board/ObstacleArea.java index ae6a5b3..051cc21 100644 --- a/board/ObstacleArea.java +++ b/src/main/java/board/ObstacleArea.java @@ -1,393 +1,473 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - */ - -package board; - -import geometry.planar.IntBox; -import geometry.planar.IntPoint; -import geometry.planar.Area; -import geometry.planar.TileShape; -import geometry.planar.Vector; -import geometry.planar.Point; -import geometry.planar.FloatPoint; - -import java.awt.Color; - -import boardgraphics.GraphicsContext; - -/** - * - * An item on the board with an relative_area shape, for example keepout, conduction relative_area - * - * - * - * @author Alfons Wirtz - */ - -public class ObstacleArea extends Item implements java.io.Serializable -{ - /** - * Creates a new relative_area item which may belong to several nets. - * p_name is null, if the ObstacleArea does not belong to a component. - */ - ObstacleArea(Area p_area, int p_layer, Vector p_translation, double p_rotation_in_degree, boolean p_side_changed, - int[] p_net_no_arr, int p_clearance_type, int p_id_no, int p_cmp_no, String p_name, FixedState p_fixed_state, BasicBoard p_board) - { - super(p_net_no_arr, p_clearance_type, p_id_no, p_cmp_no, p_fixed_state, p_board); - this.relative_area = p_area; - this.layer = p_layer; - this.translation = p_translation; - this.rotation_in_degree = p_rotation_in_degree; - this.side_changed = p_side_changed; - this.name = p_name; - } - - /** - * Creates a new relative_area item without net. - * p_name is null, if the ObstacleArea does not belong to a component. - */ - ObstacleArea(Area p_area, int p_layer, Vector p_translation, double p_rotation_in_degree, boolean p_side_changed, - int p_clearance_type, int p_id_no, int p_group_no, String p_name, FixedState p_fixed_state, BasicBoard p_board) - { - this(p_area, p_layer, p_translation, p_rotation_in_degree, p_side_changed, new int[0], p_clearance_type, p_id_no, p_group_no, p_name, p_fixed_state, p_board); - } - - public Item copy(int p_id_no) - { - int [] copied_net_nos = new int[net_no_arr.length]; - System.arraycopy(net_no_arr, 0, copied_net_nos, 0, net_no_arr.length); - return new ObstacleArea(relative_area, layer, translation, rotation_in_degree, side_changed, copied_net_nos, clearance_class_no(), p_id_no, get_component_no(), name, get_fixed_state(), board); - } - - public Area get_area() - { - if (this.precalculated_absolute_area == null) - { - if (this.relative_area == null) - { - System.out.println("ObstacleArea.get_area: area is null"); - return null; - } - Area turned_area = this.relative_area; - if (this.side_changed && !this.board.components.get_flip_style_rotate_first()) - { - turned_area = turned_area.mirror_vertical(Point.ZERO); - } - if (this.rotation_in_degree != 0) - { - double rotation = this.rotation_in_degree; - if (rotation % 90 == 0) - { - turned_area = turned_area.turn_90_degree(((int) rotation )/ 90, Point.ZERO); - } - else - { - turned_area = turned_area.rotate_approx(Math.toRadians(rotation), FloatPoint.ZERO); - } - - } - if (this.side_changed && this.board.components.get_flip_style_rotate_first()) - { - turned_area = turned_area.mirror_vertical(Point.ZERO); - } - this.precalculated_absolute_area = turned_area.translate_by(this.translation); - } - return this.precalculated_absolute_area; - } - - protected Area get_relative_area() - { - return this.relative_area; - } - - public boolean is_on_layer(int p_layer) - { - return layer == p_layer; - } - - public int first_layer() - { - return this.layer; - } - - public int last_layer() - { - return this.layer; - } - - public int get_layer() - { - return this.layer; - } - - public IntBox bounding_box() - { - return this.get_area().bounding_box(); - } - - public boolean is_obstacle(Item p_other) - { - if (p_other.shares_net(this)) - { - return false; - } - return p_other instanceof Trace || p_other instanceof Via; - } - - protected TileShape[] calculate_tree_shapes(ShapeSearchTree p_search_tree) - { - return p_search_tree.calculate_tree_shapes(this); - } - - public int tile_shape_count() - { - TileShape[] tile_shapes = this.split_to_convex(); - if (tile_shapes == null) - { - // an error accured while dividing the relative_area - return 0; - } - return tile_shapes.length; - } - - public TileShape get_tile_shape(int p_no) - { - TileShape[] tile_shapes = this.split_to_convex(); - if (tile_shapes == null || p_no < 0 || p_no >= tile_shapes.length) - { - System.out.println("ConvexObstacle.get_tile_shape: p_no out of range"); - return null; - } - return tile_shapes[p_no]; - } - - public void translate_by(Vector p_vector) - { - this.translation = this.translation.add(p_vector); - this.clear_derived_data(); - } - - public void turn_90_degree(int p_factor, IntPoint p_pole) - { - this.rotation_in_degree += p_factor * 90; - while(this.rotation_in_degree >= 360) - { - this.rotation_in_degree -= 360; - } - while(this.rotation_in_degree < 0) - { - this.rotation_in_degree += 360; - } - Point rel_location = Point.ZERO.translate_by(this.translation); - this.translation = rel_location.turn_90_degree(p_factor, p_pole).difference_by(Point.ZERO); - this.clear_derived_data(); - } - - public void rotate_approx(double p_angle_in_degree, FloatPoint p_pole) - { - double turn_angle = p_angle_in_degree; - if (this.side_changed && this.board.components.get_flip_style_rotate_first()) - { - turn_angle = 360 - p_angle_in_degree; - } - this.rotation_in_degree += turn_angle; - while(this.rotation_in_degree >= 360) - { - this.rotation_in_degree -= 360; - } - while(this.rotation_in_degree < 0) - { - this.rotation_in_degree += 360; - } - FloatPoint new_translation = this.translation.to_float().rotate(Math.toRadians(p_angle_in_degree), p_pole); - this.translation = new_translation.round().difference_by(Point.ZERO); - this.clear_derived_data(); - } - - public void change_placement_side(IntPoint p_pole) - { - this.side_changed = !this.side_changed; - if (this.board != null) - { - this.layer = board.get_layer_count() - this.layer - 1; - } - Point rel_location = Point.ZERO.translate_by(this.translation); - this.translation = rel_location.mirror_vertical(p_pole).difference_by(Point.ZERO); - this.clear_derived_data(); - } - - public boolean is_selected_by_filter(ItemSelectionFilter p_filter) - { - if (!this.is_selected_by_fixed_filter(p_filter)) - { - return false; - } - return p_filter.is_selected(ItemSelectionFilter.SelectableChoices.KEEPOUT); - } - - public Color[] get_draw_colors(GraphicsContext p_graphics_context) - { - return p_graphics_context.get_obstacle_colors(); - } - - public double get_draw_intensity(GraphicsContext p_graphics_context) - { - return p_graphics_context.get_obstacle_color_intensity(); - } - - public int get_draw_priority() - { - return boardgraphics.Drawable.MIN_DRAW_PRIORITY; - } - - public void draw(java.awt.Graphics p_g, GraphicsContext p_graphics_context, Color[] p_color_arr, double p_intensity) - { - if (p_graphics_context == null || p_intensity <= 0) - { - return; - } - Color color = p_color_arr[this.layer]; - double intensity = p_graphics_context.get_layer_visibility(this.layer) * p_intensity; - p_graphics_context.fill_area(this.get_area(), p_g, color, intensity); - if (intensity > 0 && display_tree_shapes) - { - ShapeSearchTree default_tree = this.board.search_tree_manager.get_default_tree(); - for (int i = 0; i < this.tree_shape_count(default_tree); ++i) - { - p_graphics_context.draw_boundary(this.get_tree_shape(default_tree, i), 1, Color.white, p_g, 1); - } - } - } - - public int shape_layer(int p_index) - { - return layer; - } - - protected Vector get_translation() - { - return translation; - } - - protected double get_rotation_in_degree() - { - return rotation_in_degree; - } - - protected boolean get_side_changed() - { - return side_changed; - } - - public void print_info(ObjectInfoPanel p_window, java.util.Locale p_locale) - { - java.util.ResourceBundle resources = - java.util.ResourceBundle.getBundle("board.resources.ObjectInfoPanel", p_locale); - p_window.append_bold(resources.getString("keepout")); - int cmp_no = this.get_component_no(); - if (cmp_no > 0) - { - p_window.append(" " + resources.getString("of_component") + " "); - Component component = board.components.get(cmp_no); - p_window.append(component.name, resources.getString("component_info"), component); - } - this.print_shape_info(p_window, p_locale); - this.print_item_info(p_window, p_locale); - p_window.newline(); - } - - /** - * Used in the implementation of print_info for this class and derived classes. - */ - protected final void print_shape_info(ObjectInfoPanel p_window, java.util.Locale p_locale) - { - java.util.ResourceBundle resources = - java.util.ResourceBundle.getBundle("board.resources.ObjectInfoPanel", p_locale); - p_window.append(" " + resources.getString("at") + " "); - geometry.planar.FloatPoint center = this.get_area().get_border().centre_of_gravity(); - p_window.append(center); - Integer hole_count = this.relative_area.get_holes().length; - if(hole_count > 0) - { - p_window.append(" " + resources.getString("with") + " "); - java.text.NumberFormat nf = java.text.NumberFormat.getInstance(p_locale); - p_window.append(nf.format(hole_count)); - if (hole_count == 1) - { - p_window.append(" " + resources.getString("hole")); - } - else - { - p_window.append(" " + resources.getString("holes")); - } - } - p_window.append(" " + resources.getString("on_layer") + " "); - p_window.append(this.board.layer_structure.arr[this.get_layer()].name); - } - - TileShape[] split_to_convex() - { - if (this.relative_area == null) - { - System.out.println("ObstacleArea.split_to_convex: area is null"); - return null; - } - return this.get_area().split_to_convex(); - } - - public void clear_derived_data() - { - super.clear_derived_data(); - this.precalculated_absolute_area = null; - } - - - public boolean write(java.io.ObjectOutputStream p_stream) - { - try - { - p_stream.writeObject(this); - } - catch (java.io.IOException e) - { - return false; - } - return true; - } - - /** - * The name of this ObstacleArea, which is null, if the ObstacleArea doos not belong to a component. - */ - public final String name; - - /** - * the layer of this relative_area - */ - private int layer; - - private Area relative_area; - - private transient Area precalculated_absolute_area = null; - - private Vector translation; - - private double rotation_in_degree; - - private boolean side_changed; - - /** For debugging the division into tree shapes */ - private static final boolean display_tree_shapes = false; -} \ No newline at end of file +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + */ + +package board; + +import geometry.planar.IntBox; +import geometry.planar.IntPoint; +import geometry.planar.Area; +import geometry.planar.TileShape; +import geometry.planar.Vector; +import geometry.planar.Point; +import geometry.planar.FloatPoint; + +import java.awt.Color; + +import boardgraphics.GraphicsContext; + +/** + * + * An item on the board with an relative_area shape, for example keepout, conduction relative_area + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class ObstacleArea extends Item implements java.io.Serializable +{ + /** + * Creates a new relative_area item which may belong to several nets. + * p_name is null, if the ObstacleArea does not belong to a component. + */ + ObstacleArea(Area p_area, int p_layer, Vector p_translation, double p_rotation_in_degree, boolean p_side_changed, + int[] p_net_no_arr, int p_clearance_type, int p_id_no, int p_cmp_no, String p_name, FixedState p_fixed_state, BasicBoard p_board) + { + super(p_net_no_arr, p_clearance_type, p_id_no, p_cmp_no, p_fixed_state, p_board); + this.relative_area = p_area; + this.layer = p_layer; + this.translation = p_translation; + this.rotation_in_degree = p_rotation_in_degree; + this.side_changed = p_side_changed; + this.name = p_name; + } + + /** + * Creates a new relative_area item without net. + * p_name is null, if the ObstacleArea does not belong to a component. + */ + ObstacleArea(Area p_area, int p_layer, Vector p_translation, double p_rotation_in_degree, boolean p_side_changed, + int p_clearance_type, int p_id_no, int p_group_no, String p_name, FixedState p_fixed_state, BasicBoard p_board) + { + this(p_area, p_layer, p_translation, p_rotation_in_degree, p_side_changed, new int[0], p_clearance_type, p_id_no, p_group_no, p_name, p_fixed_state, p_board); + } + + /** {@inheritDoc} */ + public Item copy(int p_id_no) + { + int [] copied_net_nos = new int[net_no_arr.length]; + System.arraycopy(net_no_arr, 0, copied_net_nos, 0, net_no_arr.length); + return new ObstacleArea(relative_area, layer, translation, rotation_in_degree, side_changed, copied_net_nos, clearance_class_no(), p_id_no, get_component_no(), name, get_fixed_state(), board); + } + + /** + *

get_area.

+ * + * @return a {@link geometry.planar.Area} object. + */ + public Area get_area() + { + if (this.precalculated_absolute_area == null) + { + if (this.relative_area == null) + { + System.out.println("ObstacleArea.get_area: area is null"); + return null; + } + Area turned_area = this.relative_area; + if (this.side_changed && !this.board.components.get_flip_style_rotate_first()) + { + turned_area = turned_area.mirror_vertical(Point.ZERO); + } + if (this.rotation_in_degree != 0) + { + double rotation = this.rotation_in_degree; + if (rotation % 90 == 0) + { + turned_area = turned_area.turn_90_degree(((int) rotation )/ 90, Point.ZERO); + } + else + { + turned_area = turned_area.rotate_approx(Math.toRadians(rotation), FloatPoint.ZERO); + } + + } + if (this.side_changed && this.board.components.get_flip_style_rotate_first()) + { + turned_area = turned_area.mirror_vertical(Point.ZERO); + } + this.precalculated_absolute_area = turned_area.translate_by(this.translation); + } + return this.precalculated_absolute_area; + } + + /** + *

get_relative_area.

+ * + * @return a {@link geometry.planar.Area} object. + */ + protected Area get_relative_area() + { + return this.relative_area; + } + + /** {@inheritDoc} */ + public boolean is_on_layer(int p_layer) + { + return layer == p_layer; + } + + /** + *

first_layer.

+ * + * @return a int. + */ + public int first_layer() + { + return this.layer; + } + + /** + *

last_layer.

+ * + * @return a int. + */ + public int last_layer() + { + return this.layer; + } + + /** + *

get_layer.

+ * + * @return a int. + */ + public int get_layer() + { + return this.layer; + } + + /** + *

bounding_box.

+ * + * @return a {@link geometry.planar.IntBox} object. + */ + public IntBox bounding_box() + { + return this.get_area().bounding_box(); + } + + /** + *

is_obstacle.

+ * + * @param p_other a {@link board.Item} object. + * @return a boolean. + */ + public boolean is_obstacle(Item p_other) + { + if (p_other.shares_net(this)) + { + return false; + } + return p_other instanceof Trace || p_other instanceof Via; + } + + /** {@inheritDoc} */ + protected TileShape[] calculate_tree_shapes(ShapeSearchTree p_search_tree) + { + return p_search_tree.calculate_tree_shapes(this); + } + + /** + *

tile_shape_count.

+ * + * @return a int. + */ + public int tile_shape_count() + { + TileShape[] tile_shapes = this.split_to_convex(); + if (tile_shapes == null) + { + // an error accured while dividing the relative_area + return 0; + } + return tile_shapes.length; + } + + /** {@inheritDoc} */ + public TileShape get_tile_shape(int p_no) + { + TileShape[] tile_shapes = this.split_to_convex(); + if (tile_shapes == null || p_no < 0 || p_no >= tile_shapes.length) + { + System.out.println("ConvexObstacle.get_tile_shape: p_no out of range"); + return null; + } + return tile_shapes[p_no]; + } + + /** {@inheritDoc} */ + public void translate_by(Vector p_vector) + { + this.translation = this.translation.add(p_vector); + this.clear_derived_data(); + } + + /** {@inheritDoc} */ + public void turn_90_degree(int p_factor, IntPoint p_pole) + { + this.rotation_in_degree += p_factor * 90; + while(this.rotation_in_degree >= 360) + { + this.rotation_in_degree -= 360; + } + while(this.rotation_in_degree < 0) + { + this.rotation_in_degree += 360; + } + Point rel_location = Point.ZERO.translate_by(this.translation); + this.translation = rel_location.turn_90_degree(p_factor, p_pole).difference_by(Point.ZERO); + this.clear_derived_data(); + } + + /** {@inheritDoc} */ + public void rotate_approx(double p_angle_in_degree, FloatPoint p_pole) + { + double turn_angle = p_angle_in_degree; + if (this.side_changed && this.board.components.get_flip_style_rotate_first()) + { + turn_angle = 360 - p_angle_in_degree; + } + this.rotation_in_degree += turn_angle; + while(this.rotation_in_degree >= 360) + { + this.rotation_in_degree -= 360; + } + while(this.rotation_in_degree < 0) + { + this.rotation_in_degree += 360; + } + FloatPoint new_translation = this.translation.to_float().rotate(Math.toRadians(p_angle_in_degree), p_pole); + this.translation = new_translation.round().difference_by(Point.ZERO); + this.clear_derived_data(); + } + + /** {@inheritDoc} */ + public void change_placement_side(IntPoint p_pole) + { + this.side_changed = !this.side_changed; + if (this.board != null) + { + this.layer = board.get_layer_count() - this.layer - 1; + } + Point rel_location = Point.ZERO.translate_by(this.translation); + this.translation = rel_location.mirror_vertical(p_pole).difference_by(Point.ZERO); + this.clear_derived_data(); + } + + /** {@inheritDoc} */ + public boolean is_selected_by_filter(ItemSelectionFilter p_filter) + { + if (!this.is_selected_by_fixed_filter(p_filter)) + { + return false; + } + return p_filter.is_selected(ItemSelectionFilter.SelectableChoices.KEEPOUT); + } + + /** {@inheritDoc} */ + public Color[] get_draw_colors(GraphicsContext p_graphics_context) + { + return p_graphics_context.get_obstacle_colors(); + } + + /** {@inheritDoc} */ + public double get_draw_intensity(GraphicsContext p_graphics_context) + { + return p_graphics_context.get_obstacle_color_intensity(); + } + + /** + *

get_draw_priority.

+ * + * @return a int. + */ + public int get_draw_priority() + { + return boardgraphics.Drawable.MIN_DRAW_PRIORITY; + } + + /** {@inheritDoc} */ + public void draw(java.awt.Graphics p_g, GraphicsContext p_graphics_context, Color[] p_color_arr, double p_intensity) + { + if (p_graphics_context == null || p_intensity <= 0) + { + return; + } + Color color = p_color_arr[this.layer]; + double intensity = p_graphics_context.get_layer_visibility(this.layer) * p_intensity; + p_graphics_context.fill_area(this.get_area(), p_g, color, intensity); + if (intensity > 0 && display_tree_shapes) + { + ShapeSearchTree default_tree = this.board.search_tree_manager.get_default_tree(); + for (int i = 0; i < this.tree_shape_count(default_tree); ++i) + { + p_graphics_context.draw_boundary(this.get_tree_shape(default_tree, i), 1, Color.white, p_g, 1); + } + } + } + + /** {@inheritDoc} */ + public int shape_layer(int p_index) + { + return layer; + } + + /** + *

get_translation.

+ * + * @return a {@link geometry.planar.Vector} object. + */ + protected Vector get_translation() + { + return translation; + } + + /** + *

get_rotation_in_degree.

+ * + * @return a double. + */ + protected double get_rotation_in_degree() + { + return rotation_in_degree; + } + + /** + *

get_side_changed.

+ * + * @return a boolean. + */ + protected boolean get_side_changed() + { + return side_changed; + } + + /** {@inheritDoc} */ + public void print_info(ObjectInfoPanel p_window, java.util.Locale p_locale) + { + java.util.ResourceBundle resources = + java.util.ResourceBundle.getBundle("board.resources.ObjectInfoPanel", p_locale); + p_window.append_bold(resources.getString("keepout")); + int cmp_no = this.get_component_no(); + if (cmp_no > 0) + { + p_window.append(" " + resources.getString("of_component") + " "); + Component component = board.components.get(cmp_no); + p_window.append(component.name, resources.getString("component_info"), component); + } + this.print_shape_info(p_window, p_locale); + this.print_item_info(p_window, p_locale); + p_window.newline(); + } + + /** + * Used in the implementation of print_info for this class and derived classes. + * + * @param p_window a {@link board.ObjectInfoPanel} object. + * @param p_locale a {@link java.util.Locale} object. + */ + protected final void print_shape_info(ObjectInfoPanel p_window, java.util.Locale p_locale) + { + java.util.ResourceBundle resources = + java.util.ResourceBundle.getBundle("board.resources.ObjectInfoPanel", p_locale); + p_window.append(" " + resources.getString("at") + " "); + geometry.planar.FloatPoint center = this.get_area().get_border().centre_of_gravity(); + p_window.append(center); + Integer hole_count = this.relative_area.get_holes().length; + if(hole_count > 0) + { + p_window.append(" " + resources.getString("with") + " "); + java.text.NumberFormat nf = java.text.NumberFormat.getInstance(p_locale); + p_window.append(nf.format(hole_count)); + if (hole_count == 1) + { + p_window.append(" " + resources.getString("hole")); + } + else + { + p_window.append(" " + resources.getString("holes")); + } + } + p_window.append(" " + resources.getString("on_layer") + " "); + p_window.append(this.board.layer_structure.arr[this.get_layer()].name); + } + + TileShape[] split_to_convex() + { + if (this.relative_area == null) + { + System.out.println("ObstacleArea.split_to_convex: area is null"); + return null; + } + return this.get_area().split_to_convex(); + } + + /** + *

clear_derived_data.

+ */ + public void clear_derived_data() + { + super.clear_derived_data(); + this.precalculated_absolute_area = null; + } + + + /** {@inheritDoc} */ + public boolean write(java.io.ObjectOutputStream p_stream) + { + try + { + p_stream.writeObject(this); + } + catch (java.io.IOException e) + { + return false; + } + return true; + } + + /** + * The name of this ObstacleArea, which is null, if the ObstacleArea doos not belong to a component. + */ + public final String name; + + /** + * the layer of this relative_area + */ + private int layer; + + private Area relative_area; + + private transient Area precalculated_absolute_area = null; + + private Vector translation; + + private double rotation_in_degree; + + private boolean side_changed; + + /** For debugging the division into tree shapes */ + private static final boolean display_tree_shapes = false; +} diff --git a/board/OptViaAlgo.java b/src/main/java/board/OptViaAlgo.java similarity index 97% rename from board/OptViaAlgo.java rename to src/main/java/board/OptViaAlgo.java index 2380f42..cfa3f20 100644 --- a/board/OptViaAlgo.java +++ b/src/main/java/board/OptViaAlgo.java @@ -1,724 +1,732 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * OptViaAlgo.java - * - * Created on 31. Maerz 2006, 06:58 - * - */ - -package board; - -import java.util.Collection; -import java.util.Iterator; - -import geometry.planar.Point; -import geometry.planar.IntPoint; -import geometry.planar.Vector; -import geometry.planar.Polyline; -import geometry.planar.FloatPoint; -import geometry.planar.FloatLine; -import geometry.planar.Side; - -import autoroute.AutorouteControl.ExpansionCostFactor; - -/** - * Contains functions for optimizing and improving via locations. - * - * @author Alfons Wirtz - */ -public class OptViaAlgo -{ - - /** - * Optimizes the location of a via connected to at most 2 traces - * according to the trace costs on the layers of the connected traces - * If p_trace_cost_arr == null, the horizontal and vertical trace costs will be set to 1. - * Returns false, if the via was not changed. - */ - public static boolean opt_via_location(RoutingBoard p_board, Via p_via, - ExpansionCostFactor[] p_trace_cost_arr, int p_trace_pull_tight_accuracy, int p_max_recursion_depth) - { - if (p_via.is_shove_fixed()) - { - return false; - } - if (p_max_recursion_depth <= 0) - { - if (p_board.get_test_level().ordinal() >= TestLevel.CRITICAL_DEBUGGING_OUTPUT.ordinal()) - { - System.out.println("OptViaAlgo.opt_via_location: probably endless loop") ; - } - return false; - } - Collection contacts = p_via.get_normal_contacts(); - boolean is_plane_or_fanout_via = (contacts.size() == 1); - PolylineTrace first_trace = null; - PolylineTrace second_trace = null; - if (!is_plane_or_fanout_via) - { - if (contacts.size() != 2) - { - return false; - } - Iterator it = contacts.iterator(); - Item curr_item = it.next(); - if (curr_item.is_shove_fixed() || !(curr_item instanceof PolylineTrace)) - { - if (curr_item instanceof ConductionArea) - { - is_plane_or_fanout_via = true; - } - else - { - return false; - } - } - else - { - first_trace = (PolylineTrace) curr_item; - } - curr_item = it.next(); - if (curr_item.is_shove_fixed() || !(curr_item instanceof PolylineTrace)) - { - if (curr_item instanceof ConductionArea) - { - is_plane_or_fanout_via = true; - } - else - { - return false; - } - } - else - { - second_trace = (PolylineTrace) curr_item; - } - } - if (is_plane_or_fanout_via) - { - return opt_plane_or_fanout_via(p_board, p_via, p_trace_pull_tight_accuracy, p_max_recursion_depth); - } - Point via_center = p_via.get_center(); - int first_layer = first_trace.get_layer(); - int second_layer = second_trace.get_layer(); - Point first_trace_from_corner; - Point second_trace_from_corner; - - // calculate first_trace_from_corner and second_trace_from_corner - - if (first_trace.first_corner().equals(via_center)) - { - first_trace_from_corner = first_trace.polyline().corner(1); - } - else if (first_trace.last_corner().equals(via_center)) - { - first_trace_from_corner - = first_trace.polyline().corner(first_trace.polyline().corner_count() - 2); - } - else - { - System.out.println("OptViaAlgo.opt_via_location: incorrect first contact"); - return false; - } - - if (second_trace.first_corner().equals(via_center)) - { - second_trace_from_corner = second_trace.polyline().corner(1); - } - else if (second_trace.last_corner().equals(via_center)) - { - second_trace_from_corner - = second_trace.polyline().corner(second_trace.polyline().corner_count() - 2); - } - else - { - System.out.println("OptViaAlgo.opt_via_location: incorrect second contact"); - return false; - } - - ExpansionCostFactor first_layer_trace_costs; - ExpansionCostFactor second_layer_trace_costs; - if (p_trace_cost_arr != null) - { - first_layer_trace_costs = p_trace_cost_arr[first_layer]; - second_layer_trace_costs = p_trace_cost_arr[second_layer]; - } - else - { - first_layer_trace_costs = new ExpansionCostFactor(1, 1); - second_layer_trace_costs = first_layer_trace_costs; - } - - Point new_location = - reposition_via(p_board, p_via, - first_trace.get_half_width(), first_trace.clearance_class_no(), first_trace.get_layer(), - first_layer_trace_costs, first_trace_from_corner, - second_trace.get_half_width(), second_trace.clearance_class_no(), second_trace.get_layer(), - second_layer_trace_costs, second_trace_from_corner); - if (new_location == null || new_location.equals(via_center)) - { - return false; - } - Vector delta = new_location.difference_by(via_center); - if (!MoveDrillItemAlgo.insert(p_via, delta, 9, 9, null, p_board)) - { - System.out.println("OptViaAlgo.opt_via_location: move via failed"); - return false; - } - ItemSelectionFilter filter = new ItemSelectionFilter(ItemSelectionFilter.SelectableChoices.TRACES); - Collection picked_items = p_board.pick_items(new_location, first_trace.get_layer(), filter); - for (Item curr_item : picked_items) - { - ((PolylineTrace) curr_item).pull_tight(true, p_trace_pull_tight_accuracy, null); - } - picked_items = p_board.pick_items(new_location, second_trace.get_layer(), filter); - for (Item curr_item : picked_items) - { - ((PolylineTrace) curr_item).pull_tight(true, p_trace_pull_tight_accuracy, null); - } - filter = new ItemSelectionFilter(ItemSelectionFilter.SelectableChoices.VIAS); - picked_items = p_board.pick_items(new_location, first_trace.get_layer(), filter); - for (Item curr_item : picked_items) - { - opt_via_location(p_board, (Via) curr_item, p_trace_cost_arr, - p_trace_pull_tight_accuracy, p_max_recursion_depth - 1); - break; - } - return true; - } - - /** - * Optimisations for vias with only 1 connected Trace (Plane or Fanout Vias). - */ - private static boolean opt_plane_or_fanout_via(RoutingBoard p_board, Via p_via, - int p_trace_pull_tight_accuracy, int p_max_recursion_depth) - { - if (p_max_recursion_depth <= 0) - { - if (p_board.get_test_level().ordinal() >= TestLevel.CRITICAL_DEBUGGING_OUTPUT.ordinal()) - { - System.out.println("OptViaAlgo.opt_plane_or_fanout_via: probably endless loop") ; - } - return false; - } - Collection contact_list = p_via.get_normal_contacts(); - if (contact_list.isEmpty()) - { - return false; - } - ConductionArea contact_plane = null; - PolylineTrace contact_trace = null; - for (Item curr_contact : contact_list) - { - if (curr_contact instanceof ConductionArea) - { - if (contact_plane != null) - { - return false; - } - contact_plane = (ConductionArea) curr_contact; - } - else if (curr_contact instanceof PolylineTrace) - { - if (curr_contact.is_shove_fixed() || contact_trace != null) - { - return false; - } - contact_trace = (PolylineTrace) curr_contact; - } - else - { - return false; - } - } - if (contact_trace == null) - { - return false; - } - Point via_center = p_via.get_center(); - boolean at_first_corner; - if (contact_trace.first_corner().equals(via_center)) - { - at_first_corner = true; - } - else if (contact_trace.last_corner().equals(via_center)) - { - at_first_corner = false; - } - else - { - System.out.println("OptViaAlgo.opt_plane_or_fanout_via: unconsistant contact"); - return false; - } - Polyline trace_polyline = contact_trace.polyline(); - Point check_corner; - if (at_first_corner) - { - check_corner = trace_polyline.corner(1); - } - else - { - check_corner = trace_polyline.corner(trace_polyline.corner_count() - 2); - } - IntPoint rounded_check_corner = check_corner.to_float().round(); - int trace_half_width = contact_trace.get_half_width(); - int trace_layer = contact_trace.get_layer(); - int trace_cl_class_no = contact_trace.clearance_class_no(); - Point new_via_location = - reposition_via(p_board, p_via, rounded_check_corner, trace_half_width , - trace_layer, trace_cl_class_no); - if (new_via_location == null && trace_polyline.corner_count() >= 3) - { - - // try to project the via to the previous line - Point prev_corner; - - if (at_first_corner) - { - prev_corner = trace_polyline.corner(2); - } - else - { - prev_corner = trace_polyline.corner(trace_polyline.corner_count() - 3); - } - FloatPoint float_check_corner = check_corner.to_float(); - FloatPoint float_via_center = via_center.to_float(); - FloatPoint float_prev_corner = prev_corner.to_float(); - if (float_check_corner.scalar_product(float_via_center, float_prev_corner) != 0) - { - FloatLine curr_line = new FloatLine(float_check_corner, float_prev_corner); - Point projection = curr_line.perpendicular_projection(float_via_center).round(); - Vector diff_vector = projection.difference_by(via_center); - boolean projection_ok = true; - AngleRestriction angle_restriction = p_board.rules.get_trace_angle_restriction(); - if (projection.equals(via_center) || - angle_restriction == AngleRestriction.NINETY_DEGREE && !diff_vector.is_orthogonal() || - angle_restriction == AngleRestriction.FORTYFIVE_DEGREE && !diff_vector.is_multiple_of_45_degree()) - { - projection_ok = false; - } - if (projection_ok) - { - if(MoveDrillItemAlgo.check(p_via, diff_vector, 0, 0, null, p_board, null)) - { - double ok_length = - p_board.check_trace_segment(via_center, projection, trace_layer, p_via.net_no_arr, - trace_half_width, trace_cl_class_no, false); - if (ok_length >= Integer.MAX_VALUE) - { - new_via_location = projection; - } - } - - } - } - } - if (new_via_location == null) - { - return false; - } - if (contact_plane != null) - { - // check, that the new location is inside the contact plane - ItemSelectionFilter filter = new ItemSelectionFilter(ItemSelectionFilter.SelectableChoices.CONDUCTION); - Collection picked_items = p_board.pick_items(new_via_location, contact_plane.get_layer(), filter); - boolean contact_ok = false; - for (Item curr_item : picked_items) - { - if (curr_item == contact_plane) - { - contact_ok = true; - break; - } - } - if (!contact_ok) - { - return false; - } - } - Vector diff_vector = new_via_location.difference_by(via_center); - if (!MoveDrillItemAlgo.insert(p_via, diff_vector, 9, 9, null, p_board)) - { - System.out.println("OptViaAlgo.opt_plane_or_fanout_via: move via failed"); - return false; - } - ItemSelectionFilter filter = new ItemSelectionFilter(ItemSelectionFilter.SelectableChoices.TRACES); - Collection picked_items = p_board.pick_items(new_via_location, contact_trace.get_layer(), filter); - for (Item curr_item : picked_items) - { - ((PolylineTrace) curr_item).pull_tight(true, p_trace_pull_tight_accuracy, null); - } - if (new_via_location.equals(check_corner)) - { - opt_plane_or_fanout_via(p_board, p_via, p_trace_pull_tight_accuracy, p_max_recursion_depth - 1); - } - return true; - } - - /** - * Tries to move the via into the direction of p_to_location as far as possible - * Return the new location of the via, or null, if no move was possible. - */ - private static Point reposition_via(RoutingBoard p_board, Via p_via, - IntPoint p_to_location, int p_trace_half_width, int p_trace_layer, int p_trace_cl_class) - - { - Point from_location = p_via.get_center(); - - if (from_location.equals(p_to_location)) - { - return null; - } - - double ok_length = p_board.check_trace_segment(from_location, p_to_location, p_trace_layer, p_via.net_no_arr, - p_trace_half_width, p_trace_cl_class, false); - if (ok_length <= 0) - { - return null; - } - FloatPoint float_from_location = from_location.to_float(); - FloatPoint float_to_location = p_to_location.to_float(); - FloatPoint new_float_to_location; - if (ok_length >= Integer.MAX_VALUE) - { - new_float_to_location = float_to_location; - } - else - { - new_float_to_location = float_from_location.change_length(float_to_location, ok_length); - } - Point new_to_location = new_float_to_location.round(); - Vector delta = new_to_location.difference_by(from_location); - boolean check_ok = - MoveDrillItemAlgo.check(p_via, delta, 0, 0, null, p_board, null); - - if (check_ok) - { - return new_to_location; - } - - final double c_min_length = 0.3 * p_trace_half_width + 1; - - ok_length = Math.min(ok_length, float_from_location.distance(float_to_location)); - - double curr_length = ok_length / 2; - - ok_length = 0; - Point result = null; - - while (curr_length >= c_min_length) - { - Point check_point = float_from_location.change_length(float_to_location, ok_length + curr_length).round(); - - delta = check_point.difference_by(from_location); - if (MoveDrillItemAlgo.check(p_via, delta, 0, 0, null, p_board, null)) - { - ok_length += curr_length; - result = check_point; - } - curr_length /= 2; - } - return result; - } - - private static boolean reposition_via(RoutingBoard p_board, Via p_via, - IntPoint p_to_location, int p_trace_half_width_1, int p_trace_layer_1, int p_trace_cl_class_1, - IntPoint p_connect_location, int p_trace_half_width_2, int p_trace_layer_2, int p_trace_cl_class_2) - - { - Point from_location = p_via.get_center(); - - if (from_location.equals(p_to_location)) - { - if (p_board.get_test_level() == TestLevel.ALL_DEBUGGING_OUTPUT) - { - System.out.println("OptViaAlgo.reposition_via: from_location equal p_to_location"); - } - return false; - } - - Vector delta = p_to_location.difference_by(from_location); - - if ( p_board.rules.get_trace_angle_restriction() == AngleRestriction.NONE && delta.length_approx() <= 1.5) - { - // PullTightAlgoAnyAngle.reduce_corners mmay not be able to remove the new generated overlap - // because of numerical stability problems - // That would result in an endless loop with removing the generated acute angle in reposition_via. - return false; - } - - int[] net_no_arr = p_via.net_no_arr; - - double ok_length = p_board.check_trace_segment(from_location, p_to_location, p_trace_layer_1, net_no_arr, - p_trace_half_width_1, p_trace_cl_class_1, false); - - if (ok_length < Integer.MAX_VALUE) - { - return false; - } - - ok_length = p_board.check_trace_segment(p_to_location, p_connect_location, p_trace_layer_2, net_no_arr, - p_trace_half_width_2, p_trace_cl_class_2, false); - - if (ok_length < Integer.MAX_VALUE) - { - return false; - } - if (!MoveDrillItemAlgo.check(p_via, delta, 0, 0, null, p_board, null)) - { - return false; - } - return true; - } - - /** - * Tries to reposition the via to a better location according to the - * trace costs. Returns null, if no better location was found. - */ - private static Point reposition_via(RoutingBoard p_board, Via p_via, - int p_first_trace_half_width, int p_first_trace_cl_class, int p_first_trace_layer, - ExpansionCostFactor p_first_trace_costs, Point p_first_trace_from_corner, - int p_second_trace_half_width, int p_second_trace_cl_class, int p_second_trace_layer, - ExpansionCostFactor p_second_trace_costs, Point p_second_trace_from_corner) - { - Point via_location = p_via.get_center(); - - Vector first_delta = p_first_trace_from_corner.difference_by(via_location); - Vector second_delta = p_second_trace_from_corner.difference_by(via_location); - double scalar_product = first_delta.scalar_product(second_delta); - - FloatPoint float_via_location = via_location.to_float(); - FloatPoint float_first_trace_from_corner = p_first_trace_from_corner.to_float(); - FloatPoint float_second_trace_from_corner = p_second_trace_from_corner.to_float(); - double first_trace_from_corner_distance = float_via_location.distance(float_first_trace_from_corner); - double second_trace_from_corner_distance = float_via_location.distance(float_second_trace_from_corner); - IntPoint rounded_first_trace_from_corner = float_first_trace_from_corner.round(); - IntPoint rounded_second_trace_from_corner = float_second_trace_from_corner.round(); - - // handle case of overlapping lines first - - if (via_location.side_of(p_first_trace_from_corner, p_second_trace_from_corner) == Side.COLLINEAR - && scalar_product > 0) - { - if (second_trace_from_corner_distance < first_trace_from_corner_distance) - { - return reposition_via(p_board, p_via, rounded_second_trace_from_corner, - p_first_trace_half_width, p_first_trace_layer, p_first_trace_cl_class); - } - return reposition_via(p_board, p_via, rounded_first_trace_from_corner, - p_second_trace_half_width, p_second_trace_layer, p_second_trace_cl_class); - } - Point result = null; - - double curr_weighted_distance_1 = - float_via_location.weighted_distance(float_first_trace_from_corner, p_first_trace_costs.horizontal, - p_first_trace_costs.vertical); - double curr_weighted_distance_2 = - float_via_location.weighted_distance(float_first_trace_from_corner, p_second_trace_costs.horizontal, - p_second_trace_costs.vertical); - - if (curr_weighted_distance_1 > curr_weighted_distance_2) - { - // try to move the via in direction of p_first_trace_from_corner - result = reposition_via(p_board, p_via, rounded_first_trace_from_corner, - p_second_trace_half_width, p_second_trace_layer, p_second_trace_cl_class); - if (result != null) - { - return result; - } - } - - curr_weighted_distance_1 = - float_via_location.weighted_distance(float_second_trace_from_corner, p_second_trace_costs.horizontal, - p_second_trace_costs.vertical); - curr_weighted_distance_2 = - float_via_location.weighted_distance(float_second_trace_from_corner, p_first_trace_costs.horizontal, - p_first_trace_costs.vertical); - - if (curr_weighted_distance_1 > curr_weighted_distance_2) - { - // try to move the via in direction of p_second_trace_from_corner - result = reposition_via(p_board, p_via, rounded_second_trace_from_corner, - p_first_trace_half_width, p_first_trace_layer, p_first_trace_cl_class); - if (result != null) - { - return result; - } - } - if (scalar_product > 0 && p_board.rules.get_trace_angle_restriction() != AngleRestriction.NINETY_DEGREE) - { - // acute angle - IntPoint to_point_1; - IntPoint to_point_2; - FloatPoint float_to_point_1; - FloatPoint float_to_point_2; - if (first_trace_from_corner_distance < second_trace_from_corner_distance) - { - to_point_1 = rounded_first_trace_from_corner; - float_to_point_1 = float_first_trace_from_corner; - float_to_point_2 = - float_via_location.change_length(float_second_trace_from_corner, - first_trace_from_corner_distance); - to_point_2 = float_to_point_2.round(); - } - else - { - float_to_point_1 = - float_via_location.change_length(float_first_trace_from_corner, - second_trace_from_corner_distance); - to_point_1 = float_to_point_1.round(); - to_point_2 = rounded_second_trace_from_corner; - float_to_point_2 = float_second_trace_from_corner; - } - curr_weighted_distance_1 = - float_to_point_1.weighted_distance(float_to_point_2, p_first_trace_costs.horizontal, - p_first_trace_costs.vertical); - curr_weighted_distance_2 = - float_to_point_1.weighted_distance(float_to_point_2, p_second_trace_costs.horizontal, - p_second_trace_costs.vertical); - - if (curr_weighted_distance_1 > curr_weighted_distance_2) - { - // try moving the via first into the direction of to_point_1 - result = reposition_via(p_board, p_via, to_point_1, - p_second_trace_half_width, p_second_trace_layer, p_second_trace_cl_class); - if (result == null) - { - result = reposition_via(p_board, p_via, to_point_2, - p_first_trace_half_width, p_first_trace_layer, p_first_trace_cl_class); - } - } - else - { - // try moving the via first into the direction of to_point_2 - result = reposition_via(p_board, p_via, to_point_2, - p_first_trace_half_width, p_first_trace_layer, p_first_trace_cl_class); - if (result == null) - { - result = reposition_via(p_board, p_via, to_point_1, - p_second_trace_half_width, p_second_trace_layer, p_second_trace_cl_class); - } - } - if (result != null) - { - return result; - } - } - - // try decomposition in axisparallel parts - - if (!first_delta.is_orthogonal()) - { - FloatPoint float_check_location = new FloatPoint(float_via_location.x, float_first_trace_from_corner.y); - - curr_weighted_distance_1 = - float_via_location.weighted_distance(float_first_trace_from_corner, p_first_trace_costs.horizontal, - p_first_trace_costs.vertical); - curr_weighted_distance_2 = - float_via_location.weighted_distance(float_check_location, p_second_trace_costs.horizontal, - p_second_trace_costs.vertical); - double curr_weighted_distance_3 = - float_check_location.weighted_distance(float_first_trace_from_corner, p_first_trace_costs.horizontal, - p_first_trace_costs.vertical); - - if (curr_weighted_distance_1 > curr_weighted_distance_2 + curr_weighted_distance_3) - { - IntPoint check_location = float_check_location.round(); - boolean check_ok = - reposition_via(p_board, p_via, check_location, p_second_trace_half_width, - p_second_trace_layer, p_second_trace_cl_class, rounded_first_trace_from_corner, - p_first_trace_half_width, p_first_trace_layer, p_first_trace_cl_class); - if (check_ok) - { - return check_location; - } - } - - float_check_location = new FloatPoint(float_first_trace_from_corner.x, float_via_location.y); - - curr_weighted_distance_2 = - float_via_location.weighted_distance(float_check_location, p_second_trace_costs.horizontal, - p_second_trace_costs.vertical); - curr_weighted_distance_3 = - float_check_location.weighted_distance(float_first_trace_from_corner, p_first_trace_costs.horizontal, - p_first_trace_costs.vertical); - - if (curr_weighted_distance_1 > curr_weighted_distance_2 + curr_weighted_distance_3) - { - IntPoint check_location = float_check_location.round(); - boolean check_ok = - reposition_via(p_board, p_via, check_location, p_second_trace_half_width, - p_second_trace_layer, p_second_trace_cl_class, rounded_first_trace_from_corner, - p_first_trace_half_width, p_first_trace_layer, p_first_trace_cl_class); - if (check_ok) - { - return check_location; - } - } - } - - if (!second_delta.is_orthogonal()) - { - FloatPoint float_check_location = new FloatPoint(float_via_location.x, float_second_trace_from_corner.y); - - curr_weighted_distance_1 = - float_via_location.weighted_distance(float_second_trace_from_corner, p_second_trace_costs.horizontal, - p_second_trace_costs.vertical); - curr_weighted_distance_2 = - float_via_location.weighted_distance(float_check_location, p_first_trace_costs.horizontal, - p_first_trace_costs.vertical); - double curr_weighted_distance_3 = - float_check_location.weighted_distance(float_second_trace_from_corner, p_second_trace_costs.horizontal, - p_second_trace_costs.vertical); - - if (curr_weighted_distance_1 > curr_weighted_distance_2 + curr_weighted_distance_3) - { - IntPoint check_location = float_check_location.round(); - boolean check_ok = - reposition_via(p_board, p_via, check_location, p_first_trace_half_width, - p_first_trace_layer, p_first_trace_cl_class, rounded_second_trace_from_corner, - p_second_trace_half_width, p_second_trace_layer, p_second_trace_cl_class); - if (check_ok) - { - return check_location; - } - } - - float_check_location = new FloatPoint(float_second_trace_from_corner.x, float_via_location.y); - - curr_weighted_distance_2 = - float_via_location.weighted_distance(float_check_location, p_first_trace_costs.horizontal, - p_first_trace_costs.vertical); - curr_weighted_distance_3 = - float_check_location.weighted_distance(float_second_trace_from_corner, p_second_trace_costs.horizontal, - p_second_trace_costs.vertical); - - if (curr_weighted_distance_1 > curr_weighted_distance_2 + curr_weighted_distance_3) - { - IntPoint check_location = float_check_location.round(); - boolean check_ok = - reposition_via(p_board, p_via, check_location, p_first_trace_half_width, - p_first_trace_layer, p_first_trace_cl_class, rounded_second_trace_from_corner, - p_second_trace_half_width, p_second_trace_layer, p_second_trace_cl_class); - if (check_ok) - { - return check_location; - } - } - } - return null; - } -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * OptViaAlgo.java + * + * Created on 31. Maerz 2006, 06:58 + * + */ + +package board; + +import java.util.Collection; +import java.util.Iterator; + +import geometry.planar.Point; +import geometry.planar.IntPoint; +import geometry.planar.Vector; +import geometry.planar.Polyline; +import geometry.planar.FloatPoint; +import geometry.planar.FloatLine; +import geometry.planar.Side; + +import autoroute.AutorouteControl.ExpansionCostFactor; + +/** + * Contains functions for optimizing and improving via locations. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class OptViaAlgo +{ + + /** + * Optimizes the location of a via connected to at most 2 traces + * according to the trace costs on the layers of the connected traces + * If p_trace_cost_arr == null, the horizontal and vertical trace costs will be set to 1. + * Returns false, if the via was not changed. + * + * @param p_board a {@link board.RoutingBoard} object. + * @param p_via a {@link board.Via} object. + * @param p_trace_cost_arr an array of {@link autoroute.AutorouteControl.ExpansionCostFactor} objects. + * @param p_trace_pull_tight_accuracy a int. + * @param p_max_recursion_depth a int. + * @return a boolean. + */ + public static boolean opt_via_location(RoutingBoard p_board, Via p_via, + ExpansionCostFactor[] p_trace_cost_arr, int p_trace_pull_tight_accuracy, int p_max_recursion_depth) + { + if (p_via.is_shove_fixed()) + { + return false; + } + if (p_max_recursion_depth <= 0) + { + if (p_board.get_test_level().ordinal() >= TestLevel.CRITICAL_DEBUGGING_OUTPUT.ordinal()) + { + System.out.println("OptViaAlgo.opt_via_location: probably endless loop") ; + } + return false; + } + Collection contacts = p_via.get_normal_contacts(); + boolean is_plane_or_fanout_via = (contacts.size() == 1); + PolylineTrace first_trace = null; + PolylineTrace second_trace = null; + if (!is_plane_or_fanout_via) + { + if (contacts.size() != 2) + { + return false; + } + Iterator it = contacts.iterator(); + Item curr_item = it.next(); + if (curr_item.is_shove_fixed() || !(curr_item instanceof PolylineTrace)) + { + if (curr_item instanceof ConductionArea) + { + is_plane_or_fanout_via = true; + } + else + { + return false; + } + } + else + { + first_trace = (PolylineTrace) curr_item; + } + curr_item = it.next(); + if (curr_item.is_shove_fixed() || !(curr_item instanceof PolylineTrace)) + { + if (curr_item instanceof ConductionArea) + { + is_plane_or_fanout_via = true; + } + else + { + return false; + } + } + else + { + second_trace = (PolylineTrace) curr_item; + } + } + if (is_plane_or_fanout_via) + { + return opt_plane_or_fanout_via(p_board, p_via, p_trace_pull_tight_accuracy, p_max_recursion_depth); + } + Point via_center = p_via.get_center(); + int first_layer = first_trace.get_layer(); + int second_layer = second_trace.get_layer(); + Point first_trace_from_corner; + Point second_trace_from_corner; + + // calculate first_trace_from_corner and second_trace_from_corner + + if (first_trace.first_corner().equals(via_center)) + { + first_trace_from_corner = first_trace.polyline().corner(1); + } + else if (first_trace.last_corner().equals(via_center)) + { + first_trace_from_corner + = first_trace.polyline().corner(first_trace.polyline().corner_count() - 2); + } + else + { + System.out.println("OptViaAlgo.opt_via_location: incorrect first contact"); + return false; + } + + if (second_trace.first_corner().equals(via_center)) + { + second_trace_from_corner = second_trace.polyline().corner(1); + } + else if (second_trace.last_corner().equals(via_center)) + { + second_trace_from_corner + = second_trace.polyline().corner(second_trace.polyline().corner_count() - 2); + } + else + { + System.out.println("OptViaAlgo.opt_via_location: incorrect second contact"); + return false; + } + + ExpansionCostFactor first_layer_trace_costs; + ExpansionCostFactor second_layer_trace_costs; + if (p_trace_cost_arr != null) + { + first_layer_trace_costs = p_trace_cost_arr[first_layer]; + second_layer_trace_costs = p_trace_cost_arr[second_layer]; + } + else + { + first_layer_trace_costs = new ExpansionCostFactor(1, 1); + second_layer_trace_costs = first_layer_trace_costs; + } + + Point new_location = + reposition_via(p_board, p_via, + first_trace.get_half_width(), first_trace.clearance_class_no(), first_trace.get_layer(), + first_layer_trace_costs, first_trace_from_corner, + second_trace.get_half_width(), second_trace.clearance_class_no(), second_trace.get_layer(), + second_layer_trace_costs, second_trace_from_corner); + if (new_location == null || new_location.equals(via_center)) + { + return false; + } + Vector delta = new_location.difference_by(via_center); + if (!MoveDrillItemAlgo.insert(p_via, delta, 9, 9, null, p_board)) + { + System.out.println("OptViaAlgo.opt_via_location: move via failed"); + return false; + } + ItemSelectionFilter filter = new ItemSelectionFilter(ItemSelectionFilter.SelectableChoices.TRACES); + Collection picked_items = p_board.pick_items(new_location, first_trace.get_layer(), filter); + for (Item curr_item : picked_items) + { + ((PolylineTrace) curr_item).pull_tight(true, p_trace_pull_tight_accuracy, null); + } + picked_items = p_board.pick_items(new_location, second_trace.get_layer(), filter); + for (Item curr_item : picked_items) + { + ((PolylineTrace) curr_item).pull_tight(true, p_trace_pull_tight_accuracy, null); + } + filter = new ItemSelectionFilter(ItemSelectionFilter.SelectableChoices.VIAS); + picked_items = p_board.pick_items(new_location, first_trace.get_layer(), filter); + for (Item curr_item : picked_items) + { + opt_via_location(p_board, (Via) curr_item, p_trace_cost_arr, + p_trace_pull_tight_accuracy, p_max_recursion_depth - 1); + break; + } + return true; + } + + /** + * Optimisations for vias with only 1 connected Trace (Plane or Fanout Vias). + */ + private static boolean opt_plane_or_fanout_via(RoutingBoard p_board, Via p_via, + int p_trace_pull_tight_accuracy, int p_max_recursion_depth) + { + if (p_max_recursion_depth <= 0) + { + if (p_board.get_test_level().ordinal() >= TestLevel.CRITICAL_DEBUGGING_OUTPUT.ordinal()) + { + System.out.println("OptViaAlgo.opt_plane_or_fanout_via: probably endless loop") ; + } + return false; + } + Collection contact_list = p_via.get_normal_contacts(); + if (contact_list.isEmpty()) + { + return false; + } + ConductionArea contact_plane = null; + PolylineTrace contact_trace = null; + for (Item curr_contact : contact_list) + { + if (curr_contact instanceof ConductionArea) + { + if (contact_plane != null) + { + return false; + } + contact_plane = (ConductionArea) curr_contact; + } + else if (curr_contact instanceof PolylineTrace) + { + if (curr_contact.is_shove_fixed() || contact_trace != null) + { + return false; + } + contact_trace = (PolylineTrace) curr_contact; + } + else + { + return false; + } + } + if (contact_trace == null) + { + return false; + } + Point via_center = p_via.get_center(); + boolean at_first_corner; + if (contact_trace.first_corner().equals(via_center)) + { + at_first_corner = true; + } + else if (contact_trace.last_corner().equals(via_center)) + { + at_first_corner = false; + } + else + { + System.out.println("OptViaAlgo.opt_plane_or_fanout_via: unconsistant contact"); + return false; + } + Polyline trace_polyline = contact_trace.polyline(); + Point check_corner; + if (at_first_corner) + { + check_corner = trace_polyline.corner(1); + } + else + { + check_corner = trace_polyline.corner(trace_polyline.corner_count() - 2); + } + IntPoint rounded_check_corner = check_corner.to_float().round(); + int trace_half_width = contact_trace.get_half_width(); + int trace_layer = contact_trace.get_layer(); + int trace_cl_class_no = contact_trace.clearance_class_no(); + Point new_via_location = + reposition_via(p_board, p_via, rounded_check_corner, trace_half_width , + trace_layer, trace_cl_class_no); + if (new_via_location == null && trace_polyline.corner_count() >= 3) + { + + // try to project the via to the previous line + Point prev_corner; + + if (at_first_corner) + { + prev_corner = trace_polyline.corner(2); + } + else + { + prev_corner = trace_polyline.corner(trace_polyline.corner_count() - 3); + } + FloatPoint float_check_corner = check_corner.to_float(); + FloatPoint float_via_center = via_center.to_float(); + FloatPoint float_prev_corner = prev_corner.to_float(); + if (float_check_corner.scalar_product(float_via_center, float_prev_corner) != 0) + { + FloatLine curr_line = new FloatLine(float_check_corner, float_prev_corner); + Point projection = curr_line.perpendicular_projection(float_via_center).round(); + Vector diff_vector = projection.difference_by(via_center); + boolean projection_ok = true; + AngleRestriction angle_restriction = p_board.rules.get_trace_angle_restriction(); + if (projection.equals(via_center) || + angle_restriction == AngleRestriction.NINETY_DEGREE && !diff_vector.is_orthogonal() || + angle_restriction == AngleRestriction.FORTYFIVE_DEGREE && !diff_vector.is_multiple_of_45_degree()) + { + projection_ok = false; + } + if (projection_ok) + { + if(MoveDrillItemAlgo.check(p_via, diff_vector, 0, 0, null, p_board, null)) + { + double ok_length = + p_board.check_trace_segment(via_center, projection, trace_layer, p_via.net_no_arr, + trace_half_width, trace_cl_class_no, false); + if (ok_length >= Integer.MAX_VALUE) + { + new_via_location = projection; + } + } + + } + } + } + if (new_via_location == null) + { + return false; + } + if (contact_plane != null) + { + // check, that the new location is inside the contact plane + ItemSelectionFilter filter = new ItemSelectionFilter(ItemSelectionFilter.SelectableChoices.CONDUCTION); + Collection picked_items = p_board.pick_items(new_via_location, contact_plane.get_layer(), filter); + boolean contact_ok = false; + for (Item curr_item : picked_items) + { + if (curr_item == contact_plane) + { + contact_ok = true; + break; + } + } + if (!contact_ok) + { + return false; + } + } + Vector diff_vector = new_via_location.difference_by(via_center); + if (!MoveDrillItemAlgo.insert(p_via, diff_vector, 9, 9, null, p_board)) + { + System.out.println("OptViaAlgo.opt_plane_or_fanout_via: move via failed"); + return false; + } + ItemSelectionFilter filter = new ItemSelectionFilter(ItemSelectionFilter.SelectableChoices.TRACES); + Collection picked_items = p_board.pick_items(new_via_location, contact_trace.get_layer(), filter); + for (Item curr_item : picked_items) + { + ((PolylineTrace) curr_item).pull_tight(true, p_trace_pull_tight_accuracy, null); + } + if (new_via_location.equals(check_corner)) + { + opt_plane_or_fanout_via(p_board, p_via, p_trace_pull_tight_accuracy, p_max_recursion_depth - 1); + } + return true; + } + + /** + * Tries to move the via into the direction of p_to_location as far as possible + * Return the new location of the via, or null, if no move was possible. + */ + private static Point reposition_via(RoutingBoard p_board, Via p_via, + IntPoint p_to_location, int p_trace_half_width, int p_trace_layer, int p_trace_cl_class) + + { + Point from_location = p_via.get_center(); + + if (from_location.equals(p_to_location)) + { + return null; + } + + double ok_length = p_board.check_trace_segment(from_location, p_to_location, p_trace_layer, p_via.net_no_arr, + p_trace_half_width, p_trace_cl_class, false); + if (ok_length <= 0) + { + return null; + } + FloatPoint float_from_location = from_location.to_float(); + FloatPoint float_to_location = p_to_location.to_float(); + FloatPoint new_float_to_location; + if (ok_length >= Integer.MAX_VALUE) + { + new_float_to_location = float_to_location; + } + else + { + new_float_to_location = float_from_location.change_length(float_to_location, ok_length); + } + Point new_to_location = new_float_to_location.round(); + Vector delta = new_to_location.difference_by(from_location); + boolean check_ok = + MoveDrillItemAlgo.check(p_via, delta, 0, 0, null, p_board, null); + + if (check_ok) + { + return new_to_location; + } + + final double c_min_length = 0.3 * p_trace_half_width + 1; + + ok_length = Math.min(ok_length, float_from_location.distance(float_to_location)); + + double curr_length = ok_length / 2; + + ok_length = 0; + Point result = null; + + while (curr_length >= c_min_length) + { + Point check_point = float_from_location.change_length(float_to_location, ok_length + curr_length).round(); + + delta = check_point.difference_by(from_location); + if (MoveDrillItemAlgo.check(p_via, delta, 0, 0, null, p_board, null)) + { + ok_length += curr_length; + result = check_point; + } + curr_length /= 2; + } + return result; + } + + private static boolean reposition_via(RoutingBoard p_board, Via p_via, + IntPoint p_to_location, int p_trace_half_width_1, int p_trace_layer_1, int p_trace_cl_class_1, + IntPoint p_connect_location, int p_trace_half_width_2, int p_trace_layer_2, int p_trace_cl_class_2) + + { + Point from_location = p_via.get_center(); + + if (from_location.equals(p_to_location)) + { + if (p_board.get_test_level() == TestLevel.ALL_DEBUGGING_OUTPUT) + { + System.out.println("OptViaAlgo.reposition_via: from_location equal p_to_location"); + } + return false; + } + + Vector delta = p_to_location.difference_by(from_location); + + if ( p_board.rules.get_trace_angle_restriction() == AngleRestriction.NONE && delta.length_approx() <= 1.5) + { + // PullTightAlgoAnyAngle.reduce_corners mmay not be able to remove the new generated overlap + // because of numerical stability problems + // That would result in an endless loop with removing the generated acute angle in reposition_via. + return false; + } + + int[] net_no_arr = p_via.net_no_arr; + + double ok_length = p_board.check_trace_segment(from_location, p_to_location, p_trace_layer_1, net_no_arr, + p_trace_half_width_1, p_trace_cl_class_1, false); + + if (ok_length < Integer.MAX_VALUE) + { + return false; + } + + ok_length = p_board.check_trace_segment(p_to_location, p_connect_location, p_trace_layer_2, net_no_arr, + p_trace_half_width_2, p_trace_cl_class_2, false); + + if (ok_length < Integer.MAX_VALUE) + { + return false; + } + if (!MoveDrillItemAlgo.check(p_via, delta, 0, 0, null, p_board, null)) + { + return false; + } + return true; + } + + /** + * Tries to reposition the via to a better location according to the + * trace costs. Returns null, if no better location was found. + */ + private static Point reposition_via(RoutingBoard p_board, Via p_via, + int p_first_trace_half_width, int p_first_trace_cl_class, int p_first_trace_layer, + ExpansionCostFactor p_first_trace_costs, Point p_first_trace_from_corner, + int p_second_trace_half_width, int p_second_trace_cl_class, int p_second_trace_layer, + ExpansionCostFactor p_second_trace_costs, Point p_second_trace_from_corner) + { + Point via_location = p_via.get_center(); + + Vector first_delta = p_first_trace_from_corner.difference_by(via_location); + Vector second_delta = p_second_trace_from_corner.difference_by(via_location); + double scalar_product = first_delta.scalar_product(second_delta); + + FloatPoint float_via_location = via_location.to_float(); + FloatPoint float_first_trace_from_corner = p_first_trace_from_corner.to_float(); + FloatPoint float_second_trace_from_corner = p_second_trace_from_corner.to_float(); + double first_trace_from_corner_distance = float_via_location.distance(float_first_trace_from_corner); + double second_trace_from_corner_distance = float_via_location.distance(float_second_trace_from_corner); + IntPoint rounded_first_trace_from_corner = float_first_trace_from_corner.round(); + IntPoint rounded_second_trace_from_corner = float_second_trace_from_corner.round(); + + // handle case of overlapping lines first + + if (via_location.side_of(p_first_trace_from_corner, p_second_trace_from_corner) == Side.COLLINEAR + && scalar_product > 0) + { + if (second_trace_from_corner_distance < first_trace_from_corner_distance) + { + return reposition_via(p_board, p_via, rounded_second_trace_from_corner, + p_first_trace_half_width, p_first_trace_layer, p_first_trace_cl_class); + } + return reposition_via(p_board, p_via, rounded_first_trace_from_corner, + p_second_trace_half_width, p_second_trace_layer, p_second_trace_cl_class); + } + Point result = null; + + double curr_weighted_distance_1 = + float_via_location.weighted_distance(float_first_trace_from_corner, p_first_trace_costs.horizontal, + p_first_trace_costs.vertical); + double curr_weighted_distance_2 = + float_via_location.weighted_distance(float_first_trace_from_corner, p_second_trace_costs.horizontal, + p_second_trace_costs.vertical); + + if (curr_weighted_distance_1 > curr_weighted_distance_2) + { + // try to move the via in direction of p_first_trace_from_corner + result = reposition_via(p_board, p_via, rounded_first_trace_from_corner, + p_second_trace_half_width, p_second_trace_layer, p_second_trace_cl_class); + if (result != null) + { + return result; + } + } + + curr_weighted_distance_1 = + float_via_location.weighted_distance(float_second_trace_from_corner, p_second_trace_costs.horizontal, + p_second_trace_costs.vertical); + curr_weighted_distance_2 = + float_via_location.weighted_distance(float_second_trace_from_corner, p_first_trace_costs.horizontal, + p_first_trace_costs.vertical); + + if (curr_weighted_distance_1 > curr_weighted_distance_2) + { + // try to move the via in direction of p_second_trace_from_corner + result = reposition_via(p_board, p_via, rounded_second_trace_from_corner, + p_first_trace_half_width, p_first_trace_layer, p_first_trace_cl_class); + if (result != null) + { + return result; + } + } + if (scalar_product > 0 && p_board.rules.get_trace_angle_restriction() != AngleRestriction.NINETY_DEGREE) + { + // acute angle + IntPoint to_point_1; + IntPoint to_point_2; + FloatPoint float_to_point_1; + FloatPoint float_to_point_2; + if (first_trace_from_corner_distance < second_trace_from_corner_distance) + { + to_point_1 = rounded_first_trace_from_corner; + float_to_point_1 = float_first_trace_from_corner; + float_to_point_2 = + float_via_location.change_length(float_second_trace_from_corner, + first_trace_from_corner_distance); + to_point_2 = float_to_point_2.round(); + } + else + { + float_to_point_1 = + float_via_location.change_length(float_first_trace_from_corner, + second_trace_from_corner_distance); + to_point_1 = float_to_point_1.round(); + to_point_2 = rounded_second_trace_from_corner; + float_to_point_2 = float_second_trace_from_corner; + } + curr_weighted_distance_1 = + float_to_point_1.weighted_distance(float_to_point_2, p_first_trace_costs.horizontal, + p_first_trace_costs.vertical); + curr_weighted_distance_2 = + float_to_point_1.weighted_distance(float_to_point_2, p_second_trace_costs.horizontal, + p_second_trace_costs.vertical); + + if (curr_weighted_distance_1 > curr_weighted_distance_2) + { + // try moving the via first into the direction of to_point_1 + result = reposition_via(p_board, p_via, to_point_1, + p_second_trace_half_width, p_second_trace_layer, p_second_trace_cl_class); + if (result == null) + { + result = reposition_via(p_board, p_via, to_point_2, + p_first_trace_half_width, p_first_trace_layer, p_first_trace_cl_class); + } + } + else + { + // try moving the via first into the direction of to_point_2 + result = reposition_via(p_board, p_via, to_point_2, + p_first_trace_half_width, p_first_trace_layer, p_first_trace_cl_class); + if (result == null) + { + result = reposition_via(p_board, p_via, to_point_1, + p_second_trace_half_width, p_second_trace_layer, p_second_trace_cl_class); + } + } + if (result != null) + { + return result; + } + } + + // try decomposition in axisparallel parts + + if (!first_delta.is_orthogonal()) + { + FloatPoint float_check_location = new FloatPoint(float_via_location.x, float_first_trace_from_corner.y); + + curr_weighted_distance_1 = + float_via_location.weighted_distance(float_first_trace_from_corner, p_first_trace_costs.horizontal, + p_first_trace_costs.vertical); + curr_weighted_distance_2 = + float_via_location.weighted_distance(float_check_location, p_second_trace_costs.horizontal, + p_second_trace_costs.vertical); + double curr_weighted_distance_3 = + float_check_location.weighted_distance(float_first_trace_from_corner, p_first_trace_costs.horizontal, + p_first_trace_costs.vertical); + + if (curr_weighted_distance_1 > curr_weighted_distance_2 + curr_weighted_distance_3) + { + IntPoint check_location = float_check_location.round(); + boolean check_ok = + reposition_via(p_board, p_via, check_location, p_second_trace_half_width, + p_second_trace_layer, p_second_trace_cl_class, rounded_first_trace_from_corner, + p_first_trace_half_width, p_first_trace_layer, p_first_trace_cl_class); + if (check_ok) + { + return check_location; + } + } + + float_check_location = new FloatPoint(float_first_trace_from_corner.x, float_via_location.y); + + curr_weighted_distance_2 = + float_via_location.weighted_distance(float_check_location, p_second_trace_costs.horizontal, + p_second_trace_costs.vertical); + curr_weighted_distance_3 = + float_check_location.weighted_distance(float_first_trace_from_corner, p_first_trace_costs.horizontal, + p_first_trace_costs.vertical); + + if (curr_weighted_distance_1 > curr_weighted_distance_2 + curr_weighted_distance_3) + { + IntPoint check_location = float_check_location.round(); + boolean check_ok = + reposition_via(p_board, p_via, check_location, p_second_trace_half_width, + p_second_trace_layer, p_second_trace_cl_class, rounded_first_trace_from_corner, + p_first_trace_half_width, p_first_trace_layer, p_first_trace_cl_class); + if (check_ok) + { + return check_location; + } + } + } + + if (!second_delta.is_orthogonal()) + { + FloatPoint float_check_location = new FloatPoint(float_via_location.x, float_second_trace_from_corner.y); + + curr_weighted_distance_1 = + float_via_location.weighted_distance(float_second_trace_from_corner, p_second_trace_costs.horizontal, + p_second_trace_costs.vertical); + curr_weighted_distance_2 = + float_via_location.weighted_distance(float_check_location, p_first_trace_costs.horizontal, + p_first_trace_costs.vertical); + double curr_weighted_distance_3 = + float_check_location.weighted_distance(float_second_trace_from_corner, p_second_trace_costs.horizontal, + p_second_trace_costs.vertical); + + if (curr_weighted_distance_1 > curr_weighted_distance_2 + curr_weighted_distance_3) + { + IntPoint check_location = float_check_location.round(); + boolean check_ok = + reposition_via(p_board, p_via, check_location, p_first_trace_half_width, + p_first_trace_layer, p_first_trace_cl_class, rounded_second_trace_from_corner, + p_second_trace_half_width, p_second_trace_layer, p_second_trace_cl_class); + if (check_ok) + { + return check_location; + } + } + + float_check_location = new FloatPoint(float_second_trace_from_corner.x, float_via_location.y); + + curr_weighted_distance_2 = + float_via_location.weighted_distance(float_check_location, p_first_trace_costs.horizontal, + p_first_trace_costs.vertical); + curr_weighted_distance_3 = + float_check_location.weighted_distance(float_second_trace_from_corner, p_second_trace_costs.horizontal, + p_second_trace_costs.vertical); + + if (curr_weighted_distance_1 > curr_weighted_distance_2 + curr_weighted_distance_3) + { + IntPoint check_location = float_check_location.round(); + boolean check_ok = + reposition_via(p_board, p_via, check_location, p_first_trace_half_width, + p_first_trace_layer, p_first_trace_cl_class, rounded_second_trace_from_corner, + p_second_trace_half_width, p_second_trace_layer, p_second_trace_cl_class); + if (check_ok) + { + return check_location; + } + } + } + return null; + } +} diff --git a/board/Pin.java b/src/main/java/board/Pin.java similarity index 94% rename from board/Pin.java rename to src/main/java/board/Pin.java index 6a7b939..35b675e 100644 --- a/board/Pin.java +++ b/src/main/java/board/Pin.java @@ -40,6 +40,7 @@ * with a shape on 1 or several layers. * * @author Alfons Wirtz + * @version $Id: $Id */ public class Pin extends DrillItem implements java.io.Serializable { @@ -57,6 +58,8 @@ public class Pin extends DrillItem implements java.io.Serializable /** * Calculates the relative location of this pin to its component. + * + * @return a {@link geometry.planar.Vector} object. */ public Vector relative_location() { @@ -92,6 +95,11 @@ public Vector relative_location() } + /** + *

get_center.

+ * + * @return a {@link geometry.planar.Point} object. + */ public Point get_center() { Point pin_center = super.get_center(); @@ -129,6 +137,11 @@ else if (!curr_shape.contains_inside(pin_center)) return pin_center; } + /** + *

get_padstack.

+ * + * @return a {@link library.Padstack} object. + */ public Padstack get_padstack() { Component component = board.components.get(get_component_no()); @@ -141,6 +154,7 @@ public Padstack get_padstack() return board.library.padstacks.get(padstack_no); } + /** {@inheritDoc} */ public Item copy(int p_id_no) { int [] curr_net_no_arr = new int [this.net_count()]; @@ -154,6 +168,8 @@ public Item copy(int p_id_no) /** * Return the name of this pin in the package of this component. + * + * @return a {@link java.lang.String} object. */ public String name() { @@ -168,12 +184,15 @@ public String name() /** * Gets index of this pin in the library package of the pins component. + * + * @return a int. */ public int get_index_in_package() { return pin_no; } + /** {@inheritDoc} */ public Shape get_shape(int p_index) { Padstack padstack = get_padstack(); @@ -292,6 +311,9 @@ int get_padstack_layer(int p_index) * together with the minimal trace line lengths into thei directions. * Currently only implemented only for box shapes, where traces are allowed to exit * the pad only on the small sides. + * + * @param p_layer a int. + * @return a {@link java.util.Collection} object. */ public java.util.Collection get_trace_exit_restrictions(int p_layer) { @@ -375,6 +397,8 @@ public java.util.Collection get_trace_exit_restrictions(in /** * Returns true, if this pin has exit restrictions on some kayer. + * + * @return a boolean. */ public boolean has_trace_exit_restrictions() { @@ -392,12 +416,20 @@ public boolean has_trace_exit_restrictions() /** * Returns true, if vias throw the pads of this pins are allowed, false, otherwise. * Currently drills are allowed to SMD-pins. + * + * @return a boolean. */ public boolean drill_allowed() { return (this.first_layer() == this.last_layer()); } + /** + *

is_obstacle.

+ * + * @param p_other a {@link board.Item} object. + * @return a boolean. + */ public boolean is_obstacle(Item p_other) { if (p_other == this || p_other instanceof ObstacleArea) @@ -419,24 +451,30 @@ public boolean is_obstacle(Item p_other) return true; } + /** {@inheritDoc} */ public void turn_90_degree(int p_factor, IntPoint p_pole) { this.set_center(null); clear_derived_data(); } + /** {@inheritDoc} */ public void rotate_approx(double p_angle_in_degree, FloatPoint p_pole) { this.set_center(null); this.clear_derived_data(); } + /** {@inheritDoc} */ public void change_placement_side(IntPoint p_pole) { this.set_center(null); this.clear_derived_data(); } + /** + *

clear_derived_data.

+ */ public void clear_derived_data() { super.clear_derived_data(); @@ -445,6 +483,8 @@ public void clear_derived_data() /** * Return all Pins, that can be swapped with this pin. + * + * @return a {@link java.util.Set} object. */ public java.util.Set get_swappable_pins() { @@ -493,6 +533,7 @@ public java.util.Set get_swappable_pins() return result; } + /** {@inheritDoc} */ public boolean is_selected_by_filter(ItemSelectionFilter p_filter) { if (!this.is_selected_by_fixed_filter(p_filter)) @@ -502,6 +543,7 @@ public boolean is_selected_by_filter(ItemSelectionFilter p_filter) return p_filter.is_selected(ItemSelectionFilter.SelectableChoices.PINS); } + /** {@inheritDoc} */ public java.awt.Color[] get_draw_colors(boardgraphics.GraphicsContext p_graphics_context) { java.awt.Color[] result; @@ -517,6 +559,7 @@ public java.awt.Color[] get_draw_colors(boardgraphics.GraphicsContext p_graphics return result; } + /** {@inheritDoc} */ public double get_draw_intensity(boardgraphics.GraphicsContext p_graphics_context) { return p_graphics_context.get_pin_color_intensity(); @@ -525,6 +568,9 @@ public double get_draw_intensity(boardgraphics.GraphicsContext p_graphics_contex /** * Swaps the nets of this pin and p_other. * Returns false on error. + * + * @param p_other a {@link board.Pin} object. + * @return a boolean. */ public boolean swap(Pin p_other) { @@ -561,12 +607,15 @@ public boolean swap(Pin p_other) /** * Returns the pin, this pin was changed to by pin swapping, or this pin, if it was not swapped. + * + * @return a {@link board.Pin} object. */ public Pin get_changed_to() { return changed_to; } + /** {@inheritDoc} */ public boolean write(java.io.ObjectOutputStream p_stream) { try @@ -581,7 +630,11 @@ public boolean write(java.io.ObjectOutputStream p_stream) } - /** False, if this drillitem is places on the back side of the board */ + /** + * False, if this drillitem is places on the back side of the board + * + * @return a boolean. + */ public boolean is_placed_on_front() { boolean result = true; @@ -595,6 +648,9 @@ public boolean is_placed_on_front() /** * Returns the smallest width of the pin shape on layer p_layer. + * + * @param p_layer a int. + * @return a double. */ public double get_min_width(int p_layer) { @@ -618,6 +674,9 @@ public double get_min_width(int p_layer) * Returns the neckdown half width for traces on p_layer. * The neckdown width is used, when the pin width is smmaller than the trace width * to enter or leave the pin with a trace. + * + * @param p_layer a int. + * @return a int. */ public int get_trace_neckdown_halfwidth(int p_layer) { @@ -627,6 +686,9 @@ public int get_trace_neckdown_halfwidth(int p_layer) /** * Returns the largest width of the pin shape on layer p_layer. + * + * @param p_layer a int. + * @return a double. */ public double get_max_width(int p_layer) { @@ -646,6 +708,7 @@ public double get_max_width(int p_layer) return padstack_bounding_box.max_width(); } + /** {@inheritDoc} */ public void print_info(ObjectInfoPanel p_window, java.util.Locale p_locale) { java.util.ResourceBundle resources = @@ -745,6 +808,11 @@ else if (curr_trace_corner_distance > old_trace_corner_distance + TOLERANCE) /** * Calculates the nearest trace exit point of the pin on p_layer. * Returns null, if the pin has no trace exit restrictions. + * + * @param p_from_point a {@link geometry.planar.FloatPoint} object. + * @param p_trace_half_width a int. + * @param p_layer a int. + * @return a {@link geometry.planar.FloatPoint} object. */ public FloatPoint nearest_trace_exit_corner(FloatPoint p_from_point, int p_trace_half_width, int p_layer) { diff --git a/board/PolylineTrace.java b/src/main/java/board/PolylineTrace.java similarity index 96% rename from board/PolylineTrace.java rename to src/main/java/board/PolylineTrace.java index b234e21..efbdd9c 100644 --- a/board/PolylineTrace.java +++ b/src/main/java/board/PolylineTrace.java @@ -1,1407 +1,1479 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - */ -package board; - -import datastructures.Signum; -import datastructures.Stoppable; - -import geometry.planar.IntBox; -import geometry.planar.IntOctagon; -import geometry.planar.Line; -import geometry.planar.LineSegment; -import geometry.planar.Point; -import geometry.planar.IntPoint; -import geometry.planar.FloatPoint; -import geometry.planar.Polyline; -import geometry.planar.Shape; -import geometry.planar.TileShape; -import geometry.planar.Direction; -import geometry.planar.Vector; - -import java.awt.Color; -import java.awt.Graphics; -import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedList; - -import boardgraphics.GraphicsContext; - -/** - * - * Objects of class Trace, whose geometry is described by a Polyline - * - * - * @author Alfons Wirtz - */ -public class PolylineTrace extends Trace implements java.io.Serializable -{ - - /** - * creates a new instance of a PolylineTrace with the input data - */ - public PolylineTrace(Polyline p_polyline, int p_layer, int p_half_width, - int[] p_net_no_arr, int p_clearance_type, int p_id_no, - int p_group_no, FixedState p_fixed_state, BasicBoard p_board) - { - super(p_layer, p_half_width, p_net_no_arr, p_clearance_type, - p_id_no, p_group_no, p_fixed_state, p_board); - if (p_polyline.arr.length < 3) - { - System.out.println("PolylineTrace: p_polyline.arr.length >= 3 expected"); - } - lines = p_polyline; - } - - public Item copy(int p_id_no) - { - int[] curr_net_no_arr = new int[this.net_count()]; - for (int i = 0; i < curr_net_no_arr.length; ++i) - { - curr_net_no_arr[i] = get_net_no(i); - } - return new PolylineTrace(lines, get_layer(), get_half_width(), curr_net_no_arr, clearance_class_no(), - p_id_no, get_component_no(), get_fixed_state(), board); - } - - /** - * checks, if this trace is on layer p_layer - */ - public boolean is_on_layer(int p_layer) - { - return get_layer() == p_layer; - } - - /** - * returns the first corner of this trace, which is the intersection - * of the first and second lines of its polyline - */ - public Point first_corner() - { - return lines.corner(0); - } - - /** - * returns the last corner of this trace, which is the intersection - * of the last two lines of its polyline - */ - public Point last_corner() - { - return lines.corner(lines.arr.length - 2); - } - - /** - * returns the number of corners of this trace, which is the - * number of lines of its polyline minus one - */ - public int corner_count() - { - return lines.arr.length - 1; - } - - public double get_length() - { - return lines.length_approx(); - } - - public IntBox bounding_box() - { - IntBox result = this.lines.bounding_box(); - return result.offset(this.get_half_width()); - } - - public void draw(Graphics p_g, GraphicsContext p_graphics_context, Color[] p_color_arr, double p_intensity) - { - if (p_graphics_context == null) - { - return; - } - int layer = this.get_layer(); - Color color = p_color_arr[layer]; - double display_width = get_half_width(); - double intensity = p_intensity * p_graphics_context.get_layer_visibility(layer); - p_graphics_context.draw(lines.corner_approx_arr(), display_width, color, p_g, intensity); - } - - /** - * Returns the polyline of this trace. - */ - public Polyline polyline() - { - return lines; - } - - protected TileShape[] calculate_tree_shapes(ShapeSearchTree p_search_tree) - { - return p_search_tree.calculate_tree_shapes(this); - } - - /** - * returns the count of tile shapes of this polyline - */ - public int tile_shape_count() - { - return Math.max(lines.arr.length - 2, 0); - } - - public void translate_by(Vector p_vector) - { - lines = lines.translate_by(p_vector); - this.clear_derived_data(); - } - - public void turn_90_degree(int p_factor, IntPoint p_pole) - { - lines = lines.turn_90_degree(p_factor, p_pole); - this.clear_derived_data(); - } - - public void rotate_approx(double p_angle_in_degree, FloatPoint p_pole) - { - this.lines = this.lines.rotate_approx(Math.toRadians(p_angle_in_degree), p_pole); - } - - public void change_placement_side(IntPoint p_pole) - { - lines = lines.mirror_vertical(p_pole); - - if (this.board != null) - { - this.set_layer(board.get_layer_count() - this.get_layer() - 1); - } - this.clear_derived_data(); - } - - /** - * Looks, if other traces can be combined with this trace. - * Returns true, if somthing has been combined. - * This trace will be the combined trace, so that only other traces may be deleted. - */ - public boolean combine() - { - if (!this.is_on_the_board()) - { - return false; - } - boolean something_changed; - if (this.combine_at_start(true)) - { - something_changed = true; - this.combine(); - } - else if (this.combine_at_end(true)) - { - something_changed = true; - this.combine(); - } - else - { - something_changed = false; - } - if (something_changed) - { - // let the observers syncronize the changes - board.communication.observers.notify_changed(this); - board.additional_update_after_change(this); - } - return something_changed; - } - - /** - * looks, if this trace can be combined at its first point with - * an other trace. Returns true, if somthing was combined. - * The corners of the other trace will be inserted in front of thie trace. - * In case of combine the other trace will be deleted and this trace will - * remain. - */ - private boolean combine_at_start(boolean p_ignore_areas) - { - Point start_corner = first_corner(); - Collection contacts = get_normal_contacts(start_corner, false); - if (p_ignore_areas) - { - // remove conduction areas from the list - Iterator it = contacts.iterator(); - while (it.hasNext()) - { - if (it.next() instanceof ConductionArea) - { - it.remove(); - } - } - } - if (contacts.size() != 1) - { - return false; - } - PolylineTrace other_trace = null; - boolean trace_found = false; - boolean reverse_order = false; - Iterator it = contacts.iterator(); - while (it.hasNext()) - { - Item curr_ob = it.next(); - if (curr_ob instanceof PolylineTrace) - { - other_trace = (PolylineTrace) curr_ob; - if (other_trace.get_layer() == get_layer() && other_trace.nets_equal(this) && other_trace.get_half_width() == get_half_width() && other_trace.get_fixed_state() == this.get_fixed_state()) - { - if (start_corner.equals(other_trace.last_corner())) - { - trace_found = true; - break; - } - else if (start_corner.equals(other_trace.first_corner())) - { - reverse_order = true; - trace_found = true; - break; - } - } - } - } - if (!trace_found) - { - return false; - } - - board.item_list.save_for_undo(this); - // create the lines of the joined polyline - Line[] this_lines = lines.arr; - Line[] other_lines; - if (reverse_order) - { - other_lines = new Line[other_trace.lines.arr.length]; - for (int i = 0; i < other_lines.length; ++i) - { - other_lines[i] = other_trace.lines.arr[other_lines.length - 1 - i].opposite(); - } - } - else - { - other_lines = other_trace.lines.arr; - } - boolean skip_line = - other_lines[other_lines.length - 2].is_equal_or_opposite(this_lines[1]); - int new_line_count = this_lines.length + other_lines.length - 2; - if (skip_line) - { - --new_line_count; - } - Line[] new_lines = new Line[new_line_count]; - System.arraycopy(other_lines, 0, new_lines, 0, other_lines.length - 1); - int join_pos = other_lines.length - 1; - if (skip_line) - { - --join_pos; - } - System.arraycopy(this_lines, 1, new_lines, join_pos, this_lines.length - 1); - Polyline joined_polyline = new Polyline(new_lines); - if (joined_polyline.arr.length != new_line_count) - { - // consecutive parallel lines where skipped at the join location - // combine without performance optimation - board.search_tree_manager.remove(this); - this.lines = joined_polyline; - this.clear_derived_data(); - board.search_tree_manager.insert(this); - } - else - { - // reuse the tree entries for better performance - // create the changed line shape at the join location - int to_no = other_lines.length; - if (skip_line) - { - --to_no; - } - board.search_tree_manager.merge_entries_in_front(other_trace, this, joined_polyline, - other_lines.length - 3, to_no); - other_trace.clear_search_tree_entries(); - this.lines = joined_polyline; - } - if (this.lines.arr.length < 3) - { - board.remove_item(this); - } - board.remove_item(other_trace); - if (board instanceof RoutingBoard) - { - ((RoutingBoard) board).join_changed_area(start_corner.to_float(), get_layer()); - } - return true; - } - - /** - * looks, if this trace can be combined at its last point with - * another trace. Returns true, if somthing was combined. - * The corners of the other trace will be inserted at the end of thie trace. - * In case of combine the other trace will be deleted and this trace will - * remain. - */ - private boolean combine_at_end(boolean p_ignore_areas) - { - Point end_corner = last_corner(); - Collection contacts = get_normal_contacts(end_corner, false); - if (p_ignore_areas) - { - // remove conduction areas from the list - Iterator it = contacts.iterator(); - while (it.hasNext()) - { - if (it.next() instanceof ConductionArea) - { - it.remove(); - } - } - } - if (contacts.size() != 1) - { - return false; - } - PolylineTrace other_trace = null; - boolean trace_found = false; - boolean reverse_order = false; - Iterator it = contacts.iterator(); - while (it.hasNext()) - { - Item curr_ob = it.next(); - if (curr_ob instanceof PolylineTrace) - { - other_trace = (PolylineTrace) curr_ob; - if (other_trace.get_layer() == get_layer() && other_trace.nets_equal(this) && other_trace.get_half_width() == get_half_width() && other_trace.get_fixed_state() == this.get_fixed_state()) - { - if (end_corner.equals(other_trace.first_corner())) - { - trace_found = true; - break; - } - else if (end_corner.equals(other_trace.last_corner())) - { - reverse_order = true; - trace_found = true; - break; - } - } - } - } - if (!trace_found) - { - return false; - } - - board.item_list.save_for_undo(this); - // create the lines of the joined polyline - Line[] this_lines = lines.arr; - Line[] other_lines; - if (reverse_order) - { - other_lines = new Line[other_trace.lines.arr.length]; - for (int i = 0; i < other_lines.length; ++i) - { - other_lines[i] = other_trace.lines.arr[other_lines.length - 1 - i].opposite(); - } - } - else - { - other_lines = other_trace.lines.arr; - } - boolean skip_line = - this_lines[this_lines.length - 2].is_equal_or_opposite(other_lines[1]); - int new_line_count = this_lines.length + other_lines.length - 2; - if (skip_line) - { - --new_line_count; - } - Line[] new_lines = new Line[new_line_count]; - System.arraycopy(this_lines, 0, new_lines, 0, this_lines.length - 1); - int join_pos = this_lines.length - 1; - if (skip_line) - { - --join_pos; - } - System.arraycopy(other_lines, 1, new_lines, join_pos, other_lines.length - 1); - Polyline joined_polyline = new Polyline(new_lines); - if (joined_polyline.arr.length != new_line_count) - { - // consecutive parallel lines where skipped at the join location - // combine without performance optimation - board.search_tree_manager.remove(this); - this.clear_search_tree_entries(); - this.lines = joined_polyline; - this.clear_derived_data(); - board.search_tree_manager.insert(this); - } - else - { - // reuse tree entries for better performance - // create the changed line shape at the join location - int to_no = this_lines.length; - if (skip_line) - { - --to_no; - } - board.search_tree_manager.merge_entries_at_end(other_trace, this, joined_polyline, this_lines.length - 3, to_no); - other_trace.clear_search_tree_entries(); - this.lines = joined_polyline; - } - if (this.lines.arr.length < 3) - { - board.remove_item(this); - } - board.remove_item(other_trace); - if (board instanceof RoutingBoard) - { - ((RoutingBoard) board).join_changed_area(end_corner.to_float(), get_layer()); - } - return true; - } - - /** - * Looks up traces intersecting with this trace and splits them at the intersection points. - * In case of an overlaps, the traces are split at their first and their last common point. - * Returns the pieces resulting from splitting. - * Found cycles are removed. - * If nothing is split, the result will contain just this Trace. - * If p_clip_shape != null, the split may be resticted to p_clip_shape. - */ - public Collection split(IntOctagon p_clip_shape) - { - Collection result = new LinkedList(); - if (!this.nets_normal()) - { - // only normal nets are split - result.add(this); - return result; - } - boolean own_trace_split = false; - ShapeSearchTree default_tree = board.search_tree_manager.get_default_tree(); - for (int i = 0; i < this.lines.arr.length - 2; ++i) - { - if (p_clip_shape != null) - { - LineSegment curr_segment = new LineSegment(this.lines, i + 1); - if (!p_clip_shape.intersects(curr_segment.bounding_box())) - { - continue; - } - } - TileShape curr_shape = this.get_tree_shape(default_tree, i); - LineSegment curr_line_segment = new LineSegment(this.lines, i + 1); - Collection overlapping_tree_entries = new LinkedList(); - // look for intersecting traces with the i-th line segment - default_tree.overlapping_tree_entries(curr_shape, get_layer(), overlapping_tree_entries); - Iterator it = overlapping_tree_entries.iterator(); - while (it.hasNext()) - { - if (!this.is_on_the_board()) - { - // this trace has been deleted in a cleanup operation - return result; - } - ShapeSearchTree.TreeEntry found_entry = it.next(); - if (!(found_entry.object instanceof Item)) - { - continue; - } - Item found_item = (Item) found_entry.object; - if (found_item == this) - { - - if (found_entry.shape_index_in_object >= i - 1 && found_entry.shape_index_in_object <= i + 1) - { - // don't split own trace at this line or at neighbour lines - continue; - } - // try to handle intermediate segments of length 0 by comparing end corners - if (i < found_entry.shape_index_in_object) - { - if (lines.corner(i + 1).equals(lines.corner(found_entry.shape_index_in_object))) - { - continue; - } - } - else if (found_entry.shape_index_in_object < i) - { - if (lines.corner(found_entry.shape_index_in_object + 1).equals(lines.corner(i))) - { - continue; - } - } - } - if (!found_item.shares_net(this)) - { - continue; - } - if (found_item instanceof PolylineTrace) - { - PolylineTrace found_trace = (PolylineTrace) found_item; - LineSegment found_line_segment = - new LineSegment(found_trace.lines, found_entry.shape_index_in_object + 1); - Line[] intersecting_lines = found_line_segment.intersection(curr_line_segment); - Collection split_pieces = new LinkedList(); - - // try splitting the found trace first - boolean found_trace_split = false; - - if (found_trace != this) - { - for (int j = 0; j < intersecting_lines.length; ++j) - { - int line_no = found_entry.shape_index_in_object + 1; - PolylineTrace[] curr_split_pieces = found_trace.split(line_no, intersecting_lines[j]); - if (curr_split_pieces != null) - { - - for (int k = 0; k < 2; ++k) - { - if (curr_split_pieces[k] != null) - { - found_trace_split = true; - split_pieces.add(curr_split_pieces[k]); - - } - } - if (found_trace_split) - { - // reread the overlapping tree entries and reset the iterator, - // because the board has changed - default_tree.overlapping_tree_entries(curr_shape, get_layer(), overlapping_tree_entries); - it = overlapping_tree_entries.iterator(); - break; - } - } - } - if (!found_trace_split) - { - split_pieces.add(found_trace); - } - } - // now try splitting the own trace - - intersecting_lines = curr_line_segment.intersection(found_line_segment); - for (int j = 0; j < intersecting_lines.length; ++j) - { - PolylineTrace[] curr_split_pieces = split(i + 1, intersecting_lines[j]); - if (curr_split_pieces != null) - { - own_trace_split = true; - // this trace was split itself into 2. - if (curr_split_pieces[0] != null) - { - result.addAll(curr_split_pieces[0].split(p_clip_shape)); - } - if (curr_split_pieces[1] != null) - { - result.addAll(curr_split_pieces[1].split(p_clip_shape)); - } - break; - } - } - if (found_trace_split || own_trace_split) - { - // something was split, - // remove cycles containing a split piece - Iterator it2 = split_pieces.iterator(); - for (int j = 0; j < 2; ++j) - { - while (it2.hasNext()) - { - PolylineTrace curr_piece = it2.next(); - board.remove_if_cycle(curr_piece); - } - - // remove cycles in the own split pieces last - // to preserve them, if possible - it2 = result.iterator(); - } - } - if (own_trace_split) - { - break; - } - } - else if (found_item instanceof DrillItem) - { - DrillItem curr_drill_item = (DrillItem) found_item; - Point split_point = curr_drill_item.get_center(); - if (curr_line_segment.contains(split_point)) - { - Direction split_line_direction = curr_line_segment.get_line().direction().turn_45_degree(2); - Line split_line = new Line(split_point, split_line_direction); - split(i + 1, split_line); - } - } - else if (!this.is_user_fixed() && (found_item instanceof ConductionArea)) - { - boolean ignore_areas = false; - if (this.net_no_arr.length > 0) - { - rules.Net curr_net = this.board.rules.nets.get(this.net_no_arr[0]); - if (curr_net != null && curr_net.get_class() != null) - { - ignore_areas = curr_net.get_class().get_ignore_cycles_with_areas(); - } - } - if (!ignore_areas && this.get_start_contacts().contains(found_item) && - this.get_end_contacts().contains(found_item)) - { - // this trace can be removed because of cycle with conduction area - board.remove_item(this); - return result; - } - } - } - if (own_trace_split) - { - break; - } - } - if (!own_trace_split) - { - result.add(this); - } - if (result.size() > 1) - { - for (Item curr_item : result) - { - board.additional_update_after_change(curr_item); - } - } - return result; - } - - /** - * Checks, if the intersection of the p_line_no-th line of this trace with p_line is inside - * the pad of a pin. In this case the trace will be split only, if the intersection - * is at the center of the pin. - * Extending the function to vias leaded to broken connection problems wenn the autorouter connected to a trace. - */ - private boolean split_inside_drill_pad_prohibited(int p_line_no, Line p_line) - { - if (this.board == null) - { - return false; - } - Point intersection = this.lines.arr[p_line_no].intersection(p_line); - java.util.Collection overlap_items = this.board.pick_items(intersection, this.get_layer(), null); - boolean pad_found = false; - for (Item curr_item : overlap_items) - { - if (!curr_item.shares_net(this)) - { - continue; - } - if (curr_item instanceof Pin) - { - DrillItem curr_drill_item = (DrillItem) curr_item; - if (curr_drill_item.get_center().equals(intersection)) - { - return false; // split always at the center of a drill item. - } - pad_found = true; - } - else if (curr_item instanceof Trace) - { - Trace curr_trace = (Trace) curr_item; - if (curr_trace != this && curr_trace.first_corner().equals(intersection) || curr_trace.last_corner().equals(intersection)) - { - return false; - } - } - } - return pad_found; - } - - /** - * Splits this trace into two at p_point. - * Returns the 2 pieces of the splitted trace, or null if nothing was splitted because for example - * p_point is not located on a line segment of the p_polyline of this trace. - */ - public Trace[] split(Point p_point) - { - for (int i = 0; i < this.lines.arr.length - 2; ++i) - { - LineSegment curr_line_segment = new LineSegment(this.lines, i + 1); - if (curr_line_segment.contains(p_point)) - { - Direction split_line_direction = curr_line_segment.get_line().direction().turn_45_degree(2); - Line split_line = new Line(p_point, split_line_direction); - Trace[] result = split(i + 1, split_line); - if (result != null) - { - return result; - } - } - } - return null; - } - - /** - * Splits this trace at the line with number p_line_no - * into two by inserting p_endline as concluding line of the first split piece - * and as the start line of the second split piece. - * Returns the 2 pieces of the splitted trace, or null, if nothing was splitted. - */ - private PolylineTrace[] split(int p_line_no, Line p_new_end_line) - { - if (!this.is_on_the_board()) - { - return null; - } - Polyline[] split_polylines = lines.split(p_line_no, p_new_end_line); - if (split_polylines == null) - { - return null; - } - if (split_polylines.length != 2) - { - System.out.println("PolylineTrace.split: array of length 2 expected for split_polylines"); - return null; - } - if (split_inside_drill_pad_prohibited(p_line_no, p_new_end_line)) - { - return null; - } - board.remove_item(this); - PolylineTrace[] result = new PolylineTrace[2]; - result[0] = board.insert_trace_without_cleaning(split_polylines[0], get_layer(), get_half_width(), - net_no_arr, clearance_class_no(), get_fixed_state()); - result[1] = board.insert_trace_without_cleaning(split_polylines[1], get_layer(), get_half_width(), - net_no_arr, clearance_class_no(), get_fixed_state()); - return result; - } - - /** - * Splits this trace and overlapping traces, and combines this trace. - * Returns true, if something was changed. - * If p_clip_shape != null, splitting is restricted to p_clip_shape. - */ - public boolean normalize(IntOctagon p_clip_shape) - { - boolean observers_activated = false; - BasicBoard routing_board = this.board; - if (this.board != null) - { - // Let the observers know the trace changes. - observers_activated = !routing_board.observers_active(); - if (observers_activated) - { - routing_board.start_notify_observers(); - } - } - Collection split_pieces = this.split(p_clip_shape); - boolean result = (split_pieces.size() != 1); - Iterator it = split_pieces.iterator(); - while (it.hasNext()) - { - PolylineTrace curr_split_trace = it.next(); - if (curr_split_trace.is_on_the_board()) - { - boolean trace_combined = curr_split_trace.combine(); - if (curr_split_trace.corner_count() == 2 && curr_split_trace.first_corner().equals(curr_split_trace.last_corner())) - { - // remove trace with only 1 corner - board.remove_item(curr_split_trace); - result = true; - } - else if (trace_combined) - { - curr_split_trace.normalize(p_clip_shape); - result = true; - } - } - } - if (observers_activated) - { - routing_board.end_notify_observers(); - } - return result; - } - - /** - * Tries to shorten this trace without creating clearance violations - * Returns true, if the trace was changed. - */ - public boolean pull_tight(PullTightAlgo p_pull_tight_algo) - { - if (!this.is_on_the_board()) - { - // This trace may have been deleted in a trace split for example - return false; - } - if (this.is_shove_fixed()) - { - return false; - } - if (!this.nets_normal()) - { - return false; - } - if (p_pull_tight_algo.only_net_no_arr.length > 0 && !this.nets_equal(p_pull_tight_algo.only_net_no_arr)) - { - return false; - } - if (this.net_no_arr.length > 0) - { - if (!this.board.rules.nets.get(this.net_no_arr[0]).get_class().get_pull_tight()) - { - return false; - } - } - Polyline new_lines = - p_pull_tight_algo.pull_tight(lines, get_layer(), get_half_width(), net_no_arr, clearance_class_no(), - this.touching_pins_at_end_corners()); - if (new_lines != lines) - { - change(new_lines); - return true; - } - AngleRestriction angle_restriction = this.board.rules.get_trace_angle_restriction(); - if (angle_restriction != AngleRestriction.NINETY_DEGREE && this.board.rules.get_pin_edge_to_turn_dist() > 0) - { - if (this.swap_connection_to_pin(true)) - { - pull_tight(p_pull_tight_algo); - return true; - } - if (this.swap_connection_to_pin(false)) - { - pull_tight(p_pull_tight_algo); - return true; - } - // optimize algorithm could not improve the trace, try to remove acid traps - if (this.correct_connection_to_pin(true, angle_restriction)) - { - pull_tight(p_pull_tight_algo); - return true; - } - if (this.correct_connection_to_pin(false, angle_restriction)) - { - pull_tight(p_pull_tight_algo); - return true; - } - } - return false; - } - - /** - * Tries to pull this trace tight without creating clearance violations - * Returns true, if the trace was changed. - */ - public boolean pull_tight(boolean p_own_net_only, int p_pull_tight_accuracy, Stoppable p_stoppable_thread) - { - if (!(this.board instanceof RoutingBoard)) - { - return false; - } - int[] opt_net_no_arr; - if (p_own_net_only) - { - opt_net_no_arr = this.net_no_arr; - } - else - { - opt_net_no_arr = new int[0]; - } - PullTightAlgo pull_tight_algo = - PullTightAlgo.get_instance((RoutingBoard) this.board, opt_net_no_arr, - null, p_pull_tight_accuracy, p_stoppable_thread, -1, null, -1); - return pull_tight(pull_tight_algo); - } - - /** - * Tries to smoothen the end corners of this trace, which are at a fork with other traces. - */ - public boolean smoothen_end_corners_fork(boolean p_own_net_only, int p_pull_tight_accuracy, Stoppable p_stoppable_thread) - { - if (!(this.board instanceof RoutingBoard)) - { - return false; - } - int[] opt_net_no_arr; - if (p_own_net_only) - { - opt_net_no_arr = this.net_no_arr; - } - else - { - opt_net_no_arr = new int[0]; - } - PullTightAlgo pull_tight_algo = - PullTightAlgo.get_instance((RoutingBoard) this.board, opt_net_no_arr, - null, p_pull_tight_accuracy, p_stoppable_thread, -1, null, -1); - return pull_tight_algo.smoothen_end_corners_at_trace(this); - } - - public TileShape get_trace_connection_shape(ShapeSearchTree p_search_tree, int p_index) - { - if (p_index < 0 || p_index >= this.tile_shape_count()) - { - System.out.println("PolylineTrace.get_trace_connection_shape p_index out of range"); - return null; - } - LineSegment curr_line_segment = new LineSegment(this.lines, p_index + 1); - TileShape result = curr_line_segment.to_simplex().simplify(); - return result; - } - - public boolean write(java.io.ObjectOutputStream p_stream) - { - try - { - p_stream.writeObject(this); - } catch (java.io.IOException e) - { - return false; - } - return true; - } - - /** - * changes the geometry of this trace to p_new_polyline - */ - void change(Polyline p_new_polyline) - { - if (!this.is_on_the_board()) - { - // Just change the polyline of this trace. - lines = p_new_polyline; - return; - } - - board.additional_update_after_change(this); - - // The precalculated tile shapes must not be cleared here here because they are used and modified - // in ShapeSearchTree.change_entries. - - board.item_list.save_for_undo(this); - - // for performance reasons there is some effort to reuse - // ShapeTree entries of the old trace in the changed trace - - // look for the first line in p_new_polyline different from - // the lines of the existung trace - int last_index = Math.min(p_new_polyline.arr.length, lines.arr.length); - int index_of_first_different_line = last_index; - for (int i = 0; i < last_index; ++i) - { - if (p_new_polyline.arr[i] != lines.arr[i]) - { - index_of_first_different_line = i; - break; - } - } - if (index_of_first_different_line == last_index) - { - return; // both polylines are equal, no change nessesary - } - // look for the last line in p_new_polyline different from - // the lines of the existung trace - int index_of_last_different_line = -1; - for (int i = 1; i <= last_index; ++i) - { - if (p_new_polyline.arr[p_new_polyline.arr.length - i] != - lines.arr[lines.arr.length - i]) - { - index_of_last_different_line = p_new_polyline.arr.length - i; - break; - } - } - if (index_of_last_different_line < 0) - { - return; // both polylines are equal, no change nessesary - } - int keep_at_start_count = Math.max(index_of_first_different_line - 2, 0); - int keep_at_end_count = Math.max(p_new_polyline.arr.length - index_of_last_different_line - 3, 0); - board.search_tree_manager.change_entries(this, p_new_polyline, keep_at_start_count, keep_at_end_count); - lines = p_new_polyline; - - // let the observers syncronize the changes - board.communication.observers.notify_changed(this); - - IntOctagon clip_shape = null; - if (board instanceof RoutingBoard) - { - ChangedArea changed_area = ((RoutingBoard) board).changed_area; - if (changed_area != null) - { - clip_shape = changed_area.get_area(this.get_layer()); - } - } - this.normalize(clip_shape); - } - - /** - * checks, that the connection restrictions to the contact pins - * are satisfied. If p_at_start, the start of this trace is checked, - * else the end. Returns false, if a pin is at that end, where - * the connection is checked and the connection is not ok. - */ - public boolean check_connection_to_pin(boolean p_at_start) - { - if (this.board == null) - { - return true; - } - if (this.corner_count() < 2) - { - return true; - } - Collection contact_list; - if (p_at_start) - { - contact_list = this.get_start_contacts(); - } - else - { - contact_list = this.get_end_contacts(); - } - Pin contact_pin = null; - for (Item curr_contact : contact_list) - { - if (curr_contact instanceof Pin) - { - contact_pin = (Pin) curr_contact; - break; - } - } - if (contact_pin == null) - { - return true; - } - Collection trace_exit_restrictions = contact_pin.get_trace_exit_restrictions(this.get_layer()); - if (trace_exit_restrictions.isEmpty()) - { - return true; - } - Point end_corner; - Point prev_end_corner; - if (p_at_start) - { - end_corner = this.first_corner(); - prev_end_corner = this.lines.corner(1); - } - else - { - end_corner = this.last_corner(); - prev_end_corner = this.lines.corner(this.lines.corner_count() - 2); - } - Direction trace_end_direction = Direction.get_instance(end_corner, prev_end_corner); - if (trace_end_direction == null) - { - return true; - } - Pin.TraceExitRestriction matching_exit_restriction = null; - for (Pin.TraceExitRestriction curr_exit_restriction : trace_exit_restrictions) - { - if (curr_exit_restriction.direction.equals(trace_end_direction)) - { - matching_exit_restriction = curr_exit_restriction; - break; - } - } - if (matching_exit_restriction == null) - { - return false; - } - final double edge_to_turn_dist = this.board.rules.get_pin_edge_to_turn_dist(); - if (edge_to_turn_dist < 0) - { - return false; - } - double end_line_length = end_corner.to_float().distance(prev_end_corner.to_float()); - double curr_clearance = board.clearance_value(this.clearance_class_no(), contact_pin.clearance_class_no(), this.get_layer()); - double add_width = Math.max(edge_to_turn_dist, curr_clearance + 1); - double preserve_length = matching_exit_restriction.min_length + this.get_half_width() + add_width; - if (preserve_length > end_line_length) - { - return false; - } - return true; - } - - /** - * Tries to correct a connection restriction of this trace. - * If p_at_start, the start of the trace polygon is corrected, else the end. - *Returns true, if this trace was changed. - */ - public boolean correct_connection_to_pin(boolean p_at_start, AngleRestriction p_angle_restriction) - { - if (this.check_connection_to_pin(p_at_start)) - { - return false; - } - - Polyline trace_polyline; - Collection contact_list; - if (p_at_start) - { - trace_polyline = this.polyline(); - contact_list = this.get_start_contacts(); - } - else - { - trace_polyline = this.polyline().reverse(); - contact_list = this.get_end_contacts(); - } - Pin contact_pin = null; - for (Item curr_contact : contact_list) - { - if (curr_contact instanceof Pin) - { - contact_pin = (Pin) curr_contact; - break; - } - } - if (contact_pin == null) - { - return false; - } - Collection trace_exit_restrictions = contact_pin.get_trace_exit_restrictions(this.get_layer()); - if (trace_exit_restrictions.isEmpty()) - { - return false; - } - Shape pin_shape = contact_pin.get_shape(this.get_layer() - contact_pin.first_layer()); - if (!(pin_shape instanceof TileShape)) - { - return false; - } - Point pin_center = contact_pin.get_center(); - - final double edge_to_turn_dist = this.board.rules.get_pin_edge_to_turn_dist(); - if (edge_to_turn_dist < 0) - { - return false; - } - double curr_clearance = board.clearance_value(this.clearance_class_no(), contact_pin.clearance_class_no(), this.get_layer()); - double add_width = Math.max(edge_to_turn_dist, curr_clearance + 1); - TileShape offset_pin_shape = (TileShape) ((TileShape) pin_shape).offset(this.get_half_width() + add_width); - if (p_angle_restriction == AngleRestriction.NINETY_DEGREE || offset_pin_shape.is_IntBox()) - { - offset_pin_shape = offset_pin_shape.bounding_box(); - } - else if (p_angle_restriction == AngleRestriction.FORTYFIVE_DEGREE) - { - offset_pin_shape = offset_pin_shape.bounding_octagon(); - } - int[][] entries = offset_pin_shape.entrance_points(trace_polyline); - if (entries.length == 0) - { - return false; - } - int[] latest_entry_tuple = entries[entries.length - 1]; - FloatPoint trace_entry_location_approx = - trace_polyline.arr[latest_entry_tuple[0]].intersection_approx(offset_pin_shape.border_line(latest_entry_tuple[1])); - // calculate the nearest legal pin exit point to trace_entry_location_approx - double min_exit_corner_distance = Double.MAX_VALUE; - Line nearest_pin_exit_ray = null; - int nearest_border_line_no = -1; - Direction pin_exit_direction = null; - FloatPoint nearest_exit_corner = null; - final double TOLERANCE = 1; - for (Pin.TraceExitRestriction curr_exit_restriction : trace_exit_restrictions) - { - int curr_intersecting_border_line_no = offset_pin_shape.intersecting_border_line_no(pin_center, curr_exit_restriction.direction); - Line curr_pin_exit_ray = new Line(pin_center, curr_exit_restriction.direction); - FloatPoint curr_exit_corner = curr_pin_exit_ray.intersection_approx(offset_pin_shape.border_line(curr_intersecting_border_line_no)); - double curr_exit_corner_distance = curr_exit_corner.distance_square(trace_entry_location_approx); - boolean new_nearest_corner_found = false; - if (curr_exit_corner_distance + TOLERANCE < min_exit_corner_distance) - { - new_nearest_corner_found = true; - } - else if (curr_exit_corner_distance < min_exit_corner_distance + TOLERANCE) - { - // the distances are near equal, compare to the previous corners of p_trace_polyline - for (int i = 1; i < trace_polyline.corner_count(); ++i) - { - FloatPoint curr_trace_corner = trace_polyline.corner_approx(i); - double curr_trace_corner_distance = curr_trace_corner.distance_square(curr_exit_corner); - double old_trace_corner_distance = curr_trace_corner.distance_square(nearest_exit_corner); - if (curr_trace_corner_distance + TOLERANCE < old_trace_corner_distance) - { - new_nearest_corner_found = true; - break; - } - else if (curr_trace_corner_distance > old_trace_corner_distance + TOLERANCE) - { - break; - } - } - } - if (new_nearest_corner_found) - { - min_exit_corner_distance = curr_exit_corner_distance; - nearest_pin_exit_ray = curr_pin_exit_ray; - nearest_border_line_no = curr_intersecting_border_line_no; - pin_exit_direction = curr_exit_restriction.direction; - nearest_exit_corner = curr_exit_corner; - } - } - - // append the polygon piece around the border of the pin shape. - - Line[] curr_lines; - - int corner_count = offset_pin_shape.border_line_count(); - int clock_wise_side_diff = - (nearest_border_line_no - latest_entry_tuple[1] + corner_count) % corner_count; - int counter_clock_wise_side_diff = - (latest_entry_tuple[1] - nearest_border_line_no + corner_count) % corner_count; - int curr_border_line_no = nearest_border_line_no; - if (counter_clock_wise_side_diff <= clock_wise_side_diff) - { - curr_lines = new Line[counter_clock_wise_side_diff + 3]; - for (int i = 0; i <= counter_clock_wise_side_diff; ++i) - { - curr_lines[i + 1] = offset_pin_shape.border_line(curr_border_line_no); - curr_border_line_no = (curr_border_line_no + 1) % corner_count; - } - } - else - { - curr_lines = new Line[clock_wise_side_diff + 3]; - for (int i = 0; i <= clock_wise_side_diff; ++i) - { - curr_lines[i + 1] = offset_pin_shape.border_line(curr_border_line_no); - curr_border_line_no = (curr_border_line_no - 1 + corner_count) % corner_count; - } - } - curr_lines[0] = nearest_pin_exit_ray; - curr_lines[curr_lines.length - 1] = trace_polyline.arr[latest_entry_tuple[0]]; - - Polyline border_polyline = new Polyline(curr_lines); - if (!this.board.check_polyline_trace(border_polyline, this.get_layer(), - this.get_half_width(), this.net_no_arr, this.clearance_class_no())) - { - return false; - } - - Line[] cut_lines = new Line[trace_polyline.arr.length - latest_entry_tuple[0] + 1]; - cut_lines[0] = curr_lines[curr_lines.length - 2]; - for (int i = 1; i < cut_lines.length; ++i) - { - cut_lines[i] = trace_polyline.arr[latest_entry_tuple[0] + i - 1]; - - } - Polyline cut_polyline = new Polyline(cut_lines); - Polyline changed_polyline; - if (cut_polyline.first_corner().equals(cut_polyline.last_corner())) - { - changed_polyline = border_polyline; - } - else - { - changed_polyline = border_polyline.combine(cut_polyline); - } - if (!p_at_start) - { - changed_polyline = changed_polyline.reverse(); - } - this.change(changed_polyline); - - - // create an shove_fixed exit line. - curr_lines = new Line[3]; - curr_lines[0] = new Line(pin_center, pin_exit_direction.turn_45_degree(2)); - curr_lines[1] = nearest_pin_exit_ray; - curr_lines[2] = offset_pin_shape.border_line(nearest_border_line_no); - Polyline exit_line_segment = new Polyline(curr_lines); - this.board.insert_trace(exit_line_segment, this.get_layer(), this.get_half_width(), this.net_no_arr, - this.clearance_class_no(), FixedState.SHOVE_FIXED); - return true; - } - - /** - * Looks, if an other pin connection restriction fits better than the current connection restriction - * and changes this trace in this case. - * If p_at_start, the start of the trace polygon is changed, else the end. - * Returns true, if this trace was changed. - */ - public boolean swap_connection_to_pin(boolean p_at_start) - { - Polyline trace_polyline; - Collection contact_list; - if (p_at_start) - { - trace_polyline = this.polyline(); - contact_list = this.get_start_contacts(); - } - else - { - trace_polyline = this.polyline().reverse(); - contact_list = this.get_end_contacts(); - } - if (contact_list.size() != 1) - { - return false; - } - Item curr_contact = contact_list.iterator().next(); - if (!(curr_contact.get_fixed_state() == FixedState.SHOVE_FIXED && (curr_contact instanceof PolylineTrace))) - { - return false; - } - PolylineTrace contact_trace = (PolylineTrace) curr_contact; - Polyline contact_polyline = contact_trace.polyline(); - Line contact_last_line = contact_polyline.arr[contact_polyline.arr.length - 2]; - // look, if this trace has a sharp angle with the contact trace. - Line first_line = trace_polyline.arr[1]; - // check for sharp angle - boolean check_swap = contact_last_line.direction().projection(first_line.direction()) == Signum.NEGATIVE; - if (!check_swap) - { - double half_width = this.get_half_width(); - if (trace_polyline.arr.length > 3 && - trace_polyline.corner_approx(0).distance_square(trace_polyline.corner_approx(1)) <= half_width * half_width) - { - // check also for sharp angle with the second line - check_swap = - (contact_last_line.direction().projection(trace_polyline.arr[2].direction()) == Signum.NEGATIVE); - } - } - if (!check_swap) - { - return false; - } - Pin contact_pin = null; - Collection curr_contacts = contact_trace.get_start_contacts(); - for (Item tmp_contact : curr_contacts) - { - if (tmp_contact instanceof Pin) - { - contact_pin = (Pin) tmp_contact; - break; - } - } - if (contact_pin == null) - { - return false; - } - Polyline combined_polyline = contact_polyline.combine(trace_polyline); - Direction nearest_pin_exit_direction = - contact_pin.calc_nearest_exit_restriction_direction(combined_polyline, this.get_half_width(), this.get_layer()); - if (nearest_pin_exit_direction == null || nearest_pin_exit_direction.equals(contact_polyline.arr[1].direction())) - { - return false; // direction would not be changed - } - contact_trace.set_fixed_state(this.get_fixed_state()); - this.combine(); - return true; - } - // primary data - private Polyline lines; -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + */ +package board; + +import datastructures.Signum; +import datastructures.Stoppable; + +import geometry.planar.IntBox; +import geometry.planar.IntOctagon; +import geometry.planar.Line; +import geometry.planar.LineSegment; +import geometry.planar.Point; +import geometry.planar.IntPoint; +import geometry.planar.FloatPoint; +import geometry.planar.Polyline; +import geometry.planar.Shape; +import geometry.planar.TileShape; +import geometry.planar.Direction; +import geometry.planar.Vector; + +import java.awt.Color; +import java.awt.Graphics; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; + +import boardgraphics.GraphicsContext; + +/** + * + * Objects of class Trace, whose geometry is described by a Polyline + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class PolylineTrace extends Trace implements java.io.Serializable +{ + + /** + * creates a new instance of a PolylineTrace with the input data + * + * @param p_polyline a {@link geometry.planar.Polyline} object. + * @param p_layer a int. + * @param p_half_width a int. + * @param p_net_no_arr an array of int. + * @param p_clearance_type a int. + * @param p_id_no a int. + * @param p_group_no a int. + * @param p_fixed_state a {@link board.FixedState} object. + * @param p_board a {@link board.BasicBoard} object. + */ + public PolylineTrace(Polyline p_polyline, int p_layer, int p_half_width, + int[] p_net_no_arr, int p_clearance_type, int p_id_no, + int p_group_no, FixedState p_fixed_state, BasicBoard p_board) + { + super(p_layer, p_half_width, p_net_no_arr, p_clearance_type, + p_id_no, p_group_no, p_fixed_state, p_board); + if (p_polyline.arr.length < 3) + { + System.out.println("PolylineTrace: p_polyline.arr.length >= 3 expected"); + } + lines = p_polyline; + } + + /** {@inheritDoc} */ + public Item copy(int p_id_no) + { + int[] curr_net_no_arr = new int[this.net_count()]; + for (int i = 0; i < curr_net_no_arr.length; ++i) + { + curr_net_no_arr[i] = get_net_no(i); + } + return new PolylineTrace(lines, get_layer(), get_half_width(), curr_net_no_arr, clearance_class_no(), + p_id_no, get_component_no(), get_fixed_state(), board); + } + + /** + * {@inheritDoc} + * + * checks, if this trace is on layer p_layer + */ + public boolean is_on_layer(int p_layer) + { + return get_layer() == p_layer; + } + + /** + * returns the first corner of this trace, which is the intersection + * of the first and second lines of its polyline + * + * @return a {@link geometry.planar.Point} object. + */ + public Point first_corner() + { + return lines.corner(0); + } + + /** + * returns the last corner of this trace, which is the intersection + * of the last two lines of its polyline + * + * @return a {@link geometry.planar.Point} object. + */ + public Point last_corner() + { + return lines.corner(lines.arr.length - 2); + } + + /** + * returns the number of corners of this trace, which is the + * number of lines of its polyline minus one + * + * @return a int. + */ + public int corner_count() + { + return lines.arr.length - 1; + } + + /** + *

get_length.

+ * + * @return a double. + */ + public double get_length() + { + return lines.length_approx(); + } + + /** + *

bounding_box.

+ * + * @return a {@link geometry.planar.IntBox} object. + */ + public IntBox bounding_box() + { + IntBox result = this.lines.bounding_box(); + return result.offset(this.get_half_width()); + } + + /** {@inheritDoc} */ + public void draw(Graphics p_g, GraphicsContext p_graphics_context, Color[] p_color_arr, double p_intensity) + { + if (p_graphics_context == null) + { + return; + } + int layer = this.get_layer(); + Color color = p_color_arr[layer]; + double display_width = get_half_width(); + double intensity = p_intensity * p_graphics_context.get_layer_visibility(layer); + p_graphics_context.draw(lines.corner_approx_arr(), display_width, color, p_g, intensity); + } + + /** + * Returns the polyline of this trace. + * + * @return a {@link geometry.planar.Polyline} object. + */ + public Polyline polyline() + { + return lines; + } + + /** {@inheritDoc} */ + protected TileShape[] calculate_tree_shapes(ShapeSearchTree p_search_tree) + { + return p_search_tree.calculate_tree_shapes(this); + } + + /** + * returns the count of tile shapes of this polyline + * + * @return a int. + */ + public int tile_shape_count() + { + return Math.max(lines.arr.length - 2, 0); + } + + /** {@inheritDoc} */ + public void translate_by(Vector p_vector) + { + lines = lines.translate_by(p_vector); + this.clear_derived_data(); + } + + /** {@inheritDoc} */ + public void turn_90_degree(int p_factor, IntPoint p_pole) + { + lines = lines.turn_90_degree(p_factor, p_pole); + this.clear_derived_data(); + } + + /** {@inheritDoc} */ + public void rotate_approx(double p_angle_in_degree, FloatPoint p_pole) + { + this.lines = this.lines.rotate_approx(Math.toRadians(p_angle_in_degree), p_pole); + } + + /** {@inheritDoc} */ + public void change_placement_side(IntPoint p_pole) + { + lines = lines.mirror_vertical(p_pole); + + if (this.board != null) + { + this.set_layer(board.get_layer_count() - this.get_layer() - 1); + } + this.clear_derived_data(); + } + + /** + * Looks, if other traces can be combined with this trace. + * Returns true, if somthing has been combined. + * This trace will be the combined trace, so that only other traces may be deleted. + * + * @return a boolean. + */ + public boolean combine() + { + if (!this.is_on_the_board()) + { + return false; + } + boolean something_changed; + if (this.combine_at_start(true)) + { + something_changed = true; + this.combine(); + } + else if (this.combine_at_end(true)) + { + something_changed = true; + this.combine(); + } + else + { + something_changed = false; + } + if (something_changed) + { + // let the observers syncronize the changes + board.communication.observers.notify_changed(this); + board.additional_update_after_change(this); + } + return something_changed; + } + + /** + * looks, if this trace can be combined at its first point with + * an other trace. Returns true, if somthing was combined. + * The corners of the other trace will be inserted in front of thie trace. + * In case of combine the other trace will be deleted and this trace will + * remain. + */ + private boolean combine_at_start(boolean p_ignore_areas) + { + Point start_corner = first_corner(); + Collection contacts = get_normal_contacts(start_corner, false); + if (p_ignore_areas) + { + // remove conduction areas from the list + Iterator it = contacts.iterator(); + while (it.hasNext()) + { + if (it.next() instanceof ConductionArea) + { + it.remove(); + } + } + } + if (contacts.size() != 1) + { + return false; + } + PolylineTrace other_trace = null; + boolean trace_found = false; + boolean reverse_order = false; + Iterator it = contacts.iterator(); + while (it.hasNext()) + { + Item curr_ob = it.next(); + if (curr_ob instanceof PolylineTrace) + { + other_trace = (PolylineTrace) curr_ob; + if (other_trace.get_layer() == get_layer() && other_trace.nets_equal(this) && other_trace.get_half_width() == get_half_width() && other_trace.get_fixed_state() == this.get_fixed_state()) + { + if (start_corner.equals(other_trace.last_corner())) + { + trace_found = true; + break; + } + else if (start_corner.equals(other_trace.first_corner())) + { + reverse_order = true; + trace_found = true; + break; + } + } + } + } + if (!trace_found) + { + return false; + } + + board.item_list.save_for_undo(this); + // create the lines of the joined polyline + Line[] this_lines = lines.arr; + Line[] other_lines; + if (reverse_order) + { + other_lines = new Line[other_trace.lines.arr.length]; + for (int i = 0; i < other_lines.length; ++i) + { + other_lines[i] = other_trace.lines.arr[other_lines.length - 1 - i].opposite(); + } + } + else + { + other_lines = other_trace.lines.arr; + } + boolean skip_line = + other_lines[other_lines.length - 2].is_equal_or_opposite(this_lines[1]); + int new_line_count = this_lines.length + other_lines.length - 2; + if (skip_line) + { + --new_line_count; + } + Line[] new_lines = new Line[new_line_count]; + System.arraycopy(other_lines, 0, new_lines, 0, other_lines.length - 1); + int join_pos = other_lines.length - 1; + if (skip_line) + { + --join_pos; + } + System.arraycopy(this_lines, 1, new_lines, join_pos, this_lines.length - 1); + Polyline joined_polyline = new Polyline(new_lines); + if (joined_polyline.arr.length != new_line_count) + { + // consecutive parallel lines where skipped at the join location + // combine without performance optimation + board.search_tree_manager.remove(this); + this.lines = joined_polyline; + this.clear_derived_data(); + board.search_tree_manager.insert(this); + } + else + { + // reuse the tree entries for better performance + // create the changed line shape at the join location + int to_no = other_lines.length; + if (skip_line) + { + --to_no; + } + board.search_tree_manager.merge_entries_in_front(other_trace, this, joined_polyline, + other_lines.length - 3, to_no); + other_trace.clear_search_tree_entries(); + this.lines = joined_polyline; + } + if (this.lines.arr.length < 3) + { + board.remove_item(this); + } + board.remove_item(other_trace); + if (board instanceof RoutingBoard) + { + ((RoutingBoard) board).join_changed_area(start_corner.to_float(), get_layer()); + } + return true; + } + + /** + * looks, if this trace can be combined at its last point with + * another trace. Returns true, if somthing was combined. + * The corners of the other trace will be inserted at the end of thie trace. + * In case of combine the other trace will be deleted and this trace will + * remain. + */ + private boolean combine_at_end(boolean p_ignore_areas) + { + Point end_corner = last_corner(); + Collection contacts = get_normal_contacts(end_corner, false); + if (p_ignore_areas) + { + // remove conduction areas from the list + Iterator it = contacts.iterator(); + while (it.hasNext()) + { + if (it.next() instanceof ConductionArea) + { + it.remove(); + } + } + } + if (contacts.size() != 1) + { + return false; + } + PolylineTrace other_trace = null; + boolean trace_found = false; + boolean reverse_order = false; + Iterator it = contacts.iterator(); + while (it.hasNext()) + { + Item curr_ob = it.next(); + if (curr_ob instanceof PolylineTrace) + { + other_trace = (PolylineTrace) curr_ob; + if (other_trace.get_layer() == get_layer() && other_trace.nets_equal(this) && other_trace.get_half_width() == get_half_width() && other_trace.get_fixed_state() == this.get_fixed_state()) + { + if (end_corner.equals(other_trace.first_corner())) + { + trace_found = true; + break; + } + else if (end_corner.equals(other_trace.last_corner())) + { + reverse_order = true; + trace_found = true; + break; + } + } + } + } + if (!trace_found) + { + return false; + } + + board.item_list.save_for_undo(this); + // create the lines of the joined polyline + Line[] this_lines = lines.arr; + Line[] other_lines; + if (reverse_order) + { + other_lines = new Line[other_trace.lines.arr.length]; + for (int i = 0; i < other_lines.length; ++i) + { + other_lines[i] = other_trace.lines.arr[other_lines.length - 1 - i].opposite(); + } + } + else + { + other_lines = other_trace.lines.arr; + } + boolean skip_line = + this_lines[this_lines.length - 2].is_equal_or_opposite(other_lines[1]); + int new_line_count = this_lines.length + other_lines.length - 2; + if (skip_line) + { + --new_line_count; + } + Line[] new_lines = new Line[new_line_count]; + System.arraycopy(this_lines, 0, new_lines, 0, this_lines.length - 1); + int join_pos = this_lines.length - 1; + if (skip_line) + { + --join_pos; + } + System.arraycopy(other_lines, 1, new_lines, join_pos, other_lines.length - 1); + Polyline joined_polyline = new Polyline(new_lines); + if (joined_polyline.arr.length != new_line_count) + { + // consecutive parallel lines where skipped at the join location + // combine without performance optimation + board.search_tree_manager.remove(this); + this.clear_search_tree_entries(); + this.lines = joined_polyline; + this.clear_derived_data(); + board.search_tree_manager.insert(this); + } + else + { + // reuse tree entries for better performance + // create the changed line shape at the join location + int to_no = this_lines.length; + if (skip_line) + { + --to_no; + } + board.search_tree_manager.merge_entries_at_end(other_trace, this, joined_polyline, this_lines.length - 3, to_no); + other_trace.clear_search_tree_entries(); + this.lines = joined_polyline; + } + if (this.lines.arr.length < 3) + { + board.remove_item(this); + } + board.remove_item(other_trace); + if (board instanceof RoutingBoard) + { + ((RoutingBoard) board).join_changed_area(end_corner.to_float(), get_layer()); + } + return true; + } + + /** + * {@inheritDoc} + * + * Looks up traces intersecting with this trace and splits them at the intersection points. + * In case of an overlaps, the traces are split at their first and their last common point. + * Returns the pieces resulting from splitting. + * Found cycles are removed. + * If nothing is split, the result will contain just this Trace. + * If p_clip_shape != null, the split may be resticted to p_clip_shape. + */ + public Collection split(IntOctagon p_clip_shape) + { + Collection result = new LinkedList(); + if (!this.nets_normal()) + { + // only normal nets are split + result.add(this); + return result; + } + boolean own_trace_split = false; + ShapeSearchTree default_tree = board.search_tree_manager.get_default_tree(); + for (int i = 0; i < this.lines.arr.length - 2; ++i) + { + if (p_clip_shape != null) + { + LineSegment curr_segment = new LineSegment(this.lines, i + 1); + if (!p_clip_shape.intersects(curr_segment.bounding_box())) + { + continue; + } + } + TileShape curr_shape = this.get_tree_shape(default_tree, i); + LineSegment curr_line_segment = new LineSegment(this.lines, i + 1); + Collection overlapping_tree_entries = new LinkedList(); + // look for intersecting traces with the i-th line segment + default_tree.overlapping_tree_entries(curr_shape, get_layer(), overlapping_tree_entries); + Iterator it = overlapping_tree_entries.iterator(); + while (it.hasNext()) + { + if (!this.is_on_the_board()) + { + // this trace has been deleted in a cleanup operation + return result; + } + ShapeSearchTree.TreeEntry found_entry = it.next(); + if (!(found_entry.object instanceof Item)) + { + continue; + } + Item found_item = (Item) found_entry.object; + if (found_item == this) + { + + if (found_entry.shape_index_in_object >= i - 1 && found_entry.shape_index_in_object <= i + 1) + { + // don't split own trace at this line or at neighbour lines + continue; + } + // try to handle intermediate segments of length 0 by comparing end corners + if (i < found_entry.shape_index_in_object) + { + if (lines.corner(i + 1).equals(lines.corner(found_entry.shape_index_in_object))) + { + continue; + } + } + else if (found_entry.shape_index_in_object < i) + { + if (lines.corner(found_entry.shape_index_in_object + 1).equals(lines.corner(i))) + { + continue; + } + } + } + if (!found_item.shares_net(this)) + { + continue; + } + if (found_item instanceof PolylineTrace) + { + PolylineTrace found_trace = (PolylineTrace) found_item; + LineSegment found_line_segment = + new LineSegment(found_trace.lines, found_entry.shape_index_in_object + 1); + Line[] intersecting_lines = found_line_segment.intersection(curr_line_segment); + Collection split_pieces = new LinkedList(); + + // try splitting the found trace first + boolean found_trace_split = false; + + if (found_trace != this) + { + for (int j = 0; j < intersecting_lines.length; ++j) + { + int line_no = found_entry.shape_index_in_object + 1; + PolylineTrace[] curr_split_pieces = found_trace.split(line_no, intersecting_lines[j]); + if (curr_split_pieces != null) + { + + for (int k = 0; k < 2; ++k) + { + if (curr_split_pieces[k] != null) + { + found_trace_split = true; + split_pieces.add(curr_split_pieces[k]); + + } + } + if (found_trace_split) + { + // reread the overlapping tree entries and reset the iterator, + // because the board has changed + default_tree.overlapping_tree_entries(curr_shape, get_layer(), overlapping_tree_entries); + it = overlapping_tree_entries.iterator(); + break; + } + } + } + if (!found_trace_split) + { + split_pieces.add(found_trace); + } + } + // now try splitting the own trace + + intersecting_lines = curr_line_segment.intersection(found_line_segment); + for (int j = 0; j < intersecting_lines.length; ++j) + { + PolylineTrace[] curr_split_pieces = split(i + 1, intersecting_lines[j]); + if (curr_split_pieces != null) + { + own_trace_split = true; + // this trace was split itself into 2. + if (curr_split_pieces[0] != null) + { + result.addAll(curr_split_pieces[0].split(p_clip_shape)); + } + if (curr_split_pieces[1] != null) + { + result.addAll(curr_split_pieces[1].split(p_clip_shape)); + } + break; + } + } + if (found_trace_split || own_trace_split) + { + // something was split, + // remove cycles containing a split piece + Iterator it2 = split_pieces.iterator(); + for (int j = 0; j < 2; ++j) + { + while (it2.hasNext()) + { + PolylineTrace curr_piece = it2.next(); + board.remove_if_cycle(curr_piece); + } + + // remove cycles in the own split pieces last + // to preserve them, if possible + it2 = result.iterator(); + } + } + if (own_trace_split) + { + break; + } + } + else if (found_item instanceof DrillItem) + { + DrillItem curr_drill_item = (DrillItem) found_item; + Point split_point = curr_drill_item.get_center(); + if (curr_line_segment.contains(split_point)) + { + Direction split_line_direction = curr_line_segment.get_line().direction().turn_45_degree(2); + Line split_line = new Line(split_point, split_line_direction); + split(i + 1, split_line); + } + } + else if (!this.is_user_fixed() && (found_item instanceof ConductionArea)) + { + boolean ignore_areas = false; + if (this.net_no_arr.length > 0) + { + rules.Net curr_net = this.board.rules.nets.get(this.net_no_arr[0]); + if (curr_net != null && curr_net.get_class() != null) + { + ignore_areas = curr_net.get_class().get_ignore_cycles_with_areas(); + } + } + if (!ignore_areas && this.get_start_contacts().contains(found_item) && + this.get_end_contacts().contains(found_item)) + { + // this trace can be removed because of cycle with conduction area + board.remove_item(this); + return result; + } + } + } + if (own_trace_split) + { + break; + } + } + if (!own_trace_split) + { + result.add(this); + } + if (result.size() > 1) + { + for (Item curr_item : result) + { + board.additional_update_after_change(curr_item); + } + } + return result; + } + + /** + * Checks, if the intersection of the p_line_no-th line of this trace with p_line is inside + * the pad of a pin. In this case the trace will be split only, if the intersection + * is at the center of the pin. + * Extending the function to vias leaded to broken connection problems wenn the autorouter connected to a trace. + */ + private boolean split_inside_drill_pad_prohibited(int p_line_no, Line p_line) + { + if (this.board == null) + { + return false; + } + Point intersection = this.lines.arr[p_line_no].intersection(p_line); + java.util.Collection overlap_items = this.board.pick_items(intersection, this.get_layer(), null); + boolean pad_found = false; + for (Item curr_item : overlap_items) + { + if (!curr_item.shares_net(this)) + { + continue; + } + if (curr_item instanceof Pin) + { + DrillItem curr_drill_item = (DrillItem) curr_item; + if (curr_drill_item.get_center().equals(intersection)) + { + return false; // split always at the center of a drill item. + } + pad_found = true; + } + else if (curr_item instanceof Trace) + { + Trace curr_trace = (Trace) curr_item; + if (curr_trace != this && curr_trace.first_corner().equals(intersection) || curr_trace.last_corner().equals(intersection)) + { + return false; + } + } + } + return pad_found; + } + + /** + * Splits this trace into two at p_point. + * Returns the 2 pieces of the splitted trace, or null if nothing was splitted because for example + * p_point is not located on a line segment of the p_polyline of this trace. + * + * @param p_point a {@link geometry.planar.Point} object. + * @return an array of {@link board.Trace} objects. + */ + public Trace[] split(Point p_point) + { + for (int i = 0; i < this.lines.arr.length - 2; ++i) + { + LineSegment curr_line_segment = new LineSegment(this.lines, i + 1); + if (curr_line_segment.contains(p_point)) + { + Direction split_line_direction = curr_line_segment.get_line().direction().turn_45_degree(2); + Line split_line = new Line(p_point, split_line_direction); + Trace[] result = split(i + 1, split_line); + if (result != null) + { + return result; + } + } + } + return null; + } + + /** + * Splits this trace at the line with number p_line_no + * into two by inserting p_endline as concluding line of the first split piece + * and as the start line of the second split piece. + * Returns the 2 pieces of the splitted trace, or null, if nothing was splitted. + */ + private PolylineTrace[] split(int p_line_no, Line p_new_end_line) + { + if (!this.is_on_the_board()) + { + return null; + } + Polyline[] split_polylines = lines.split(p_line_no, p_new_end_line); + if (split_polylines == null) + { + return null; + } + if (split_polylines.length != 2) + { + System.out.println("PolylineTrace.split: array of length 2 expected for split_polylines"); + return null; + } + if (split_inside_drill_pad_prohibited(p_line_no, p_new_end_line)) + { + return null; + } + board.remove_item(this); + PolylineTrace[] result = new PolylineTrace[2]; + result[0] = board.insert_trace_without_cleaning(split_polylines[0], get_layer(), get_half_width(), + net_no_arr, clearance_class_no(), get_fixed_state()); + result[1] = board.insert_trace_without_cleaning(split_polylines[1], get_layer(), get_half_width(), + net_no_arr, clearance_class_no(), get_fixed_state()); + return result; + } + + /** + * Splits this trace and overlapping traces, and combines this trace. + * Returns true, if something was changed. + * If p_clip_shape != null, splitting is restricted to p_clip_shape. + * + * @param p_clip_shape a {@link geometry.planar.IntOctagon} object. + * @return a boolean. + */ + public boolean normalize(IntOctagon p_clip_shape) + { + boolean observers_activated = false; + BasicBoard routing_board = this.board; + if (this.board != null) + { + // Let the observers know the trace changes. + observers_activated = !routing_board.observers_active(); + if (observers_activated) + { + routing_board.start_notify_observers(); + } + } + Collection split_pieces = this.split(p_clip_shape); + boolean result = (split_pieces.size() != 1); + Iterator it = split_pieces.iterator(); + while (it.hasNext()) + { + PolylineTrace curr_split_trace = it.next(); + if (curr_split_trace.is_on_the_board()) + { + boolean trace_combined = curr_split_trace.combine(); + if (curr_split_trace.corner_count() == 2 && curr_split_trace.first_corner().equals(curr_split_trace.last_corner())) + { + // remove trace with only 1 corner + board.remove_item(curr_split_trace); + result = true; + } + else if (trace_combined) + { + curr_split_trace.normalize(p_clip_shape); + result = true; + } + } + } + if (observers_activated) + { + routing_board.end_notify_observers(); + } + return result; + } + + /** + * {@inheritDoc} + * + * Tries to shorten this trace without creating clearance violations + * Returns true, if the trace was changed. + */ + public boolean pull_tight(PullTightAlgo p_pull_tight_algo) + { + if (!this.is_on_the_board()) + { + // This trace may have been deleted in a trace split for example + return false; + } + if (this.is_shove_fixed()) + { + return false; + } + if (!this.nets_normal()) + { + return false; + } + if (p_pull_tight_algo.only_net_no_arr.length > 0 && !this.nets_equal(p_pull_tight_algo.only_net_no_arr)) + { + return false; + } + if (this.net_no_arr.length > 0) + { + if (!this.board.rules.nets.get(this.net_no_arr[0]).get_class().get_pull_tight()) + { + return false; + } + } + Polyline new_lines = + p_pull_tight_algo.pull_tight(lines, get_layer(), get_half_width(), net_no_arr, clearance_class_no(), + this.touching_pins_at_end_corners()); + if (new_lines != lines) + { + change(new_lines); + return true; + } + AngleRestriction angle_restriction = this.board.rules.get_trace_angle_restriction(); + if (angle_restriction != AngleRestriction.NINETY_DEGREE && this.board.rules.get_pin_edge_to_turn_dist() > 0) + { + if (this.swap_connection_to_pin(true)) + { + pull_tight(p_pull_tight_algo); + return true; + } + if (this.swap_connection_to_pin(false)) + { + pull_tight(p_pull_tight_algo); + return true; + } + // optimize algorithm could not improve the trace, try to remove acid traps + if (this.correct_connection_to_pin(true, angle_restriction)) + { + pull_tight(p_pull_tight_algo); + return true; + } + if (this.correct_connection_to_pin(false, angle_restriction)) + { + pull_tight(p_pull_tight_algo); + return true; + } + } + return false; + } + + /** + * Tries to pull this trace tight without creating clearance violations + * Returns true, if the trace was changed. + * + * @param p_own_net_only a boolean. + * @param p_pull_tight_accuracy a int. + * @param p_stoppable_thread a {@link datastructures.Stoppable} object. + * @return a boolean. + */ + public boolean pull_tight(boolean p_own_net_only, int p_pull_tight_accuracy, Stoppable p_stoppable_thread) + { + if (!(this.board instanceof RoutingBoard)) + { + return false; + } + int[] opt_net_no_arr; + if (p_own_net_only) + { + opt_net_no_arr = this.net_no_arr; + } + else + { + opt_net_no_arr = new int[0]; + } + PullTightAlgo pull_tight_algo = + PullTightAlgo.get_instance((RoutingBoard) this.board, opt_net_no_arr, + null, p_pull_tight_accuracy, p_stoppable_thread, -1, null, -1); + return pull_tight(pull_tight_algo); + } + + /** + * Tries to smoothen the end corners of this trace, which are at a fork with other traces. + * + * @param p_own_net_only a boolean. + * @param p_pull_tight_accuracy a int. + * @param p_stoppable_thread a {@link datastructures.Stoppable} object. + * @return a boolean. + */ + public boolean smoothen_end_corners_fork(boolean p_own_net_only, int p_pull_tight_accuracy, Stoppable p_stoppable_thread) + { + if (!(this.board instanceof RoutingBoard)) + { + return false; + } + int[] opt_net_no_arr; + if (p_own_net_only) + { + opt_net_no_arr = this.net_no_arr; + } + else + { + opt_net_no_arr = new int[0]; + } + PullTightAlgo pull_tight_algo = + PullTightAlgo.get_instance((RoutingBoard) this.board, opt_net_no_arr, + null, p_pull_tight_accuracy, p_stoppable_thread, -1, null, -1); + return pull_tight_algo.smoothen_end_corners_at_trace(this); + } + + /** {@inheritDoc} */ + public TileShape get_trace_connection_shape(ShapeSearchTree p_search_tree, int p_index) + { + if (p_index < 0 || p_index >= this.tile_shape_count()) + { + System.out.println("PolylineTrace.get_trace_connection_shape p_index out of range"); + return null; + } + LineSegment curr_line_segment = new LineSegment(this.lines, p_index + 1); + TileShape result = curr_line_segment.to_simplex().simplify(); + return result; + } + + /** {@inheritDoc} */ + public boolean write(java.io.ObjectOutputStream p_stream) + { + try + { + p_stream.writeObject(this); + } catch (java.io.IOException e) + { + return false; + } + return true; + } + + /** + * changes the geometry of this trace to p_new_polyline + */ + void change(Polyline p_new_polyline) + { + if (!this.is_on_the_board()) + { + // Just change the polyline of this trace. + lines = p_new_polyline; + return; + } + + board.additional_update_after_change(this); + + // The precalculated tile shapes must not be cleared here here because they are used and modified + // in ShapeSearchTree.change_entries. + + board.item_list.save_for_undo(this); + + // for performance reasons there is some effort to reuse + // ShapeTree entries of the old trace in the changed trace + + // look for the first line in p_new_polyline different from + // the lines of the existung trace + int last_index = Math.min(p_new_polyline.arr.length, lines.arr.length); + int index_of_first_different_line = last_index; + for (int i = 0; i < last_index; ++i) + { + if (p_new_polyline.arr[i] != lines.arr[i]) + { + index_of_first_different_line = i; + break; + } + } + if (index_of_first_different_line == last_index) + { + return; // both polylines are equal, no change nessesary + } + // look for the last line in p_new_polyline different from + // the lines of the existung trace + int index_of_last_different_line = -1; + for (int i = 1; i <= last_index; ++i) + { + if (p_new_polyline.arr[p_new_polyline.arr.length - i] != + lines.arr[lines.arr.length - i]) + { + index_of_last_different_line = p_new_polyline.arr.length - i; + break; + } + } + if (index_of_last_different_line < 0) + { + return; // both polylines are equal, no change nessesary + } + int keep_at_start_count = Math.max(index_of_first_different_line - 2, 0); + int keep_at_end_count = Math.max(p_new_polyline.arr.length - index_of_last_different_line - 3, 0); + board.search_tree_manager.change_entries(this, p_new_polyline, keep_at_start_count, keep_at_end_count); + lines = p_new_polyline; + + // let the observers syncronize the changes + board.communication.observers.notify_changed(this); + + IntOctagon clip_shape = null; + if (board instanceof RoutingBoard) + { + ChangedArea changed_area = ((RoutingBoard) board).changed_area; + if (changed_area != null) + { + clip_shape = changed_area.get_area(this.get_layer()); + } + } + this.normalize(clip_shape); + } + + /** + * {@inheritDoc} + * + * checks, that the connection restrictions to the contact pins + * are satisfied. If p_at_start, the start of this trace is checked, + * else the end. Returns false, if a pin is at that end, where + * the connection is checked and the connection is not ok. + */ + public boolean check_connection_to_pin(boolean p_at_start) + { + if (this.board == null) + { + return true; + } + if (this.corner_count() < 2) + { + return true; + } + Collection contact_list; + if (p_at_start) + { + contact_list = this.get_start_contacts(); + } + else + { + contact_list = this.get_end_contacts(); + } + Pin contact_pin = null; + for (Item curr_contact : contact_list) + { + if (curr_contact instanceof Pin) + { + contact_pin = (Pin) curr_contact; + break; + } + } + if (contact_pin == null) + { + return true; + } + Collection trace_exit_restrictions = contact_pin.get_trace_exit_restrictions(this.get_layer()); + if (trace_exit_restrictions.isEmpty()) + { + return true; + } + Point end_corner; + Point prev_end_corner; + if (p_at_start) + { + end_corner = this.first_corner(); + prev_end_corner = this.lines.corner(1); + } + else + { + end_corner = this.last_corner(); + prev_end_corner = this.lines.corner(this.lines.corner_count() - 2); + } + Direction trace_end_direction = Direction.get_instance(end_corner, prev_end_corner); + if (trace_end_direction == null) + { + return true; + } + Pin.TraceExitRestriction matching_exit_restriction = null; + for (Pin.TraceExitRestriction curr_exit_restriction : trace_exit_restrictions) + { + if (curr_exit_restriction.direction.equals(trace_end_direction)) + { + matching_exit_restriction = curr_exit_restriction; + break; + } + } + if (matching_exit_restriction == null) + { + return false; + } + final double edge_to_turn_dist = this.board.rules.get_pin_edge_to_turn_dist(); + if (edge_to_turn_dist < 0) + { + return false; + } + double end_line_length = end_corner.to_float().distance(prev_end_corner.to_float()); + double curr_clearance = board.clearance_value(this.clearance_class_no(), contact_pin.clearance_class_no(), this.get_layer()); + double add_width = Math.max(edge_to_turn_dist, curr_clearance + 1); + double preserve_length = matching_exit_restriction.min_length + this.get_half_width() + add_width; + if (preserve_length > end_line_length) + { + return false; + } + return true; + } + + /** + * Tries to correct a connection restriction of this trace. + * If p_at_start, the start of the trace polygon is corrected, else the end. + *Returns true, if this trace was changed. + * + * @param p_at_start a boolean. + * @param p_angle_restriction a {@link board.AngleRestriction} object. + * @return a boolean. + */ + public boolean correct_connection_to_pin(boolean p_at_start, AngleRestriction p_angle_restriction) + { + if (this.check_connection_to_pin(p_at_start)) + { + return false; + } + + Polyline trace_polyline; + Collection contact_list; + if (p_at_start) + { + trace_polyline = this.polyline(); + contact_list = this.get_start_contacts(); + } + else + { + trace_polyline = this.polyline().reverse(); + contact_list = this.get_end_contacts(); + } + Pin contact_pin = null; + for (Item curr_contact : contact_list) + { + if (curr_contact instanceof Pin) + { + contact_pin = (Pin) curr_contact; + break; + } + } + if (contact_pin == null) + { + return false; + } + Collection trace_exit_restrictions = contact_pin.get_trace_exit_restrictions(this.get_layer()); + if (trace_exit_restrictions.isEmpty()) + { + return false; + } + Shape pin_shape = contact_pin.get_shape(this.get_layer() - contact_pin.first_layer()); + if (!(pin_shape instanceof TileShape)) + { + return false; + } + Point pin_center = contact_pin.get_center(); + + final double edge_to_turn_dist = this.board.rules.get_pin_edge_to_turn_dist(); + if (edge_to_turn_dist < 0) + { + return false; + } + double curr_clearance = board.clearance_value(this.clearance_class_no(), contact_pin.clearance_class_no(), this.get_layer()); + double add_width = Math.max(edge_to_turn_dist, curr_clearance + 1); + TileShape offset_pin_shape = (TileShape) ((TileShape) pin_shape).offset(this.get_half_width() + add_width); + if (p_angle_restriction == AngleRestriction.NINETY_DEGREE || offset_pin_shape.is_IntBox()) + { + offset_pin_shape = offset_pin_shape.bounding_box(); + } + else if (p_angle_restriction == AngleRestriction.FORTYFIVE_DEGREE) + { + offset_pin_shape = offset_pin_shape.bounding_octagon(); + } + int[][] entries = offset_pin_shape.entrance_points(trace_polyline); + if (entries.length == 0) + { + return false; + } + int[] latest_entry_tuple = entries[entries.length - 1]; + FloatPoint trace_entry_location_approx = + trace_polyline.arr[latest_entry_tuple[0]].intersection_approx(offset_pin_shape.border_line(latest_entry_tuple[1])); + // calculate the nearest legal pin exit point to trace_entry_location_approx + double min_exit_corner_distance = Double.MAX_VALUE; + Line nearest_pin_exit_ray = null; + int nearest_border_line_no = -1; + Direction pin_exit_direction = null; + FloatPoint nearest_exit_corner = null; + final double TOLERANCE = 1; + for (Pin.TraceExitRestriction curr_exit_restriction : trace_exit_restrictions) + { + int curr_intersecting_border_line_no = offset_pin_shape.intersecting_border_line_no(pin_center, curr_exit_restriction.direction); + Line curr_pin_exit_ray = new Line(pin_center, curr_exit_restriction.direction); + FloatPoint curr_exit_corner = curr_pin_exit_ray.intersection_approx(offset_pin_shape.border_line(curr_intersecting_border_line_no)); + double curr_exit_corner_distance = curr_exit_corner.distance_square(trace_entry_location_approx); + boolean new_nearest_corner_found = false; + if (curr_exit_corner_distance + TOLERANCE < min_exit_corner_distance) + { + new_nearest_corner_found = true; + } + else if (curr_exit_corner_distance < min_exit_corner_distance + TOLERANCE) + { + // the distances are near equal, compare to the previous corners of p_trace_polyline + for (int i = 1; i < trace_polyline.corner_count(); ++i) + { + FloatPoint curr_trace_corner = trace_polyline.corner_approx(i); + double curr_trace_corner_distance = curr_trace_corner.distance_square(curr_exit_corner); + double old_trace_corner_distance = curr_trace_corner.distance_square(nearest_exit_corner); + if (curr_trace_corner_distance + TOLERANCE < old_trace_corner_distance) + { + new_nearest_corner_found = true; + break; + } + else if (curr_trace_corner_distance > old_trace_corner_distance + TOLERANCE) + { + break; + } + } + } + if (new_nearest_corner_found) + { + min_exit_corner_distance = curr_exit_corner_distance; + nearest_pin_exit_ray = curr_pin_exit_ray; + nearest_border_line_no = curr_intersecting_border_line_no; + pin_exit_direction = curr_exit_restriction.direction; + nearest_exit_corner = curr_exit_corner; + } + } + + // append the polygon piece around the border of the pin shape. + + Line[] curr_lines; + + int corner_count = offset_pin_shape.border_line_count(); + int clock_wise_side_diff = + (nearest_border_line_no - latest_entry_tuple[1] + corner_count) % corner_count; + int counter_clock_wise_side_diff = + (latest_entry_tuple[1] - nearest_border_line_no + corner_count) % corner_count; + int curr_border_line_no = nearest_border_line_no; + if (counter_clock_wise_side_diff <= clock_wise_side_diff) + { + curr_lines = new Line[counter_clock_wise_side_diff + 3]; + for (int i = 0; i <= counter_clock_wise_side_diff; ++i) + { + curr_lines[i + 1] = offset_pin_shape.border_line(curr_border_line_no); + curr_border_line_no = (curr_border_line_no + 1) % corner_count; + } + } + else + { + curr_lines = new Line[clock_wise_side_diff + 3]; + for (int i = 0; i <= clock_wise_side_diff; ++i) + { + curr_lines[i + 1] = offset_pin_shape.border_line(curr_border_line_no); + curr_border_line_no = (curr_border_line_no - 1 + corner_count) % corner_count; + } + } + curr_lines[0] = nearest_pin_exit_ray; + curr_lines[curr_lines.length - 1] = trace_polyline.arr[latest_entry_tuple[0]]; + + Polyline border_polyline = new Polyline(curr_lines); + if (!this.board.check_polyline_trace(border_polyline, this.get_layer(), + this.get_half_width(), this.net_no_arr, this.clearance_class_no())) + { + return false; + } + + Line[] cut_lines = new Line[trace_polyline.arr.length - latest_entry_tuple[0] + 1]; + cut_lines[0] = curr_lines[curr_lines.length - 2]; + for (int i = 1; i < cut_lines.length; ++i) + { + cut_lines[i] = trace_polyline.arr[latest_entry_tuple[0] + i - 1]; + + } + Polyline cut_polyline = new Polyline(cut_lines); + Polyline changed_polyline; + if (cut_polyline.first_corner().equals(cut_polyline.last_corner())) + { + changed_polyline = border_polyline; + } + else + { + changed_polyline = border_polyline.combine(cut_polyline); + } + if (!p_at_start) + { + changed_polyline = changed_polyline.reverse(); + } + this.change(changed_polyline); + + + // create an shove_fixed exit line. + curr_lines = new Line[3]; + curr_lines[0] = new Line(pin_center, pin_exit_direction.turn_45_degree(2)); + curr_lines[1] = nearest_pin_exit_ray; + curr_lines[2] = offset_pin_shape.border_line(nearest_border_line_no); + Polyline exit_line_segment = new Polyline(curr_lines); + this.board.insert_trace(exit_line_segment, this.get_layer(), this.get_half_width(), this.net_no_arr, + this.clearance_class_no(), FixedState.SHOVE_FIXED); + return true; + } + + /** + * Looks, if an other pin connection restriction fits better than the current connection restriction + * and changes this trace in this case. + * If p_at_start, the start of the trace polygon is changed, else the end. + * Returns true, if this trace was changed. + * + * @param p_at_start a boolean. + * @return a boolean. + */ + public boolean swap_connection_to_pin(boolean p_at_start) + { + Polyline trace_polyline; + Collection contact_list; + if (p_at_start) + { + trace_polyline = this.polyline(); + contact_list = this.get_start_contacts(); + } + else + { + trace_polyline = this.polyline().reverse(); + contact_list = this.get_end_contacts(); + } + if (contact_list.size() != 1) + { + return false; + } + Item curr_contact = contact_list.iterator().next(); + if (!(curr_contact.get_fixed_state() == FixedState.SHOVE_FIXED && (curr_contact instanceof PolylineTrace))) + { + return false; + } + PolylineTrace contact_trace = (PolylineTrace) curr_contact; + Polyline contact_polyline = contact_trace.polyline(); + Line contact_last_line = contact_polyline.arr[contact_polyline.arr.length - 2]; + // look, if this trace has a sharp angle with the contact trace. + Line first_line = trace_polyline.arr[1]; + // check for sharp angle + boolean check_swap = contact_last_line.direction().projection(first_line.direction()) == Signum.NEGATIVE; + if (!check_swap) + { + double half_width = this.get_half_width(); + if (trace_polyline.arr.length > 3 && + trace_polyline.corner_approx(0).distance_square(trace_polyline.corner_approx(1)) <= half_width * half_width) + { + // check also for sharp angle with the second line + check_swap = + (contact_last_line.direction().projection(trace_polyline.arr[2].direction()) == Signum.NEGATIVE); + } + } + if (!check_swap) + { + return false; + } + Pin contact_pin = null; + Collection curr_contacts = contact_trace.get_start_contacts(); + for (Item tmp_contact : curr_contacts) + { + if (tmp_contact instanceof Pin) + { + contact_pin = (Pin) tmp_contact; + break; + } + } + if (contact_pin == null) + { + return false; + } + Polyline combined_polyline = contact_polyline.combine(trace_polyline); + Direction nearest_pin_exit_direction = + contact_pin.calc_nearest_exit_restriction_direction(combined_polyline, this.get_half_width(), this.get_layer()); + if (nearest_pin_exit_direction == null || nearest_pin_exit_direction.equals(contact_polyline.arr[1].direction())) + { + return false; // direction would not be changed + } + contact_trace.set_fixed_state(this.get_fixed_state()); + this.combine(); + return true; + } + // primary data + private Polyline lines; +} diff --git a/board/PrintableShape.java b/src/main/java/board/PrintableShape.java similarity index 95% rename from board/PrintableShape.java rename to src/main/java/board/PrintableShape.java index 6d82bfc..35988d7 100644 --- a/board/PrintableShape.java +++ b/src/main/java/board/PrintableShape.java @@ -26,9 +26,15 @@ * Shape class used for printing a geometry.planar.Shape after transforming it to user coordinates. * * @author Alfons Wirtz + * @version $Id: $Id */ public abstract class PrintableShape { + /** + *

Constructor for PrintableShape.

+ * + * @param p_locale a {@link java.util.Locale} object. + */ protected PrintableShape(java.util.Locale p_locale) { this.locale = p_locale; @@ -36,6 +42,8 @@ protected PrintableShape(java.util.Locale p_locale) /** * Returns text information about the PrintableShape. + * + * @return a {@link java.lang.String} object. */ public abstract String toString(); diff --git a/board/PullTightAlgo.java b/src/main/java/board/PullTightAlgo.java similarity index 97% rename from board/PullTightAlgo.java rename to src/main/java/board/PullTightAlgo.java index 2f9583f..38fcf98 100644 --- a/board/PullTightAlgo.java +++ b/src/main/java/board/PullTightAlgo.java @@ -42,6 +42,7 @@ * Class with functionality for optimising traces and vias. * * @author Alfons Wirtz + * @version $Id: $Id */ public abstract class PullTightAlgo { @@ -187,6 +188,8 @@ Polyline pull_tight(Polyline p_polyline, int p_layer, int p_half_width, /** * Termitates the pull tight algorithm, if the user has made a stop request. + * + * @return a boolean. */ protected boolean is_stop_requested() { @@ -233,6 +236,10 @@ Polyline reposition_lines(Polyline p_polyline) /** * Tries to reposition the line with index p_no to make the polyline consisting * of p_line_arr shorter. + * + * @param p_line_arr an array of {@link geometry.planar.Line} objects. + * @param p_no a int. + * @return a {@link geometry.planar.Line} object. */ protected Line reposition_line(Line[] p_line_arr, int p_no) { @@ -546,6 +553,9 @@ else if (board.changed_area != null) /** * Wraps around pins of the own net to avoid acid traps. + * + * @param p_polyline a {@link geometry.planar.Polyline} object. + * @return a {@link geometry.planar.Polyline} object. */ protected Polyline avoid_acid_traps(Polyline p_polyline) { @@ -574,7 +584,7 @@ protected Polyline avoid_acid_traps(Polyline p_polyline) abstract Polyline smoothen_end_corner_at_trace(PolylineTrace p_trace); protected final RoutingBoard board; - /** If only_net_no > 0, only nets with this net numbers are optimized. */ + /** If {@code only_net_no > 0}, only nets with this net numbers are optimized. */ protected final int[] only_net_no_arr; protected int curr_layer; protected int curr_half_width; @@ -583,9 +593,11 @@ protected Polyline avoid_acid_traps(Polyline p_polyline) protected IntOctagon curr_clip_shape; protected Set contact_pins; protected int min_translate_dist; + /** Constant c_max_cos_angle=0.999 */ protected static final double c_max_cos_angle = 0.999; // with angles to close to 180 degree the algorithm becomes numerically // unstable + /** Constant c_min_corner_dist_square=0.9 */ protected static final double c_min_corner_dist_square = 0.9; /** * If stoppable_thread != null, the agorithm can be requested to be stopped. diff --git a/board/PullTightAlgo45.java b/src/main/java/board/PullTightAlgo45.java similarity index 98% rename from board/PullTightAlgo45.java rename to src/main/java/board/PullTightAlgo45.java index af7215a..0d1117c 100644 --- a/board/PullTightAlgo45.java +++ b/src/main/java/board/PullTightAlgo45.java @@ -40,7 +40,17 @@ class PullTightAlgo45 extends PullTightAlgo { - /** Creates a new instance of PullTight90 */ + /** + * Creates a new instance of PullTight90 + * + * @param p_board a {@link board.RoutingBoard} object. + * @param p_only_net_no_arr an array of int. + * @param p_stoppable_thread a {@link datastructures.Stoppable} object. + * @param p_time_limit a int. + * @param p_keep_point a {@link geometry.planar.Point} object. + * @param p_keep_point_layer a int. + * @param p_keep_point_layer a int. + */ public PullTightAlgo45(RoutingBoard p_board, int[] p_only_net_no_arr, Stoppable p_stoppable_thread, int p_time_limit, Point p_keep_point, int p_keep_point_layer) { diff --git a/board/PullTightAlgo90.java b/src/main/java/board/PullTightAlgo90.java similarity index 94% rename from board/PullTightAlgo90.java rename to src/main/java/board/PullTightAlgo90.java index d54faae..b51df0f 100644 --- a/board/PullTightAlgo90.java +++ b/src/main/java/board/PullTightAlgo90.java @@ -35,7 +35,17 @@ class PullTightAlgo90 extends PullTightAlgo { - /** Creates a new instance of PullTight90 */ + /** + * Creates a new instance of PullTight90 + * + * @param p_board a {@link board.RoutingBoard} object. + * @param p_only_net_no_arr an array of int. + * @param p_stoppable_thread a {@link datastructures.Stoppable} object. + * @param p_time_limit a int. + * @param p_keep_point a {@link geometry.planar.Point} object. + * @param p_keep_point_layer a int. + * @param p_keep_point_layer a int. + */ public PullTightAlgo90(RoutingBoard p_board, int[] p_only_net_no_arr, Stoppable p_stoppable_thread, int p_time_limit, Point p_keep_point, int p_keep_point_layer) { diff --git a/board/PullTightAlgoAnyAngle.java b/src/main/java/board/PullTightAlgoAnyAngle.java similarity index 97% rename from board/PullTightAlgoAnyAngle.java rename to src/main/java/board/PullTightAlgoAnyAngle.java index df746bd..868f875 100644 --- a/board/PullTightAlgoAnyAngle.java +++ b/src/main/java/board/PullTightAlgoAnyAngle.java @@ -1,1238 +1,1239 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - */ - -package board; - -import datastructures.Stoppable; -import geometry.planar.Limits; -import datastructures.Signum; - -import geometry.planar.Direction; -import geometry.planar.FloatPoint; -import geometry.planar.IntPoint; -import geometry.planar.Point; -import geometry.planar.Line; -import geometry.planar.Polyline; -import geometry.planar.Side; -import geometry.planar.TileShape; - -/** - * - * Auxiliary class containing internal functions for pulling any angle traces tight. - * - * - * @author Alfons Wirtz - */ - -class PullTightAlgoAnyAngle extends PullTightAlgo -{ - - PullTightAlgoAnyAngle(RoutingBoard p_board, int[] p_only_net_no_arr, Stoppable p_stoppable_thread, int p_time_limit, - Point p_keep_point, int p_keep_point_layer) - { - super(p_board, p_only_net_no_arr, p_stoppable_thread, p_time_limit, p_keep_point, p_keep_point_layer); - } - - Polyline pull_tight(Polyline p_polyline) - { - Polyline new_result = avoid_acid_traps(p_polyline); - Polyline prev_result = null; - while (new_result != prev_result) - { - if (is_stop_requested()) - { - break; - } - prev_result = new_result; - Polyline tmp = skip_segments_of_length_0(prev_result); - Polyline tmp0 = reduce_lines(tmp); - Polyline tmp1 = skip_lines(tmp0); - - // I intended to replace reduce_corners by the previous 2 - // functions, because with consecutive corners closer than - // 1 grid point reduce_corners may loop with smoothen_corners - // because of changing directions heavily. - // Unlike reduce_corners, the above 2 functions do not - // introduce new directions - - Polyline tmp2 = reduce_corners(tmp1); - Polyline tmp3 = reposition_lines(tmp2); - new_result = smoothen_corners(tmp3); - } - return new_result; - } - - - // tries to reduce the corner count of p_polyline by replacing two consecutive - // lines by a line through IntPoints near the previous corner and the next - // corner, if that is possible without clearance violation. - private Polyline reduce_corners(Polyline p_polyline) - { - if (p_polyline.arr.length < 4) - { - return p_polyline; - } - int last_index = p_polyline.arr.length - 4; - - Line [] new_lines = new Line [p_polyline.arr.length]; - new_lines[0] = p_polyline.arr[0]; - new_lines[1] = p_polyline.arr[1]; - - int new_line_index = 1; - - boolean polyline_changed = false; - - Line [] curr_lines = new Line[3]; - - for (int i = 0; i <= last_index; ++i) - { - boolean skip_line = false; - FloatPoint new_a = new_lines[new_line_index - 1].intersection_approx(new_lines[new_line_index]); - FloatPoint new_b = p_polyline.corner_approx(i + 2); - boolean in_clip_shape = curr_clip_shape == null || - curr_clip_shape.contains(new_a) && curr_clip_shape.contains(new_b) - && curr_clip_shape.contains(p_polyline.corner_approx(new_line_index)); - - if (in_clip_shape) - { - FloatPoint skip_corner = - new_lines[new_line_index].intersection_approx(p_polyline.arr[i + 2]); - curr_lines [1] = new Line(new_a.round(), new_b.round()); - boolean ok = true; - if (new_line_index == 1) - { - if (!(p_polyline.first_corner() instanceof IntPoint)) - { - // first corner must not be changed - ok = false; - } - else - { - Direction dir = curr_lines[1].direction(); - curr_lines[0] = - Line.get_instance(p_polyline.first_corner(), dir.turn_45_degree(2)); - } - } - else - { - curr_lines[0] = new_lines[new_line_index - 1]; - } - if (i == last_index) - { - if (!(p_polyline.last_corner() instanceof IntPoint)) - { - // last corner must not be changed - ok = false; - } - else - { - Direction dir = curr_lines[1].direction(); - curr_lines[2] = Line.get_instance(p_polyline.last_corner(), dir.turn_45_degree(2)); - } - } - else - { - curr_lines[2] = p_polyline.arr[i + 3]; - } - - - // check, if the intersection of curr_lines[0] and curr_lines[1] - // is near new_a and the intersection of curr_lines[0] and - // curr_lines[1] and curr_lines[2] is near new_b. - // There may be numerical stability proplems with - // near parallel lines. - - final double check_dist = 100; - if (ok) - { - FloatPoint check_is = curr_lines[0].intersection_approx(curr_lines[1]); - double dist = check_is.distance_square(new_a); - - if (dist > check_dist) - { - ok = false; - } - } - if (ok) - { - FloatPoint check_is = curr_lines[1].intersection_approx(curr_lines[2]); - double dist = check_is.distance_square(new_b); - if (dist > check_dist) - { - ok = false; - } - } - if (ok && i == 1 && !(p_polyline.first_corner() instanceof IntPoint)) - { - // There may be a connection to a trace. - // make shure that the second corner of the new polyline - // is on the same side of the trace as the third corner. (There may be splitting problems) - Point new_corner = curr_lines[0].intersection(curr_lines[1]); - if (new_corner.side_of(new_lines[0]) != p_polyline.corner(1).side_of(new_lines[0])) - { - ok = false; - } - } - if (ok && i == last_index - 1 && !(p_polyline.last_corner() instanceof IntPoint)) - { - // There may be a connection to a trace. - // make shure that the second last corner of the new polyline - // is on the same side of the trace as the third last corner (There may be splitting problems) - Point new_corner = curr_lines[1].intersection(curr_lines[2]); - if (new_corner.side_of(new_lines[0]) != - p_polyline.corner(p_polyline.corner_count() - 2).side_of(new_lines[0])) - { - ok = false; - } - } - Polyline curr_polyline = null; - if (ok) - { - curr_polyline = new Polyline(curr_lines); - if ( curr_polyline.arr.length != 3) - { - ok = false; - } - double length_before = skip_corner.distance(new_a) + - skip_corner.distance(new_b); - double length_after = curr_polyline.length_approx() + 1.5; - // 1.5 added because of possible inacurracy SQRT_2 - // by twice rounding. - if (length_after >= length_before) - // May happen from rounding to integer. - // Prevent infinite loop. - { - ok = false; - } - } - - if (ok) - { - TileShape shape_to_check = curr_polyline.offset_shape(curr_half_width, 0); - skip_line = board.check_trace_shape(shape_to_check, - curr_layer, curr_net_no_arr, curr_cl_type, this.contact_pins); - } - } - if (skip_line) - { - polyline_changed = true; - new_lines[new_line_index] = curr_lines[1]; - if (new_line_index == 1) - { - // make the first line perpendicular to the current line - new_lines[0] = curr_lines [0]; - } - if (i == last_index) - { - // make the last line perpendicular to the current line - ++new_line_index; - new_lines[new_line_index] = curr_lines[2]; - } - if (board.changed_area != null) - { - board.changed_area.join(new_a, curr_layer); - board.changed_area.join(new_b, curr_layer); - } - } - else - { - ++new_line_index; - new_lines[new_line_index] = p_polyline.arr[i + 2]; - if (i == last_index) - { - ++new_line_index; - new_lines[new_line_index] = p_polyline.arr[i + 3]; - } - } - if (new_lines[new_line_index].is_parallel(new_lines[new_line_index - 1])) - { - // skip line, if it is parallel to the previous one - --new_line_index; - } - } - if (!polyline_changed) - { - return p_polyline; - } - Line [] cleaned_new_lines = new Line [new_line_index + 1]; - System.arraycopy(new_lines, 0, cleaned_new_lines, 0, cleaned_new_lines.length); - Polyline result = new Polyline(cleaned_new_lines); - return result; - } - - /** - * tries to smoothen p_polyline by cutting of corners, if possible - */ - private Polyline smoothen_corners(Polyline p_polyline) - { - if (p_polyline.arr.length < 4) - { - return p_polyline; - } - boolean polyline_changed = false; - Line[] line_arr = new Line[p_polyline.arr.length]; - System.arraycopy(p_polyline.arr, 0, line_arr, 0, line_arr.length); - - for (int i = 0; i < line_arr.length - 3; ++i) - { - Line new_line = smoothen_corner(line_arr, i); - if (new_line != null) - { - polyline_changed = true; - // add the new line into the line array - Line[] tmp_lines = new Line[line_arr.length + 1]; - System.arraycopy(line_arr, 0, tmp_lines, 0, i + 2); - tmp_lines [i + 2] = new_line; - System.arraycopy(line_arr, i + 2, tmp_lines, i + 3, - tmp_lines.length - (i + 3)); - line_arr = tmp_lines; - ++i; - } - } - if (!polyline_changed) - { - return p_polyline; - } - return new Polyline(line_arr); - } - - /** - * tries to shorten p_polyline by relocating its lines - */ - Polyline reposition_lines(Polyline p_polyline) - { - if (p_polyline.arr.length < 5) - { - return p_polyline; - } - boolean polyline_changed = false; - Line[] line_arr = new Line[p_polyline.arr.length]; - System.arraycopy(p_polyline.arr, 0, line_arr, 0, line_arr.length); - for (int i = 0; i < line_arr.length - 4; ++i) - { - Line new_line = reposition_line(line_arr, i); - if (new_line != null) - { - polyline_changed = true; - line_arr [i + 2] = new_line; - if (line_arr[i + 2].is_parallel(line_arr[i + 1]) || - line_arr[i + 2].is_parallel(line_arr[i + 3])) - { - // calculation of corners not possible before skipping - // parallel lines - break; - } - } - } - if (!polyline_changed) - { - return p_polyline; - } - return new Polyline(line_arr); - } - - /** - * tries to reduce te number of lines of p_polyline by moving - * lines parallel beyond the intersection of the next or privious lines. - */ - private Polyline reduce_lines(Polyline p_polyline) - { - if (p_polyline.arr.length < 6) - { - return p_polyline; - } - boolean polyline_changed = false; - Line[] line_arr = p_polyline.arr; - for (int i = 2; i < line_arr.length - 2; ++i) - { - FloatPoint prev_corner = - line_arr[i - 2].intersection_approx( line_arr[i - 1]); - FloatPoint next_corner = - line_arr[i +1 ].intersection_approx( line_arr[i + 2]); - boolean in_clip_shape = curr_clip_shape == null || - curr_clip_shape.contains(prev_corner) && - curr_clip_shape.contains(next_corner); - if (!in_clip_shape) - { - continue; - } - Line translate_line = line_arr [i]; - double prev_dist = translate_line.signed_distance(prev_corner); - double next_dist = translate_line.signed_distance(next_corner); - if (Signum.of(prev_dist)!= Signum.of(next_dist)) - // the 2 corners are on different sides of the translate_line - { - continue; - } - double translate_dist; - if (Math.abs(prev_dist) < Math.abs(next_dist)) - { - - translate_dist = prev_dist; - } - else - { - translate_dist = next_dist; - } - if (translate_dist == 0) - { - //line segment may have length 0 - continue; - } - Side line_side = translate_line.side_of(prev_corner); - Line new_line = translate_line.translate(-translate_dist); - // make shure, we have crossed the nearest_corner; - int sign = Signum.as_int(translate_dist); - Side new_line_side_of_prev_corner = new_line.side_of(prev_corner); - Side new_line_side_of_next_corner = new_line.side_of(next_corner); - while (new_line_side_of_prev_corner == line_side && - new_line_side_of_next_corner == line_side) - { - translate_dist += sign * 0.5; - new_line = translate_line.translate(-translate_dist); - new_line_side_of_prev_corner = new_line.side_of(prev_corner); - new_line_side_of_next_corner = new_line.side_of(next_corner); - } - int crossed_corners_before_count = 0; - int crossed_corners_after_count = 0; - if (new_line_side_of_prev_corner != line_side) - { - ++crossed_corners_before_count; - } - if (new_line_side_of_next_corner != line_side) - { - ++crossed_corners_after_count; - } - // check, that we havent crossed both corners - if (crossed_corners_before_count > 1 || crossed_corners_after_count > 1) - { - continue; - } - // check, that next_nearest_corner and nearest_corner are on - // different sides of new_line; - if (crossed_corners_before_count > 0) - { - if (i < 3) - { - continue; - } - FloatPoint prev_prev_corner = - line_arr[i - 3].intersection_approx( line_arr[i - 2]); - if (new_line.side_of(prev_prev_corner) != line_side) - { - continue; - } - } - if (crossed_corners_after_count > 0) - { - if (i >= line_arr.length - 3) - { - continue; - } - FloatPoint next_next_corner = - line_arr[i + 2 ].intersection_approx( line_arr[i + 3]); - if (new_line.side_of(next_next_corner) != line_side) - { - continue; - } - } - Line [] curr_lines = new Line[line_arr.length - - crossed_corners_before_count - crossed_corners_after_count]; - int keep_before_ind = i - crossed_corners_before_count; - System.arraycopy(line_arr, 0, curr_lines, 0, keep_before_ind); - curr_lines [keep_before_ind] = new_line; - System.arraycopy(line_arr, i + 1 + crossed_corners_after_count, curr_lines, - keep_before_ind + 1, curr_lines.length - ( keep_before_ind + 1)); - Polyline tmp = new Polyline( curr_lines); - boolean check_ok = false; - if (tmp.arr.length == curr_lines.length) - { - TileShape shape_to_check = - tmp.offset_shape(curr_half_width, keep_before_ind - 1); - check_ok = board.check_trace_shape(shape_to_check, - curr_layer, curr_net_no_arr, curr_cl_type, this.contact_pins); - - } - if (check_ok) - { - if (board.changed_area != null) - { - board.changed_area.join(prev_corner, curr_layer); - board.changed_area.join(next_corner, curr_layer); - } - polyline_changed = true; - line_arr = curr_lines; - --i; - } - } - if (!polyline_changed) - { - return p_polyline; - } - return new Polyline(line_arr); - } - - - private Line smoothen_corner(Line[] p_line_arr, int p_start_no) - { - if ( p_line_arr.length - p_start_no < 4) - { - return null; - } - FloatPoint curr_corner = - p_line_arr[p_start_no + 1].intersection_approx(p_line_arr[p_start_no + 2]); - if (curr_clip_shape != null && - !curr_clip_shape.contains(curr_corner)) - { - return null; - } - double cosinus_angle = - p_line_arr[p_start_no + 1].cos_angle(p_line_arr[p_start_no + 2]); - if (cosinus_angle > c_max_cos_angle) - // lines are already nearly parallel, don't divide angle any further - // because of problems with numerical stability - { - return null; - } - FloatPoint prev_corner = - p_line_arr[p_start_no].intersection_approx( p_line_arr[p_start_no + 1]); - FloatPoint next_corner = - p_line_arr[p_start_no + 2].intersection_approx(p_line_arr[p_start_no + 3]); - - // create a line approximately through curr_corner, whose - // direction is about the middle of the directions of the - // previous and the next line. - // Translations of this line are used to cut off the corner. - Direction prev_dir = p_line_arr[p_start_no + 1].direction(); - Direction next_dir = p_line_arr[p_start_no + 2].direction(); - Direction middle_dir = prev_dir.middle_approx(next_dir); - Line translate_line = Line.get_instance(curr_corner.round(), middle_dir); - double prev_dist = translate_line.signed_distance(prev_corner); - double next_dist = translate_line.signed_distance(next_corner); - FloatPoint nearest_point; - double max_translate_dist; - if (Math.abs(prev_dist) < Math.abs(next_dist)) - { - nearest_point = prev_corner; - max_translate_dist = prev_dist; - } - else - { - nearest_point = next_corner; - max_translate_dist = next_dist; - } - if (Math.abs(max_translate_dist) < 1) - { - return null; - } - Line [] curr_lines = new Line[p_line_arr.length + 1]; - System.arraycopy(p_line_arr, 0, curr_lines, 0, p_start_no + 2); - System.arraycopy(p_line_arr, p_start_no + 2, curr_lines, - p_start_no + 3, curr_lines.length - p_start_no - 3); - double translate_dist = max_translate_dist; - double delta_dist = max_translate_dist; - Side side_of_nearest_point = translate_line.side_of(nearest_point); - int sign = Signum.as_int(max_translate_dist); - Line result = null; - while (Math.abs(delta_dist) > this.min_translate_dist) - { - boolean check_ok = false; - Line new_line = translate_line.translate(-translate_dist); - Side new_line_side_of_nearest_point = new_line.side_of(nearest_point); - if (new_line_side_of_nearest_point == side_of_nearest_point - || new_line_side_of_nearest_point == Side.COLLINEAR) - { - curr_lines [p_start_no + 2] = new_line; - Polyline tmp = new Polyline( curr_lines); - - if (tmp.arr.length == curr_lines.length) - { - TileShape shape_to_check = - tmp.offset_shape(curr_half_width, p_start_no + 1); - check_ok = board.check_trace_shape(shape_to_check, - curr_layer, curr_net_no_arr, curr_cl_type, this.contact_pins); - } - delta_dist /= 2; - if (check_ok) - { - result = curr_lines[p_start_no + 2]; - if (translate_dist == max_translate_dist) - { - // biggest possible change - break; - } - translate_dist += delta_dist; - } - else - { - translate_dist -= delta_dist; - } - } - else - // moved a little bit to far at the first time - // because of numerical inaccuracy - { - double shorten_value = sign * 0.5; - max_translate_dist -= shorten_value; - translate_dist -= shorten_value; - delta_dist -= shorten_value; - } - } - if (result == null) - { - return null; - } - - if (board.changed_area != null) - { - FloatPoint new_prev_corner = - curr_lines[p_start_no].intersection_approx( curr_lines[p_start_no + 1]); - FloatPoint new_next_corner = - curr_lines[p_start_no + 3].intersection_approx( curr_lines[p_start_no + 4]); - board.changed_area.join(new_prev_corner, curr_layer); - board.changed_area.join(new_next_corner, curr_layer); - } - return result; - } - - protected Line reposition_line(Line[] p_line_arr, int p_start_no) - { - if ( p_line_arr.length - p_start_no < 5) - { - return null; - } - if (curr_clip_shape != null) - // check, that the corners of the line to translate are inside - // the clip shape - { - for (int i = 1; i < 3; ++i) - { - FloatPoint curr_corner = - p_line_arr[p_start_no + i].intersection_approx(p_line_arr[p_start_no + i + 1]); - if(!curr_clip_shape.contains(curr_corner)) - { - return null; - } - } - } - Line translate_line = p_line_arr[p_start_no + 2]; - FloatPoint prev_corner = - p_line_arr[p_start_no].intersection_approx( p_line_arr[p_start_no + 1]); - FloatPoint next_corner = - p_line_arr[p_start_no + 3].intersection_approx(p_line_arr[p_start_no + 4]); - double prev_dist = translate_line.signed_distance(prev_corner); - int corners_skipped_before = 0; - int corners_skipped_after = 0; - final double c_epsilon = 0.001; - while (Math.abs(prev_dist) < c_epsilon) - // move also all lines trough the start corner of the line to translate - { - ++corners_skipped_before; - int curr_no = p_start_no - corners_skipped_before; - if (curr_no < 0) - // the first corner is on the line to translate - { - return null; - } - prev_corner = p_line_arr[curr_no].intersection_approx( p_line_arr[curr_no + 1]); - prev_dist = translate_line.signed_distance(prev_corner); - } - double next_dist = translate_line.signed_distance(next_corner); - while (Math.abs(next_dist) < c_epsilon) - // move also all lines trough the end corner of the line to translate - { - ++corners_skipped_after; - int curr_no = p_start_no + 3 + corners_skipped_after; - if (curr_no >= p_line_arr.length - 2) - // the last corner is on the line to translate - { - return null; - } - next_corner = p_line_arr[curr_no].intersection_approx( p_line_arr[curr_no + 1]); - next_dist = translate_line.signed_distance(next_corner); - } - if (Signum.of(prev_dist)!= Signum.of(next_dist)) - // the 2 corners are at different sides of translate_line - { - return null; - } - FloatPoint nearest_point; - double max_translate_dist; - if (Math.abs(prev_dist) < Math.abs(next_dist)) - { - nearest_point = prev_corner; - max_translate_dist = prev_dist; - } - else - { - nearest_point = next_corner; - max_translate_dist = next_dist; - } - Line [] curr_lines = new Line[p_line_arr.length]; - System.arraycopy(p_line_arr, 0, curr_lines, 0, p_start_no + 2); - System.arraycopy(p_line_arr, p_start_no + 3, - curr_lines, p_start_no + 3, curr_lines.length - p_start_no - 3); - double translate_dist = max_translate_dist; - double delta_dist = max_translate_dist; - Side side_of_nearest_point = translate_line.side_of(nearest_point); - int sign = Signum.as_int(max_translate_dist); - Line result = null; - boolean first_time = true; - while (first_time || Math.abs(delta_dist) > this.min_translate_dist) - { - boolean check_ok = false; - Line new_line = translate_line.translate(-translate_dist); - if (first_time && Math.abs(translate_dist) < 1) - { - if (new_line.equals(translate_line)) - { - // try the parallel line through the nearest_point - IntPoint rounded_nearest_point = nearest_point.round(); - if (nearest_point.distance(rounded_nearest_point.to_float()) - < Math.abs(translate_dist)) - { - new_line = Line.get_instance(rounded_nearest_point, - translate_line.direction()); - } - first_time = false; - } - if (new_line.equals(translate_line)) - { - return null; - } - } - Side new_line_side_of_nearest_point = new_line.side_of(nearest_point); - if (new_line_side_of_nearest_point == side_of_nearest_point - || new_line_side_of_nearest_point == Side.COLLINEAR) - { - first_time = false; - curr_lines [p_start_no + 2] = new_line; - // corners_skipped_before > 0 or corners_skipped_after > 0 - // happens very rarely. But this handling seems to be - // important because there are situations which no other - // tightening function can solve. For example when 3 ore more - // consecutive corners are equal. - Line prev_translated_line = new_line; - for (int i = 0; i < corners_skipped_before; ++i) - // Translate the previous lines onto or past the - // intersection of new_line with the first untranslated line. - { - int prev_line_no = p_start_no + 1 - corners_skipped_before; - FloatPoint curr_prev_corner = - prev_translated_line.intersection_approx(curr_lines[prev_line_no]); - Line curr_translate_line = p_line_arr [p_start_no + 1 - i]; - double curr_translate_dist = curr_translate_line.signed_distance(curr_prev_corner); - prev_translated_line = curr_translate_line.translate(-curr_translate_dist); - curr_lines[p_start_no + 1 - i] = prev_translated_line; - } - prev_translated_line = new_line; - for (int i = 0; i < corners_skipped_after; ++i) - // Translate the next lines onto or past the - // intersection of new_line with the first untranslated line. - { - int next_line_no = p_start_no + 3 + corners_skipped_after; - FloatPoint curr_next_corner = - prev_translated_line.intersection_approx(curr_lines[next_line_no]); - Line curr_translate_line = p_line_arr [p_start_no + 3 + i]; - double curr_translate_dist = curr_translate_line.signed_distance(curr_next_corner); - prev_translated_line = curr_translate_line.translate(-curr_translate_dist); - curr_lines[p_start_no + 3 + i] = prev_translated_line; - } - Polyline tmp = new Polyline( curr_lines); - - if (tmp.arr.length == curr_lines.length) - { - TileShape shape_to_check = - tmp.offset_shape(curr_half_width, p_start_no + 1); - check_ok = board.check_trace_shape(shape_to_check, - curr_layer, curr_net_no_arr, curr_cl_type, this.contact_pins); - - } - delta_dist /= 2; - if (check_ok) - { - result = curr_lines[p_start_no + 2]; - if (translate_dist == max_translate_dist) - { - // biggest possible change - break; - } - translate_dist += delta_dist; - } - else - { - translate_dist -= delta_dist; - } - } - else - // moved a little bit to far at the first time - // because of numerical inaccuracy - { - double shorten_value = sign * 0.5; - max_translate_dist -= shorten_value; - translate_dist -= shorten_value; - delta_dist -= shorten_value; - } - } - if (result == null) - { - return null; - } - - if (board.changed_area != null) - { - FloatPoint new_prev_corner = - curr_lines[p_start_no].intersection_approx( curr_lines[p_start_no + 1]); - FloatPoint new_next_corner = - curr_lines[p_start_no + 3].intersection_approx( curr_lines[p_start_no + 4]); - board.changed_area.join(new_prev_corner, curr_layer); - board.changed_area.join(new_next_corner, curr_layer); - } - return result; - } - - - private Polyline skip_lines(Polyline p_polyline) - { - for (int i = 1; i < p_polyline.arr.length - 3; ++i) - { - for (int j = 0; j <= 1; ++j) - { - FloatPoint corner1; - FloatPoint corner2; - Line curr_line; - if (j == 0) // try to skip the line before the i+2-th line - { - curr_line = p_polyline.arr[i + 2]; - corner1 = p_polyline.corner_approx(i); - corner2 = p_polyline.corner_approx(i - 1); - } - else // try to skip the line after i-th line - { - curr_line = p_polyline.arr[i]; - corner1 = p_polyline.corner_approx(i + 1); - corner2 = p_polyline.corner_approx(i + 2); - } - boolean in_clip_shape = curr_clip_shape == null || - curr_clip_shape.contains(corner1) && - curr_clip_shape.contains(corner2); - if (!in_clip_shape) - { - continue; - } - - Side side1 = curr_line.side_of(corner1); - Side side2 = curr_line.side_of(corner2); - if (side1 != side2) - // the two corners are on different sides of the line - { - Polyline reduced_polyline = p_polyline.skip_lines(i + 1, i + 1); - if (reduced_polyline.arr.length == p_polyline.arr.length - 1) - { - int shape_no = i - 1; - if (j == 0) - { - ++shape_no; - } - TileShape shape_to_check = - reduced_polyline.offset_shape(curr_half_width, shape_no); - if (board.check_trace_shape(shape_to_check, - curr_layer, curr_net_no_arr, curr_cl_type, this.contact_pins)) - { - if (board.changed_area != null) - { - board.changed_area.join(corner1, curr_layer); - board.changed_area.join(corner2, curr_layer); - } - return reduced_polyline; - } - } - } - // now try skipping 2 lines - if (i >= p_polyline.arr.length - 4) - { - break; - } - FloatPoint corner3; - if (j == 1) - { - corner3 = p_polyline.corner_approx(i + 3); - } - else - { - corner3 = p_polyline.corner_approx(i + 1); - } - if (curr_clip_shape != null && !curr_clip_shape.contains(corner3)) - { - continue; - } - if (j == 0) - // curr_line is 1 line later than in the case skipping 1 line - // when coming from behind - { - curr_line = p_polyline.arr[i + 3]; - side1 = curr_line.side_of(corner1); - side2 = curr_line.side_of(corner2); - } - else - { - side1 = curr_line.side_of(corner3); - } - if (side1 != side2) - // the two corners are on different sides of the line - { - Polyline reduced_polyline = p_polyline.skip_lines(i + 1, i + 2); - if (reduced_polyline.arr.length == p_polyline.arr.length - 2) - { - int shape_no = i - 1; - if (j == 0) - { - ++shape_no; - } - TileShape shape_to_check = - reduced_polyline.offset_shape(curr_half_width, shape_no); - if (board.check_trace_shape(shape_to_check, - curr_layer, curr_net_no_arr, curr_cl_type, this.contact_pins)) - { - if (board.changed_area != null) - { - board.changed_area.join(corner1, curr_layer); - board.changed_area.join(corner2, curr_layer); - board.changed_area.join(corner3, curr_layer); - } - return reduced_polyline; - } - } - } - - } - } - return p_polyline; - } - - Polyline smoothen_start_corner_at_trace(PolylineTrace p_trace) - { - boolean acute_angle = false; - boolean bend = false; - FloatPoint other_trace_corner_approx = null; - Line other_trace_line = null; - Line other_prev_trace_line = null; - Polyline trace_polyline = p_trace.polyline(); - Point curr_end_corner = trace_polyline.corner(0); - - if (this.curr_clip_shape != null && this.curr_clip_shape.is_outside(curr_end_corner)) - { - return null; - } - - Point curr_prev_end_corner = trace_polyline.corner(1); - boolean skip_short_segment = !(curr_end_corner instanceof IntPoint) && - curr_end_corner.to_float().distance_square(curr_prev_end_corner.to_float()) < SKIP_LENGTH; - int start_line_no = 1; - if (skip_short_segment) - { - if (trace_polyline.corner_count() < 3) - { - return null; - } - curr_prev_end_corner = trace_polyline.corner(2); - ++start_line_no; - } - Side prev_corner_side = null; - Direction line_direction = trace_polyline.arr[start_line_no].direction(); - Direction prev_line_direction = trace_polyline.arr[start_line_no + 1].direction(); - - java.util.Collection contact_list = p_trace.get_start_contacts(); - for (Item curr_contact : contact_list) - { - if (curr_contact instanceof PolylineTrace && !curr_contact.is_shove_fixed()) - { - Polyline contact_trace_polyline = ((PolylineTrace) curr_contact).polyline(); - FloatPoint curr_other_trace_corner_approx; - Line curr_other_trace_line; - Line curr_other_prev_trace_line; - if (contact_trace_polyline.first_corner().equals(curr_end_corner)) - { - curr_other_trace_corner_approx = contact_trace_polyline.corner_approx(1); - curr_other_trace_line = contact_trace_polyline.arr[1]; - curr_other_prev_trace_line = contact_trace_polyline.arr[2]; - } - else - { - int curr_corner_no = contact_trace_polyline.corner_count() - 2; - curr_other_trace_corner_approx = contact_trace_polyline.corner_approx(curr_corner_no); - curr_other_trace_line = contact_trace_polyline.arr[curr_corner_no + 1].opposite(); - curr_other_prev_trace_line = contact_trace_polyline.arr[curr_corner_no]; - } - Side curr_prev_corner_side = curr_prev_end_corner.side_of(curr_other_trace_line); - Signum curr_projection = line_direction.projection(curr_other_trace_line.direction()); - boolean other_trace_found = false; - if (curr_projection == Signum.POSITIVE && curr_prev_corner_side != Side.COLLINEAR) - { - acute_angle = true; - other_trace_found = true; - - } - else if (curr_projection == Signum.ZERO && trace_polyline.corner_count() > 2) - { - if (prev_line_direction.projection(curr_other_trace_line.direction()) == Signum.POSITIVE) - { - bend = true; - other_trace_found = true; - } - } - if (other_trace_found) - { - other_trace_corner_approx = curr_other_trace_corner_approx; - other_trace_line = curr_other_trace_line; - prev_corner_side = curr_prev_corner_side; - other_prev_trace_line = curr_other_prev_trace_line; - } - } - else - { - return null; - } - } - int new_line_count = trace_polyline.arr.length + 1; - int diff = 1; - if (skip_short_segment) - { - --new_line_count; - --diff; - } - if (acute_angle) - { - Direction new_line_dir; - if (prev_corner_side == Side.ON_THE_LEFT) - { - new_line_dir = other_trace_line.direction().turn_45_degree(2); - } - else - { - new_line_dir = other_trace_line.direction().turn_45_degree(6); - } - Line translate_line = Line.get_instance(curr_end_corner.to_float().round(), new_line_dir); - double translate_dist = (Limits.sqrt2 - 1) * this.curr_half_width; - double prev_corner_dist = Math.abs(translate_line.signed_distance(curr_prev_end_corner.to_float())); - double other_dist = Math.abs(translate_line.signed_distance(other_trace_corner_approx)); - translate_dist = Math.min(translate_dist, prev_corner_dist); - translate_dist = Math.min(translate_dist, other_dist); - if (translate_dist >= 0.99) - { - - translate_dist = Math.max(translate_dist - 1, 1); - if (translate_line.side_of(curr_prev_end_corner) == Side.ON_THE_LEFT) - { - translate_dist = -translate_dist; - } - Line add_line = translate_line.translate(translate_dist); - // constract the new trace polyline. - Line[] new_lines = new Line[new_line_count]; - new_lines[0] = other_trace_line; - new_lines[1] = add_line; - for (int i = 2; i < new_lines.length; ++i) - { - new_lines[i] = trace_polyline.arr[i - diff]; - } - return new Polyline(new_lines); - } - } - else if (bend) - { - Line[] check_line_arr = new Line[new_line_count]; - check_line_arr [0] = other_prev_trace_line; - check_line_arr [1] = other_trace_line; - for (int i = 2; i < check_line_arr.length; ++i) - { - check_line_arr [i] = trace_polyline.arr[i - diff]; - } - Line new_line = reposition_line(check_line_arr, 0); - if (new_line != null) - { - Line [] new_lines = new Line[trace_polyline.arr.length]; - new_lines[0] = other_trace_line; - new_lines[1] = new_line; - for (int i = 2; i < new_lines.length; ++i) - { - new_lines [i] = trace_polyline.arr[i]; - } - return new Polyline(new_lines); - } - } - return null; - } - - Polyline smoothen_end_corner_at_trace(PolylineTrace p_trace) - { - boolean acute_angle = false; - boolean bend = false; - FloatPoint other_trace_corner_approx = null; - Line other_trace_line = null; - Line other_prev_trace_line = null; - Polyline trace_polyline = p_trace.polyline(); - Point curr_end_corner = trace_polyline.last_corner(); - - if (this.curr_clip_shape != null && this.curr_clip_shape.is_outside(curr_end_corner)) - { - return null; - } - - Point curr_prev_end_corner = trace_polyline.corner(trace_polyline.corner_count() - 2); - boolean skip_short_segment = !(curr_end_corner instanceof IntPoint) && - curr_end_corner.to_float().distance_square(curr_prev_end_corner.to_float()) < SKIP_LENGTH; - int end_line_no = trace_polyline.arr.length - 2; - if (skip_short_segment) - { - if (trace_polyline.corner_count() < 3) - { - return null; - } - curr_prev_end_corner = trace_polyline.corner(trace_polyline.corner_count() - 3); - --end_line_no; - } - Side prev_corner_side = null; - Direction line_direction = trace_polyline.arr[end_line_no].direction().opposite(); - Direction prev_line_direction = trace_polyline.arr[end_line_no].direction().opposite(); - - java.util.Collection contact_list = p_trace.get_end_contacts(); - for (Item curr_contact : contact_list) - { - if (curr_contact instanceof PolylineTrace && !curr_contact.is_shove_fixed()) - { - Polyline contact_trace_polyline = ((PolylineTrace) curr_contact).polyline(); - if (contact_trace_polyline.corner_count() > 2) - { - FloatPoint curr_other_trace_corner_approx; - Line curr_other_trace_line; - Line curr_other_prev_trace_line; - if (contact_trace_polyline.first_corner().equals(curr_end_corner)) - { - curr_other_trace_corner_approx = contact_trace_polyline.corner_approx(1); - curr_other_trace_line = contact_trace_polyline.arr[1]; - curr_other_prev_trace_line = contact_trace_polyline.arr[2]; - } - else - { - int curr_corner_no = contact_trace_polyline.corner_count() - 2; - curr_other_trace_corner_approx = contact_trace_polyline.corner_approx(curr_corner_no); - curr_other_trace_line = contact_trace_polyline.arr[curr_corner_no + 1].opposite(); - curr_other_prev_trace_line = contact_trace_polyline.arr[curr_corner_no]; - } - Side curr_prev_corner_side = curr_prev_end_corner.side_of(curr_other_trace_line); - Signum curr_projection = line_direction.projection(curr_other_trace_line.direction()); - boolean other_trace_found = false; - if (curr_projection == Signum.POSITIVE && curr_prev_corner_side != Side.COLLINEAR) - { - acute_angle = true; - other_trace_found = true; - } - else if (curr_projection == Signum.ZERO && trace_polyline.corner_count() > 2) - { - if (prev_line_direction.projection(curr_other_trace_line.direction()) == Signum.POSITIVE) - { - bend = true; - other_trace_found = true; - } - } - if (other_trace_found) - { - other_trace_corner_approx = curr_other_trace_corner_approx; - other_trace_line = curr_other_trace_line; - prev_corner_side = curr_prev_corner_side; - other_prev_trace_line = curr_other_prev_trace_line; - } - } - } - else - { - return null; - } - } - - int new_line_count = trace_polyline.arr.length + 1; - int diff = 0; - if (skip_short_segment) - { - --new_line_count; - ++diff; - } - - if (acute_angle) - { - Direction new_line_dir; - if (prev_corner_side == Side.ON_THE_LEFT) - { - new_line_dir = other_trace_line.direction().turn_45_degree(6); - } - else - { - new_line_dir = other_trace_line.direction().turn_45_degree(2); - } - Line translate_line = Line.get_instance(curr_end_corner.to_float().round(), new_line_dir); - double translate_dist = (Limits.sqrt2 - 1) * this.curr_half_width; - double prev_corner_dist = Math.abs(translate_line.signed_distance(curr_prev_end_corner.to_float())); - double other_dist = Math.abs(translate_line.signed_distance(other_trace_corner_approx)); - translate_dist = Math.min(translate_dist, prev_corner_dist); - translate_dist = Math.min(translate_dist, other_dist); - if (translate_dist >= 0.99) - { - - translate_dist = Math.max(translate_dist - 1, 1); - if (translate_line.side_of(curr_prev_end_corner) == Side.ON_THE_LEFT) - { - translate_dist = -translate_dist; - } - Line add_line = translate_line.translate(translate_dist); - // constract the new trace polyline. - Line[] new_lines = new Line[new_line_count]; - for (int i = 0; i < trace_polyline.arr.length - 1; ++i) - { - new_lines[i] = trace_polyline.arr[i]; - } - new_lines[new_lines.length - 2] = add_line; - new_lines[new_lines.length - 1] = other_trace_line; - return new Polyline(new_lines); - } - } - else if (bend) - { - Line[] check_line_arr = new Line[new_line_count]; - for (int i = 0; i < check_line_arr.length - 2; ++i) - { - check_line_arr[i] = trace_polyline.arr[i + diff]; - } - check_line_arr[check_line_arr.length - 2] = other_trace_line; - check_line_arr[check_line_arr.length - 1] = other_prev_trace_line; - Line new_line = reposition_line(check_line_arr, check_line_arr.length - 5); - if (new_line != null) - { - Line [] new_lines = new Line[trace_polyline.arr.length]; - for (int i = 0; i < new_lines.length - 2; ++i) - { - new_lines[i] = trace_polyline.arr[i]; - } - new_lines[new_lines.length - 2] = new_line; - new_lines[new_lines.length - 1] = other_trace_line; - return new Polyline(new_lines); - } - } - return null; - } - - - private static double SKIP_LENGTH = 10.0; -} \ No newline at end of file +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + */ + +package board; + +import datastructures.Stoppable; +import geometry.planar.Limits; +import datastructures.Signum; + +import geometry.planar.Direction; +import geometry.planar.FloatPoint; +import geometry.planar.IntPoint; +import geometry.planar.Point; +import geometry.planar.Line; +import geometry.planar.Polyline; +import geometry.planar.Side; +import geometry.planar.TileShape; + +/** + * + * Auxiliary class containing internal functions for pulling any angle traces tight. + * + * + * @author Alfons Wirtz + */ + +class PullTightAlgoAnyAngle extends PullTightAlgo +{ + + PullTightAlgoAnyAngle(RoutingBoard p_board, int[] p_only_net_no_arr, Stoppable p_stoppable_thread, int p_time_limit, + Point p_keep_point, int p_keep_point_layer) + { + super(p_board, p_only_net_no_arr, p_stoppable_thread, p_time_limit, p_keep_point, p_keep_point_layer); + } + + Polyline pull_tight(Polyline p_polyline) + { + Polyline new_result = avoid_acid_traps(p_polyline); + Polyline prev_result = null; + while (new_result != prev_result) + { + if (is_stop_requested()) + { + break; + } + prev_result = new_result; + Polyline tmp = skip_segments_of_length_0(prev_result); + Polyline tmp0 = reduce_lines(tmp); + Polyline tmp1 = skip_lines(tmp0); + + // I intended to replace reduce_corners by the previous 2 + // functions, because with consecutive corners closer than + // 1 grid point reduce_corners may loop with smoothen_corners + // because of changing directions heavily. + // Unlike reduce_corners, the above 2 functions do not + // introduce new directions + + Polyline tmp2 = reduce_corners(tmp1); + Polyline tmp3 = reposition_lines(tmp2); + new_result = smoothen_corners(tmp3); + } + return new_result; + } + + + // tries to reduce the corner count of p_polyline by replacing two consecutive + // lines by a line through IntPoints near the previous corner and the next + // corner, if that is possible without clearance violation. + private Polyline reduce_corners(Polyline p_polyline) + { + if (p_polyline.arr.length < 4) + { + return p_polyline; + } + int last_index = p_polyline.arr.length - 4; + + Line [] new_lines = new Line [p_polyline.arr.length]; + new_lines[0] = p_polyline.arr[0]; + new_lines[1] = p_polyline.arr[1]; + + int new_line_index = 1; + + boolean polyline_changed = false; + + Line [] curr_lines = new Line[3]; + + for (int i = 0; i <= last_index; ++i) + { + boolean skip_line = false; + FloatPoint new_a = new_lines[new_line_index - 1].intersection_approx(new_lines[new_line_index]); + FloatPoint new_b = p_polyline.corner_approx(i + 2); + boolean in_clip_shape = curr_clip_shape == null || + curr_clip_shape.contains(new_a) && curr_clip_shape.contains(new_b) + && curr_clip_shape.contains(p_polyline.corner_approx(new_line_index)); + + if (in_clip_shape) + { + FloatPoint skip_corner = + new_lines[new_line_index].intersection_approx(p_polyline.arr[i + 2]); + curr_lines [1] = new Line(new_a.round(), new_b.round()); + boolean ok = true; + if (new_line_index == 1) + { + if (!(p_polyline.first_corner() instanceof IntPoint)) + { + // first corner must not be changed + ok = false; + } + else + { + Direction dir = curr_lines[1].direction(); + curr_lines[0] = + Line.get_instance(p_polyline.first_corner(), dir.turn_45_degree(2)); + } + } + else + { + curr_lines[0] = new_lines[new_line_index - 1]; + } + if (i == last_index) + { + if (!(p_polyline.last_corner() instanceof IntPoint)) + { + // last corner must not be changed + ok = false; + } + else + { + Direction dir = curr_lines[1].direction(); + curr_lines[2] = Line.get_instance(p_polyline.last_corner(), dir.turn_45_degree(2)); + } + } + else + { + curr_lines[2] = p_polyline.arr[i + 3]; + } + + + // check, if the intersection of curr_lines[0] and curr_lines[1] + // is near new_a and the intersection of curr_lines[0] and + // curr_lines[1] and curr_lines[2] is near new_b. + // There may be numerical stability proplems with + // near parallel lines. + + final double check_dist = 100; + if (ok) + { + FloatPoint check_is = curr_lines[0].intersection_approx(curr_lines[1]); + double dist = check_is.distance_square(new_a); + + if (dist > check_dist) + { + ok = false; + } + } + if (ok) + { + FloatPoint check_is = curr_lines[1].intersection_approx(curr_lines[2]); + double dist = check_is.distance_square(new_b); + if (dist > check_dist) + { + ok = false; + } + } + if (ok && i == 1 && !(p_polyline.first_corner() instanceof IntPoint)) + { + // There may be a connection to a trace. + // make shure that the second corner of the new polyline + // is on the same side of the trace as the third corner. (There may be splitting problems) + Point new_corner = curr_lines[0].intersection(curr_lines[1]); + if (new_corner.side_of(new_lines[0]) != p_polyline.corner(1).side_of(new_lines[0])) + { + ok = false; + } + } + if (ok && i == last_index - 1 && !(p_polyline.last_corner() instanceof IntPoint)) + { + // There may be a connection to a trace. + // make shure that the second last corner of the new polyline + // is on the same side of the trace as the third last corner (There may be splitting problems) + Point new_corner = curr_lines[1].intersection(curr_lines[2]); + if (new_corner.side_of(new_lines[0]) != + p_polyline.corner(p_polyline.corner_count() - 2).side_of(new_lines[0])) + { + ok = false; + } + } + Polyline curr_polyline = null; + if (ok) + { + curr_polyline = new Polyline(curr_lines); + if ( curr_polyline.arr.length != 3) + { + ok = false; + } + double length_before = skip_corner.distance(new_a) + + skip_corner.distance(new_b); + double length_after = curr_polyline.length_approx() + 1.5; + // 1.5 added because of possible inacurracy SQRT_2 + // by twice rounding. + if (length_after >= length_before) + // May happen from rounding to integer. + // Prevent infinite loop. + { + ok = false; + } + } + + if (ok) + { + TileShape shape_to_check = curr_polyline.offset_shape(curr_half_width, 0); + skip_line = board.check_trace_shape(shape_to_check, + curr_layer, curr_net_no_arr, curr_cl_type, this.contact_pins); + } + } + if (skip_line) + { + polyline_changed = true; + new_lines[new_line_index] = curr_lines[1]; + if (new_line_index == 1) + { + // make the first line perpendicular to the current line + new_lines[0] = curr_lines [0]; + } + if (i == last_index) + { + // make the last line perpendicular to the current line + ++new_line_index; + new_lines[new_line_index] = curr_lines[2]; + } + if (board.changed_area != null) + { + board.changed_area.join(new_a, curr_layer); + board.changed_area.join(new_b, curr_layer); + } + } + else + { + ++new_line_index; + new_lines[new_line_index] = p_polyline.arr[i + 2]; + if (i == last_index) + { + ++new_line_index; + new_lines[new_line_index] = p_polyline.arr[i + 3]; + } + } + if (new_lines[new_line_index].is_parallel(new_lines[new_line_index - 1])) + { + // skip line, if it is parallel to the previous one + --new_line_index; + } + } + if (!polyline_changed) + { + return p_polyline; + } + Line [] cleaned_new_lines = new Line [new_line_index + 1]; + System.arraycopy(new_lines, 0, cleaned_new_lines, 0, cleaned_new_lines.length); + Polyline result = new Polyline(cleaned_new_lines); + return result; + } + + /** + * tries to smoothen p_polyline by cutting of corners, if possible + */ + private Polyline smoothen_corners(Polyline p_polyline) + { + if (p_polyline.arr.length < 4) + { + return p_polyline; + } + boolean polyline_changed = false; + Line[] line_arr = new Line[p_polyline.arr.length]; + System.arraycopy(p_polyline.arr, 0, line_arr, 0, line_arr.length); + + for (int i = 0; i < line_arr.length - 3; ++i) + { + Line new_line = smoothen_corner(line_arr, i); + if (new_line != null) + { + polyline_changed = true; + // add the new line into the line array + Line[] tmp_lines = new Line[line_arr.length + 1]; + System.arraycopy(line_arr, 0, tmp_lines, 0, i + 2); + tmp_lines [i + 2] = new_line; + System.arraycopy(line_arr, i + 2, tmp_lines, i + 3, + tmp_lines.length - (i + 3)); + line_arr = tmp_lines; + ++i; + } + } + if (!polyline_changed) + { + return p_polyline; + } + return new Polyline(line_arr); + } + + /** + * tries to shorten p_polyline by relocating its lines + */ + Polyline reposition_lines(Polyline p_polyline) + { + if (p_polyline.arr.length < 5) + { + return p_polyline; + } + boolean polyline_changed = false; + Line[] line_arr = new Line[p_polyline.arr.length]; + System.arraycopy(p_polyline.arr, 0, line_arr, 0, line_arr.length); + for (int i = 0; i < line_arr.length - 4; ++i) + { + Line new_line = reposition_line(line_arr, i); + if (new_line != null) + { + polyline_changed = true; + line_arr [i + 2] = new_line; + if (line_arr[i + 2].is_parallel(line_arr[i + 1]) || + line_arr[i + 2].is_parallel(line_arr[i + 3])) + { + // calculation of corners not possible before skipping + // parallel lines + break; + } + } + } + if (!polyline_changed) + { + return p_polyline; + } + return new Polyline(line_arr); + } + + /** + * tries to reduce te number of lines of p_polyline by moving + * lines parallel beyond the intersection of the next or privious lines. + */ + private Polyline reduce_lines(Polyline p_polyline) + { + if (p_polyline.arr.length < 6) + { + return p_polyline; + } + boolean polyline_changed = false; + Line[] line_arr = p_polyline.arr; + for (int i = 2; i < line_arr.length - 2; ++i) + { + FloatPoint prev_corner = + line_arr[i - 2].intersection_approx( line_arr[i - 1]); + FloatPoint next_corner = + line_arr[i +1 ].intersection_approx( line_arr[i + 2]); + boolean in_clip_shape = curr_clip_shape == null || + curr_clip_shape.contains(prev_corner) && + curr_clip_shape.contains(next_corner); + if (!in_clip_shape) + { + continue; + } + Line translate_line = line_arr [i]; + double prev_dist = translate_line.signed_distance(prev_corner); + double next_dist = translate_line.signed_distance(next_corner); + if (Signum.of(prev_dist)!= Signum.of(next_dist)) + // the 2 corners are on different sides of the translate_line + { + continue; + } + double translate_dist; + if (Math.abs(prev_dist) < Math.abs(next_dist)) + { + + translate_dist = prev_dist; + } + else + { + translate_dist = next_dist; + } + if (translate_dist == 0) + { + //line segment may have length 0 + continue; + } + Side line_side = translate_line.side_of(prev_corner); + Line new_line = translate_line.translate(-translate_dist); + // make shure, we have crossed the nearest_corner; + int sign = Signum.as_int(translate_dist); + Side new_line_side_of_prev_corner = new_line.side_of(prev_corner); + Side new_line_side_of_next_corner = new_line.side_of(next_corner); + while (new_line_side_of_prev_corner == line_side && + new_line_side_of_next_corner == line_side) + { + translate_dist += sign * 0.5; + new_line = translate_line.translate(-translate_dist); + new_line_side_of_prev_corner = new_line.side_of(prev_corner); + new_line_side_of_next_corner = new_line.side_of(next_corner); + } + int crossed_corners_before_count = 0; + int crossed_corners_after_count = 0; + if (new_line_side_of_prev_corner != line_side) + { + ++crossed_corners_before_count; + } + if (new_line_side_of_next_corner != line_side) + { + ++crossed_corners_after_count; + } + // check, that we havent crossed both corners + if (crossed_corners_before_count > 1 || crossed_corners_after_count > 1) + { + continue; + } + // check, that next_nearest_corner and nearest_corner are on + // different sides of new_line; + if (crossed_corners_before_count > 0) + { + if (i < 3) + { + continue; + } + FloatPoint prev_prev_corner = + line_arr[i - 3].intersection_approx( line_arr[i - 2]); + if (new_line.side_of(prev_prev_corner) != line_side) + { + continue; + } + } + if (crossed_corners_after_count > 0) + { + if (i >= line_arr.length - 3) + { + continue; + } + FloatPoint next_next_corner = + line_arr[i + 2 ].intersection_approx( line_arr[i + 3]); + if (new_line.side_of(next_next_corner) != line_side) + { + continue; + } + } + Line [] curr_lines = new Line[line_arr.length - + crossed_corners_before_count - crossed_corners_after_count]; + int keep_before_ind = i - crossed_corners_before_count; + System.arraycopy(line_arr, 0, curr_lines, 0, keep_before_ind); + curr_lines [keep_before_ind] = new_line; + System.arraycopy(line_arr, i + 1 + crossed_corners_after_count, curr_lines, + keep_before_ind + 1, curr_lines.length - ( keep_before_ind + 1)); + Polyline tmp = new Polyline( curr_lines); + boolean check_ok = false; + if (tmp.arr.length == curr_lines.length) + { + TileShape shape_to_check = + tmp.offset_shape(curr_half_width, keep_before_ind - 1); + check_ok = board.check_trace_shape(shape_to_check, + curr_layer, curr_net_no_arr, curr_cl_type, this.contact_pins); + + } + if (check_ok) + { + if (board.changed_area != null) + { + board.changed_area.join(prev_corner, curr_layer); + board.changed_area.join(next_corner, curr_layer); + } + polyline_changed = true; + line_arr = curr_lines; + --i; + } + } + if (!polyline_changed) + { + return p_polyline; + } + return new Polyline(line_arr); + } + + + private Line smoothen_corner(Line[] p_line_arr, int p_start_no) + { + if ( p_line_arr.length - p_start_no < 4) + { + return null; + } + FloatPoint curr_corner = + p_line_arr[p_start_no + 1].intersection_approx(p_line_arr[p_start_no + 2]); + if (curr_clip_shape != null && + !curr_clip_shape.contains(curr_corner)) + { + return null; + } + double cosinus_angle = + p_line_arr[p_start_no + 1].cos_angle(p_line_arr[p_start_no + 2]); + if (cosinus_angle > c_max_cos_angle) + // lines are already nearly parallel, don't divide angle any further + // because of problems with numerical stability + { + return null; + } + FloatPoint prev_corner = + p_line_arr[p_start_no].intersection_approx( p_line_arr[p_start_no + 1]); + FloatPoint next_corner = + p_line_arr[p_start_no + 2].intersection_approx(p_line_arr[p_start_no + 3]); + + // create a line approximately through curr_corner, whose + // direction is about the middle of the directions of the + // previous and the next line. + // Translations of this line are used to cut off the corner. + Direction prev_dir = p_line_arr[p_start_no + 1].direction(); + Direction next_dir = p_line_arr[p_start_no + 2].direction(); + Direction middle_dir = prev_dir.middle_approx(next_dir); + Line translate_line = Line.get_instance(curr_corner.round(), middle_dir); + double prev_dist = translate_line.signed_distance(prev_corner); + double next_dist = translate_line.signed_distance(next_corner); + FloatPoint nearest_point; + double max_translate_dist; + if (Math.abs(prev_dist) < Math.abs(next_dist)) + { + nearest_point = prev_corner; + max_translate_dist = prev_dist; + } + else + { + nearest_point = next_corner; + max_translate_dist = next_dist; + } + if (Math.abs(max_translate_dist) < 1) + { + return null; + } + Line [] curr_lines = new Line[p_line_arr.length + 1]; + System.arraycopy(p_line_arr, 0, curr_lines, 0, p_start_no + 2); + System.arraycopy(p_line_arr, p_start_no + 2, curr_lines, + p_start_no + 3, curr_lines.length - p_start_no - 3); + double translate_dist = max_translate_dist; + double delta_dist = max_translate_dist; + Side side_of_nearest_point = translate_line.side_of(nearest_point); + int sign = Signum.as_int(max_translate_dist); + Line result = null; + while (Math.abs(delta_dist) > this.min_translate_dist) + { + boolean check_ok = false; + Line new_line = translate_line.translate(-translate_dist); + Side new_line_side_of_nearest_point = new_line.side_of(nearest_point); + if (new_line_side_of_nearest_point == side_of_nearest_point + || new_line_side_of_nearest_point == Side.COLLINEAR) + { + curr_lines [p_start_no + 2] = new_line; + Polyline tmp = new Polyline( curr_lines); + + if (tmp.arr.length == curr_lines.length) + { + TileShape shape_to_check = + tmp.offset_shape(curr_half_width, p_start_no + 1); + check_ok = board.check_trace_shape(shape_to_check, + curr_layer, curr_net_no_arr, curr_cl_type, this.contact_pins); + } + delta_dist /= 2; + if (check_ok) + { + result = curr_lines[p_start_no + 2]; + if (translate_dist == max_translate_dist) + { + // biggest possible change + break; + } + translate_dist += delta_dist; + } + else + { + translate_dist -= delta_dist; + } + } + else + // moved a little bit to far at the first time + // because of numerical inaccuracy + { + double shorten_value = sign * 0.5; + max_translate_dist -= shorten_value; + translate_dist -= shorten_value; + delta_dist -= shorten_value; + } + } + if (result == null) + { + return null; + } + + if (board.changed_area != null) + { + FloatPoint new_prev_corner = + curr_lines[p_start_no].intersection_approx( curr_lines[p_start_no + 1]); + FloatPoint new_next_corner = + curr_lines[p_start_no + 3].intersection_approx( curr_lines[p_start_no + 4]); + board.changed_area.join(new_prev_corner, curr_layer); + board.changed_area.join(new_next_corner, curr_layer); + } + return result; + } + + /** {@inheritDoc} */ + protected Line reposition_line(Line[] p_line_arr, int p_start_no) + { + if ( p_line_arr.length - p_start_no < 5) + { + return null; + } + if (curr_clip_shape != null) + // check, that the corners of the line to translate are inside + // the clip shape + { + for (int i = 1; i < 3; ++i) + { + FloatPoint curr_corner = + p_line_arr[p_start_no + i].intersection_approx(p_line_arr[p_start_no + i + 1]); + if(!curr_clip_shape.contains(curr_corner)) + { + return null; + } + } + } + Line translate_line = p_line_arr[p_start_no + 2]; + FloatPoint prev_corner = + p_line_arr[p_start_no].intersection_approx( p_line_arr[p_start_no + 1]); + FloatPoint next_corner = + p_line_arr[p_start_no + 3].intersection_approx(p_line_arr[p_start_no + 4]); + double prev_dist = translate_line.signed_distance(prev_corner); + int corners_skipped_before = 0; + int corners_skipped_after = 0; + final double c_epsilon = 0.001; + while (Math.abs(prev_dist) < c_epsilon) + // move also all lines trough the start corner of the line to translate + { + ++corners_skipped_before; + int curr_no = p_start_no - corners_skipped_before; + if (curr_no < 0) + // the first corner is on the line to translate + { + return null; + } + prev_corner = p_line_arr[curr_no].intersection_approx( p_line_arr[curr_no + 1]); + prev_dist = translate_line.signed_distance(prev_corner); + } + double next_dist = translate_line.signed_distance(next_corner); + while (Math.abs(next_dist) < c_epsilon) + // move also all lines trough the end corner of the line to translate + { + ++corners_skipped_after; + int curr_no = p_start_no + 3 + corners_skipped_after; + if (curr_no >= p_line_arr.length - 2) + // the last corner is on the line to translate + { + return null; + } + next_corner = p_line_arr[curr_no].intersection_approx( p_line_arr[curr_no + 1]); + next_dist = translate_line.signed_distance(next_corner); + } + if (Signum.of(prev_dist)!= Signum.of(next_dist)) + // the 2 corners are at different sides of translate_line + { + return null; + } + FloatPoint nearest_point; + double max_translate_dist; + if (Math.abs(prev_dist) < Math.abs(next_dist)) + { + nearest_point = prev_corner; + max_translate_dist = prev_dist; + } + else + { + nearest_point = next_corner; + max_translate_dist = next_dist; + } + Line [] curr_lines = new Line[p_line_arr.length]; + System.arraycopy(p_line_arr, 0, curr_lines, 0, p_start_no + 2); + System.arraycopy(p_line_arr, p_start_no + 3, + curr_lines, p_start_no + 3, curr_lines.length - p_start_no - 3); + double translate_dist = max_translate_dist; + double delta_dist = max_translate_dist; + Side side_of_nearest_point = translate_line.side_of(nearest_point); + int sign = Signum.as_int(max_translate_dist); + Line result = null; + boolean first_time = true; + while (first_time || Math.abs(delta_dist) > this.min_translate_dist) + { + boolean check_ok = false; + Line new_line = translate_line.translate(-translate_dist); + if (first_time && Math.abs(translate_dist) < 1) + { + if (new_line.equals(translate_line)) + { + // try the parallel line through the nearest_point + IntPoint rounded_nearest_point = nearest_point.round(); + if (nearest_point.distance(rounded_nearest_point.to_float()) + < Math.abs(translate_dist)) + { + new_line = Line.get_instance(rounded_nearest_point, + translate_line.direction()); + } + first_time = false; + } + if (new_line.equals(translate_line)) + { + return null; + } + } + Side new_line_side_of_nearest_point = new_line.side_of(nearest_point); + if (new_line_side_of_nearest_point == side_of_nearest_point + || new_line_side_of_nearest_point == Side.COLLINEAR) + { + first_time = false; + curr_lines [p_start_no + 2] = new_line; + // corners_skipped_before > 0 or corners_skipped_after > 0 + // happens very rarely. But this handling seems to be + // important because there are situations which no other + // tightening function can solve. For example when 3 ore more + // consecutive corners are equal. + Line prev_translated_line = new_line; + for (int i = 0; i < corners_skipped_before; ++i) + // Translate the previous lines onto or past the + // intersection of new_line with the first untranslated line. + { + int prev_line_no = p_start_no + 1 - corners_skipped_before; + FloatPoint curr_prev_corner = + prev_translated_line.intersection_approx(curr_lines[prev_line_no]); + Line curr_translate_line = p_line_arr [p_start_no + 1 - i]; + double curr_translate_dist = curr_translate_line.signed_distance(curr_prev_corner); + prev_translated_line = curr_translate_line.translate(-curr_translate_dist); + curr_lines[p_start_no + 1 - i] = prev_translated_line; + } + prev_translated_line = new_line; + for (int i = 0; i < corners_skipped_after; ++i) + // Translate the next lines onto or past the + // intersection of new_line with the first untranslated line. + { + int next_line_no = p_start_no + 3 + corners_skipped_after; + FloatPoint curr_next_corner = + prev_translated_line.intersection_approx(curr_lines[next_line_no]); + Line curr_translate_line = p_line_arr [p_start_no + 3 + i]; + double curr_translate_dist = curr_translate_line.signed_distance(curr_next_corner); + prev_translated_line = curr_translate_line.translate(-curr_translate_dist); + curr_lines[p_start_no + 3 + i] = prev_translated_line; + } + Polyline tmp = new Polyline( curr_lines); + + if (tmp.arr.length == curr_lines.length) + { + TileShape shape_to_check = + tmp.offset_shape(curr_half_width, p_start_no + 1); + check_ok = board.check_trace_shape(shape_to_check, + curr_layer, curr_net_no_arr, curr_cl_type, this.contact_pins); + + } + delta_dist /= 2; + if (check_ok) + { + result = curr_lines[p_start_no + 2]; + if (translate_dist == max_translate_dist) + { + // biggest possible change + break; + } + translate_dist += delta_dist; + } + else + { + translate_dist -= delta_dist; + } + } + else + // moved a little bit to far at the first time + // because of numerical inaccuracy + { + double shorten_value = sign * 0.5; + max_translate_dist -= shorten_value; + translate_dist -= shorten_value; + delta_dist -= shorten_value; + } + } + if (result == null) + { + return null; + } + + if (board.changed_area != null) + { + FloatPoint new_prev_corner = + curr_lines[p_start_no].intersection_approx( curr_lines[p_start_no + 1]); + FloatPoint new_next_corner = + curr_lines[p_start_no + 3].intersection_approx( curr_lines[p_start_no + 4]); + board.changed_area.join(new_prev_corner, curr_layer); + board.changed_area.join(new_next_corner, curr_layer); + } + return result; + } + + + private Polyline skip_lines(Polyline p_polyline) + { + for (int i = 1; i < p_polyline.arr.length - 3; ++i) + { + for (int j = 0; j <= 1; ++j) + { + FloatPoint corner1; + FloatPoint corner2; + Line curr_line; + if (j == 0) // try to skip the line before the i+2-th line + { + curr_line = p_polyline.arr[i + 2]; + corner1 = p_polyline.corner_approx(i); + corner2 = p_polyline.corner_approx(i - 1); + } + else // try to skip the line after i-th line + { + curr_line = p_polyline.arr[i]; + corner1 = p_polyline.corner_approx(i + 1); + corner2 = p_polyline.corner_approx(i + 2); + } + boolean in_clip_shape = curr_clip_shape == null || + curr_clip_shape.contains(corner1) && + curr_clip_shape.contains(corner2); + if (!in_clip_shape) + { + continue; + } + + Side side1 = curr_line.side_of(corner1); + Side side2 = curr_line.side_of(corner2); + if (side1 != side2) + // the two corners are on different sides of the line + { + Polyline reduced_polyline = p_polyline.skip_lines(i + 1, i + 1); + if (reduced_polyline.arr.length == p_polyline.arr.length - 1) + { + int shape_no = i - 1; + if (j == 0) + { + ++shape_no; + } + TileShape shape_to_check = + reduced_polyline.offset_shape(curr_half_width, shape_no); + if (board.check_trace_shape(shape_to_check, + curr_layer, curr_net_no_arr, curr_cl_type, this.contact_pins)) + { + if (board.changed_area != null) + { + board.changed_area.join(corner1, curr_layer); + board.changed_area.join(corner2, curr_layer); + } + return reduced_polyline; + } + } + } + // now try skipping 2 lines + if (i >= p_polyline.arr.length - 4) + { + break; + } + FloatPoint corner3; + if (j == 1) + { + corner3 = p_polyline.corner_approx(i + 3); + } + else + { + corner3 = p_polyline.corner_approx(i + 1); + } + if (curr_clip_shape != null && !curr_clip_shape.contains(corner3)) + { + continue; + } + if (j == 0) + // curr_line is 1 line later than in the case skipping 1 line + // when coming from behind + { + curr_line = p_polyline.arr[i + 3]; + side1 = curr_line.side_of(corner1); + side2 = curr_line.side_of(corner2); + } + else + { + side1 = curr_line.side_of(corner3); + } + if (side1 != side2) + // the two corners are on different sides of the line + { + Polyline reduced_polyline = p_polyline.skip_lines(i + 1, i + 2); + if (reduced_polyline.arr.length == p_polyline.arr.length - 2) + { + int shape_no = i - 1; + if (j == 0) + { + ++shape_no; + } + TileShape shape_to_check = + reduced_polyline.offset_shape(curr_half_width, shape_no); + if (board.check_trace_shape(shape_to_check, + curr_layer, curr_net_no_arr, curr_cl_type, this.contact_pins)) + { + if (board.changed_area != null) + { + board.changed_area.join(corner1, curr_layer); + board.changed_area.join(corner2, curr_layer); + board.changed_area.join(corner3, curr_layer); + } + return reduced_polyline; + } + } + } + + } + } + return p_polyline; + } + + Polyline smoothen_start_corner_at_trace(PolylineTrace p_trace) + { + boolean acute_angle = false; + boolean bend = false; + FloatPoint other_trace_corner_approx = null; + Line other_trace_line = null; + Line other_prev_trace_line = null; + Polyline trace_polyline = p_trace.polyline(); + Point curr_end_corner = trace_polyline.corner(0); + + if (this.curr_clip_shape != null && this.curr_clip_shape.is_outside(curr_end_corner)) + { + return null; + } + + Point curr_prev_end_corner = trace_polyline.corner(1); + boolean skip_short_segment = !(curr_end_corner instanceof IntPoint) && + curr_end_corner.to_float().distance_square(curr_prev_end_corner.to_float()) < SKIP_LENGTH; + int start_line_no = 1; + if (skip_short_segment) + { + if (trace_polyline.corner_count() < 3) + { + return null; + } + curr_prev_end_corner = trace_polyline.corner(2); + ++start_line_no; + } + Side prev_corner_side = null; + Direction line_direction = trace_polyline.arr[start_line_no].direction(); + Direction prev_line_direction = trace_polyline.arr[start_line_no + 1].direction(); + + java.util.Collection contact_list = p_trace.get_start_contacts(); + for (Item curr_contact : contact_list) + { + if (curr_contact instanceof PolylineTrace && !curr_contact.is_shove_fixed()) + { + Polyline contact_trace_polyline = ((PolylineTrace) curr_contact).polyline(); + FloatPoint curr_other_trace_corner_approx; + Line curr_other_trace_line; + Line curr_other_prev_trace_line; + if (contact_trace_polyline.first_corner().equals(curr_end_corner)) + { + curr_other_trace_corner_approx = contact_trace_polyline.corner_approx(1); + curr_other_trace_line = contact_trace_polyline.arr[1]; + curr_other_prev_trace_line = contact_trace_polyline.arr[2]; + } + else + { + int curr_corner_no = contact_trace_polyline.corner_count() - 2; + curr_other_trace_corner_approx = contact_trace_polyline.corner_approx(curr_corner_no); + curr_other_trace_line = contact_trace_polyline.arr[curr_corner_no + 1].opposite(); + curr_other_prev_trace_line = contact_trace_polyline.arr[curr_corner_no]; + } + Side curr_prev_corner_side = curr_prev_end_corner.side_of(curr_other_trace_line); + Signum curr_projection = line_direction.projection(curr_other_trace_line.direction()); + boolean other_trace_found = false; + if (curr_projection == Signum.POSITIVE && curr_prev_corner_side != Side.COLLINEAR) + { + acute_angle = true; + other_trace_found = true; + + } + else if (curr_projection == Signum.ZERO && trace_polyline.corner_count() > 2) + { + if (prev_line_direction.projection(curr_other_trace_line.direction()) == Signum.POSITIVE) + { + bend = true; + other_trace_found = true; + } + } + if (other_trace_found) + { + other_trace_corner_approx = curr_other_trace_corner_approx; + other_trace_line = curr_other_trace_line; + prev_corner_side = curr_prev_corner_side; + other_prev_trace_line = curr_other_prev_trace_line; + } + } + else + { + return null; + } + } + int new_line_count = trace_polyline.arr.length + 1; + int diff = 1; + if (skip_short_segment) + { + --new_line_count; + --diff; + } + if (acute_angle) + { + Direction new_line_dir; + if (prev_corner_side == Side.ON_THE_LEFT) + { + new_line_dir = other_trace_line.direction().turn_45_degree(2); + } + else + { + new_line_dir = other_trace_line.direction().turn_45_degree(6); + } + Line translate_line = Line.get_instance(curr_end_corner.to_float().round(), new_line_dir); + double translate_dist = (Limits.sqrt2 - 1) * this.curr_half_width; + double prev_corner_dist = Math.abs(translate_line.signed_distance(curr_prev_end_corner.to_float())); + double other_dist = Math.abs(translate_line.signed_distance(other_trace_corner_approx)); + translate_dist = Math.min(translate_dist, prev_corner_dist); + translate_dist = Math.min(translate_dist, other_dist); + if (translate_dist >= 0.99) + { + + translate_dist = Math.max(translate_dist - 1, 1); + if (translate_line.side_of(curr_prev_end_corner) == Side.ON_THE_LEFT) + { + translate_dist = -translate_dist; + } + Line add_line = translate_line.translate(translate_dist); + // constract the new trace polyline. + Line[] new_lines = new Line[new_line_count]; + new_lines[0] = other_trace_line; + new_lines[1] = add_line; + for (int i = 2; i < new_lines.length; ++i) + { + new_lines[i] = trace_polyline.arr[i - diff]; + } + return new Polyline(new_lines); + } + } + else if (bend) + { + Line[] check_line_arr = new Line[new_line_count]; + check_line_arr [0] = other_prev_trace_line; + check_line_arr [1] = other_trace_line; + for (int i = 2; i < check_line_arr.length; ++i) + { + check_line_arr [i] = trace_polyline.arr[i - diff]; + } + Line new_line = reposition_line(check_line_arr, 0); + if (new_line != null) + { + Line [] new_lines = new Line[trace_polyline.arr.length]; + new_lines[0] = other_trace_line; + new_lines[1] = new_line; + for (int i = 2; i < new_lines.length; ++i) + { + new_lines [i] = trace_polyline.arr[i]; + } + return new Polyline(new_lines); + } + } + return null; + } + + Polyline smoothen_end_corner_at_trace(PolylineTrace p_trace) + { + boolean acute_angle = false; + boolean bend = false; + FloatPoint other_trace_corner_approx = null; + Line other_trace_line = null; + Line other_prev_trace_line = null; + Polyline trace_polyline = p_trace.polyline(); + Point curr_end_corner = trace_polyline.last_corner(); + + if (this.curr_clip_shape != null && this.curr_clip_shape.is_outside(curr_end_corner)) + { + return null; + } + + Point curr_prev_end_corner = trace_polyline.corner(trace_polyline.corner_count() - 2); + boolean skip_short_segment = !(curr_end_corner instanceof IntPoint) && + curr_end_corner.to_float().distance_square(curr_prev_end_corner.to_float()) < SKIP_LENGTH; + int end_line_no = trace_polyline.arr.length - 2; + if (skip_short_segment) + { + if (trace_polyline.corner_count() < 3) + { + return null; + } + curr_prev_end_corner = trace_polyline.corner(trace_polyline.corner_count() - 3); + --end_line_no; + } + Side prev_corner_side = null; + Direction line_direction = trace_polyline.arr[end_line_no].direction().opposite(); + Direction prev_line_direction = trace_polyline.arr[end_line_no].direction().opposite(); + + java.util.Collection contact_list = p_trace.get_end_contacts(); + for (Item curr_contact : contact_list) + { + if (curr_contact instanceof PolylineTrace && !curr_contact.is_shove_fixed()) + { + Polyline contact_trace_polyline = ((PolylineTrace) curr_contact).polyline(); + if (contact_trace_polyline.corner_count() > 2) + { + FloatPoint curr_other_trace_corner_approx; + Line curr_other_trace_line; + Line curr_other_prev_trace_line; + if (contact_trace_polyline.first_corner().equals(curr_end_corner)) + { + curr_other_trace_corner_approx = contact_trace_polyline.corner_approx(1); + curr_other_trace_line = contact_trace_polyline.arr[1]; + curr_other_prev_trace_line = contact_trace_polyline.arr[2]; + } + else + { + int curr_corner_no = contact_trace_polyline.corner_count() - 2; + curr_other_trace_corner_approx = contact_trace_polyline.corner_approx(curr_corner_no); + curr_other_trace_line = contact_trace_polyline.arr[curr_corner_no + 1].opposite(); + curr_other_prev_trace_line = contact_trace_polyline.arr[curr_corner_no]; + } + Side curr_prev_corner_side = curr_prev_end_corner.side_of(curr_other_trace_line); + Signum curr_projection = line_direction.projection(curr_other_trace_line.direction()); + boolean other_trace_found = false; + if (curr_projection == Signum.POSITIVE && curr_prev_corner_side != Side.COLLINEAR) + { + acute_angle = true; + other_trace_found = true; + } + else if (curr_projection == Signum.ZERO && trace_polyline.corner_count() > 2) + { + if (prev_line_direction.projection(curr_other_trace_line.direction()) == Signum.POSITIVE) + { + bend = true; + other_trace_found = true; + } + } + if (other_trace_found) + { + other_trace_corner_approx = curr_other_trace_corner_approx; + other_trace_line = curr_other_trace_line; + prev_corner_side = curr_prev_corner_side; + other_prev_trace_line = curr_other_prev_trace_line; + } + } + } + else + { + return null; + } + } + + int new_line_count = trace_polyline.arr.length + 1; + int diff = 0; + if (skip_short_segment) + { + --new_line_count; + ++diff; + } + + if (acute_angle) + { + Direction new_line_dir; + if (prev_corner_side == Side.ON_THE_LEFT) + { + new_line_dir = other_trace_line.direction().turn_45_degree(6); + } + else + { + new_line_dir = other_trace_line.direction().turn_45_degree(2); + } + Line translate_line = Line.get_instance(curr_end_corner.to_float().round(), new_line_dir); + double translate_dist = (Limits.sqrt2 - 1) * this.curr_half_width; + double prev_corner_dist = Math.abs(translate_line.signed_distance(curr_prev_end_corner.to_float())); + double other_dist = Math.abs(translate_line.signed_distance(other_trace_corner_approx)); + translate_dist = Math.min(translate_dist, prev_corner_dist); + translate_dist = Math.min(translate_dist, other_dist); + if (translate_dist >= 0.99) + { + + translate_dist = Math.max(translate_dist - 1, 1); + if (translate_line.side_of(curr_prev_end_corner) == Side.ON_THE_LEFT) + { + translate_dist = -translate_dist; + } + Line add_line = translate_line.translate(translate_dist); + // constract the new trace polyline. + Line[] new_lines = new Line[new_line_count]; + for (int i = 0; i < trace_polyline.arr.length - 1; ++i) + { + new_lines[i] = trace_polyline.arr[i]; + } + new_lines[new_lines.length - 2] = add_line; + new_lines[new_lines.length - 1] = other_trace_line; + return new Polyline(new_lines); + } + } + else if (bend) + { + Line[] check_line_arr = new Line[new_line_count]; + for (int i = 0; i < check_line_arr.length - 2; ++i) + { + check_line_arr[i] = trace_polyline.arr[i + diff]; + } + check_line_arr[check_line_arr.length - 2] = other_trace_line; + check_line_arr[check_line_arr.length - 1] = other_prev_trace_line; + Line new_line = reposition_line(check_line_arr, check_line_arr.length - 5); + if (new_line != null) + { + Line [] new_lines = new Line[trace_polyline.arr.length]; + for (int i = 0; i < new_lines.length - 2; ++i) + { + new_lines[i] = trace_polyline.arr[i]; + } + new_lines[new_lines.length - 2] = new_line; + new_lines[new_lines.length - 1] = other_trace_line; + return new Polyline(new_lines); + } + } + return null; + } + + + private static double SKIP_LENGTH = 10.0; +} diff --git a/board/RoutingBoard.java b/src/main/java/board/RoutingBoard.java similarity index 86% rename from board/RoutingBoard.java rename to src/main/java/board/RoutingBoard.java index 651e0f3..0ffc4e3 100644 --- a/board/RoutingBoard.java +++ b/src/main/java/board/RoutingBoard.java @@ -1,1403 +1,1580 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - */ -package board; - -import geometry.planar.FloatPoint; -import geometry.planar.IntBox; -import geometry.planar.IntOctagon; -import geometry.planar.IntPoint; -import geometry.planar.LineSegment; -import geometry.planar.Point; -import geometry.planar.Polyline; -import geometry.planar.PolylineShape; -import geometry.planar.TileShape; -import geometry.planar.Vector; - -import java.util.Collection; -import java.util.Iterator; -import java.util.Set; -import java.util.SortedSet; -import java.util.TreeSet; - -import datastructures.UndoableObjects; -import datastructures.Stoppable; -import datastructures.TimeLimit; -import datastructures.ShapeTree.TreeEntry; - -import rules.ViaInfo; -import rules.BoardRules; - -import autoroute.AutorouteControl; -import autoroute.AutorouteEngine; -import autoroute.AutorouteControl.ExpansionCostFactor; -import autoroute.CompleteFreeSpaceExpansionRoom; - -/** - * - * Contains higher level functions of a board - * - * @author Alfons Wirtz - */ -public class RoutingBoard extends BasicBoard implements java.io.Serializable -{ - - /** - * Creates a new instance of a routing Board with surrrounding box - * p_bounding_box - * Rules contains the restrictions to obey when inserting items. - * Among other things it may contain a clearance matrix. - */ - public RoutingBoard(IntBox p_bounding_box, LayerStructure p_layer_structure, PolylineShape[] p_outline_shapes, - int p_outline_cl_class_no, BoardRules p_rules, Communication p_board_communication, TestLevel p_test_level) - { - super(p_bounding_box, p_layer_structure, p_outline_shapes, p_outline_cl_class_no, - p_rules, p_board_communication, p_test_level); - } - - /** - * Maintains the autorouter database after p_item is inserted, changed, or deleted. - */ - public void additional_update_after_change(Item p_item) - { - if (p_item == null) - { - return; - } - if (this.autoroute_engine == null || !this.autoroute_engine.maintain_database) - { - return; - } - // Invalidate the free space expansion rooms touching a shape of p_item. - int shape_count = p_item.tree_shape_count(this.autoroute_engine.autoroute_search_tree); - for (int i = 0; i < shape_count; ++i) - { - TileShape curr_shape = p_item.get_tree_shape(this.autoroute_engine.autoroute_search_tree, i); - this.autoroute_engine.invalidate_drill_pages(curr_shape); - int curr_layer = p_item.shape_layer(i); - Collection overlaps = - this.autoroute_engine.autoroute_search_tree.overlapping_objects(curr_shape, curr_layer); - for (SearchTreeObject curr_object : overlaps) - { - if (curr_object instanceof CompleteFreeSpaceExpansionRoom) - { - this.autoroute_engine.remove_complete_expansion_room((CompleteFreeSpaceExpansionRoom) curr_object); - } - } - } - p_item.clear_autoroute_info(); - } - - /** - * Removes the items in p_item_list and pulls the nearby rubbertraces tight. - * Returns false, if some items could not be removed, because they were fixed. - */ - public boolean remove_items_and_pull_tight(Collection p_item_list, int p_tidy_width, - int p_pull_tight_accuracy, boolean p_with_delete_fixed) - { - boolean result = true; - IntOctagon tidy_region; - boolean calculate_tidy_region; - if (p_tidy_width < Integer.MAX_VALUE) - { - tidy_region = IntOctagon.EMPTY; - calculate_tidy_region = (p_tidy_width > 0); - } - else - { - tidy_region = null; - calculate_tidy_region = false; - } - start_marking_changed_area(); - Set changed_nets = new TreeSet(); - Iterator it = p_item_list.iterator(); - while (it.hasNext()) - { - Item curr_item = it.next(); - if (!p_with_delete_fixed && curr_item.is_delete_fixed() || curr_item.is_user_fixed()) - { - result = false; - } - else - { - for (int i = 0; i < curr_item.tile_shape_count(); ++i) - { - TileShape curr_shape = curr_item.get_tile_shape(i); - changed_area.join(curr_shape, curr_item.shape_layer(i)); - if (calculate_tidy_region) - { - tidy_region = tidy_region.union(curr_shape.bounding_octagon()); - } - } - remove_item(curr_item); - for (int i = 0; i < curr_item.net_count(); ++i) - { - changed_nets.add(curr_item.get_net_no(i)); - } - } - } - for (Integer curr_net_no : changed_nets) - { - this.combine_traces(curr_net_no); - } - if (calculate_tidy_region) - { - tidy_region = tidy_region.enlarge(p_tidy_width); - } - opt_changed_area(new int[0], tidy_region, p_pull_tight_accuracy, null, null, PULL_TIGHT_TIME_LIMIT); - return result; - } - - /** - * starts marking the changed areas for optimizing traces - */ - public void start_marking_changed_area() - { - if (changed_area == null) - { - changed_area = new ChangedArea(get_layer_count()); - } - } - - /** - * enlarges the changed area on p_layer, so that it contains p_point - */ - public void join_changed_area(FloatPoint p_point, int p_layer) - { - if (changed_area != null) - { - changed_area.join(p_point, p_layer); - } - } - - /** - * marks the whole board as changed - */ - public void mark_all_changed_area() - { - start_marking_changed_area(); - FloatPoint[] board_corners = new FloatPoint[4]; - board_corners[0] = bounding_box.ll.to_float(); - board_corners[1] = new FloatPoint(bounding_box.ur.x, bounding_box.ll.y); - board_corners[2] = bounding_box.ur.to_float(); - board_corners[3] = new FloatPoint(bounding_box.ll.x, bounding_box.ur.y); - for (int i = 0; i < get_layer_count(); ++i) - { - for (int j = 0; j < 4; ++j) - { - join_changed_area(board_corners[j], i); - } - } - } - - /** - * Optimizes the route in the internally marked area. - * If p_net_no > 0, only traces with net number p_net_no are optimized. - * If p_clip_shape != null the optimizing is restricted to p_clip_shape. - * p_trace_cost_arr is used for optimizing vias and may be null. - * If p_stoppable_thread != null, the agorithm can be requested to be stopped. - * If p_time_limit > 0; the algorithm will be stopped after p_time_limit Milliseconds. - */ - public void opt_changed_area(int[] p_only_net_no_arr, IntOctagon p_clip_shape, int p_accuracy, ExpansionCostFactor[] p_trace_cost_arr, - Stoppable p_stoppable_thread, int p_time_limit) - { - opt_changed_area(p_only_net_no_arr, p_clip_shape, p_accuracy, p_trace_cost_arr, - p_stoppable_thread, p_time_limit, null, 0); - } - - /** - * Optimizes the route in the internally marked area. - * If p_net_no > 0, only traces with net number p_net_no are optimized. - * If p_clip_shape != null the optimizing is restricted to p_clip_shape. - * p_trace_cost_arr is used for optimizing vias and may be null. - * If p_stoppable_thread != null, the agorithm can be requested to be stopped. - * If p_time_limit > 0; the algorithm will be stopped after p_time_limit Milliseconds. - * If p_keep_point != null, traces on layer p_keep_point_layer containing p_keep_point - * will also contain this point after optimizing. - */ - public void opt_changed_area(int[] p_only_net_no_arr, IntOctagon p_clip_shape, int p_accuracy, ExpansionCostFactor[] p_trace_cost_arr, - Stoppable p_stoppable_thread, int p_time_limit, Point p_keep_point, int p_keep_point_layer) - { - if (changed_area == null) - { - return; - } - if (p_clip_shape != IntOctagon.EMPTY) - { - PullTightAlgo pull_tight_algo = - PullTightAlgo.get_instance(this, p_only_net_no_arr, p_clip_shape, - p_accuracy, p_stoppable_thread, p_time_limit, p_keep_point, p_keep_point_layer); - pull_tight_algo.opt_changed_area(p_trace_cost_arr); - } - join_graphics_update_box(changed_area.surrounding_box()); - changed_area = null; - } - - /** - * Checks if a rectangular boxed trace line segment with the input parameters can - * be inserted without conflict. If a conflict exists, - * The result length is the maximal line length from p_line.a to p_line.b, - * which can be inserted without conflict (Integer.MAX_VALUE, if no conflict exists). - * If p_only_not_shovable_obstacles, unfixed traces and vias are ignored. - */ - public double check_trace_segment(Point p_from_point, Point p_to_point, int p_layer, int[] p_net_no_arr, - int p_trace_half_width, int p_cl_class_no, boolean p_only_not_shovable_obstacles) - { - if (p_from_point.equals(p_to_point)) - { - return 0; - } - Polyline curr_polyline = new Polyline(p_from_point, p_to_point); - LineSegment curr_line_segment = new LineSegment(curr_polyline, 1); - return check_trace_segment(curr_line_segment, p_layer, p_net_no_arr, - p_trace_half_width, p_cl_class_no, p_only_not_shovable_obstacles); - } - - /** - * Checks if a trace shape around the input parameters can - * be inserted without conflict. If a conflict exists, - * The result length is the maximal line length from p_line.a to p_line.b, - * which can be inserted without conflict (Integer.MAX_VALUE, if no conflict exists). - * If p_only_not_shovable_obstacles, unfixed traces and vias are ignored. - */ - public double check_trace_segment(LineSegment p_line_segment, int p_layer, int[] p_net_no_arr, - int p_trace_half_width, int p_cl_class_no, boolean p_only_not_shovable_obstacles) - { - Polyline check_polyline = p_line_segment.to_polyline(); - if (check_polyline.arr.length != 3) - { - return 0; - } - TileShape shape_to_check = check_polyline.offset_shape(p_trace_half_width, 0); - FloatPoint from_point = p_line_segment.start_point_approx(); - FloatPoint to_point = p_line_segment.end_point_approx(); - double line_length = to_point.distance(from_point); - double ok_length = Integer.MAX_VALUE; - ShapeSearchTree default_tree = this.search_tree_manager.get_default_tree(); - - Collection obstacle_entries = default_tree.overlapping_tree_entries_with_clearance(shape_to_check, p_layer, p_net_no_arr, p_cl_class_no); - - for (TreeEntry curr_obstacle_entry : obstacle_entries) - { - - if (!(curr_obstacle_entry.object instanceof Item)) - { - continue; - } - Item curr_obstacle = (Item) curr_obstacle_entry.object; - if (p_only_not_shovable_obstacles && curr_obstacle.is_route() && !curr_obstacle.is_shove_fixed()) - { - continue; - } - TileShape curr_obstacle_shape = curr_obstacle_entry.object.get_tree_shape(default_tree, curr_obstacle_entry.shape_index_in_object); - TileShape curr_offset_shape; - FloatPoint nearest_obstacle_point; - double shorten_value; - if (default_tree.is_clearance_compensation_used()) - { - curr_offset_shape = shape_to_check; - shorten_value = p_trace_half_width + rules.clearance_matrix.clearance_compensation_value(curr_obstacle.clearance_class_no(), p_layer); - } - else - { - int clearance_value = this.clearance_value(curr_obstacle.clearance_class_no(), p_cl_class_no, p_layer); - curr_offset_shape = (TileShape) shape_to_check.offset(clearance_value); - shorten_value = p_trace_half_width + clearance_value; - } - TileShape intersection = curr_obstacle_shape.intersection(curr_offset_shape); - if (intersection.is_empty()) - { - continue; - } - nearest_obstacle_point = intersection.nearest_point_approx(from_point); - - double projection = from_point.scalar_product(to_point, nearest_obstacle_point) / line_length; - - projection = Math.max(0.0, projection - shorten_value - 1); - - if (projection < ok_length) - { - ok_length = projection; - if (ok_length <= 0) - { - return 0; - } - } - } - - return ok_length; - } - - /** - * Checks, if p_item can be translated by p_vector without - * producing overlaps or clearance violations. - */ - public boolean check_move_item(Item p_item, Vector p_vector, Collection p_ignore_items) - { - int net_count = p_item.net_no_arr.length; - if (net_count > 1) - { - return false; //not yet implemented - } - int contact_count = 0; - // the connected items must remain connected after moving - if (p_item instanceof Connectable) - { - contact_count = p_item.get_all_contacts().size(); - } - if (p_item instanceof Trace && contact_count > 0) - { - return false; - } - if (p_ignore_items != null) - { - p_ignore_items.add(p_item); - } - for (int i = 0; i < p_item.tile_shape_count(); ++i) - { - TileShape moved_shape = (TileShape) p_item.get_tile_shape(i).translate_by(p_vector); - if (!moved_shape.is_contained_in(bounding_box)) - { - return false; - } - Set obstacles = - this.overlapping_items_with_clearance(moved_shape, p_item.shape_layer(i), p_item.net_no_arr, - p_item.clearance_class_no()); - for (Item curr_item : obstacles) - { - if (p_ignore_items != null) - { - if (!p_ignore_items.contains(curr_item)) - { - if (curr_item.is_obstacle(p_item)) - { - return false; - } - } - } - else if (curr_item != p_item) - { - if (curr_item.is_obstacle(p_item)) - { - return false; - } - } - } - } - return true; - } - - /** - * Checks, if the net number of p_item can be changed without producing clearance violations. - */ - public boolean check_change_net(Item p_item, int p_new_net_no) - { - int[] net_no_arr = new int[1]; - net_no_arr[0] = p_new_net_no; - for (int i = 0; i < p_item.tile_shape_count(); ++i) - { - TileShape curr_shape = p_item.get_tile_shape(i); - Set obstacles = - this.overlapping_items_with_clearance(curr_shape, p_item.shape_layer(i), - net_no_arr, p_item.clearance_class_no()); - for (SearchTreeObject curr_ob : obstacles) - { - if (curr_ob != p_item && curr_ob instanceof Connectable && !((Connectable) curr_ob).contains_net(p_new_net_no)) - { - return false; - } - } - } - return true; - } - - /** - * Translates p_drill_item by p_vector and shoves obstacle - * traces aside. Returns false, if that was not possible without creating - * clearance violations. In this case the database may be damaged, so that an undo - * becomes necessesary. - */ - public boolean move_drill_item(DrillItem p_drill_item, Vector p_vector, - int p_max_recursion_depth, int p_max_via_recursion_depth, - int p_tidy_width, int p_pull_tight_accuracy, int p_pull_tight_time_limit) - { - clear_shove_failing_obstacle(); - // unfix the connected shove fixed traces. - Collection contact_list = p_drill_item.get_normal_contacts(); - Iterator it = contact_list.iterator(); - while (it.hasNext()) - { - Item curr_contact = it.next(); - if (curr_contact.get_fixed_state() == FixedState.SHOVE_FIXED) - { - curr_contact.set_fixed_state(FixedState.UNFIXED); - } - } - - IntOctagon tidy_region; - boolean calculate_tidy_region; - if (p_tidy_width < Integer.MAX_VALUE) - { - tidy_region = IntOctagon.EMPTY; - calculate_tidy_region = (p_tidy_width > 0); - } - else - { - tidy_region = null; - calculate_tidy_region = false; - } - int[] net_no_arr = p_drill_item.net_no_arr; - start_marking_changed_area(); - if (!MoveDrillItemAlgo.insert(p_drill_item, p_vector, - p_max_recursion_depth, p_max_via_recursion_depth, tidy_region, this)) - { - return false; - } - if (calculate_tidy_region) - { - tidy_region = tidy_region.enlarge(p_tidy_width); - } - int[] opt_net_no_arr; - if (p_max_recursion_depth <= 0) - { - opt_net_no_arr = net_no_arr; - } - else - { - opt_net_no_arr = new int[0]; - } - opt_changed_area(opt_net_no_arr, tidy_region, p_pull_tight_accuracy, null, null, p_pull_tight_time_limit); - return true; - } - - /** - * Checks, if there is an item near by sharing a net with p_net_no_arr, from where a routing can start, - * or where the routig can connect to. - * If p_from_item != null, items, which are connected to p_from_item, are - * ignored. - * Returns null, if no item is found, - * If p_layer < 0, the layer is ignored - */ - public Item pick_nearest_routing_item(Point p_location, int p_layer, Item p_from_item) - { - TileShape point_shape = TileShape.get_instance(p_location); - Collection found_items = overlapping_items(point_shape, p_layer); - FloatPoint pick_location = p_location.to_float(); - double min_dist = Integer.MAX_VALUE; - Item nearest_item = null; - Set ignore_set = null; - Iterator it = found_items.iterator(); - while (it.hasNext()) - { - Item curr_item = it.next(); - if (!curr_item.is_connectable()) - { - continue; - } - boolean candidate_found = false; - double curr_dist = 0; - if (curr_item instanceof PolylineTrace) - { - PolylineTrace curr_trace = (PolylineTrace) curr_item; - if (p_layer < 0 || curr_trace.get_layer() == p_layer) - { - if (nearest_item instanceof DrillItem) - { - continue; // prefer drill items - } - int trace_radius = curr_trace.get_half_width(); - curr_dist = curr_trace.polyline().distance(pick_location); - if (curr_dist < min_dist && curr_dist <= trace_radius) - { - candidate_found = true; - } - } - } - else if (curr_item instanceof DrillItem) - { - DrillItem curr_drill_item = (DrillItem) curr_item; - if (p_layer < 0 || curr_drill_item.is_on_layer(p_layer)) - { - FloatPoint drill_item_center = curr_drill_item.get_center().to_float(); - curr_dist = drill_item_center.distance(pick_location); - if (curr_dist < min_dist || nearest_item instanceof Trace) - { - candidate_found = true; - } - } - } - else if (curr_item instanceof ConductionArea) - { - ConductionArea curr_area = (ConductionArea) curr_item; - if ((p_layer < 0 || curr_area.get_layer() == p_layer) && nearest_item == null) - { - candidate_found = true; - curr_dist = Integer.MAX_VALUE; - } - } - if (candidate_found) - { - if (p_from_item != null) - { - if (ignore_set == null) - { - // calculated here to avoid unnessery calculations for performance reasoss. - ignore_set = p_from_item.get_connected_set(-1); - } - if (ignore_set.contains(curr_item)) - { - continue; - } - } - min_dist = curr_dist; - nearest_item = curr_item; - } - } - return nearest_item; - } - - /** - * Shoves aside traces, so that a via with the input parameters can be - * inserted without clearance violations. If the shove failed, the database may be damaged, so that an undo - * becomes necessesary. Returns false, if the forced via failed. - */ - public boolean forced_via(ViaInfo p_via_info, Point p_location, int[] p_net_no_arr, - int p_trace_clearance_class_no, int[] p_trace_pen_halfwidth_arr, - int p_max_recursion_depth, int p_max_via_recursion_depth, - int p_tidy_width, int p_pull_tight_accuracy, int p_pull_tight_time_limit) - { - clear_shove_failing_obstacle(); - this.start_marking_changed_area(); - boolean result = ForcedViaAlgo.insert(p_via_info, p_location, p_net_no_arr, - p_trace_clearance_class_no, p_trace_pen_halfwidth_arr, - p_max_recursion_depth, p_max_via_recursion_depth, this); - if (result) - { - IntOctagon tidy_clip_shape; - if (p_tidy_width < Integer.MAX_VALUE) - { - tidy_clip_shape = p_location.surrounding_octagon().enlarge(p_tidy_width); - } - else - { - tidy_clip_shape = null; - } - int[] opt_net_no_arr; - if (p_max_recursion_depth <= 0) - { - opt_net_no_arr = p_net_no_arr; - } - else - { - opt_net_no_arr = new int[0]; - } - this.opt_changed_area(opt_net_no_arr, tidy_clip_shape, - p_pull_tight_accuracy, null, null, p_pull_tight_time_limit); - } - return result; - } - - /** - * Tries to insert a trace line with the input parameters from - * p_from_corner to p_to_corner while shoving aside obstacle traces - * and vias. Returns the last point between p_from_corner and p_to_corner, - * to which the shove succeeded. - * Returns null, if the check was inaccurate and an error accured while - * inserting, so that the database may be damaged and an undo necessary. - * p_search_tree is the shape search tree used in the algorithm. - */ - public Point insert_forced_trace_segment(Point p_from_corner, - Point p_to_corner, int p_half_width, int p_layer, int[] p_net_no_arr, - int p_clearance_class_no, int p_max_recursion_depth, int p_max_via_recursion_depth, - int p_max_spring_over_recursion_depth, int p_tidy_width, - int p_pull_tight_accuracy, boolean p_with_check, TimeLimit p_time_limit) - { - if (p_from_corner.equals(p_to_corner)) - { - return p_to_corner; - } - Polyline insert_polyline = new Polyline(p_from_corner, p_to_corner); - Point ok_point = insert_forced_trace_polyline(insert_polyline, p_half_width, p_layer, p_net_no_arr, - p_clearance_class_no, p_max_recursion_depth, p_max_via_recursion_depth, - p_max_spring_over_recursion_depth, p_tidy_width, - p_pull_tight_accuracy, p_with_check, p_time_limit); - Point result; - if (ok_point == insert_polyline.first_corner()) - { - result = p_from_corner; - } - else if (ok_point == insert_polyline.last_corner()) - { - result = p_to_corner; - } - else - { - result = ok_point; - } - return result; - } - - /** - * Checks, if a trace polyline with the input parameters can be inserted - * while shoving aside obstacle traces and vias. - */ - public boolean check_forced_trace_polyline(Polyline p_polyline, int p_half_width, int p_layer, int[] p_net_no_arr, - int p_clearance_class_no, int p_max_recursion_depth, int p_max_via_recursion_depth, - int p_max_spring_over_recursion_depth) - { - ShapeSearchTree search_tree = search_tree_manager.get_default_tree(); - int compensated_half_width = p_half_width + search_tree.clearance_compensation_value(p_clearance_class_no, p_layer); - TileShape[] trace_shapes = p_polyline.offset_shapes(compensated_half_width, - 0, p_polyline.arr.length - 1); - boolean orthogonal_mode = (rules.get_trace_angle_restriction() == AngleRestriction.NINETY_DEGREE); - ShoveTraceAlgo shove_trace_algo = new ShoveTraceAlgo(this); - for (int i = 0; i < trace_shapes.length; ++i) - { - TileShape curr_trace_shape = trace_shapes[i]; - if (orthogonal_mode) - { - curr_trace_shape = curr_trace_shape.bounding_box(); - } - CalcFromSide from_side = new CalcFromSide(p_polyline, i + 1, curr_trace_shape); - - boolean check_shove_ok = shove_trace_algo.check(curr_trace_shape, from_side, null, p_layer, - p_net_no_arr, p_clearance_class_no, p_max_recursion_depth, - p_max_via_recursion_depth, p_max_spring_over_recursion_depth, null); - if (!check_shove_ok) - { - return false; - } - } - return true; - } - - /** - * Tries to insert a trace polyline with the input parameters from - * while shoving aside obstacle traces and vias. Returns the last corner - * on the polyline, to which the shove succeeded. - * Returns null, if the check was inaccurate and an error accured while - * inserting, so that the database may be damaged and an undo necessary. - */ - public Point insert_forced_trace_polyline(Polyline p_polyline, int p_half_width, int p_layer, int[] p_net_no_arr, - int p_clearance_class_no, int p_max_recursion_depth, int p_max_via_recursion_depth, - int p_max_spring_over_recursion_depth, int p_tidy_width, - int p_pull_tight_accuracy, boolean p_with_check, TimeLimit p_time_limit) - { - clear_shove_failing_obstacle(); - Point from_corner = p_polyline.first_corner(); - Point to_corner = p_polyline.last_corner(); - if (from_corner.equals(to_corner)) - { - return to_corner; - } - if (!(from_corner instanceof IntPoint && to_corner instanceof IntPoint)) - { - System.out.println("RoutingBoard.insert_forced_trace_segment: only implemented for IntPoints"); - return from_corner; - } - start_marking_changed_area(); - // Check, if there ends a item of the same net at p_from_corner. - // If so, its geometry will be used to cut off dog ears of the check shape. - Trace picked_trace = null; - ItemSelectionFilter filter = new ItemSelectionFilter(ItemSelectionFilter.SelectableChoices.TRACES); - Set picked_items = this.pick_items(from_corner, p_layer, filter); - if (picked_items.size() == 1) - { - Trace curr_picked_trace = (Trace) picked_items.iterator().next(); - if (curr_picked_trace.nets_equal(p_net_no_arr) && curr_picked_trace.get_half_width() == p_half_width && curr_picked_trace.clearance_class_no() == p_clearance_class_no && (curr_picked_trace instanceof PolylineTrace)) - { - // can combine with the picked trace - picked_trace = curr_picked_trace; - } - } - ShapeSearchTree search_tree = search_tree_manager.get_default_tree(); - int compensated_half_width = p_half_width + search_tree.clearance_compensation_value(p_clearance_class_no, p_layer); - ShoveTraceAlgo shove_trace_algo = new ShoveTraceAlgo(this); - Polyline new_polyline = shove_trace_algo.spring_over_obstacles(p_polyline, - compensated_half_width, p_layer, p_net_no_arr, p_clearance_class_no, null); - if (new_polyline == null) - { - return from_corner; - } - Polyline combined_polyline; - if (picked_trace == null) - { - combined_polyline = new_polyline; - } - else - { - PolylineTrace combine_trace = (PolylineTrace) picked_trace; - combined_polyline = new_polyline.combine(combine_trace.polyline()); - } - if (combined_polyline.arr.length < 3) - { - return from_corner; - } - int start_shape_no = combined_polyline.arr.length - new_polyline.arr.length; - // calculate the last shapes of combined_polyline for checking - TileShape[] trace_shapes = combined_polyline.offset_shapes(compensated_half_width, - start_shape_no, combined_polyline.arr.length - 1); - int last_shape_no = trace_shapes.length; - boolean orthogonal_mode = (rules.get_trace_angle_restriction() == AngleRestriction.NINETY_DEGREE); - for (int i = 0; i < trace_shapes.length; ++i) - { - TileShape curr_trace_shape = trace_shapes[i]; - if (orthogonal_mode) - { - curr_trace_shape = curr_trace_shape.bounding_box(); - } - CalcFromSide from_side = new CalcFromSide(combined_polyline, - combined_polyline.corner_count() - trace_shapes.length - 1 + i, curr_trace_shape); - if (p_with_check) - { - boolean check_shove_ok = shove_trace_algo.check(curr_trace_shape, from_side, null, p_layer, - p_net_no_arr, p_clearance_class_no, p_max_recursion_depth, - p_max_via_recursion_depth, p_max_spring_over_recursion_depth, p_time_limit); - if (!check_shove_ok) - { - last_shape_no = i; - break; - } - } - boolean insert_ok = shove_trace_algo.insert(curr_trace_shape, from_side, p_layer, p_net_no_arr, - p_clearance_class_no, null, p_max_recursion_depth, - p_max_via_recursion_depth, p_max_spring_over_recursion_depth); - if (!insert_ok) - { - return null; - } - } - Point new_corner = to_corner; - if (last_shape_no < trace_shapes.length) - { - // the shove with index last_shape_no failed. - // Sample the shove line to a shorter shove distance and try again. - TileShape last_trace_shape = trace_shapes[last_shape_no]; - if (orthogonal_mode) - { - last_trace_shape = last_trace_shape.bounding_box(); - } - int sample_width = 2 * this.get_min_trace_half_width(); - FloatPoint last_corner = new_polyline.corner_approx(last_shape_no + 1); - FloatPoint prev_last_corner = new_polyline.corner_approx(last_shape_no); - double last_segment_length = last_corner.distance(prev_last_corner); - if (last_segment_length > 100 * sample_width) - { - // to many cycles to sample - return from_corner; - } - int shape_index = combined_polyline.corner_count() - trace_shapes.length - 1 + last_shape_no; - if (last_segment_length > sample_width) - { - new_polyline = - new_polyline.shorten(new_polyline.arr.length - (trace_shapes.length - last_shape_no - 1), sample_width); - Point curr_last_corner = new_polyline.last_corner(); - if (!(curr_last_corner instanceof IntPoint)) - { - System.out.println("insert_forced_trace_segment: IntPoint expected"); - return from_corner; - } - new_corner = curr_last_corner; - if (picked_trace == null) - { - combined_polyline = new_polyline; - } - else - { - PolylineTrace combine_trace = (PolylineTrace) picked_trace; - combined_polyline = new_polyline.combine(combine_trace.polyline()); - } - if (combined_polyline.arr.length < 3) - { - return new_corner; - } - shape_index = combined_polyline.arr.length - 3; - last_trace_shape = combined_polyline.offset_shape(compensated_half_width, shape_index); - if (orthogonal_mode) - { - last_trace_shape = last_trace_shape.bounding_box(); - } - } - CalcFromSide from_side = new CalcFromSide(combined_polyline, shape_index, last_trace_shape); - boolean check_shove_ok = shove_trace_algo.check(last_trace_shape, from_side, null, p_layer, - p_net_no_arr, p_clearance_class_no, p_max_recursion_depth, - p_max_via_recursion_depth, p_max_spring_over_recursion_depth, p_time_limit); - if (!check_shove_ok) - { - return from_corner; - } - boolean insert_ok = shove_trace_algo.insert(last_trace_shape, from_side, p_layer, - p_net_no_arr, p_clearance_class_no, null, p_max_recursion_depth, - p_max_via_recursion_depth, p_max_spring_over_recursion_depth); - if (!insert_ok) - { - System.out.println("shove trace failed"); - return null; - } - } - // insert the new trace segment - for (int i = 0; i < new_polyline.corner_count(); ++i) - { - join_changed_area(new_polyline.corner_approx(i), p_layer); - } - PolylineTrace new_trace = insert_trace_without_cleaning(new_polyline, p_layer, p_half_width, p_net_no_arr, p_clearance_class_no, FixedState.UNFIXED); - new_trace.combine(); - - IntOctagon tidy_region = null; - if (p_tidy_width < Integer.MAX_VALUE) - { - tidy_region = new_corner.surrounding_octagon().enlarge(p_tidy_width); - } - int[] opt_net_no_arr; - if (p_max_recursion_depth <= 0) - { - opt_net_no_arr = p_net_no_arr; - } - else - { - opt_net_no_arr = new int[0]; - } - PullTightAlgo pull_tight_algo = - PullTightAlgo.get_instance(this, opt_net_no_arr, tidy_region, - p_pull_tight_accuracy, null, -1, new_corner, p_layer); - - // Remove evtl. generated cycles because otherwise pull_tight may not work correctly. - if (new_trace.normalize(changed_area.get_area(p_layer))) - { - - pull_tight_algo.split_traces_at_keep_point(); - // otherwise the new corner may no more be contained in the new trace after optimizing - ItemSelectionFilter item_filter = new ItemSelectionFilter(ItemSelectionFilter.SelectableChoices.TRACES); - Set curr_picked_items = this.pick_items(new_corner, p_layer, item_filter); - new_trace = null; - if (!curr_picked_items.isEmpty()) - { - Item found_trace = curr_picked_items.iterator().next(); - if (found_trace instanceof PolylineTrace) - { - new_trace = (PolylineTrace) found_trace; - } - } - } - - // To avoid, that a separate handling for moving backwards in the own trace line - // becomes necessesary, pull tight is called here. - if (p_tidy_width > 0 && new_trace != null) - { - new_trace.pull_tight(pull_tight_algo); - } - return new_corner; - } - - /** - * Initialises the autoroute database for routing a connection. - * If p_retain_autoroute_database, the autoroute database is retained and maintained after - * the algorithm for performance reasons. - */ - public AutorouteEngine init_autoroute(int p_net_no, int p_trace_clearance_class_no, - Stoppable p_stoppable_thread, TimeLimit p_time_limit, boolean p_retain_autoroute_database) - { - if (this.autoroute_engine == null || !p_retain_autoroute_database || this.autoroute_engine.autoroute_search_tree.compensated_clearance_class_no != p_trace_clearance_class_no) - { - this.autoroute_engine = new AutorouteEngine(this, p_trace_clearance_class_no, p_retain_autoroute_database); - } - this.autoroute_engine.init_connection(p_net_no, p_stoppable_thread, p_time_limit); - return this.autoroute_engine; - } - - /** - * Clears the autoroute database in case it was retained. - */ - public void finish_autoroute() - { - if (this.autoroute_engine != null) - { - this.autoroute_engine.clear(); - } - this.autoroute_engine = null; - } - - /** - * Routes automatically p_item to another item of the same net, to which it - * is not yet electrically connected. - * Returns an enum of type AutorouteEngine.AutorouteResult - */ - public AutorouteEngine.AutorouteResult autoroute(Item p_item, interactive.Settings p_settings, int p_via_costs, Stoppable p_stoppable_thread, TimeLimit p_time_limit) - { - if (!(p_item instanceof Connectable) || p_item.net_count() == 0) - { - return AutorouteEngine.AutorouteResult.ALREADY_CONNECTED; - } - if (p_item.net_count() > 1) - { - System.out.println("RoutingBoard.autoroute: net_count > 1 not yet implemented"); - } - int route_net_no = p_item.get_net_no(0); - AutorouteControl ctrl_settings = new AutorouteControl(this, route_net_no, p_settings, p_via_costs, p_settings.autoroute_settings.get_trace_cost_arr()); - ctrl_settings.remove_unconnected_vias = false; - Set route_start_set = p_item.get_connected_set(route_net_no); - rules.Net route_net = rules.nets.get(route_net_no); - if (route_net != null && route_net.contains_plane()) - { - for (Item curr_item : route_start_set) - { - if (curr_item instanceof board.ConductionArea) - { - return AutorouteEngine.AutorouteResult.ALREADY_CONNECTED; // already connected to plane - } - } - } - Set route_dest_set = p_item.get_unconnected_set(route_net_no); - if (route_dest_set.size() == 0) - { - return AutorouteEngine.AutorouteResult.ALREADY_CONNECTED; // p_item is already routed. - } - SortedSet ripped_item_list = new TreeSet(); - AutorouteEngine curr_autoroute_engine = init_autoroute(p_item.get_net_no(0), - ctrl_settings.trace_clearance_class_no, p_stoppable_thread, p_time_limit, false); - AutorouteEngine.AutorouteResult result = - curr_autoroute_engine.autoroute_connection(route_start_set, route_dest_set, ctrl_settings, ripped_item_list); - if (result == AutorouteEngine.AutorouteResult.ROUTED) - { - final int time_limit_to_prevent_endless_loop = 1000; - opt_changed_area(new int[0], null, p_settings.get_trace_pull_tight_accuracy(), ctrl_settings.trace_costs, p_stoppable_thread, time_limit_to_prevent_endless_loop); - } - return result; - } - - /** - * Autoroutes from the input pin until the first via, in case the pin and its connected set - * has only 1 layer. Ripup is allowed if p_ripup_costs is >= 0. - * Returns an enum of type AutorouteEngine.AutorouteResult - */ - public AutorouteEngine.AutorouteResult fanout(Pin p_pin, interactive.Settings p_settings, int p_ripup_costs, - Stoppable p_stoppable_thread, TimeLimit p_time_limit) - { - if (p_pin.first_layer() != p_pin.last_layer() || p_pin.net_count() != 1) - { - return AutorouteEngine.AutorouteResult.ALREADY_CONNECTED; - } - int pin_net_no = p_pin.get_net_no(0); - int pin_layer = p_pin.first_layer(); - Set pin_connected_set = p_pin.get_connected_set(pin_net_no); - for (Item curr_item : pin_connected_set) - { - if (curr_item.first_layer() != pin_layer || curr_item.last_layer() != pin_layer) - { - return AutorouteEngine.AutorouteResult.ALREADY_CONNECTED; - } - } - Set unconnected_set = p_pin.get_unconnected_set(pin_net_no); - if (unconnected_set.isEmpty()) - { - return AutorouteEngine.AutorouteResult.ALREADY_CONNECTED; - } - AutorouteControl ctrl_settings = new AutorouteControl(this, pin_net_no, p_settings); - ctrl_settings.is_fanout = true; - ctrl_settings.remove_unconnected_vias = false; - if (p_ripup_costs >= 0) - { - ctrl_settings.ripup_allowed = true; - ctrl_settings.ripup_costs = p_ripup_costs; - } - SortedSet ripped_item_list = new TreeSet(); - AutorouteEngine curr_autoroute_engine = init_autoroute(pin_net_no, - ctrl_settings.trace_clearance_class_no, p_stoppable_thread, p_time_limit, false); - AutorouteEngine.AutorouteResult result = - curr_autoroute_engine.autoroute_connection(pin_connected_set, - unconnected_set, ctrl_settings, ripped_item_list); - if (result == AutorouteEngine.AutorouteResult.ROUTED) - { - final int time_limit_to_prevent_endless_loop = 1000; - opt_changed_area(new int[0], null, p_settings.get_trace_pull_tight_accuracy(), ctrl_settings.trace_costs, p_stoppable_thread, time_limit_to_prevent_endless_loop); - } - return result; - } - - /** - * Inserts a trace from p_from_point to the nearest point on p_to_trace. - * Returns false, if that is not possible without clearance violation. - */ - public boolean connect_to_trace(IntPoint p_from_point, Trace p_to_trace, - int p_pen_half_width, int p_cl_type) - { - - Point first_corner = p_to_trace.first_corner(); - - Point last_corner = p_to_trace.last_corner(); - - int[] net_no_arr = p_to_trace.net_no_arr; - - if (!(p_to_trace instanceof PolylineTrace)) - { - return false; // not yet implemented - } - PolylineTrace to_trace = (PolylineTrace) p_to_trace; - if (to_trace.polyline().contains(p_from_point)) - { - // no connection line necessary - return true; - } - LineSegment projection_line = to_trace.polyline().projection_line(p_from_point); - if (projection_line == null) - { - return false; - } - Polyline connection_line = projection_line.to_polyline(); - if (connection_line == null || connection_line.arr.length != 3) - { - return false; - } - int trace_layer = p_to_trace.get_layer(); - if (!this.check_polyline_trace(connection_line, trace_layer, p_pen_half_width, - p_to_trace.net_no_arr, p_cl_type)) - { - return false; - } - if (this.changed_area != null) - { - for (int i = 0; i < connection_line.corner_count(); ++i) - { - this.changed_area.join(connection_line.corner_approx(i), trace_layer); - } - } - - this.insert_trace(connection_line, trace_layer, p_pen_half_width, net_no_arr, p_cl_type, FixedState.UNFIXED); - if (!p_from_point.equals(first_corner)) - { - Trace tail = this.get_trace_tail(first_corner, trace_layer, net_no_arr); - if (tail != null && !tail.is_user_fixed()) - { - this.remove_item(tail); - } - } - if (!p_from_point.equals(last_corner)) - { - Trace tail = this.get_trace_tail(last_corner, trace_layer, net_no_arr); - if (tail != null && !tail.is_user_fixed()) - { - this.remove_item(tail); - } - } - return true; - } - - /** - * Checks, if the list p_items contains traces, which have no contact at their - * start or end point. Trace with net number p_except_net_no are ignored. - */ - public boolean contains_trace_tails(Collection p_items, int[] p_except_net_no_arr) - { - Iterator it = p_items.iterator(); - while (it.hasNext()) - { - Item curr_ob = it.next(); - if (curr_ob instanceof Trace) - { - Trace curr_trace = (Trace) curr_ob; - if (!curr_trace.nets_equal(p_except_net_no_arr)) - { - if (curr_trace.is_tail()) - { - return true; - } - } - } - } - return false; - } - - /** - * Removes all trace tails of the input net. - * If p_net_no <= 0, the tails of all nets are removed. - * Returns true, if something was removed. - */ - public boolean remove_trace_tails(int p_net_no, Item.StopConnectionOption p_stop_connection_option) - { - SortedSet stub_set = new TreeSet(); - Collection board_items = this.get_items(); - for (Item curr_item : board_items) - { - if (!curr_item.is_route()) - { - continue; - } - if (curr_item.net_count() != 1) - { - continue; - } - if (p_net_no > 0 && curr_item.get_net_no(0) != p_net_no) - { - continue; - } - if (curr_item.is_tail()) - { - if (curr_item instanceof Via) - { - if (p_stop_connection_option == Item.StopConnectionOption.VIA) - { - continue; - } - if (p_stop_connection_option == Item.StopConnectionOption.FANOUT_VIA) - { - if (curr_item.is_fanout_via(null)) - { - continue; - } - } - } - stub_set.add(curr_item); - } - } - SortedSet stub_connections = new TreeSet(); - for (Item curr_item : stub_set) - { - int item_contact_count = curr_item.get_normal_contacts().size(); - if (item_contact_count == 1) - { - stub_connections.addAll(curr_item.get_connection_items(p_stop_connection_option)); - } - else - { - // the connected items are no stubs for example if a via is only connected on 1 layer, - // but to several traces. - stub_connections.add(curr_item); - } - } - if (stub_connections.isEmpty()) - { - return false; - } - this.remove_items(stub_connections, false); - this.combine_traces(p_net_no); - return true; - } - - public void clear_all_item_temporary_autoroute_data() - { - Iterator it = this.item_list.start_read_object(); - for (;;) - { - Item curr_item = (Item) item_list.read_object(it); - if (curr_item == null) - { - break; - } - curr_item.clear_autoroute_info(); - } - } - - /** - * Sets, if all conduction areas on the board are obstacles for route of foreign nets. - */ - public void change_conduction_is_obstacle(boolean p_value) - { - if (this.rules.get_ignore_conduction() != p_value) - { - return; // no muultiply - } - boolean something_changed = false; - // Change the is_obstacle property of all conduction areas of the board. - Iterator it = item_list.start_read_object(); - for (;;) - { - Item curr_item = (Item) item_list.read_object(it); - if (curr_item == null) - { - break; - } - if (curr_item instanceof ConductionArea) - { - ConductionArea curr_conduction_area = (ConductionArea) curr_item; - Layer curr_layer = layer_structure.arr[curr_conduction_area.get_layer()]; - if (curr_layer.is_signal && curr_conduction_area.get_is_obstacle() != p_value) - { - curr_conduction_area.set_is_obstacle(p_value); - something_changed = true; - } - } - } - this.rules.set_ignore_conduction(!p_value); - if (something_changed) - { - this.search_tree_manager.reinsert_tree_items(); - } - } - - /** - * Tries to educe the nets of traces and vias, so that the nets are a subset of the nets of the contact - * items. This is applied to traces and vias with more than 1 net connected to tie pins. - * Returns true, if the nets of some items were reduced. - */ - public boolean reduce_nets_of_route_items() - { - boolean result = false; - boolean something_changed = true; - while (something_changed) - { - something_changed = false; - Iterator it = item_list.start_read_object(); - for (;;) - { - UndoableObjects.Storable curr_ob = item_list.read_object(it); - if (curr_ob == null) - { - break; - } - Item curr_item = (Item) curr_ob; - if (curr_item.net_no_arr.length <= 1 || curr_item.get_fixed_state() == FixedState.SYSTEM_FIXED) - { - continue; - } - if (curr_ob instanceof Via) - { - Collection contacts = curr_item.get_normal_contacts(); - for (int curr_net_no : curr_item.net_no_arr) - { - for (Item curr_contact : contacts) - { - if (!curr_contact.contains_net(curr_net_no)) - { - curr_item.remove_from_net(curr_net_no); - something_changed = true; - break; - } - } - if (something_changed) - { - break; - } - } - - } - else if (curr_ob instanceof Trace) - { - Trace curr_trace = (Trace) curr_ob; - Collection contacts = curr_trace.get_start_contacts(); - for (int i = 0; i < 2; ++i) - { - for (int curr_net_no : curr_item.net_no_arr) - { - boolean pin_found = false; - for (Item curr_contact : contacts) - { - if (curr_contact instanceof Pin) - { - pin_found = true; - if (!curr_contact.contains_net(curr_net_no)) - { - curr_item.remove_from_net(curr_net_no); - something_changed = true; - break; - } - } - } - if (!pin_found) // at tie pins traces may have different nets - { - for (Item curr_contact : contacts) - { - if (!(curr_contact instanceof Pin) && !curr_contact.contains_net(curr_net_no)) - { - curr_item.remove_from_net(curr_net_no); - something_changed = true; - break; - } - } - } - } - if (something_changed) - { - break; - } - contacts = curr_trace.get_end_contacts(); - } - if (something_changed) - { - break; - } - } - if (something_changed) - { - break; - } - } - } - return result; - } - - /** - * Returns the obstacle responsible for the last shove to fail. - */ - public Item get_shove_failing_obstacle() - { - return shove_failing_obstacle; - } - - void set_shove_failing_obstacle(Item p_item) - { - shove_failing_obstacle = p_item; - } - - public int get_shove_failing_layer() - { - return shove_failing_layer; - } - - void set_shove_failing_layer(int p_layer) - { - shove_failing_layer = p_layer; - } - - private void clear_shove_failing_obstacle() - { - shove_failing_obstacle = null; - shove_failing_layer = -1; - } - - /** - * Sets, if the autoroute database has to be maintained outside the outoroute algorithm - * while changing items on rhe board. - */ - void set_maintaining_autoroute_database(boolean p_value) - { - if (p_value) - { - - } - else - { - this.autoroute_engine = null; - } - } - - /** - * Returns, if the autoroute database is maintained outside the outoroute algorithm - * while changing items on rhe board. - */ - boolean is_maintaining_autoroute_database() - { - return this.autoroute_engine != null; - } - /** - * Contains the database for the autorouzte algorithm. - */ - private transient AutorouteEngine autoroute_engine = null; - /** the area marked for optimizing the route */ - transient ChangedArea changed_area; - private transient Item shove_failing_obstacle = null; - private transient int shove_failing_layer = -1; - /** The time limit in milliseconds for the pull tight algorithm */ - private static final int PULL_TIGHT_TIME_LIMIT = 2000; -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + */ +package board; + +import geometry.planar.FloatPoint; +import geometry.planar.IntBox; +import geometry.planar.IntOctagon; +import geometry.planar.IntPoint; +import geometry.planar.LineSegment; +import geometry.planar.Point; +import geometry.planar.Polyline; +import geometry.planar.PolylineShape; +import geometry.planar.TileShape; +import geometry.planar.Vector; + +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; + +import datastructures.UndoableObjects; +import datastructures.Stoppable; +import datastructures.TimeLimit; +import datastructures.ShapeTree.TreeEntry; + +import rules.ViaInfo; +import rules.BoardRules; + +import autoroute.AutorouteControl; +import autoroute.AutorouteEngine; +import autoroute.AutorouteControl.ExpansionCostFactor; +import autoroute.CompleteFreeSpaceExpansionRoom; + +/** + * + * Contains higher level functions of a board + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class RoutingBoard extends BasicBoard implements java.io.Serializable +{ + + /** + * Creates a new instance of a routing Board with surrrounding box + * p_bounding_box + * Rules contains the restrictions to obey when inserting items. + * Among other things it may contain a clearance matrix. + * + * @param p_bounding_box a {@link geometry.planar.IntBox} object. + * @param p_layer_structure a {@link board.LayerStructure} object. + * @param p_outline_shapes an array of {@link geometry.planar.PolylineShape} objects. + * @param p_outline_cl_class_no a int. + * @param p_rules a rules$BoardRules object. + * @param p_board_communication a {@link board.Communication} object. + * @param p_test_level a {@link board.TestLevel} object. + */ + public RoutingBoard(IntBox p_bounding_box, LayerStructure p_layer_structure, PolylineShape[] p_outline_shapes, + int p_outline_cl_class_no, BoardRules p_rules, Communication p_board_communication, TestLevel p_test_level) + { + super(p_bounding_box, p_layer_structure, p_outline_shapes, p_outline_cl_class_no, + p_rules, p_board_communication, p_test_level); + } + + /** + * {@inheritDoc} + * + * Maintains the autorouter database after p_item is inserted, changed, or deleted. + */ + public void additional_update_after_change(Item p_item) + { + if (p_item == null) + { + return; + } + if (this.autoroute_engine == null || !this.autoroute_engine.maintain_database) + { + return; + } + // Invalidate the free space expansion rooms touching a shape of p_item. + int shape_count = p_item.tree_shape_count(this.autoroute_engine.autoroute_search_tree); + for (int i = 0; i < shape_count; ++i) + { + TileShape curr_shape = p_item.get_tree_shape(this.autoroute_engine.autoroute_search_tree, i); + this.autoroute_engine.invalidate_drill_pages(curr_shape); + int curr_layer = p_item.shape_layer(i); + Collection overlaps = + this.autoroute_engine.autoroute_search_tree.overlapping_objects(curr_shape, curr_layer); + for (SearchTreeObject curr_object : overlaps) + { + if (curr_object instanceof CompleteFreeSpaceExpansionRoom) + { + this.autoroute_engine.remove_complete_expansion_room((CompleteFreeSpaceExpansionRoom) curr_object); + } + } + } + p_item.clear_autoroute_info(); + } + + /** + * Removes the items in p_item_list and pulls the nearby rubbertraces tight. + * Returns false, if some items could not be removed, because they were fixed. + * + * @param p_item_list a {@link java.util.Collection} object. + * @param p_tidy_width a int. + * @param p_pull_tight_accuracy a int. + * @param p_with_delete_fixed a boolean. + * @return a boolean. + */ + public boolean remove_items_and_pull_tight(Collection p_item_list, int p_tidy_width, + int p_pull_tight_accuracy, boolean p_with_delete_fixed) + { + boolean result = true; + IntOctagon tidy_region; + boolean calculate_tidy_region; + if (p_tidy_width < Integer.MAX_VALUE) + { + tidy_region = IntOctagon.EMPTY; + calculate_tidy_region = (p_tidy_width > 0); + } + else + { + tidy_region = null; + calculate_tidy_region = false; + } + start_marking_changed_area(); + Set changed_nets = new TreeSet(); + Iterator it = p_item_list.iterator(); + while (it.hasNext()) + { + Item curr_item = it.next(); + if (!p_with_delete_fixed && curr_item.is_delete_fixed() || curr_item.is_user_fixed()) + { + result = false; + } + else + { + for (int i = 0; i < curr_item.tile_shape_count(); ++i) + { + TileShape curr_shape = curr_item.get_tile_shape(i); + changed_area.join(curr_shape, curr_item.shape_layer(i)); + if (calculate_tidy_region) + { + tidy_region = tidy_region.union(curr_shape.bounding_octagon()); + } + } + remove_item(curr_item); + for (int i = 0; i < curr_item.net_count(); ++i) + { + changed_nets.add(curr_item.get_net_no(i)); + } + } + } + for (Integer curr_net_no : changed_nets) + { + this.combine_traces(curr_net_no); + } + if (calculate_tidy_region) + { + tidy_region = tidy_region.enlarge(p_tidy_width); + } + opt_changed_area(new int[0], tidy_region, p_pull_tight_accuracy, null, null, PULL_TIGHT_TIME_LIMIT); + return result; + } + + /** + * starts marking the changed areas for optimizing traces + */ + public void start_marking_changed_area() + { + if (changed_area == null) + { + changed_area = new ChangedArea(get_layer_count()); + } + } + + /** + * enlarges the changed area on p_layer, so that it contains p_point + * + * @param p_point a {@link geometry.planar.FloatPoint} object. + * @param p_layer a int. + */ + public void join_changed_area(FloatPoint p_point, int p_layer) + { + if (changed_area != null) + { + changed_area.join(p_point, p_layer); + } + } + + /** + * marks the whole board as changed + */ + public void mark_all_changed_area() + { + start_marking_changed_area(); + FloatPoint[] board_corners = new FloatPoint[4]; + board_corners[0] = bounding_box.ll.to_float(); + board_corners[1] = new FloatPoint(bounding_box.ur.x, bounding_box.ll.y); + board_corners[2] = bounding_box.ur.to_float(); + board_corners[3] = new FloatPoint(bounding_box.ll.x, bounding_box.ur.y); + for (int i = 0; i < get_layer_count(); ++i) + { + for (int j = 0; j < 4; ++j) + { + join_changed_area(board_corners[j], i); + } + } + } + + /** + * Optimizes the route in the internally marked area. + * If {@code p_net_no > 0}, only traces with net number p_net_no are optimized. + * If {@code p_clip_shape != null} the optimizing is restricted to p_clip_shape. + * p_trace_cost_arr is used for optimizing vias and may be null. + * If {@code p_stoppable_thread != null}, the agorithm can be requested to be stopped. + * If {@code p_time_limit > 0}; the algorithm will be stopped after p_time_limit Milliseconds. + * + * @param p_only_net_no_arr an array of int. + * @param p_clip_shape a {@link geometry.planar.IntOctagon} object. + * @param p_accuracy a int. + * @param p_trace_cost_arr an array of {@link autoroute.AutorouteControl.ExpansionCostFactor} objects. + * @param p_stoppable_thread a {@link datastructures.Stoppable} object. + * @param p_time_limit a int. + */ + public void opt_changed_area(int[] p_only_net_no_arr, IntOctagon p_clip_shape, int p_accuracy, ExpansionCostFactor[] p_trace_cost_arr, + Stoppable p_stoppable_thread, int p_time_limit) + { + opt_changed_area(p_only_net_no_arr, p_clip_shape, p_accuracy, p_trace_cost_arr, + p_stoppable_thread, p_time_limit, null, 0); + } + + /** + * Optimizes the route in the internally marked area. + * If {@code p_net_no > 0}, only traces with net number p_net_no are optimized. + * If {@code p_clip_shape != null} the optimizing is restricted to p_clip_shape. + * p_trace_cost_arr is used for optimizing vias and may be null. + * If {@code p_stoppable_thread != null}, the agorithm can be requested to be stopped. + * If {@code p_time_limit > 0}; the algorithm will be stopped after p_time_limit Milliseconds. + * If {@code p_keep_point != null}, traces on layer p_keep_point_layer containing p_keep_point + * will also contain this point after optimizing. + * + * @param p_only_net_no_arr an array of int. + * @param p_clip_shape a {@link geometry.planar.IntOctagon} object. + * @param p_accuracy a int. + * @param p_trace_cost_arr an array of {@link autoroute.AutorouteControl.ExpansionCostFactor} objects. + * @param p_stoppable_thread a {@link datastructures.Stoppable} object. + * @param p_time_limit a int. + * @param p_keep_point a {@link geometry.planar.Point} object. + * @param p_keep_point_layer a int. + * @param p_keep_point_layer a int. + */ + public void opt_changed_area(int[] p_only_net_no_arr, IntOctagon p_clip_shape, int p_accuracy, ExpansionCostFactor[] p_trace_cost_arr, + Stoppable p_stoppable_thread, int p_time_limit, Point p_keep_point, int p_keep_point_layer) + { + if (changed_area == null) + { + return; + } + if (p_clip_shape != IntOctagon.EMPTY) + { + PullTightAlgo pull_tight_algo = + PullTightAlgo.get_instance(this, p_only_net_no_arr, p_clip_shape, + p_accuracy, p_stoppable_thread, p_time_limit, p_keep_point, p_keep_point_layer); + pull_tight_algo.opt_changed_area(p_trace_cost_arr); + } + join_graphics_update_box(changed_area.surrounding_box()); + changed_area = null; + } + + /** + * Checks if a rectangular boxed trace line segment with the input parameters can + * be inserted without conflict. If a conflict exists, + * The result length is the maximal line length from p_line.a to p_line.b, + * which can be inserted without conflict (Integer.MAX_VALUE, if no conflict exists). + * If p_only_not_shovable_obstacles, unfixed traces and vias are ignored. + * + * @param p_from_point a {@link geometry.planar.Point} object. + * @param p_to_point a {@link geometry.planar.Point} object. + * @param p_layer a int. + * @param p_net_no_arr an array of int. + * @param p_trace_half_width a int. + * @param p_cl_class_no a int. + * @param p_only_not_shovable_obstacles a boolean. + * @return a double. + */ + public double check_trace_segment(Point p_from_point, Point p_to_point, int p_layer, int[] p_net_no_arr, + int p_trace_half_width, int p_cl_class_no, boolean p_only_not_shovable_obstacles) + { + if (p_from_point.equals(p_to_point)) + { + return 0; + } + Polyline curr_polyline = new Polyline(p_from_point, p_to_point); + LineSegment curr_line_segment = new LineSegment(curr_polyline, 1); + return check_trace_segment(curr_line_segment, p_layer, p_net_no_arr, + p_trace_half_width, p_cl_class_no, p_only_not_shovable_obstacles); + } + + /** + * Checks if a trace shape around the input parameters can + * be inserted without conflict. If a conflict exists, + * The result length is the maximal line length from p_line.a to p_line.b, + * which can be inserted without conflict (Integer.MAX_VALUE, if no conflict exists). + * If p_only_not_shovable_obstacles, unfixed traces and vias are ignored. + * + * @param p_line_segment a {@link geometry.planar.LineSegment} object. + * @param p_layer a int. + * @param p_net_no_arr an array of int. + * @param p_trace_half_width a int. + * @param p_cl_class_no a int. + * @param p_only_not_shovable_obstacles a boolean. + * @return a double. + */ + public double check_trace_segment(LineSegment p_line_segment, int p_layer, int[] p_net_no_arr, + int p_trace_half_width, int p_cl_class_no, boolean p_only_not_shovable_obstacles) + { + Polyline check_polyline = p_line_segment.to_polyline(); + if (check_polyline.arr.length != 3) + { + return 0; + } + TileShape shape_to_check = check_polyline.offset_shape(p_trace_half_width, 0); + FloatPoint from_point = p_line_segment.start_point_approx(); + FloatPoint to_point = p_line_segment.end_point_approx(); + double line_length = to_point.distance(from_point); + double ok_length = Integer.MAX_VALUE; + ShapeSearchTree default_tree = this.search_tree_manager.get_default_tree(); + + Collection obstacle_entries = default_tree.overlapping_tree_entries_with_clearance(shape_to_check, p_layer, p_net_no_arr, p_cl_class_no); + + for (TreeEntry curr_obstacle_entry : obstacle_entries) + { + + if (!(curr_obstacle_entry.object instanceof Item)) + { + continue; + } + Item curr_obstacle = (Item) curr_obstacle_entry.object; + if (p_only_not_shovable_obstacles && curr_obstacle.is_route() && !curr_obstacle.is_shove_fixed()) + { + continue; + } + TileShape curr_obstacle_shape = curr_obstacle_entry.object.get_tree_shape(default_tree, curr_obstacle_entry.shape_index_in_object); + TileShape curr_offset_shape; + FloatPoint nearest_obstacle_point; + double shorten_value; + if (default_tree.is_clearance_compensation_used()) + { + curr_offset_shape = shape_to_check; + shorten_value = p_trace_half_width + rules.clearance_matrix.clearance_compensation_value(curr_obstacle.clearance_class_no(), p_layer); + } + else + { + int clearance_value = this.clearance_value(curr_obstacle.clearance_class_no(), p_cl_class_no, p_layer); + curr_offset_shape = (TileShape) shape_to_check.offset(clearance_value); + shorten_value = p_trace_half_width + clearance_value; + } + TileShape intersection = curr_obstacle_shape.intersection(curr_offset_shape); + if (intersection.is_empty()) + { + continue; + } + nearest_obstacle_point = intersection.nearest_point_approx(from_point); + + double projection = from_point.scalar_product(to_point, nearest_obstacle_point) / line_length; + + projection = Math.max(0.0, projection - shorten_value - 1); + + if (projection < ok_length) + { + ok_length = projection; + if (ok_length <= 0) + { + return 0; + } + } + } + + return ok_length; + } + + /** + * Checks, if p_item can be translated by p_vector without + * producing overlaps or clearance violations. + * + * @param p_item a {@link board.Item} object. + * @param p_vector a {@link geometry.planar.Vector} object. + * @param p_ignore_items a {@link java.util.Collection} object. + * @return a boolean. + */ + public boolean check_move_item(Item p_item, Vector p_vector, Collection p_ignore_items) + { + int net_count = p_item.net_no_arr.length; + if (net_count > 1) + { + return false; //not yet implemented + } + int contact_count = 0; + // the connected items must remain connected after moving + if (p_item instanceof Connectable) + { + contact_count = p_item.get_all_contacts().size(); + } + if (p_item instanceof Trace && contact_count > 0) + { + return false; + } + if (p_ignore_items != null) + { + p_ignore_items.add(p_item); + } + for (int i = 0; i < p_item.tile_shape_count(); ++i) + { + TileShape moved_shape = (TileShape) p_item.get_tile_shape(i).translate_by(p_vector); + if (!moved_shape.is_contained_in(bounding_box)) + { + return false; + } + Set obstacles = + this.overlapping_items_with_clearance(moved_shape, p_item.shape_layer(i), p_item.net_no_arr, + p_item.clearance_class_no()); + for (Item curr_item : obstacles) + { + if (p_ignore_items != null) + { + if (!p_ignore_items.contains(curr_item)) + { + if (curr_item.is_obstacle(p_item)) + { + return false; + } + } + } + else if (curr_item != p_item) + { + if (curr_item.is_obstacle(p_item)) + { + return false; + } + } + } + } + return true; + } + + /** + * Checks, if the net number of p_item can be changed without producing clearance violations. + * + * @param p_item a {@link board.Item} object. + * @param p_new_net_no a int. + * @return a boolean. + */ + public boolean check_change_net(Item p_item, int p_new_net_no) + { + int[] net_no_arr = new int[1]; + net_no_arr[0] = p_new_net_no; + for (int i = 0; i < p_item.tile_shape_count(); ++i) + { + TileShape curr_shape = p_item.get_tile_shape(i); + Set obstacles = + this.overlapping_items_with_clearance(curr_shape, p_item.shape_layer(i), + net_no_arr, p_item.clearance_class_no()); + for (SearchTreeObject curr_ob : obstacles) + { + if (curr_ob != p_item && curr_ob instanceof Connectable && !((Connectable) curr_ob).contains_net(p_new_net_no)) + { + return false; + } + } + } + return true; + } + + /** + * Translates p_drill_item by p_vector and shoves obstacle + * traces aside. Returns false, if that was not possible without creating + * clearance violations. In this case the database may be damaged, so that an undo + * becomes necessesary. + * + * @param p_drill_item a {@link board.DrillItem} object. + * @param p_vector a {@link geometry.planar.Vector} object. + * @param p_max_recursion_depth a int. + * @param p_max_via_recursion_depth a int. + * @param p_tidy_width a int. + * @param p_pull_tight_accuracy a int. + * @param p_pull_tight_time_limit a int. + * @return a boolean. + */ + public boolean move_drill_item(DrillItem p_drill_item, Vector p_vector, + int p_max_recursion_depth, int p_max_via_recursion_depth, + int p_tidy_width, int p_pull_tight_accuracy, int p_pull_tight_time_limit) + { + clear_shove_failing_obstacle(); + // unfix the connected shove fixed traces. + Collection contact_list = p_drill_item.get_normal_contacts(); + Iterator it = contact_list.iterator(); + while (it.hasNext()) + { + Item curr_contact = it.next(); + if (curr_contact.get_fixed_state() == FixedState.SHOVE_FIXED) + { + curr_contact.set_fixed_state(FixedState.UNFIXED); + } + } + + IntOctagon tidy_region; + boolean calculate_tidy_region; + if (p_tidy_width < Integer.MAX_VALUE) + { + tidy_region = IntOctagon.EMPTY; + calculate_tidy_region = (p_tidy_width > 0); + } + else + { + tidy_region = null; + calculate_tidy_region = false; + } + int[] net_no_arr = p_drill_item.net_no_arr; + start_marking_changed_area(); + if (!MoveDrillItemAlgo.insert(p_drill_item, p_vector, + p_max_recursion_depth, p_max_via_recursion_depth, tidy_region, this)) + { + return false; + } + if (calculate_tidy_region) + { + tidy_region = tidy_region.enlarge(p_tidy_width); + } + int[] opt_net_no_arr; + if (p_max_recursion_depth <= 0) + { + opt_net_no_arr = net_no_arr; + } + else + { + opt_net_no_arr = new int[0]; + } + opt_changed_area(opt_net_no_arr, tidy_region, p_pull_tight_accuracy, null, null, p_pull_tight_time_limit); + return true; + } + + /** + * Checks, if there is an item near by sharing a net with p_net_no_arr, from where a routing can start, + * or where the routig can connect to. + * If {@code p_from_item != null}, items, which are connected to p_from_item, are + * ignored. + * Returns null, if no item is found, + * If {@code p_layer < 0}, the layer is ignored + * + * @param p_location a {@link geometry.planar.Point} object. + * @param p_layer a int. + * @param p_from_item a {@link board.Item} object. + * @return a {@link board.Item} object. + */ + public Item pick_nearest_routing_item(Point p_location, int p_layer, Item p_from_item) + { + TileShape point_shape = TileShape.get_instance(p_location); + Collection found_items = overlapping_items(point_shape, p_layer); + FloatPoint pick_location = p_location.to_float(); + double min_dist = Integer.MAX_VALUE; + Item nearest_item = null; + Set ignore_set = null; + Iterator it = found_items.iterator(); + while (it.hasNext()) + { + Item curr_item = it.next(); + if (!curr_item.is_connectable()) + { + continue; + } + boolean candidate_found = false; + double curr_dist = 0; + if (curr_item instanceof PolylineTrace) + { + PolylineTrace curr_trace = (PolylineTrace) curr_item; + if (p_layer < 0 || curr_trace.get_layer() == p_layer) + { + if (nearest_item instanceof DrillItem) + { + continue; // prefer drill items + } + int trace_radius = curr_trace.get_half_width(); + curr_dist = curr_trace.polyline().distance(pick_location); + if (curr_dist < min_dist && curr_dist <= trace_radius) + { + candidate_found = true; + } + } + } + else if (curr_item instanceof DrillItem) + { + DrillItem curr_drill_item = (DrillItem) curr_item; + if (p_layer < 0 || curr_drill_item.is_on_layer(p_layer)) + { + FloatPoint drill_item_center = curr_drill_item.get_center().to_float(); + curr_dist = drill_item_center.distance(pick_location); + if (curr_dist < min_dist || nearest_item instanceof Trace) + { + candidate_found = true; + } + } + } + else if (curr_item instanceof ConductionArea) + { + ConductionArea curr_area = (ConductionArea) curr_item; + if ((p_layer < 0 || curr_area.get_layer() == p_layer) && nearest_item == null) + { + candidate_found = true; + curr_dist = Integer.MAX_VALUE; + } + } + if (candidate_found) + { + if (p_from_item != null) + { + if (ignore_set == null) + { + // calculated here to avoid unnessery calculations for performance reasoss. + ignore_set = p_from_item.get_connected_set(-1); + } + if (ignore_set.contains(curr_item)) + { + continue; + } + } + min_dist = curr_dist; + nearest_item = curr_item; + } + } + return nearest_item; + } + + /** + * Shoves aside traces, so that a via with the input parameters can be + * inserted without clearance violations. If the shove failed, the database may be damaged, so that an undo + * becomes necessesary. Returns false, if the forced via failed. + * + * @param p_via_info a {@link rules.ViaInfo} object. + * @param p_location a {@link geometry.planar.Point} object. + * @param p_net_no_arr an array of int. + * @param p_trace_clearance_class_no a int. + * @param p_trace_pen_halfwidth_arr an array of int. + * @param p_max_recursion_depth a int. + * @param p_max_via_recursion_depth a int. + * @param p_tidy_width a int. + * @param p_pull_tight_accuracy a int. + * @param p_pull_tight_time_limit a int. + * @return a boolean. + */ + public boolean forced_via(ViaInfo p_via_info, Point p_location, int[] p_net_no_arr, + int p_trace_clearance_class_no, int[] p_trace_pen_halfwidth_arr, + int p_max_recursion_depth, int p_max_via_recursion_depth, + int p_tidy_width, int p_pull_tight_accuracy, int p_pull_tight_time_limit) + { + clear_shove_failing_obstacle(); + this.start_marking_changed_area(); + boolean result = ForcedViaAlgo.insert(p_via_info, p_location, p_net_no_arr, + p_trace_clearance_class_no, p_trace_pen_halfwidth_arr, + p_max_recursion_depth, p_max_via_recursion_depth, this); + if (result) + { + IntOctagon tidy_clip_shape; + if (p_tidy_width < Integer.MAX_VALUE) + { + tidy_clip_shape = p_location.surrounding_octagon().enlarge(p_tidy_width); + } + else + { + tidy_clip_shape = null; + } + int[] opt_net_no_arr; + if (p_max_recursion_depth <= 0) + { + opt_net_no_arr = p_net_no_arr; + } + else + { + opt_net_no_arr = new int[0]; + } + this.opt_changed_area(opt_net_no_arr, tidy_clip_shape, + p_pull_tight_accuracy, null, null, p_pull_tight_time_limit); + } + return result; + } + + /** + * Tries to insert a trace line with the input parameters from + * p_from_corner to p_to_corner while shoving aside obstacle traces + * and vias. Returns the last point between p_from_corner and p_to_corner, + * to which the shove succeeded. + * Returns null, if the check was inaccurate and an error accured while + * inserting, so that the database may be damaged and an undo necessary. + * p_search_tree is the shape search tree used in the algorithm. + * + * @param p_from_corner a {@link geometry.planar.Point} object. + * @param p_to_corner a {@link geometry.planar.Point} object. + * @param p_half_width a int. + * @param p_layer a int. + * @param p_net_no_arr an array of int. + * @param p_clearance_class_no a int. + * @param p_max_recursion_depth a int. + * @param p_max_via_recursion_depth a int. + * @param p_max_spring_over_recursion_depth a int. + * @param p_tidy_width a int. + * @param p_pull_tight_accuracy a int. + * @param p_with_check a boolean. + * @param p_time_limit a {@link datastructures.TimeLimit} object. + * @return a {@link geometry.planar.Point} object. + */ + public Point insert_forced_trace_segment(Point p_from_corner, + Point p_to_corner, int p_half_width, int p_layer, int[] p_net_no_arr, + int p_clearance_class_no, int p_max_recursion_depth, int p_max_via_recursion_depth, + int p_max_spring_over_recursion_depth, int p_tidy_width, + int p_pull_tight_accuracy, boolean p_with_check, TimeLimit p_time_limit) + { + if (p_from_corner.equals(p_to_corner)) + { + return p_to_corner; + } + Polyline insert_polyline = new Polyline(p_from_corner, p_to_corner); + Point ok_point = insert_forced_trace_polyline(insert_polyline, p_half_width, p_layer, p_net_no_arr, + p_clearance_class_no, p_max_recursion_depth, p_max_via_recursion_depth, + p_max_spring_over_recursion_depth, p_tidy_width, + p_pull_tight_accuracy, p_with_check, p_time_limit); + Point result; + if (ok_point == insert_polyline.first_corner()) + { + result = p_from_corner; + } + else if (ok_point == insert_polyline.last_corner()) + { + result = p_to_corner; + } + else + { + result = ok_point; + } + return result; + } + + /** + * Checks, if a trace polyline with the input parameters can be inserted + * while shoving aside obstacle traces and vias. + * + * @param p_polyline a {@link geometry.planar.Polyline} object. + * @param p_half_width a int. + * @param p_layer a int. + * @param p_net_no_arr an array of int. + * @param p_clearance_class_no a int. + * @param p_max_recursion_depth a int. + * @param p_max_via_recursion_depth a int. + * @param p_max_spring_over_recursion_depth a int. + * @return a boolean. + */ + public boolean check_forced_trace_polyline(Polyline p_polyline, int p_half_width, int p_layer, int[] p_net_no_arr, + int p_clearance_class_no, int p_max_recursion_depth, int p_max_via_recursion_depth, + int p_max_spring_over_recursion_depth) + { + ShapeSearchTree search_tree = search_tree_manager.get_default_tree(); + int compensated_half_width = p_half_width + search_tree.clearance_compensation_value(p_clearance_class_no, p_layer); + TileShape[] trace_shapes = p_polyline.offset_shapes(compensated_half_width, + 0, p_polyline.arr.length - 1); + boolean orthogonal_mode = (rules.get_trace_angle_restriction() == AngleRestriction.NINETY_DEGREE); + ShoveTraceAlgo shove_trace_algo = new ShoveTraceAlgo(this); + for (int i = 0; i < trace_shapes.length; ++i) + { + TileShape curr_trace_shape = trace_shapes[i]; + if (orthogonal_mode) + { + curr_trace_shape = curr_trace_shape.bounding_box(); + } + CalcFromSide from_side = new CalcFromSide(p_polyline, i + 1, curr_trace_shape); + + boolean check_shove_ok = shove_trace_algo.check(curr_trace_shape, from_side, null, p_layer, + p_net_no_arr, p_clearance_class_no, p_max_recursion_depth, + p_max_via_recursion_depth, p_max_spring_over_recursion_depth, null); + if (!check_shove_ok) + { + return false; + } + } + return true; + } + + /** + * Tries to insert a trace polyline with the input parameters from + * while shoving aside obstacle traces and vias. Returns the last corner + * on the polyline, to which the shove succeeded. + * Returns null, if the check was inaccurate and an error accured while + * inserting, so that the database may be damaged and an undo necessary. + * + * @param p_polyline a {@link geometry.planar.Polyline} object. + * @param p_half_width a int. + * @param p_layer a int. + * @param p_net_no_arr an array of int. + * @param p_clearance_class_no a int. + * @param p_max_recursion_depth a int. + * @param p_max_via_recursion_depth a int. + * @param p_max_spring_over_recursion_depth a int. + * @param p_tidy_width a int. + * @param p_pull_tight_accuracy a int. + * @param p_with_check a boolean. + * @param p_time_limit a {@link datastructures.TimeLimit} object. + * @return a {@link geometry.planar.Point} object. + */ + public Point insert_forced_trace_polyline(Polyline p_polyline, int p_half_width, int p_layer, int[] p_net_no_arr, + int p_clearance_class_no, int p_max_recursion_depth, int p_max_via_recursion_depth, + int p_max_spring_over_recursion_depth, int p_tidy_width, + int p_pull_tight_accuracy, boolean p_with_check, TimeLimit p_time_limit) + { + clear_shove_failing_obstacle(); + Point from_corner = p_polyline.first_corner(); + Point to_corner = p_polyline.last_corner(); + if (from_corner.equals(to_corner)) + { + return to_corner; + } + if (!(from_corner instanceof IntPoint && to_corner instanceof IntPoint)) + { + System.out.println("RoutingBoard.insert_forced_trace_segment: only implemented for IntPoints"); + return from_corner; + } + start_marking_changed_area(); + // Check, if there ends a item of the same net at p_from_corner. + // If so, its geometry will be used to cut off dog ears of the check shape. + Trace picked_trace = null; + ItemSelectionFilter filter = new ItemSelectionFilter(ItemSelectionFilter.SelectableChoices.TRACES); + Set picked_items = this.pick_items(from_corner, p_layer, filter); + if (picked_items.size() == 1) + { + Trace curr_picked_trace = (Trace) picked_items.iterator().next(); + if (curr_picked_trace.nets_equal(p_net_no_arr) && curr_picked_trace.get_half_width() == p_half_width && curr_picked_trace.clearance_class_no() == p_clearance_class_no && (curr_picked_trace instanceof PolylineTrace)) + { + // can combine with the picked trace + picked_trace = curr_picked_trace; + } + } + ShapeSearchTree search_tree = search_tree_manager.get_default_tree(); + int compensated_half_width = p_half_width + search_tree.clearance_compensation_value(p_clearance_class_no, p_layer); + ShoveTraceAlgo shove_trace_algo = new ShoveTraceAlgo(this); + Polyline new_polyline = shove_trace_algo.spring_over_obstacles(p_polyline, + compensated_half_width, p_layer, p_net_no_arr, p_clearance_class_no, null); + if (new_polyline == null) + { + return from_corner; + } + Polyline combined_polyline; + if (picked_trace == null) + { + combined_polyline = new_polyline; + } + else + { + PolylineTrace combine_trace = (PolylineTrace) picked_trace; + combined_polyline = new_polyline.combine(combine_trace.polyline()); + } + if (combined_polyline.arr.length < 3) + { + return from_corner; + } + int start_shape_no = combined_polyline.arr.length - new_polyline.arr.length; + // calculate the last shapes of combined_polyline for checking + TileShape[] trace_shapes = combined_polyline.offset_shapes(compensated_half_width, + start_shape_no, combined_polyline.arr.length - 1); + int last_shape_no = trace_shapes.length; + boolean orthogonal_mode = (rules.get_trace_angle_restriction() == AngleRestriction.NINETY_DEGREE); + for (int i = 0; i < trace_shapes.length; ++i) + { + TileShape curr_trace_shape = trace_shapes[i]; + if (orthogonal_mode) + { + curr_trace_shape = curr_trace_shape.bounding_box(); + } + CalcFromSide from_side = new CalcFromSide(combined_polyline, + combined_polyline.corner_count() - trace_shapes.length - 1 + i, curr_trace_shape); + if (p_with_check) + { + boolean check_shove_ok = shove_trace_algo.check(curr_trace_shape, from_side, null, p_layer, + p_net_no_arr, p_clearance_class_no, p_max_recursion_depth, + p_max_via_recursion_depth, p_max_spring_over_recursion_depth, p_time_limit); + if (!check_shove_ok) + { + last_shape_no = i; + break; + } + } + boolean insert_ok = shove_trace_algo.insert(curr_trace_shape, from_side, p_layer, p_net_no_arr, + p_clearance_class_no, null, p_max_recursion_depth, + p_max_via_recursion_depth, p_max_spring_over_recursion_depth); + if (!insert_ok) + { + return null; + } + } + Point new_corner = to_corner; + if (last_shape_no < trace_shapes.length) + { + // the shove with index last_shape_no failed. + // Sample the shove line to a shorter shove distance and try again. + TileShape last_trace_shape = trace_shapes[last_shape_no]; + if (orthogonal_mode) + { + last_trace_shape = last_trace_shape.bounding_box(); + } + int sample_width = 2 * this.get_min_trace_half_width(); + FloatPoint last_corner = new_polyline.corner_approx(last_shape_no + 1); + FloatPoint prev_last_corner = new_polyline.corner_approx(last_shape_no); + double last_segment_length = last_corner.distance(prev_last_corner); + if (last_segment_length > 100 * sample_width) + { + // to many cycles to sample + return from_corner; + } + int shape_index = combined_polyline.corner_count() - trace_shapes.length - 1 + last_shape_no; + if (last_segment_length > sample_width) + { + new_polyline = + new_polyline.shorten(new_polyline.arr.length - (trace_shapes.length - last_shape_no - 1), sample_width); + Point curr_last_corner = new_polyline.last_corner(); + if (!(curr_last_corner instanceof IntPoint)) + { + System.out.println("insert_forced_trace_segment: IntPoint expected"); + return from_corner; + } + new_corner = curr_last_corner; + if (picked_trace == null) + { + combined_polyline = new_polyline; + } + else + { + PolylineTrace combine_trace = (PolylineTrace) picked_trace; + combined_polyline = new_polyline.combine(combine_trace.polyline()); + } + if (combined_polyline.arr.length < 3) + { + return new_corner; + } + shape_index = combined_polyline.arr.length - 3; + last_trace_shape = combined_polyline.offset_shape(compensated_half_width, shape_index); + if (orthogonal_mode) + { + last_trace_shape = last_trace_shape.bounding_box(); + } + } + CalcFromSide from_side = new CalcFromSide(combined_polyline, shape_index, last_trace_shape); + boolean check_shove_ok = shove_trace_algo.check(last_trace_shape, from_side, null, p_layer, + p_net_no_arr, p_clearance_class_no, p_max_recursion_depth, + p_max_via_recursion_depth, p_max_spring_over_recursion_depth, p_time_limit); + if (!check_shove_ok) + { + return from_corner; + } + boolean insert_ok = shove_trace_algo.insert(last_trace_shape, from_side, p_layer, + p_net_no_arr, p_clearance_class_no, null, p_max_recursion_depth, + p_max_via_recursion_depth, p_max_spring_over_recursion_depth); + if (!insert_ok) + { + System.out.println("shove trace failed"); + return null; + } + } + // insert the new trace segment + for (int i = 0; i < new_polyline.corner_count(); ++i) + { + join_changed_area(new_polyline.corner_approx(i), p_layer); + } + PolylineTrace new_trace = insert_trace_without_cleaning(new_polyline, p_layer, p_half_width, p_net_no_arr, p_clearance_class_no, FixedState.UNFIXED); + new_trace.combine(); + + IntOctagon tidy_region = null; + if (p_tidy_width < Integer.MAX_VALUE) + { + tidy_region = new_corner.surrounding_octagon().enlarge(p_tidy_width); + } + int[] opt_net_no_arr; + if (p_max_recursion_depth <= 0) + { + opt_net_no_arr = p_net_no_arr; + } + else + { + opt_net_no_arr = new int[0]; + } + PullTightAlgo pull_tight_algo = + PullTightAlgo.get_instance(this, opt_net_no_arr, tidy_region, + p_pull_tight_accuracy, null, -1, new_corner, p_layer); + + // Remove evtl. generated cycles because otherwise pull_tight may not work correctly. + if (new_trace.normalize(changed_area.get_area(p_layer))) + { + + pull_tight_algo.split_traces_at_keep_point(); + // otherwise the new corner may no more be contained in the new trace after optimizing + ItemSelectionFilter item_filter = new ItemSelectionFilter(ItemSelectionFilter.SelectableChoices.TRACES); + Set curr_picked_items = this.pick_items(new_corner, p_layer, item_filter); + new_trace = null; + if (!curr_picked_items.isEmpty()) + { + Item found_trace = curr_picked_items.iterator().next(); + if (found_trace instanceof PolylineTrace) + { + new_trace = (PolylineTrace) found_trace; + } + } + } + + // To avoid, that a separate handling for moving backwards in the own trace line + // becomes necessesary, pull tight is called here. + if (p_tidy_width > 0 && new_trace != null) + { + new_trace.pull_tight(pull_tight_algo); + } + return new_corner; + } + + /** + * Initialises the autoroute database for routing a connection. + * If p_retain_autoroute_database, the autoroute database is retained and maintained after + * the algorithm for performance reasons. + * + * @param p_net_no a int. + * @param p_trace_clearance_class_no a int. + * @param p_stoppable_thread a {@link datastructures.Stoppable} object. + * @param p_time_limit a {@link datastructures.TimeLimit} object. + * @param p_retain_autoroute_database a boolean. + * @return a {@link autoroute.AutorouteEngine} object. + */ + public AutorouteEngine init_autoroute(int p_net_no, int p_trace_clearance_class_no, + Stoppable p_stoppable_thread, TimeLimit p_time_limit, boolean p_retain_autoroute_database) + { + if (this.autoroute_engine == null || !p_retain_autoroute_database || this.autoroute_engine.autoroute_search_tree.compensated_clearance_class_no != p_trace_clearance_class_no) + { + this.autoroute_engine = new AutorouteEngine(this, p_trace_clearance_class_no, p_retain_autoroute_database); + } + this.autoroute_engine.init_connection(p_net_no, p_stoppable_thread, p_time_limit); + return this.autoroute_engine; + } + + /** + * Clears the autoroute database in case it was retained. + */ + public void finish_autoroute() + { + if (this.autoroute_engine != null) + { + this.autoroute_engine.clear(); + } + this.autoroute_engine = null; + } + + /** + * Routes automatically p_item to another item of the same net, to which it + * is not yet electrically connected. + * Returns an enum of type AutorouteEngine.AutorouteResult + * + * @param p_item a {@link board.Item} object. + * @param p_settings a {@link interactive.Settings} object. + * @param p_via_costs a int. + * @param p_stoppable_thread a {@link datastructures.Stoppable} object. + * @param p_time_limit a {@link datastructures.TimeLimit} object. + * @return a {@link autoroute.AutorouteEngine.AutorouteResult} object. + */ + public AutorouteEngine.AutorouteResult autoroute(Item p_item, interactive.Settings p_settings, int p_via_costs, Stoppable p_stoppable_thread, TimeLimit p_time_limit) + { + if (!(p_item instanceof Connectable) || p_item.net_count() == 0) + { + return AutorouteEngine.AutorouteResult.ALREADY_CONNECTED; + } + if (p_item.net_count() > 1) + { + System.out.println("RoutingBoard.autoroute: net_count > 1 not yet implemented"); + } + int route_net_no = p_item.get_net_no(0); + AutorouteControl ctrl_settings = new AutorouteControl(this, route_net_no, p_settings, p_via_costs, p_settings.autoroute_settings.get_trace_cost_arr()); + ctrl_settings.remove_unconnected_vias = false; + Set route_start_set = p_item.get_connected_set(route_net_no); + rules.Net route_net = rules.nets.get(route_net_no); + if (route_net != null && route_net.contains_plane()) + { + for (Item curr_item : route_start_set) + { + if (curr_item instanceof board.ConductionArea) + { + return AutorouteEngine.AutorouteResult.ALREADY_CONNECTED; // already connected to plane + } + } + } + Set route_dest_set = p_item.get_unconnected_set(route_net_no); + if (route_dest_set.size() == 0) + { + return AutorouteEngine.AutorouteResult.ALREADY_CONNECTED; // p_item is already routed. + } + SortedSet ripped_item_list = new TreeSet(); + AutorouteEngine curr_autoroute_engine = init_autoroute(p_item.get_net_no(0), + ctrl_settings.trace_clearance_class_no, p_stoppable_thread, p_time_limit, false); + AutorouteEngine.AutorouteResult result = + curr_autoroute_engine.autoroute_connection(route_start_set, route_dest_set, ctrl_settings, ripped_item_list); + if (result == AutorouteEngine.AutorouteResult.ROUTED) + { + final int time_limit_to_prevent_endless_loop = 1000; + opt_changed_area(new int[0], null, p_settings.get_trace_pull_tight_accuracy(), ctrl_settings.trace_costs, p_stoppable_thread, time_limit_to_prevent_endless_loop); + } + return result; + } + + /** + * Autoroutes from the input pin until the first via, in case the pin and its connected set + * has only 1 layer. Ripup is allowed if {@code p_ripup_costs is >= 0}. + * Returns an enum of type AutorouteEngine.AutorouteResult + * + * @param p_pin a {@link board.Pin} object. + * @param p_settings a {@link interactive.Settings} object. + * @param p_ripup_costs a int. + * @param p_stoppable_thread a {@link datastructures.Stoppable} object. + * @param p_time_limit a {@link datastructures.TimeLimit} object. + * @return a {@link autoroute.AutorouteEngine.AutorouteResult} object. + */ + public AutorouteEngine.AutorouteResult fanout(Pin p_pin, interactive.Settings p_settings, int p_ripup_costs, + Stoppable p_stoppable_thread, TimeLimit p_time_limit) + { + if (p_pin.first_layer() != p_pin.last_layer() || p_pin.net_count() != 1) + { + return AutorouteEngine.AutorouteResult.ALREADY_CONNECTED; + } + int pin_net_no = p_pin.get_net_no(0); + int pin_layer = p_pin.first_layer(); + Set pin_connected_set = p_pin.get_connected_set(pin_net_no); + for (Item curr_item : pin_connected_set) + { + if (curr_item.first_layer() != pin_layer || curr_item.last_layer() != pin_layer) + { + return AutorouteEngine.AutorouteResult.ALREADY_CONNECTED; + } + } + Set unconnected_set = p_pin.get_unconnected_set(pin_net_no); + if (unconnected_set.isEmpty()) + { + return AutorouteEngine.AutorouteResult.ALREADY_CONNECTED; + } + AutorouteControl ctrl_settings = new AutorouteControl(this, pin_net_no, p_settings); + ctrl_settings.is_fanout = true; + ctrl_settings.remove_unconnected_vias = false; + if (p_ripup_costs >= 0) + { + ctrl_settings.ripup_allowed = true; + ctrl_settings.ripup_costs = p_ripup_costs; + } + SortedSet ripped_item_list = new TreeSet(); + AutorouteEngine curr_autoroute_engine = init_autoroute(pin_net_no, + ctrl_settings.trace_clearance_class_no, p_stoppable_thread, p_time_limit, false); + AutorouteEngine.AutorouteResult result = + curr_autoroute_engine.autoroute_connection(pin_connected_set, + unconnected_set, ctrl_settings, ripped_item_list); + if (result == AutorouteEngine.AutorouteResult.ROUTED) + { + final int time_limit_to_prevent_endless_loop = 1000; + opt_changed_area(new int[0], null, p_settings.get_trace_pull_tight_accuracy(), ctrl_settings.trace_costs, p_stoppable_thread, time_limit_to_prevent_endless_loop); + } + return result; + } + + /** + * Inserts a trace from p_from_point to the nearest point on p_to_trace. + * Returns false, if that is not possible without clearance violation. + * + * @param p_from_point a {@link geometry.planar.IntPoint} object. + * @param p_to_trace a {@link board.Trace} object. + * @param p_pen_half_width a int. + * @param p_cl_type a int. + * @return a boolean. + */ + public boolean connect_to_trace(IntPoint p_from_point, Trace p_to_trace, + int p_pen_half_width, int p_cl_type) + { + + Point first_corner = p_to_trace.first_corner(); + + Point last_corner = p_to_trace.last_corner(); + + int[] net_no_arr = p_to_trace.net_no_arr; + + if (!(p_to_trace instanceof PolylineTrace)) + { + return false; // not yet implemented + } + PolylineTrace to_trace = (PolylineTrace) p_to_trace; + if (to_trace.polyline().contains(p_from_point)) + { + // no connection line necessary + return true; + } + LineSegment projection_line = to_trace.polyline().projection_line(p_from_point); + if (projection_line == null) + { + return false; + } + Polyline connection_line = projection_line.to_polyline(); + if (connection_line == null || connection_line.arr.length != 3) + { + return false; + } + int trace_layer = p_to_trace.get_layer(); + if (!this.check_polyline_trace(connection_line, trace_layer, p_pen_half_width, + p_to_trace.net_no_arr, p_cl_type)) + { + return false; + } + if (this.changed_area != null) + { + for (int i = 0; i < connection_line.corner_count(); ++i) + { + this.changed_area.join(connection_line.corner_approx(i), trace_layer); + } + } + + this.insert_trace(connection_line, trace_layer, p_pen_half_width, net_no_arr, p_cl_type, FixedState.UNFIXED); + if (!p_from_point.equals(first_corner)) + { + Trace tail = this.get_trace_tail(first_corner, trace_layer, net_no_arr); + if (tail != null && !tail.is_user_fixed()) + { + this.remove_item(tail); + } + } + if (!p_from_point.equals(last_corner)) + { + Trace tail = this.get_trace_tail(last_corner, trace_layer, net_no_arr); + if (tail != null && !tail.is_user_fixed()) + { + this.remove_item(tail); + } + } + return true; + } + + /** + * Checks, if the list p_items contains traces, which have no contact at their + * start or end point. Trace with net number p_except_net_no are ignored. + * + * @param p_items a {@link java.util.Collection} object. + * @param p_except_net_no_arr an array of int. + * @return a boolean. + */ + public boolean contains_trace_tails(Collection p_items, int[] p_except_net_no_arr) + { + Iterator it = p_items.iterator(); + while (it.hasNext()) + { + Item curr_ob = it.next(); + if (curr_ob instanceof Trace) + { + Trace curr_trace = (Trace) curr_ob; + if (!curr_trace.nets_equal(p_except_net_no_arr)) + { + if (curr_trace.is_tail()) + { + return true; + } + } + } + } + return false; + } + + /** + * Removes all trace tails of the input net. + * If {@code p_net_no <= 0}, the tails of all nets are removed. + * Returns true, if something was removed. + * + * @param p_net_no a int. + * @param p_stop_connection_option a {@link board.Item.StopConnectionOption} object. + * @return a boolean. + */ + public boolean remove_trace_tails(int p_net_no, Item.StopConnectionOption p_stop_connection_option) + { + SortedSet stub_set = new TreeSet(); + Collection board_items = this.get_items(); + for (Item curr_item : board_items) + { + if (!curr_item.is_route()) + { + continue; + } + if (curr_item.net_count() != 1) + { + continue; + } + if (p_net_no > 0 && curr_item.get_net_no(0) != p_net_no) + { + continue; + } + if (curr_item.is_tail()) + { + if (curr_item instanceof Via) + { + if (p_stop_connection_option == Item.StopConnectionOption.VIA) + { + continue; + } + if (p_stop_connection_option == Item.StopConnectionOption.FANOUT_VIA) + { + if (curr_item.is_fanout_via(null)) + { + continue; + } + } + } + stub_set.add(curr_item); + } + } + SortedSet stub_connections = new TreeSet(); + for (Item curr_item : stub_set) + { + int item_contact_count = curr_item.get_normal_contacts().size(); + if (item_contact_count == 1) + { + stub_connections.addAll(curr_item.get_connection_items(p_stop_connection_option)); + } + else + { + // the connected items are no stubs for example if a via is only connected on 1 layer, + // but to several traces. + stub_connections.add(curr_item); + } + } + if (stub_connections.isEmpty()) + { + return false; + } + this.remove_items(stub_connections, false); + this.combine_traces(p_net_no); + return true; + } + + /** + *

clear_all_item_temporary_autoroute_data.

+ */ + public void clear_all_item_temporary_autoroute_data() + { + Iterator it = this.item_list.start_read_object(); + for (;;) + { + Item curr_item = (Item) item_list.read_object(it); + if (curr_item == null) + { + break; + } + curr_item.clear_autoroute_info(); + } + } + + /** + * Sets, if all conduction areas on the board are obstacles for route of foreign nets. + * + * @param p_value a boolean. + */ + public void change_conduction_is_obstacle(boolean p_value) + { + if (this.rules.get_ignore_conduction() != p_value) + { + return; // no muultiply + } + boolean something_changed = false; + // Change the is_obstacle property of all conduction areas of the board. + Iterator it = item_list.start_read_object(); + for (;;) + { + Item curr_item = (Item) item_list.read_object(it); + if (curr_item == null) + { + break; + } + if (curr_item instanceof ConductionArea) + { + ConductionArea curr_conduction_area = (ConductionArea) curr_item; + Layer curr_layer = layer_structure.arr[curr_conduction_area.get_layer()]; + if (curr_layer.is_signal && curr_conduction_area.get_is_obstacle() != p_value) + { + curr_conduction_area.set_is_obstacle(p_value); + something_changed = true; + } + } + } + this.rules.set_ignore_conduction(!p_value); + if (something_changed) + { + this.search_tree_manager.reinsert_tree_items(); + } + } + + /** + * Tries to educe the nets of traces and vias, so that the nets are a subset of the nets of the contact + * items. This is applied to traces and vias with more than 1 net connected to tie pins. + * Returns true, if the nets of some items were reduced. + * + * @return a boolean. + */ + public boolean reduce_nets_of_route_items() + { + boolean result = false; + boolean something_changed = true; + while (something_changed) + { + something_changed = false; + Iterator it = item_list.start_read_object(); + for (;;) + { + UndoableObjects.Storable curr_ob = item_list.read_object(it); + if (curr_ob == null) + { + break; + } + Item curr_item = (Item) curr_ob; + if (curr_item.net_no_arr.length <= 1 || curr_item.get_fixed_state() == FixedState.SYSTEM_FIXED) + { + continue; + } + if (curr_ob instanceof Via) + { + Collection contacts = curr_item.get_normal_contacts(); + for (int curr_net_no : curr_item.net_no_arr) + { + for (Item curr_contact : contacts) + { + if (!curr_contact.contains_net(curr_net_no)) + { + curr_item.remove_from_net(curr_net_no); + something_changed = true; + break; + } + } + if (something_changed) + { + break; + } + } + + } + else if (curr_ob instanceof Trace) + { + Trace curr_trace = (Trace) curr_ob; + Collection contacts = curr_trace.get_start_contacts(); + for (int i = 0; i < 2; ++i) + { + for (int curr_net_no : curr_item.net_no_arr) + { + boolean pin_found = false; + for (Item curr_contact : contacts) + { + if (curr_contact instanceof Pin) + { + pin_found = true; + if (!curr_contact.contains_net(curr_net_no)) + { + curr_item.remove_from_net(curr_net_no); + something_changed = true; + break; + } + } + } + if (!pin_found) // at tie pins traces may have different nets + { + for (Item curr_contact : contacts) + { + if (!(curr_contact instanceof Pin) && !curr_contact.contains_net(curr_net_no)) + { + curr_item.remove_from_net(curr_net_no); + something_changed = true; + break; + } + } + } + } + if (something_changed) + { + break; + } + contacts = curr_trace.get_end_contacts(); + } + if (something_changed) + { + break; + } + } + if (something_changed) + { + break; + } + } + } + return result; + } + + /** + * Returns the obstacle responsible for the last shove to fail. + * + * @return a {@link board.Item} object. + */ + public Item get_shove_failing_obstacle() + { + return shove_failing_obstacle; + } + + void set_shove_failing_obstacle(Item p_item) + { + shove_failing_obstacle = p_item; + } + + /** + *

get_shove_failing_layer.

+ * + * @return a int. + */ + public int get_shove_failing_layer() + { + return shove_failing_layer; + } + + void set_shove_failing_layer(int p_layer) + { + shove_failing_layer = p_layer; + } + + private void clear_shove_failing_obstacle() + { + shove_failing_obstacle = null; + shove_failing_layer = -1; + } + + /** + * Sets, if the autoroute database has to be maintained outside the outoroute algorithm + * while changing items on rhe board. + */ + void set_maintaining_autoroute_database(boolean p_value) + { + if (p_value) + { + + } + else + { + this.autoroute_engine = null; + } + } + + /** + * Returns, if the autoroute database is maintained outside the outoroute algorithm + * while changing items on rhe board. + */ + boolean is_maintaining_autoroute_database() + { + return this.autoroute_engine != null; + } + /** + * Contains the database for the autorouzte algorithm. + */ + private transient AutorouteEngine autoroute_engine = null; + /** the area marked for optimizing the route */ + transient ChangedArea changed_area; + private transient Item shove_failing_obstacle = null; + private transient int shove_failing_layer = -1; + /** The time limit in milliseconds for the pull tight algorithm */ + private static final int PULL_TIGHT_TIME_LIMIT = 2000; +} diff --git a/board/SearchTreeManager.java b/src/main/java/board/SearchTreeManager.java similarity index 95% rename from board/SearchTreeManager.java rename to src/main/java/board/SearchTreeManager.java index 03e3244..fd9f463 100644 --- a/board/SearchTreeManager.java +++ b/src/main/java/board/SearchTreeManager.java @@ -32,13 +32,19 @@ import geometry.planar.Polyline; /** + *

SearchTreeManager class.

* * @author Alfons Wirtz + * @version $Id: $Id */ public class SearchTreeManager { - /** Creates a new instance of SearchTreeManager */ + /** + * Creates a new instance of SearchTreeManager + * + * @param p_board a {@link board.BasicBoard} object. + */ public SearchTreeManager(BasicBoard p_board) { board = p_board; @@ -50,6 +56,8 @@ public SearchTreeManager(BasicBoard p_board) /** * Inserts the tree shapes of p_item into all active search trees. + * + * @param p_item a {@link board.Item} object. */ public void insert(Item p_item) { @@ -62,6 +70,8 @@ public void insert(Item p_item) /** * Removes all entries of an item from the search trees. + * + * @param p_item a {@link board.Item} object. */ public void remove(Item p_item) { @@ -86,6 +96,8 @@ public void remove(Item p_item) /** * Returns the default tree used in interactive routing. + * + * @return a {@link board.ShapeSearchTree} object. */ public ShapeSearchTree get_default_tree() { @@ -110,6 +122,8 @@ boolean validate_entries(Item p_item) * Returns, if clearance compensation is used for the default tree. * This is normally the case, if there exist only the clearance classes null and default * in the clearance matrix. + * + * @return a boolean. */ public boolean is_clearance_compensation_used() { @@ -118,6 +132,8 @@ public boolean is_clearance_compensation_used() /** * Sets the usage of clearance compensation to true or false. + * + * @param p_value a boolean. */ public void set_clearance_compensation_used(boolean p_value) { @@ -167,6 +183,8 @@ public void clearance_value_changed() /** * Actions to be done, when a new clearance class is removed interactively. + * + * @param p_no a int. */ public void clearance_class_removed(int p_no) { @@ -189,6 +207,9 @@ public void clearance_class_removed(int p_no) /** * Returns the tree compensated for the clearance class with number p_clearance_vlass_no. * Initialized the tree, if it is not yet allocated. + * + * @param p_clearance_class_no a int. + * @return a {@link board.ShapeSearchTree} object. */ public ShapeSearchTree get_autoroute_tree(int p_clearance_class_no) { diff --git a/board/SearchTreeObject.java b/src/main/java/board/SearchTreeObject.java similarity index 87% rename from board/SearchTreeObject.java rename to src/main/java/board/SearchTreeObject.java index 3e0d587..a84a888 100644 --- a/board/SearchTreeObject.java +++ b/src/main/java/board/SearchTreeObject.java @@ -24,23 +24,33 @@ * Common ShapeSearchTree functionality for board.Items and autoroute.ExpansionRooms * * @author Alfons Wirtz + * @version $Id: $Id */ public interface SearchTreeObject extends datastructures.ShapeTree.Storable { /** * Returns true if this object is an obstacle to objects containing * the net number p_net_no + * + * @param p_net_no a int. + * @return a boolean. */ boolean is_obstacle(int p_net_no); /** * Returns true if this object is an obstacle to traces containing * the net number p_net_no + * + * @param p_net_no a int. + * @return a boolean. */ boolean is_trace_obstacle(int p_net_no); /** * returns for this object the layer of the shape with index p_index. + * + * @param p_index a int. + * @return a int. */ abstract int shape_layer(int p_index); } diff --git a/board/ShapeSearchTree.java b/src/main/java/board/ShapeSearchTree.java similarity index 94% rename from board/ShapeSearchTree.java rename to src/main/java/board/ShapeSearchTree.java index 6849e13..ad7709a 100644 --- a/board/ShapeSearchTree.java +++ b/src/main/java/board/ShapeSearchTree.java @@ -52,8 +52,8 @@ * Elementary geometric search functions making direct use * of the MinAreaTree in the package datastructures. * - * * @author Alfons Wirtz + * @version $Id: $Id */ public class ShapeSearchTree extends datastructures.MinAreaTree { @@ -73,6 +73,8 @@ public class ShapeSearchTree extends datastructures.MinAreaTree /** * Returns, if for the shapes stored in this tree * clearance compensatiion is used. + * + * @return a boolean. */ public boolean is_clearance_compensation_used() { @@ -83,6 +85,10 @@ public boolean is_clearance_compensation_used() * Return the clearance compensation value of p_clearance_class_no to the clearance compensation class * of this search tree with on layer p_layer. * Returns 0, if no clearance compensation is used for this tree. + * + * @param p_clearance_class_no a int. + * @param p_layer a int. + * @return a int. */ public int clearance_compensation_value(int p_clearance_class_no, int p_layer) { @@ -344,7 +350,12 @@ void reuse_entries_after_cutout(PolylineTrace p_from_trace, PolylineTrace p_star /** * Puts all items in the tree overlapping with p_shape * on layer p_layer into p_obstacles. - * If p_layer < 0, the layer is ignored. + * If {@code p_layer < 0}, the layer is ignored. + * + * @param p_shape a {@link geometry.planar.ConvexShape} object. + * @param p_layer a int. + * @param p_ignore_net_nos an array of int. + * @param p_obstacles a {@link java.util.Set} object. */ public void overlapping_objects(ConvexShape p_shape, int p_layer, int[] p_ignore_net_nos, Set p_obstacles) @@ -364,7 +375,11 @@ public void overlapping_objects(ConvexShape p_shape, int p_layer, int[] p_ignore /** * Returns all SearchTreeObjects on layer p_layer, which overlap with p_shape. - * If p_layer < 0, the layer is ignored + * If {@code p_layer < 0}, the layer is ignored + * + * @param p_shape a {@link geometry.planar.ConvexShape} object. + * @param p_layer a int. + * @return a {@link java.util.Set} object. */ public Set overlapping_objects(ConvexShape p_shape, int p_layer) { @@ -376,7 +391,11 @@ public Set overlapping_objects(ConvexShape p_shape, int p_laye /** * Puts all tree entries overlapping with p_shape * on layer p_layer into the list p_obstacles. - * If p_layer < 0, the layer is ignored. + * If {@code p_layer < 0}, the layer is ignored. + * + * @param p_shape a {@link geometry.planar.ConvexShape} object. + * @param p_layer a int. + * @param p_tree_entries a {@link java.util.Collection} object. */ public void overlapping_tree_entries(ConvexShape p_shape, int p_layer, Collection p_tree_entries) { @@ -386,8 +405,13 @@ public void overlapping_tree_entries(ConvexShape p_shape, int p_layer, Collectio /** * Puts all tree entries overlapping with p_shape * on layer p_layer into the list p_obstacles. - * If p_layer < 0, the layer is ignored. + * If {@code p_layer < 0}, the layer is ignored. * tree_entries with object containing a net number of p_ignore_net_nos are ignored. + * + * @param p_shape a {@link geometry.planar.ConvexShape} object. + * @param p_layer a int. + * @param p_ignore_net_nos an array of int. + * @param p_tree_entries a {@link java.util.Collection} object. */ public void overlapping_tree_entries(ConvexShape p_shape, int p_layer, int[] p_ignore_net_nos, Collection p_tree_entries) @@ -460,7 +484,7 @@ public void overlapping_tree_entries(ConvexShape p_shape, int p_layer, int[] p_i * layer p_layer whould produce a clearance violation, and puts them into * the set p_obstacle_entries. * The elements in p_obstacle_entries are of type TreeEntry. - * if p_layer < 0, the layer is ignored. + * if {@code p_layer < 0}, the layer is ignored. * Used only internally, because the clearance compensation is not taken iinnto account. */ void overlapping_tree_entries_with_clearance(ConvexShape p_shape, int p_layer, int[] p_ignore_net_nos, @@ -550,7 +574,13 @@ void overlapping_tree_entries_with_clearance(ConvexShape p_shape, int p_layer, i /** * Puts all items in the tree overlapping with p_shape * on layer p_layer into p_obstacles, if p_obstacles != null. - * If p_layer < 0, the layer is ignored. + * If {@code p_layer < 0}, the layer is ignored. + * + * @param p_shape a {@link geometry.planar.ConvexShape} object. + * @param p_layer a int. + * @param p_ignore_net_nos an array of int. + * @param p_cl_type a int. + * @param p_obstacles a {@link java.util.Set} object. */ public void overlapping_objects_with_clearance(ConvexShape p_shape, int p_layer, int[] p_ignore_net_nos, int p_cl_type, Set p_obstacles) @@ -582,7 +612,13 @@ public void overlapping_objects_with_clearance(ConvexShape p_shape, int p_layer, * which describes the required clearance restrictions to other items. * The function may also return items, which are nearly overlapping, * but do not overlap with exact calculation. - * If p_layer < 0, the layer is ignored. + * If {@code p_layer < 0}, the layer is ignored. + * + * @param p_shape a {@link geometry.planar.ConvexShape} object. + * @param p_layer a int. + * @param p_ignore_net_nos an array of int. + * @param p_clearance_class a int. + * @return a {@link java.util.Set} object. */ public Set overlapping_items_with_clearance(ConvexShape p_shape, int p_layer, int[] p_ignore_net_nos, int p_clearance_class) @@ -607,7 +643,13 @@ public Set overlapping_items_with_clearance(ConvexShape p_shape, int p_lay * inclusive clearance. * p_clearance_class is the index in the clearance matrix, * which describes the required clearance restrictions to other items. - * If p_layer < 0, the layer is ignored. + * If {@code p_layer < 0}, the layer is ignored. + * + * @param p_shape a {@link geometry.planar.ConvexShape} object. + * @param p_layer a int. + * @param p_ignore_net_nos an array of int. + * @param p_clearance_class a int. + * @return a {@link java.util.Collection} object. */ public Collection overlapping_tree_entries_with_clearance(ConvexShape p_shape, int p_layer, int[] p_ignore_net_nos, int p_clearance_class) @@ -635,6 +677,12 @@ public Collection overlapping_tree_entries_with_clearance(ConvexShape * If p_ignore_shape != null, objects of type CompleteFreeSpaceExpansionRoom, * whose intersection with the shape of p_room is containes in p_ignore_shape, * are ignored. + * + * @param p_room a {@link autoroute.IncompleteFreeSpaceExpansionRoom} object. + * @param p_net_no a int. + * @param p_ignore_object a {@link board.SearchTreeObject} object. + * @param p_ignore_shape a {@link geometry.planar.TileShape} object. + * @return a {@link java.util.Collection} object. */ public Collection complete_shape(IncompleteFreeSpaceExpansionRoom p_room, int p_net_no, SearchTreeObject p_ignore_object, TileShape p_ignore_shape) @@ -863,6 +911,9 @@ private Collection restrain_shape(IncompleteFr /** * Reduces the first or last shape of p_trace at a tie pin, so that the autorouter algorithm * can find a connection for a different net. + * + * @param p_tie_pin a {@link board.Pin} object. + * @param p_trace a {@link board.PolylineTrace} object. */ public void reduce_trace_shape_at_tie_pin(Pin p_tie_pin, PolylineTrace p_trace) { @@ -1092,6 +1143,12 @@ TileShape offset_shape(Polyline p_polyline, int p_half_width, int p_no) /** * Used for creating the shapes of a polyline_trace for this tree. * Overwritten in derived classes. + * + * @param p_polyline a {@link geometry.planar.Polyline} object. + * @param p_half_width a int. + * @param p_from_no a int. + * @param p_to_no a int. + * @return an array of {@link geometry.planar.TileShape} objects. */ public TileShape[] offset_shapes(Polyline p_polyline, int p_half_width, int p_from_no, int p_to_no) @@ -1119,6 +1176,10 @@ TileShape[] calculate_tree_shapes(PolylineTrace p_trace) * Makes shure that on each layer there will be more than 1 IncompleteFreeSpaceExpansionRoom, * even if there are no objects on the layer. Otherwise the maze search algprithm gets problems * with vias. + * + * @param p_room_list a {@link java.util.Collection} object. + * @param p_board_bounding_box a {@link geometry.planar.IntBox} object. + * @return a {@link java.util.Collection} object. */ protected Collection divide_large_room( Collection p_room_list, IntBox p_board_bounding_box) diff --git a/board/ShapeSearchTree45Degree.java b/src/main/java/board/ShapeSearchTree45Degree.java similarity index 97% rename from board/ShapeSearchTree45Degree.java rename to src/main/java/board/ShapeSearchTree45Degree.java index 40a9e82..92fbba1 100644 --- a/board/ShapeSearchTree45Degree.java +++ b/src/main/java/board/ShapeSearchTree45Degree.java @@ -1,537 +1,547 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * ShapeSearchTree45Degree.java - * - * Created on 15. Juli 2007, 07:26 - * - */ -package board; - -import java.util.Collection; -import java.util.LinkedList; - -import geometry.planar.FortyfiveDegreeBoundingDirections; -import geometry.planar.TileShape; -import geometry.planar.Shape; -import geometry.planar.IntOctagon; -import geometry.planar.IntBox; -import geometry.planar.Side; -import geometry.planar.Line; - -import autoroute.IncompleteFreeSpaceExpansionRoom; -import autoroute.CompleteFreeSpaceExpansionRoom; - -/** - * A special simple ShapeSearchtree, where the shapes are of class IntOctagon. - * It is used in the 45-degree autorouter algorithm. - * - * @author Alfons Wirtz - */ -public class ShapeSearchTree45Degree extends ShapeSearchTree -{ - - /** Creates a new instance of ShapeSearchTree45Degree */ - public ShapeSearchTree45Degree(BasicBoard p_board, int p_compensated_clearance_class_no) - { - super(FortyfiveDegreeBoundingDirections.INSTANCE, p_board, p_compensated_clearance_class_no); - } - - /** - * Calculates a new incomplete room with a maximal TileShape contained in the shape of p_room, - * which may overlap only with items of the input net on the input layer. - * p_room.get_contained_shape() will be contained in the shape of the result room. - * If that is not possible, several rooms are returned with shapes, - * which intersect with p_room.get_contained_shape(). - * The result room is not yet complete, because its doors are not yet calculated. - */ - public Collection complete_shape(IncompleteFreeSpaceExpansionRoom p_room, - int p_net_no, SearchTreeObject p_ignore_object, TileShape p_ignore_shape) - { - if (!(p_room.get_contained_shape().is_IntOctagon()) && this.board.get_test_level() != TestLevel.RELEASE_VERSION) - { - System.out.println("ShapeSearchTree45Degree.complete_shape: unexpected p_shape_to_be_contained"); - return new LinkedList(); - } - IntOctagon shape_to_be_contained = p_room.get_contained_shape().bounding_octagon(); - if (this.root == null) - { - return new LinkedList(); - } - IntOctagon start_shape = board.get_bounding_box().bounding_octagon(); - if (p_room.get_shape() != null) - { - if (!(p_room.get_shape() instanceof IntOctagon)) - { - System.out.println("ShapeSearchTree45Degree.complete_shape: p_start_shape of type IntOctagon expected"); - return new LinkedList(); - } - start_shape = p_room.get_shape().bounding_octagon().intersection(start_shape); - } - IntOctagon bounding_shape = start_shape; - int room_layer = p_room.get_layer(); - Collection result = new LinkedList(); - result.add(new IncompleteFreeSpaceExpansionRoom(start_shape, room_layer, shape_to_be_contained)); - this.node_stack.reset(); - this.node_stack.push(this.root); - TreeNode curr_node; - - for (;;) - { - curr_node = this.node_stack.pop(); - if (curr_node == null) - { - break; - } - if (curr_node.bounding_shape.intersects(bounding_shape)) - { - if (curr_node instanceof Leaf) - { - Leaf curr_leaf = (Leaf) curr_node; - SearchTreeObject curr_object = (SearchTreeObject) curr_leaf.object; - boolean is_obstacle = curr_object.is_trace_obstacle(p_net_no); - - int shape_index = curr_leaf.shape_index_in_object; - if (is_obstacle && curr_object.shape_layer(shape_index) == room_layer && curr_object != p_ignore_object) - { - - IntOctagon curr_object_shape = curr_object.get_tree_shape(this, shape_index).bounding_octagon(); - Collection new_result = new LinkedList(); - IntOctagon new_bounding_shape = IntOctagon.EMPTY; - for (IncompleteFreeSpaceExpansionRoom curr_room : result) - { - IntOctagon curr_shape = (IntOctagon) curr_room.get_shape(); - if (curr_shape.overlaps(curr_object_shape)) - { - if (curr_object instanceof CompleteFreeSpaceExpansionRoom && p_ignore_shape != null) - { - IntOctagon intersection = curr_shape.intersection(curr_object_shape); - if (p_ignore_shape.contains(intersection)) - { - // ignore also all objects, whose intersection is contained in the - // 2-dim overlap-door with the from_room. - if (!p_ignore_shape.contains(curr_shape)) - { - new_result.add(curr_room); - new_bounding_shape = new_bounding_shape.union(curr_shape.bounding_box()); - } - continue; - } - } - Collection new_restrained_shapes = - restrain_shape(curr_room, curr_object_shape); - new_result.addAll(new_restrained_shapes); - - - for (IncompleteFreeSpaceExpansionRoom tmp_shape : new_result) - { - new_bounding_shape = new_bounding_shape.union(tmp_shape.get_shape().bounding_box()); - } - } - else - { - new_result.add(curr_room); - new_bounding_shape = new_bounding_shape.union(curr_shape.bounding_box()); - } - } - result = new_result; - bounding_shape = new_bounding_shape; - } - } - else - { - this.node_stack.push(((InnerNode) curr_node).first_child); - this.node_stack.push(((InnerNode) curr_node).second_child); - } - } - } - result = divide_large_room(result, board.get_bounding_box()); - // remove rooms with shapes equal to the contained shape to prevent endless loop. - java.util.Iterator it = result.iterator(); - while (it.hasNext()) - { - IncompleteFreeSpaceExpansionRoom curr_room = it.next(); - if (curr_room.get_contained_shape().contains(curr_room.get_shape())) - { - it.remove(); - } - } - return result; - } - - /** - * Makes shure that on each layer there will be more than 1 IncompleteFreeSpaceExpansionRoom, - * even if there are no objects on the layer. Otherwise the maze search algprithm gets problems - * with vias. - */ - protected Collection divide_large_room( - Collection p_room_list, IntBox p_board_bounding_box) - { - Collection result = - super.divide_large_room(p_room_list, p_board_bounding_box); - for (IncompleteFreeSpaceExpansionRoom curr_room : result) - { - curr_room.set_shape(curr_room.get_shape().bounding_octagon()); - curr_room.set_contained_shape(curr_room.get_contained_shape().bounding_octagon()); - } - return result; - } - - /** - * Checks, if the border line segment with index p_obstacle_border_line_no intersects with the inside - * of p_room_shape. - */ - private static boolean obstacle_segment_touches_inside(IntOctagon p_obstacle_shape, - int p_obstacle_border_line_no, IntOctagon p_room_shape) - { - int curr_border_line_no = p_obstacle_border_line_no; - int curr_obstacle_corner_x = p_obstacle_shape.corner_x(p_obstacle_border_line_no); - int curr_obstacle_corner_y = p_obstacle_shape.corner_y(p_obstacle_border_line_no); - for (int j = 0; j < 5; ++j) - { - - if (p_room_shape.side_of_border_line(curr_obstacle_corner_x, curr_obstacle_corner_y, - curr_border_line_no) != Side.ON_THE_LEFT) - { - return false; - } - curr_border_line_no = (curr_border_line_no + 1) % 8; - } - - int next_obstacle_border_line_no = (p_obstacle_border_line_no + 1) % 8; - int next_obstacle_corner_x = p_obstacle_shape.corner_x(next_obstacle_border_line_no); - int next_obstacle_corner_y = p_obstacle_shape.corner_y(next_obstacle_border_line_no); - curr_border_line_no = (p_obstacle_border_line_no + 5) % 8; - for (int j = 0; j < 3; ++j) - { - if (p_room_shape.side_of_border_line(next_obstacle_corner_x, next_obstacle_corner_y, - curr_border_line_no) != Side.ON_THE_LEFT) - { - return false; - } - curr_border_line_no = (curr_border_line_no + 1) % 8; - } - return true; - } - - /** - * Restrains the shape of p_incomplete_room to a octagon shape, which does not intersect with the interiour - * of p_obstacle_shape. p_incomplete_room.get_contained_shape() must be contained in the shape of - * the result room. - */ - private Collection restrain_shape(IncompleteFreeSpaceExpansionRoom p_incomplete_room, IntOctagon p_obstacle_shape) - { - // Search the edge line of p_obstacle_shape, so that p_shape_to_be_contained - // are on the right side of this line, and that the line segment - // intersects with the interiour of p_shape. - // If there are more than 1 such lines take the line which is - // furthest away from the shape_to_be_contained - // Then insersect p_shape with the halfplane defined by the - // opposite of this line. - - Collection result = new LinkedList(); - if (p_incomplete_room.get_contained_shape().is_empty()) - { - if (this.board.get_test_level().ordinal() >= TestLevel.ALL_DEBUGGING_OUTPUT.ordinal()) - { - System.out.println("ShapeSearchTree45Degree.restrain_shape: p_shape_to_be_contained is empty"); - } - return result; - } - IntOctagon room_shape = p_incomplete_room.get_shape().bounding_octagon(); - IntOctagon shape_to_be_contained = p_incomplete_room.get_contained_shape().bounding_octagon(); - double cut_line_distance = -1; - int restraining_line_no = -1; - - for (int obstacle_line_no = 0; obstacle_line_no < 8; ++obstacle_line_no) - { - double curr_distance = signed_line_distance(p_obstacle_shape, obstacle_line_no, shape_to_be_contained); - if (curr_distance > cut_line_distance) - { - if (obstacle_segment_touches_inside(p_obstacle_shape, obstacle_line_no, room_shape)) - { - cut_line_distance = curr_distance; - restraining_line_no = obstacle_line_no; - } - } - } - if (cut_line_distance >= 0) - { - IntOctagon restrained_shape = calc_outside_restrained_shape(p_obstacle_shape, restraining_line_no, room_shape); - result.add(new IncompleteFreeSpaceExpansionRoom(restrained_shape, - p_incomplete_room.get_layer(), shape_to_be_contained)); - return result; - } - - // There is no cut line, so that all p_shape_to_be_contained is - // completely on the right side of that line. Search a cut line, so that - // at least part of p_shape_to_be_contained is on the right side. - if (shape_to_be_contained.dimension() < 1) - { - // There is already a completed expansion room around p_shape_to_be_contained. - return result; - } - - restraining_line_no = -1; - for (int obstacle_line_no = 0; obstacle_line_no < 8; ++obstacle_line_no) - { - if (obstacle_segment_touches_inside(p_obstacle_shape, obstacle_line_no, room_shape)) - { - Line curr_line = p_obstacle_shape.border_line(obstacle_line_no); - if (shape_to_be_contained.side_of(curr_line) == Side.COLLINEAR) - { - // curr_line intersects with the interiour of p_shape_to_be_contained - restraining_line_no = obstacle_line_no; - break; - } - } - } - if (restraining_line_no < 0) - { - // cut line not found, parts or the whole of p_shape may be already - // occupied from somewhere else. - return result; - } - IntOctagon restrained_shape = calc_outside_restrained_shape(p_obstacle_shape, restraining_line_no, room_shape); - if (restrained_shape.dimension() == 2) - { - IntOctagon new_shape_to_be_contained = shape_to_be_contained.intersection(restrained_shape); - if (new_shape_to_be_contained.dimension() > 0) - { - result.add(new IncompleteFreeSpaceExpansionRoom(restrained_shape, - p_incomplete_room.get_layer(), new_shape_to_be_contained)); - } - } - - IntOctagon rest_piece = calc_inside_restrained_shape(p_obstacle_shape, restraining_line_no, room_shape); - if (rest_piece.dimension() >= 2) - { - TileShape rest_shape_to_be_contained = shape_to_be_contained.intersection(rest_piece); - if (rest_shape_to_be_contained.dimension() >= 0) - { - IncompleteFreeSpaceExpansionRoom rest_incomplete_room = new IncompleteFreeSpaceExpansionRoom(rest_piece, p_incomplete_room.get_layer(), rest_shape_to_be_contained); - result.addAll(restrain_shape(rest_incomplete_room, p_obstacle_shape)); - } - } - return result; - } - - private static double signed_line_distance(IntOctagon p_obstacle_shape, int p_obstacle_line_no, IntOctagon p_contained_shape) - { - double result; - if (p_obstacle_line_no == 0) - { - result = p_obstacle_shape.ly - p_contained_shape.uy; - } - else if (p_obstacle_line_no == 2) - { - result = p_contained_shape.lx - p_obstacle_shape.rx; - } - else if (p_obstacle_line_no == 4) - { - result = p_contained_shape.ly - p_obstacle_shape.uy; - } - else if (p_obstacle_line_no == 6) - { - result = p_obstacle_shape.lx - p_contained_shape.rx; - } - // factor 0.5 used instead to 1 / sqrt(2) to prefer orthogonal lines slightly to diagonal restraining lines. - else if (p_obstacle_line_no == 1) - { - result = 0.5 * (p_contained_shape.ulx - p_obstacle_shape.lrx); - } - else if (p_obstacle_line_no == 3) - { - result = 0.5 * (p_contained_shape.llx - p_obstacle_shape.urx); - } - else if (p_obstacle_line_no == 5) - { - result = 0.5 * (p_obstacle_shape.ulx - p_contained_shape.lrx); - } - else if (p_obstacle_line_no == 7) - { - result = 0.5 * (p_obstacle_shape.llx - p_contained_shape.urx); - } - else - { - System.out.println("ShapeSearchTree45Degree.signed_line_distance: p_obstacle_line_no out of range"); - result = 0; - } - return result; - } - - /** Intersects p_room_shape with the half plane defined by the outside of the borderline - * with index p_obstacle_line_no of p_obstacle_shape. - */ - IntOctagon calc_outside_restrained_shape(IntOctagon p_obstacle_shape, int p_obstacle_line_no, IntOctagon p_room_shape) - { - int lx = p_room_shape.lx; - int ly = p_room_shape.ly; - int rx = p_room_shape.rx; - int uy = p_room_shape.uy; - int ulx = p_room_shape.ulx; - int lrx = p_room_shape.lrx; - int llx = p_room_shape.llx; - int urx = p_room_shape.urx; - - if (p_obstacle_line_no == 0) - { - uy = p_obstacle_shape.ly; - } - else if (p_obstacle_line_no == 2) - { - lx = p_obstacle_shape.rx; - } - else if (p_obstacle_line_no == 4) - { - ly = p_obstacle_shape.uy; - } - else if (p_obstacle_line_no == 6) - { - rx = p_obstacle_shape.lx; - } - else if (p_obstacle_line_no == 1) - { - ulx = p_obstacle_shape.lrx; - } - else if (p_obstacle_line_no == 3) - { - llx = p_obstacle_shape.urx; - } - else if (p_obstacle_line_no == 5) - { - lrx = p_obstacle_shape.ulx; - } - else if (p_obstacle_line_no == 7) - { - urx = p_obstacle_shape.llx; - } - else - { - System.out.println("ShapeSearchTree45Degree.calc_outside_restrained_shape: p_obstacle_line_no out of range"); - } - - IntOctagon result = new IntOctagon(lx, ly, rx, uy, ulx, lrx, llx, urx); - return result.normalize(); - } - - /** Intersects p_room_shape with the half plane defined by the inside of the borderline - * with index p_obstacle_line_no of p_obstacle_shape. - */ - IntOctagon calc_inside_restrained_shape(IntOctagon p_obstacle_shape, int p_obstacle_line_no, IntOctagon p_room_shape) - { - int lx = p_room_shape.lx; - int ly = p_room_shape.ly; - int rx = p_room_shape.rx; - int uy = p_room_shape.uy; - int ulx = p_room_shape.ulx; - int lrx = p_room_shape.lrx; - int llx = p_room_shape.llx; - int urx = p_room_shape.urx; - - if (p_obstacle_line_no == 0) - { - ly = p_obstacle_shape.ly; - } - else if (p_obstacle_line_no == 2) - { - rx = p_obstacle_shape.rx; - } - else if (p_obstacle_line_no == 4) - { - uy = p_obstacle_shape.uy; - } - else if (p_obstacle_line_no == 6) - { - lx = p_obstacle_shape.lx; - } - else if (p_obstacle_line_no == 1) - { - lrx = p_obstacle_shape.lrx; - } - else if (p_obstacle_line_no == 3) - { - urx = p_obstacle_shape.urx; - } - else if (p_obstacle_line_no == 5) - { - ulx = p_obstacle_shape.ulx; - } - else if (p_obstacle_line_no == 7) - { - llx = p_obstacle_shape.llx; - } - else - { - System.out.println("ShapeSearchTree45Degree.calc_inside_restrained_shape: p_obstacle_line_no out of range"); - } - - IntOctagon result = new IntOctagon(lx, ly, rx, uy, ulx, lrx, llx, urx); - return result.normalize(); - } - - TileShape[] calculate_tree_shapes(DrillItem p_drill_item) - { - if (this.board == null) - { - return new TileShape[0]; - } - TileShape[] result = new TileShape[p_drill_item.tile_shape_count()]; - for (int i = 0; i < result.length; ++i) - { - Shape curr_shape = p_drill_item.get_shape(i); - if (curr_shape == null) - { - result[i] = null; - } - else - { - TileShape curr_tile_shape = curr_shape.bounding_octagon(); - if (curr_tile_shape.is_IntBox()) - { - curr_tile_shape = curr_shape.bounding_box(); - - // To avoid small corner cutoffs when taking the offset as an octagon. - // That may complicate the room division in the maze expand algorithm unnecessesary. - } - - int offset_width = this.clearance_compensation_value(p_drill_item.clearance_class_no(), p_drill_item.shape_layer(i)); - curr_tile_shape = (TileShape) curr_tile_shape.offset(offset_width); - result[i] = curr_tile_shape.bounding_octagon(); - } - } - return result; - } - - TileShape[] calculate_tree_shapes(ObstacleArea p_obstacle_area) - { - TileShape[] result = super.calculate_tree_shapes(p_obstacle_area); - for (int i = 0; i < result.length; ++i) - { - result[i] = result[i].bounding_octagon(); - } - return result; - } - - TileShape[] calculate_tree_shapes(BoardOutline p_outline) - { - TileShape[] result = super.calculate_tree_shapes(p_outline); - for (int i = 0; i < result.length; ++i) - { - result[i] = result[i].bounding_octagon(); - } - return result; - } -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * ShapeSearchTree45Degree.java + * + * Created on 15. Juli 2007, 07:26 + * + */ +package board; + +import java.util.Collection; +import java.util.LinkedList; + +import geometry.planar.FortyfiveDegreeBoundingDirections; +import geometry.planar.TileShape; +import geometry.planar.Shape; +import geometry.planar.IntOctagon; +import geometry.planar.IntBox; +import geometry.planar.Side; +import geometry.planar.Line; + +import autoroute.IncompleteFreeSpaceExpansionRoom; +import autoroute.CompleteFreeSpaceExpansionRoom; + +/** + * A special simple ShapeSearchtree, where the shapes are of class IntOctagon. + * It is used in the 45-degree autorouter algorithm. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class ShapeSearchTree45Degree extends ShapeSearchTree +{ + + /** + * Creates a new instance of ShapeSearchTree45Degree + * + * @param p_board a {@link board.BasicBoard} object. + * @param p_compensated_clearance_class_no a int. + */ + public ShapeSearchTree45Degree(BasicBoard p_board, int p_compensated_clearance_class_no) + { + super(FortyfiveDegreeBoundingDirections.INSTANCE, p_board, p_compensated_clearance_class_no); + } + + /** + * {@inheritDoc} + * + * Calculates a new incomplete room with a maximal TileShape contained in the shape of p_room, + * which may overlap only with items of the input net on the input layer. + * p_room.get_contained_shape() will be contained in the shape of the result room. + * If that is not possible, several rooms are returned with shapes, + * which intersect with p_room.get_contained_shape(). + * The result room is not yet complete, because its doors are not yet calculated. + */ + public Collection complete_shape(IncompleteFreeSpaceExpansionRoom p_room, + int p_net_no, SearchTreeObject p_ignore_object, TileShape p_ignore_shape) + { + if (!(p_room.get_contained_shape().is_IntOctagon()) && this.board.get_test_level() != TestLevel.RELEASE_VERSION) + { + System.out.println("ShapeSearchTree45Degree.complete_shape: unexpected p_shape_to_be_contained"); + return new LinkedList(); + } + IntOctagon shape_to_be_contained = p_room.get_contained_shape().bounding_octagon(); + if (this.root == null) + { + return new LinkedList(); + } + IntOctagon start_shape = board.get_bounding_box().bounding_octagon(); + if (p_room.get_shape() != null) + { + if (!(p_room.get_shape() instanceof IntOctagon)) + { + System.out.println("ShapeSearchTree45Degree.complete_shape: p_start_shape of type IntOctagon expected"); + return new LinkedList(); + } + start_shape = p_room.get_shape().bounding_octagon().intersection(start_shape); + } + IntOctagon bounding_shape = start_shape; + int room_layer = p_room.get_layer(); + Collection result = new LinkedList(); + result.add(new IncompleteFreeSpaceExpansionRoom(start_shape, room_layer, shape_to_be_contained)); + this.node_stack.reset(); + this.node_stack.push(this.root); + TreeNode curr_node; + + for (;;) + { + curr_node = this.node_stack.pop(); + if (curr_node == null) + { + break; + } + if (curr_node.bounding_shape.intersects(bounding_shape)) + { + if (curr_node instanceof Leaf) + { + Leaf curr_leaf = (Leaf) curr_node; + SearchTreeObject curr_object = (SearchTreeObject) curr_leaf.object; + boolean is_obstacle = curr_object.is_trace_obstacle(p_net_no); + + int shape_index = curr_leaf.shape_index_in_object; + if (is_obstacle && curr_object.shape_layer(shape_index) == room_layer && curr_object != p_ignore_object) + { + + IntOctagon curr_object_shape = curr_object.get_tree_shape(this, shape_index).bounding_octagon(); + Collection new_result = new LinkedList(); + IntOctagon new_bounding_shape = IntOctagon.EMPTY; + for (IncompleteFreeSpaceExpansionRoom curr_room : result) + { + IntOctagon curr_shape = (IntOctagon) curr_room.get_shape(); + if (curr_shape.overlaps(curr_object_shape)) + { + if (curr_object instanceof CompleteFreeSpaceExpansionRoom && p_ignore_shape != null) + { + IntOctagon intersection = curr_shape.intersection(curr_object_shape); + if (p_ignore_shape.contains(intersection)) + { + // ignore also all objects, whose intersection is contained in the + // 2-dim overlap-door with the from_room. + if (!p_ignore_shape.contains(curr_shape)) + { + new_result.add(curr_room); + new_bounding_shape = new_bounding_shape.union(curr_shape.bounding_box()); + } + continue; + } + } + Collection new_restrained_shapes = + restrain_shape(curr_room, curr_object_shape); + new_result.addAll(new_restrained_shapes); + + + for (IncompleteFreeSpaceExpansionRoom tmp_shape : new_result) + { + new_bounding_shape = new_bounding_shape.union(tmp_shape.get_shape().bounding_box()); + } + } + else + { + new_result.add(curr_room); + new_bounding_shape = new_bounding_shape.union(curr_shape.bounding_box()); + } + } + result = new_result; + bounding_shape = new_bounding_shape; + } + } + else + { + this.node_stack.push(((InnerNode) curr_node).first_child); + this.node_stack.push(((InnerNode) curr_node).second_child); + } + } + } + result = divide_large_room(result, board.get_bounding_box()); + // remove rooms with shapes equal to the contained shape to prevent endless loop. + java.util.Iterator it = result.iterator(); + while (it.hasNext()) + { + IncompleteFreeSpaceExpansionRoom curr_room = it.next(); + if (curr_room.get_contained_shape().contains(curr_room.get_shape())) + { + it.remove(); + } + } + return result; + } + + /** + * {@inheritDoc} + * + * Makes shure that on each layer there will be more than 1 IncompleteFreeSpaceExpansionRoom, + * even if there are no objects on the layer. Otherwise the maze search algprithm gets problems + * with vias. + */ + protected Collection divide_large_room( + Collection p_room_list, IntBox p_board_bounding_box) + { + Collection result = + super.divide_large_room(p_room_list, p_board_bounding_box); + for (IncompleteFreeSpaceExpansionRoom curr_room : result) + { + curr_room.set_shape(curr_room.get_shape().bounding_octagon()); + curr_room.set_contained_shape(curr_room.get_contained_shape().bounding_octagon()); + } + return result; + } + + /** + * Checks, if the border line segment with index p_obstacle_border_line_no intersects with the inside + * of p_room_shape. + */ + private static boolean obstacle_segment_touches_inside(IntOctagon p_obstacle_shape, + int p_obstacle_border_line_no, IntOctagon p_room_shape) + { + int curr_border_line_no = p_obstacle_border_line_no; + int curr_obstacle_corner_x = p_obstacle_shape.corner_x(p_obstacle_border_line_no); + int curr_obstacle_corner_y = p_obstacle_shape.corner_y(p_obstacle_border_line_no); + for (int j = 0; j < 5; ++j) + { + + if (p_room_shape.side_of_border_line(curr_obstacle_corner_x, curr_obstacle_corner_y, + curr_border_line_no) != Side.ON_THE_LEFT) + { + return false; + } + curr_border_line_no = (curr_border_line_no + 1) % 8; + } + + int next_obstacle_border_line_no = (p_obstacle_border_line_no + 1) % 8; + int next_obstacle_corner_x = p_obstacle_shape.corner_x(next_obstacle_border_line_no); + int next_obstacle_corner_y = p_obstacle_shape.corner_y(next_obstacle_border_line_no); + curr_border_line_no = (p_obstacle_border_line_no + 5) % 8; + for (int j = 0; j < 3; ++j) + { + if (p_room_shape.side_of_border_line(next_obstacle_corner_x, next_obstacle_corner_y, + curr_border_line_no) != Side.ON_THE_LEFT) + { + return false; + } + curr_border_line_no = (curr_border_line_no + 1) % 8; + } + return true; + } + + /** + * Restrains the shape of p_incomplete_room to a octagon shape, which does not intersect with the interiour + * of p_obstacle_shape. p_incomplete_room.get_contained_shape() must be contained in the shape of + * the result room. + */ + private Collection restrain_shape(IncompleteFreeSpaceExpansionRoom p_incomplete_room, IntOctagon p_obstacle_shape) + { + // Search the edge line of p_obstacle_shape, so that p_shape_to_be_contained + // are on the right side of this line, and that the line segment + // intersects with the interiour of p_shape. + // If there are more than 1 such lines take the line which is + // furthest away from the shape_to_be_contained + // Then insersect p_shape with the halfplane defined by the + // opposite of this line. + + Collection result = new LinkedList(); + if (p_incomplete_room.get_contained_shape()==null || p_incomplete_room.get_contained_shape().is_empty()) + { + if (this.board.get_test_level().ordinal() >= TestLevel.ALL_DEBUGGING_OUTPUT.ordinal()) + { + System.out.println("ShapeSearchTree45Degree.restrain_shape: p_shape_to_be_contained is empty"); + } + return result; + } + IntOctagon room_shape = p_incomplete_room.get_shape().bounding_octagon(); + IntOctagon shape_to_be_contained = p_incomplete_room.get_contained_shape().bounding_octagon(); + double cut_line_distance = -1; + int restraining_line_no = -1; + + for (int obstacle_line_no = 0; obstacle_line_no < 8; ++obstacle_line_no) + { + double curr_distance = signed_line_distance(p_obstacle_shape, obstacle_line_no, shape_to_be_contained); + if (curr_distance > cut_line_distance) + { + if (obstacle_segment_touches_inside(p_obstacle_shape, obstacle_line_no, room_shape)) + { + cut_line_distance = curr_distance; + restraining_line_no = obstacle_line_no; + } + } + } + if (cut_line_distance >= 0) + { + IntOctagon restrained_shape = calc_outside_restrained_shape(p_obstacle_shape, restraining_line_no, room_shape); + result.add(new IncompleteFreeSpaceExpansionRoom(restrained_shape, + p_incomplete_room.get_layer(), shape_to_be_contained)); + return result; + } + + // There is no cut line, so that all p_shape_to_be_contained is + // completely on the right side of that line. Search a cut line, so that + // at least part of p_shape_to_be_contained is on the right side. + if (shape_to_be_contained.dimension() < 1) + { + // There is already a completed expansion room around p_shape_to_be_contained. + return result; + } + + restraining_line_no = -1; + for (int obstacle_line_no = 0; obstacle_line_no < 8; ++obstacle_line_no) + { + if (obstacle_segment_touches_inside(p_obstacle_shape, obstacle_line_no, room_shape)) + { + Line curr_line = p_obstacle_shape.border_line(obstacle_line_no); + if (shape_to_be_contained.side_of(curr_line) == Side.COLLINEAR) + { + // curr_line intersects with the interiour of p_shape_to_be_contained + restraining_line_no = obstacle_line_no; + break; + } + } + } + if (restraining_line_no < 0) + { + // cut line not found, parts or the whole of p_shape may be already + // occupied from somewhere else. + return result; + } + IntOctagon restrained_shape = calc_outside_restrained_shape(p_obstacle_shape, restraining_line_no, room_shape); + if (restrained_shape.dimension() == 2) + { + IntOctagon new_shape_to_be_contained = shape_to_be_contained.intersection(restrained_shape); + if (new_shape_to_be_contained.dimension() > 0) + { + result.add(new IncompleteFreeSpaceExpansionRoom(restrained_shape, + p_incomplete_room.get_layer(), new_shape_to_be_contained)); + } + } + + IntOctagon rest_piece = calc_inside_restrained_shape(p_obstacle_shape, restraining_line_no, room_shape); + if (rest_piece.dimension() >= 2) + { + TileShape rest_shape_to_be_contained = shape_to_be_contained.intersection(rest_piece); + if (rest_shape_to_be_contained.dimension() >= 0) + { + IncompleteFreeSpaceExpansionRoom rest_incomplete_room = new IncompleteFreeSpaceExpansionRoom(rest_piece, p_incomplete_room.get_layer(), rest_shape_to_be_contained); + result.addAll(restrain_shape(rest_incomplete_room, p_obstacle_shape)); + } + } + return result; + } + + private static double signed_line_distance(IntOctagon p_obstacle_shape, int p_obstacle_line_no, IntOctagon p_contained_shape) + { + double result; + if (p_obstacle_line_no == 0) + { + result = p_obstacle_shape.ly - p_contained_shape.uy; + } + else if (p_obstacle_line_no == 2) + { + result = p_contained_shape.lx - p_obstacle_shape.rx; + } + else if (p_obstacle_line_no == 4) + { + result = p_contained_shape.ly - p_obstacle_shape.uy; + } + else if (p_obstacle_line_no == 6) + { + result = p_obstacle_shape.lx - p_contained_shape.rx; + } + // factor 0.5 used instead to 1 / sqrt(2) to prefer orthogonal lines slightly to diagonal restraining lines. + else if (p_obstacle_line_no == 1) + { + result = 0.5 * (p_contained_shape.ulx - p_obstacle_shape.lrx); + } + else if (p_obstacle_line_no == 3) + { + result = 0.5 * (p_contained_shape.llx - p_obstacle_shape.urx); + } + else if (p_obstacle_line_no == 5) + { + result = 0.5 * (p_obstacle_shape.ulx - p_contained_shape.lrx); + } + else if (p_obstacle_line_no == 7) + { + result = 0.5 * (p_obstacle_shape.llx - p_contained_shape.urx); + } + else + { + System.out.println("ShapeSearchTree45Degree.signed_line_distance: p_obstacle_line_no out of range"); + result = 0; + } + return result; + } + + /** Intersects p_room_shape with the half plane defined by the outside of the borderline + * with index p_obstacle_line_no of p_obstacle_shape. + */ + IntOctagon calc_outside_restrained_shape(IntOctagon p_obstacle_shape, int p_obstacle_line_no, IntOctagon p_room_shape) + { + int lx = p_room_shape.lx; + int ly = p_room_shape.ly; + int rx = p_room_shape.rx; + int uy = p_room_shape.uy; + int ulx = p_room_shape.ulx; + int lrx = p_room_shape.lrx; + int llx = p_room_shape.llx; + int urx = p_room_shape.urx; + + if (p_obstacle_line_no == 0) + { + uy = p_obstacle_shape.ly; + } + else if (p_obstacle_line_no == 2) + { + lx = p_obstacle_shape.rx; + } + else if (p_obstacle_line_no == 4) + { + ly = p_obstacle_shape.uy; + } + else if (p_obstacle_line_no == 6) + { + rx = p_obstacle_shape.lx; + } + else if (p_obstacle_line_no == 1) + { + ulx = p_obstacle_shape.lrx; + } + else if (p_obstacle_line_no == 3) + { + llx = p_obstacle_shape.urx; + } + else if (p_obstacle_line_no == 5) + { + lrx = p_obstacle_shape.ulx; + } + else if (p_obstacle_line_no == 7) + { + urx = p_obstacle_shape.llx; + } + else + { + System.out.println("ShapeSearchTree45Degree.calc_outside_restrained_shape: p_obstacle_line_no out of range"); + } + + IntOctagon result = new IntOctagon(lx, ly, rx, uy, ulx, lrx, llx, urx); + return result.normalize(); + } + + /** Intersects p_room_shape with the half plane defined by the inside of the borderline + * with index p_obstacle_line_no of p_obstacle_shape. + */ + IntOctagon calc_inside_restrained_shape(IntOctagon p_obstacle_shape, int p_obstacle_line_no, IntOctagon p_room_shape) + { + int lx = p_room_shape.lx; + int ly = p_room_shape.ly; + int rx = p_room_shape.rx; + int uy = p_room_shape.uy; + int ulx = p_room_shape.ulx; + int lrx = p_room_shape.lrx; + int llx = p_room_shape.llx; + int urx = p_room_shape.urx; + + if (p_obstacle_line_no == 0) + { + ly = p_obstacle_shape.ly; + } + else if (p_obstacle_line_no == 2) + { + rx = p_obstacle_shape.rx; + } + else if (p_obstacle_line_no == 4) + { + uy = p_obstacle_shape.uy; + } + else if (p_obstacle_line_no == 6) + { + lx = p_obstacle_shape.lx; + } + else if (p_obstacle_line_no == 1) + { + lrx = p_obstacle_shape.lrx; + } + else if (p_obstacle_line_no == 3) + { + urx = p_obstacle_shape.urx; + } + else if (p_obstacle_line_no == 5) + { + ulx = p_obstacle_shape.ulx; + } + else if (p_obstacle_line_no == 7) + { + llx = p_obstacle_shape.llx; + } + else + { + System.out.println("ShapeSearchTree45Degree.calc_inside_restrained_shape: p_obstacle_line_no out of range"); + } + + IntOctagon result = new IntOctagon(lx, ly, rx, uy, ulx, lrx, llx, urx); + return result.normalize(); + } + + TileShape[] calculate_tree_shapes(DrillItem p_drill_item) + { + if (this.board == null) + { + return new TileShape[0]; + } + TileShape[] result = new TileShape[p_drill_item.tile_shape_count()]; + for (int i = 0; i < result.length; ++i) + { + Shape curr_shape = p_drill_item.get_shape(i); + if (curr_shape == null) + { + result[i] = null; + } + else + { + TileShape curr_tile_shape = curr_shape.bounding_octagon(); + if (curr_tile_shape.is_IntBox()) + { + curr_tile_shape = curr_shape.bounding_box(); + + // To avoid small corner cutoffs when taking the offset as an octagon. + // That may complicate the room division in the maze expand algorithm unnecessesary. + } + + int offset_width = this.clearance_compensation_value(p_drill_item.clearance_class_no(), p_drill_item.shape_layer(i)); + curr_tile_shape = (TileShape) curr_tile_shape.offset(offset_width); + result[i] = curr_tile_shape.bounding_octagon(); + } + } + return result; + } + + TileShape[] calculate_tree_shapes(ObstacleArea p_obstacle_area) + { + TileShape[] result = super.calculate_tree_shapes(p_obstacle_area); + for (int i = 0; i < result.length; ++i) + { + result[i] = result[i].bounding_octagon(); + } + return result; + } + + TileShape[] calculate_tree_shapes(BoardOutline p_outline) + { + TileShape[] result = super.calculate_tree_shapes(p_outline); + for (int i = 0; i < result.length; ++i) + { + result[i] = result[i].bounding_octagon(); + } + return result; + } +} diff --git a/board/ShapeSearchTree90Degree.java b/src/main/java/board/ShapeSearchTree90Degree.java similarity index 97% rename from board/ShapeSearchTree90Degree.java rename to src/main/java/board/ShapeSearchTree90Degree.java index 2da0bdb..81b0609 100644 --- a/board/ShapeSearchTree90Degree.java +++ b/src/main/java/board/ShapeSearchTree90Degree.java @@ -1,359 +1,369 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * BoxShapeSearchTree.java - * - * Created on 20. Mai 2007, 07:33 - * - */ - -package board; - -import java.util.Collection; -import java.util.LinkedList; - -import geometry.planar.OrthogonalBoundingDirections; -import geometry.planar.TileShape; -import geometry.planar.Shape; -import geometry.planar.IntBox; -import geometry.planar.Polyline; - -import autoroute.IncompleteFreeSpaceExpansionRoom; -import autoroute.CompleteFreeSpaceExpansionRoom; - -/** - * A special simple ShapeSearchtree, where the shapes are of class IntBox. - * It is used in the 90-degree autorouter algorithm. - * - * @author Alfons Wirtz - */ -public class ShapeSearchTree90Degree extends ShapeSearchTree -{ - - /** Creates a new instance of ShapeSearchTree90Degree */ - public ShapeSearchTree90Degree(BasicBoard p_board, int p_compensated_clearance_class_no) - { - super(OrthogonalBoundingDirections.INSTANCE, p_board, p_compensated_clearance_class_no); - } - - /** - * Calculates a new incomplete room with a maximal TileShape contained in the shape of p_room, - * which may overlap only with items of the input net on the input layer. - * p_room.get_contained_shape() will be contained in the shape of the result room. - * If that is not possible, several rooms are returned with shapes, - * which intersect with p_room.get_contained_shape(). - * The result room is not yet complete, because its doors are not yet calculated. - */ - public Collection complete_shape(IncompleteFreeSpaceExpansionRoom p_room, - int p_net_no, SearchTreeObject p_ignore_object, TileShape p_ignore_shape) - { - if (!(p_room.get_contained_shape() instanceof IntBox)) - { - System.out.println("BoxShapeSearchTree.complete_shape: unexpected p_shape_to_be_contained"); - return new LinkedList(); - } - IntBox shape_to_be_contained = (IntBox) p_room.get_contained_shape(); - if (this.root == null) - { - return new LinkedList(); - } - IntBox start_shape = board.get_bounding_box(); - if (p_room.get_shape() != null) - { - if (!(p_room.get_shape() instanceof IntBox)) - { - System.out.println("BoxShapeSearchTree.complete_shape: p_start_shape of type IntBox expected"); - return new LinkedList(); - } - start_shape = ((IntBox)p_room.get_shape()).intersection(start_shape); - } - IntBox bounding_shape = start_shape; - int room_layer = p_room.get_layer(); - Collection result = new LinkedList(); - result.add(new IncompleteFreeSpaceExpansionRoom(start_shape, room_layer, shape_to_be_contained)); - this.node_stack.reset(); - this.node_stack.push(this.root); - TreeNode curr_node; - - for (;;) - { - curr_node = this.node_stack.pop(); - if (curr_node == null) - { - break; - } - if (curr_node.bounding_shape.intersects(bounding_shape)) - { - if (curr_node instanceof Leaf) - { - Leaf curr_leaf = (Leaf) curr_node; - SearchTreeObject curr_object = (SearchTreeObject) curr_leaf.object; - int shape_index = curr_leaf.shape_index_in_object; - if (curr_object.is_trace_obstacle(p_net_no) && curr_object.shape_layer(shape_index) == room_layer - && curr_object != p_ignore_object) - { - - IntBox curr_object_shape = curr_object.get_tree_shape(this, shape_index).bounding_box(); - Collection new_result = new LinkedList(); - IntBox new_bounding_shape = IntBox.EMPTY; - for (IncompleteFreeSpaceExpansionRoom curr_room : result) - { - IntBox curr_shape = (IntBox) curr_room.get_shape(); - if (curr_shape.overlaps(curr_object_shape)) - { - if (curr_object instanceof CompleteFreeSpaceExpansionRoom - && p_ignore_shape != null ) - { - IntBox intersection = curr_shape.intersection(curr_object_shape); - if (p_ignore_shape.contains(intersection)) - { - // ignore also all objects, whose intersection is contained in the - // 2-dim overlap-door with the from_room. - continue; - } - } - Collection new_restrained_shapes = - restrain_shape(curr_room, curr_object_shape); - new_result.addAll(new_restrained_shapes); - - - for (IncompleteFreeSpaceExpansionRoom tmp_shape : new_result) - { - new_bounding_shape = new_bounding_shape.union(tmp_shape.get_shape().bounding_box()); - } - } - else - { - new_result.add(curr_room); - new_bounding_shape = new_bounding_shape.union(curr_shape.bounding_box()); - } - } - result = new_result; - bounding_shape = new_bounding_shape; - } - } - else - { - this.node_stack.push(((InnerNode)curr_node).first_child); - this.node_stack.push(((InnerNode)curr_node).second_child); - } - } - } - return result; - } - - /** - * Restrains the shape of p_incomplete_room to a box shape, which does not intersect with the interiour - * of p_obstacle_shape. p_incomplete_room.get_contained_shape() must be contained in the shape of - * the result room. - */ - private Collection restrain_shape(IncompleteFreeSpaceExpansionRoom p_incomplete_room, IntBox p_obstacle_shape) - { - // Search the edge line of p_obstacle_shape, so that p_shape_to_be_contained - // are on the right side of this line, and that the line segment - // intersects with the interiour of p_shape. - // If there are more than 1 such lines take the line which is - // furthest away from the shape_to_be_contained - // Then insersect p_shape with the halfplane defined by the - // opposite of this line. - - Collection result = new LinkedList(); - if (p_incomplete_room.get_contained_shape().is_empty()) - { - if (this.board.get_test_level().ordinal() >= TestLevel.ALL_DEBUGGING_OUTPUT.ordinal()) - { - System.out.println("BoxShapeSearchTree.restrain_shape: p_shape_to_be_contained is empty"); - } - return result; - } - IntBox room_shape = p_incomplete_room.get_shape().bounding_box(); - IntBox shape_to_be_contained = p_incomplete_room.get_contained_shape().bounding_box(); - int cut_line_distance = 0; - IntBox restrained_shape = null; - - if (room_shape.ll.x < p_obstacle_shape.ur.x && room_shape.ur.x > p_obstacle_shape.ur.x - && room_shape.ur.y > p_obstacle_shape.ll.y && room_shape.ll.y < p_obstacle_shape.ur.y ) - { - // The right line segment of the obstacle_shape intersects the interiour of p_shape - int curr_distance = shape_to_be_contained.ll.x - p_obstacle_shape.ur.x; - if (curr_distance > cut_line_distance) - { - cut_line_distance = curr_distance; - restrained_shape = new IntBox(p_obstacle_shape.ur.x, room_shape.ll.y, room_shape.ur.x, room_shape.ur.y); - } - } - if (room_shape.ll.x < p_obstacle_shape.ll.x && room_shape.ur.x > p_obstacle_shape.ll.x - && room_shape.ur.y > p_obstacle_shape.ll.y && room_shape.ll.y < p_obstacle_shape.ur.y ) - { - // The left line segment of the obstacle_shape intersects the interiour of p_shape - int curr_distance = p_obstacle_shape.ll.x - shape_to_be_contained.ur.x; - if (curr_distance > cut_line_distance) - { - cut_line_distance = curr_distance; - restrained_shape = new IntBox(room_shape.ll.x, room_shape.ll.y, p_obstacle_shape.ll.x, room_shape.ur.y); - } - } - if (room_shape.ll.y < p_obstacle_shape.ll.y && room_shape.ur.y > p_obstacle_shape.ll.y - && room_shape.ur.x > p_obstacle_shape.ll.x && room_shape.ll.x < p_obstacle_shape.ur.x ) - { - // The lower line segment of the obstacle_shape intersects the interiour of p_shape - int curr_distance = p_obstacle_shape.ll.y - shape_to_be_contained.ur.y; - if (curr_distance > cut_line_distance) - { - cut_line_distance = curr_distance; - restrained_shape = new IntBox(room_shape.ll.x, room_shape.ll.y, room_shape.ur.x, p_obstacle_shape.ll.y); - } - } - if (room_shape.ll.y < p_obstacle_shape.ur.y && room_shape.ur.y > p_obstacle_shape.ur.y - && room_shape.ur.x > p_obstacle_shape.ll.x && room_shape.ll.x < p_obstacle_shape.ur.x ) - { - // The upper line segment of the obstacle_shape intersects the interiour of p_shape - int curr_distance = shape_to_be_contained.ll.y - p_obstacle_shape.ur.y; - if (curr_distance > cut_line_distance) - { - cut_line_distance = curr_distance; - restrained_shape = new IntBox(room_shape.ll.x, p_obstacle_shape.ur.y, room_shape.ur.x, room_shape.ur.y); - } - } - if (restrained_shape != null) - { - result.add(new IncompleteFreeSpaceExpansionRoom(restrained_shape, - p_incomplete_room.get_layer(), shape_to_be_contained)); - return result; - } - - // Now shape_to_be_contained intersects with the obstacle_shape. - // shape_to_be_contained and p_shape evtl. need to be divided in two. - IntBox is = shape_to_be_contained.intersection(p_obstacle_shape); - if (is.is_empty()) - { - System.out.println("BoxShapeSearchTree.restrain_shape: Intersection between obstacle_shape and shape_to_be_contained expected"); - return result; - } - IntBox new_shape_1 = null; - IntBox new_shape_2 = null; - if (is.ll.x > room_shape.ll.x && is.ll.x == p_obstacle_shape.ll.x && is.ll.x < room_shape.ur.x) - { - new_shape_1 = new IntBox(room_shape.ll.x, room_shape.ll.y, is.ll.x, room_shape.ur.y); - new_shape_2 = new IntBox(is.ll.x, room_shape.ll.y, room_shape.ur.x, room_shape.ur.y); - } - else if (is.ur.x > room_shape.ll.x && is.ur.x == p_obstacle_shape.ur.x && is.ur.x < room_shape.ur.x) - { - new_shape_2 = new IntBox(room_shape.ll.x, room_shape.ll.y, is.ur.x, room_shape.ur.y); - new_shape_1 = new IntBox(is.ur.x, room_shape.ll.y, room_shape.ur.x, room_shape.ur.y); - } - else if (is.ll.y > room_shape.ll.y && is.ll.y == p_obstacle_shape.ll.y && is.ll.y < room_shape.ur.y) - { - new_shape_1 = new IntBox(room_shape.ll.x, room_shape.ll.y, room_shape.ur.x, is.ll.y); - new_shape_2 = new IntBox(room_shape.ll.x, is.ll.y, room_shape.ur.x, room_shape.ur.y); - } - else if (is.ur.y > room_shape.ll.y && is.ur.y == p_obstacle_shape.ur.y && is.ur.y < room_shape.ur.y) - { - new_shape_2 = new IntBox(room_shape.ll.x, room_shape.ll.y, room_shape.ur.x, is.ur.y); - new_shape_1 = new IntBox(room_shape.ll.x, is.ur.y, room_shape.ur.x, room_shape.ur.y); - } - if (new_shape_1 != null) - { - IntBox new_shape_to_be_contained = shape_to_be_contained.intersection(new_shape_1); - if (new_shape_to_be_contained.dimension() > 0) - { - result.add(new IncompleteFreeSpaceExpansionRoom(new_shape_1, - p_incomplete_room.get_layer(), new_shape_to_be_contained)); - IncompleteFreeSpaceExpansionRoom new_incomplete_room = - new IncompleteFreeSpaceExpansionRoom( new_shape_2, p_incomplete_room.get_layer(), - shape_to_be_contained.intersection(new_shape_2)); - result.addAll(restrain_shape(new_incomplete_room, p_obstacle_shape)); - } - } - return result; - } - - TileShape[] calculate_tree_shapes(DrillItem p_drill_item) - { - if (this.board == null) - { - return new TileShape[0]; - } - TileShape[] result = new TileShape [p_drill_item.tile_shape_count()]; - for (int i = 0; i < result.length; ++i) - { - Shape curr_shape = p_drill_item.get_shape(i); - if (curr_shape == null) - { - result[i] = null; - } - else - { - IntBox curr_tile_shape = curr_shape.bounding_box(); - int offset_width = this.clearance_compensation_value(p_drill_item.clearance_class_no(), p_drill_item.shape_layer(i)); - if (curr_tile_shape == null) - { - System.out.println("BoxShapeSearchTree.calculate_tree_shapes: shape is null"); - } - else - { - curr_tile_shape = curr_tile_shape.offset(offset_width); - } - result [i] = curr_tile_shape; - } - } - return result; - } - - TileShape[] calculate_tree_shapes(ObstacleArea p_obstacle_area) - { - TileShape[] result = super.calculate_tree_shapes(p_obstacle_area); - for (int i = 0; i < result.length; ++i) - { - result[i] = result[i].bounding_box(); - } - return result; - } - - TileShape[] calculate_tree_shapes(BoardOutline p_outline) - { - TileShape[] result = super.calculate_tree_shapes(p_outline); - for (int i = 0; i < result.length; ++i) - { - result[i] = result[i].bounding_box(); - } - return result; - } - - /** - * Used for creating the shapes of a polyline_trace for this tree. - */ - TileShape offset_shape(Polyline p_polyline, int p_half_width, int p_no) - { - return p_polyline.offset_box(p_half_width, p_no); - } - - /** - * Used for creating the shapes of a polyline_trace for this tree. - */ - public TileShape[] offset_shapes(Polyline p_polyline, int p_half_width, - int p_from_no, int p_to_no) - { - int from_no = Math.max(p_from_no, 0); - int to_no = Math.min(p_to_no, p_polyline.arr.length -1); - int shape_count = Math.max(to_no - from_no -1, 0); - TileShape[] shape_arr = new TileShape[shape_count]; - for (int j = from_no; j < to_no - 1; ++j) - { - shape_arr [j - from_no] = p_polyline.offset_box(p_half_width, j); - } - return shape_arr; - } -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * BoxShapeSearchTree.java + * + * Created on 20. Mai 2007, 07:33 + * + */ + +package board; + +import java.util.Collection; +import java.util.LinkedList; + +import geometry.planar.OrthogonalBoundingDirections; +import geometry.planar.TileShape; +import geometry.planar.Shape; +import geometry.planar.IntBox; +import geometry.planar.Polyline; + +import autoroute.IncompleteFreeSpaceExpansionRoom; +import autoroute.CompleteFreeSpaceExpansionRoom; + +/** + * A special simple ShapeSearchtree, where the shapes are of class IntBox. + * It is used in the 90-degree autorouter algorithm. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class ShapeSearchTree90Degree extends ShapeSearchTree +{ + + /** + * Creates a new instance of ShapeSearchTree90Degree + * + * @param p_board a {@link board.BasicBoard} object. + * @param p_compensated_clearance_class_no a int. + */ + public ShapeSearchTree90Degree(BasicBoard p_board, int p_compensated_clearance_class_no) + { + super(OrthogonalBoundingDirections.INSTANCE, p_board, p_compensated_clearance_class_no); + } + + /** + * {@inheritDoc} + * + * Calculates a new incomplete room with a maximal TileShape contained in the shape of p_room, + * which may overlap only with items of the input net on the input layer. + * p_room.get_contained_shape() will be contained in the shape of the result room. + * If that is not possible, several rooms are returned with shapes, + * which intersect with p_room.get_contained_shape(). + * The result room is not yet complete, because its doors are not yet calculated. + */ + public Collection complete_shape(IncompleteFreeSpaceExpansionRoom p_room, + int p_net_no, SearchTreeObject p_ignore_object, TileShape p_ignore_shape) + { + if (!(p_room.get_contained_shape() instanceof IntBox)) + { + System.out.println("BoxShapeSearchTree.complete_shape: unexpected p_shape_to_be_contained"); + return new LinkedList(); + } + IntBox shape_to_be_contained = (IntBox) p_room.get_contained_shape(); + if (this.root == null) + { + return new LinkedList(); + } + IntBox start_shape = board.get_bounding_box(); + if (p_room.get_shape() != null) + { + if (!(p_room.get_shape() instanceof IntBox)) + { + System.out.println("BoxShapeSearchTree.complete_shape: p_start_shape of type IntBox expected"); + return new LinkedList(); + } + start_shape = ((IntBox)p_room.get_shape()).intersection(start_shape); + } + IntBox bounding_shape = start_shape; + int room_layer = p_room.get_layer(); + Collection result = new LinkedList(); + result.add(new IncompleteFreeSpaceExpansionRoom(start_shape, room_layer, shape_to_be_contained)); + this.node_stack.reset(); + this.node_stack.push(this.root); + TreeNode curr_node; + + for (;;) + { + curr_node = this.node_stack.pop(); + if (curr_node == null) + { + break; + } + if (curr_node.bounding_shape.intersects(bounding_shape)) + { + if (curr_node instanceof Leaf) + { + Leaf curr_leaf = (Leaf) curr_node; + SearchTreeObject curr_object = (SearchTreeObject) curr_leaf.object; + int shape_index = curr_leaf.shape_index_in_object; + if (curr_object.is_trace_obstacle(p_net_no) && curr_object.shape_layer(shape_index) == room_layer + && curr_object != p_ignore_object) + { + + IntBox curr_object_shape = curr_object.get_tree_shape(this, shape_index).bounding_box(); + Collection new_result = new LinkedList(); + IntBox new_bounding_shape = IntBox.EMPTY; + for (IncompleteFreeSpaceExpansionRoom curr_room : result) + { + IntBox curr_shape = (IntBox) curr_room.get_shape(); + if (curr_shape.overlaps(curr_object_shape)) + { + if (curr_object instanceof CompleteFreeSpaceExpansionRoom + && p_ignore_shape != null ) + { + IntBox intersection = curr_shape.intersection(curr_object_shape); + if (p_ignore_shape.contains(intersection)) + { + // ignore also all objects, whose intersection is contained in the + // 2-dim overlap-door with the from_room. + continue; + } + } + Collection new_restrained_shapes = + restrain_shape(curr_room, curr_object_shape); + new_result.addAll(new_restrained_shapes); + + + for (IncompleteFreeSpaceExpansionRoom tmp_shape : new_result) + { + new_bounding_shape = new_bounding_shape.union(tmp_shape.get_shape().bounding_box()); + } + } + else + { + new_result.add(curr_room); + new_bounding_shape = new_bounding_shape.union(curr_shape.bounding_box()); + } + } + result = new_result; + bounding_shape = new_bounding_shape; + } + } + else + { + this.node_stack.push(((InnerNode)curr_node).first_child); + this.node_stack.push(((InnerNode)curr_node).second_child); + } + } + } + return result; + } + + /** + * Restrains the shape of p_incomplete_room to a box shape, which does not intersect with the interiour + * of p_obstacle_shape. p_incomplete_room.get_contained_shape() must be contained in the shape of + * the result room. + */ + private Collection restrain_shape(IncompleteFreeSpaceExpansionRoom p_incomplete_room, IntBox p_obstacle_shape) + { + // Search the edge line of p_obstacle_shape, so that p_shape_to_be_contained + // are on the right side of this line, and that the line segment + // intersects with the interiour of p_shape. + // If there are more than 1 such lines take the line which is + // furthest away from the shape_to_be_contained + // Then insersect p_shape with the halfplane defined by the + // opposite of this line. + + Collection result = new LinkedList(); + if (p_incomplete_room.get_contained_shape().is_empty()) + { + if (this.board.get_test_level().ordinal() >= TestLevel.ALL_DEBUGGING_OUTPUT.ordinal()) + { + System.out.println("BoxShapeSearchTree.restrain_shape: p_shape_to_be_contained is empty"); + } + return result; + } + IntBox room_shape = p_incomplete_room.get_shape().bounding_box(); + IntBox shape_to_be_contained = p_incomplete_room.get_contained_shape().bounding_box(); + int cut_line_distance = 0; + IntBox restrained_shape = null; + + if (room_shape.ll.x < p_obstacle_shape.ur.x && room_shape.ur.x > p_obstacle_shape.ur.x + && room_shape.ur.y > p_obstacle_shape.ll.y && room_shape.ll.y < p_obstacle_shape.ur.y ) + { + // The right line segment of the obstacle_shape intersects the interiour of p_shape + int curr_distance = shape_to_be_contained.ll.x - p_obstacle_shape.ur.x; + if (curr_distance > cut_line_distance) + { + cut_line_distance = curr_distance; + restrained_shape = new IntBox(p_obstacle_shape.ur.x, room_shape.ll.y, room_shape.ur.x, room_shape.ur.y); + } + } + if (room_shape.ll.x < p_obstacle_shape.ll.x && room_shape.ur.x > p_obstacle_shape.ll.x + && room_shape.ur.y > p_obstacle_shape.ll.y && room_shape.ll.y < p_obstacle_shape.ur.y ) + { + // The left line segment of the obstacle_shape intersects the interiour of p_shape + int curr_distance = p_obstacle_shape.ll.x - shape_to_be_contained.ur.x; + if (curr_distance > cut_line_distance) + { + cut_line_distance = curr_distance; + restrained_shape = new IntBox(room_shape.ll.x, room_shape.ll.y, p_obstacle_shape.ll.x, room_shape.ur.y); + } + } + if (room_shape.ll.y < p_obstacle_shape.ll.y && room_shape.ur.y > p_obstacle_shape.ll.y + && room_shape.ur.x > p_obstacle_shape.ll.x && room_shape.ll.x < p_obstacle_shape.ur.x ) + { + // The lower line segment of the obstacle_shape intersects the interiour of p_shape + int curr_distance = p_obstacle_shape.ll.y - shape_to_be_contained.ur.y; + if (curr_distance > cut_line_distance) + { + cut_line_distance = curr_distance; + restrained_shape = new IntBox(room_shape.ll.x, room_shape.ll.y, room_shape.ur.x, p_obstacle_shape.ll.y); + } + } + if (room_shape.ll.y < p_obstacle_shape.ur.y && room_shape.ur.y > p_obstacle_shape.ur.y + && room_shape.ur.x > p_obstacle_shape.ll.x && room_shape.ll.x < p_obstacle_shape.ur.x ) + { + // The upper line segment of the obstacle_shape intersects the interiour of p_shape + int curr_distance = shape_to_be_contained.ll.y - p_obstacle_shape.ur.y; + if (curr_distance > cut_line_distance) + { + cut_line_distance = curr_distance; + restrained_shape = new IntBox(room_shape.ll.x, p_obstacle_shape.ur.y, room_shape.ur.x, room_shape.ur.y); + } + } + if (restrained_shape != null) + { + result.add(new IncompleteFreeSpaceExpansionRoom(restrained_shape, + p_incomplete_room.get_layer(), shape_to_be_contained)); + return result; + } + + // Now shape_to_be_contained intersects with the obstacle_shape. + // shape_to_be_contained and p_shape evtl. need to be divided in two. + IntBox is = shape_to_be_contained.intersection(p_obstacle_shape); + if (is.is_empty()) + { + System.out.println("BoxShapeSearchTree.restrain_shape: Intersection between obstacle_shape and shape_to_be_contained expected"); + return result; + } + IntBox new_shape_1 = null; + IntBox new_shape_2 = null; + if (is.ll.x > room_shape.ll.x && is.ll.x == p_obstacle_shape.ll.x && is.ll.x < room_shape.ur.x) + { + new_shape_1 = new IntBox(room_shape.ll.x, room_shape.ll.y, is.ll.x, room_shape.ur.y); + new_shape_2 = new IntBox(is.ll.x, room_shape.ll.y, room_shape.ur.x, room_shape.ur.y); + } + else if (is.ur.x > room_shape.ll.x && is.ur.x == p_obstacle_shape.ur.x && is.ur.x < room_shape.ur.x) + { + new_shape_2 = new IntBox(room_shape.ll.x, room_shape.ll.y, is.ur.x, room_shape.ur.y); + new_shape_1 = new IntBox(is.ur.x, room_shape.ll.y, room_shape.ur.x, room_shape.ur.y); + } + else if (is.ll.y > room_shape.ll.y && is.ll.y == p_obstacle_shape.ll.y && is.ll.y < room_shape.ur.y) + { + new_shape_1 = new IntBox(room_shape.ll.x, room_shape.ll.y, room_shape.ur.x, is.ll.y); + new_shape_2 = new IntBox(room_shape.ll.x, is.ll.y, room_shape.ur.x, room_shape.ur.y); + } + else if (is.ur.y > room_shape.ll.y && is.ur.y == p_obstacle_shape.ur.y && is.ur.y < room_shape.ur.y) + { + new_shape_2 = new IntBox(room_shape.ll.x, room_shape.ll.y, room_shape.ur.x, is.ur.y); + new_shape_1 = new IntBox(room_shape.ll.x, is.ur.y, room_shape.ur.x, room_shape.ur.y); + } + if (new_shape_1 != null) + { + IntBox new_shape_to_be_contained = shape_to_be_contained.intersection(new_shape_1); + if (new_shape_to_be_contained.dimension() > 0) + { + result.add(new IncompleteFreeSpaceExpansionRoom(new_shape_1, + p_incomplete_room.get_layer(), new_shape_to_be_contained)); + IncompleteFreeSpaceExpansionRoom new_incomplete_room = + new IncompleteFreeSpaceExpansionRoom( new_shape_2, p_incomplete_room.get_layer(), + shape_to_be_contained.intersection(new_shape_2)); + result.addAll(restrain_shape(new_incomplete_room, p_obstacle_shape)); + } + } + return result; + } + + TileShape[] calculate_tree_shapes(DrillItem p_drill_item) + { + if (this.board == null) + { + return new TileShape[0]; + } + TileShape[] result = new TileShape [p_drill_item.tile_shape_count()]; + for (int i = 0; i < result.length; ++i) + { + Shape curr_shape = p_drill_item.get_shape(i); + if (curr_shape == null) + { + result[i] = null; + } + else + { + IntBox curr_tile_shape = curr_shape.bounding_box(); + int offset_width = this.clearance_compensation_value(p_drill_item.clearance_class_no(), p_drill_item.shape_layer(i)); + if (curr_tile_shape == null) + { + System.out.println("BoxShapeSearchTree.calculate_tree_shapes: shape is null"); + } + else + { + curr_tile_shape = curr_tile_shape.offset(offset_width); + } + result [i] = curr_tile_shape; + } + } + return result; + } + + TileShape[] calculate_tree_shapes(ObstacleArea p_obstacle_area) + { + TileShape[] result = super.calculate_tree_shapes(p_obstacle_area); + for (int i = 0; i < result.length; ++i) + { + result[i] = result[i].bounding_box(); + } + return result; + } + + TileShape[] calculate_tree_shapes(BoardOutline p_outline) + { + TileShape[] result = super.calculate_tree_shapes(p_outline); + for (int i = 0; i < result.length; ++i) + { + result[i] = result[i].bounding_box(); + } + return result; + } + + /** + * Used for creating the shapes of a polyline_trace for this tree. + */ + TileShape offset_shape(Polyline p_polyline, int p_half_width, int p_no) + { + return p_polyline.offset_box(p_half_width, p_no); + } + + /** + * {@inheritDoc} + * + * Used for creating the shapes of a polyline_trace for this tree. + */ + public TileShape[] offset_shapes(Polyline p_polyline, int p_half_width, + int p_from_no, int p_to_no) + { + int from_no = Math.max(p_from_no, 0); + int to_no = Math.min(p_to_no, p_polyline.arr.length -1); + int shape_count = Math.max(to_no - from_no -1, 0); + TileShape[] shape_arr = new TileShape[shape_count]; + for (int j = from_no; j < to_no - 1; ++j) + { + shape_arr [j - from_no] = p_polyline.offset_box(p_half_width, j); + } + return shape_arr; + } +} diff --git a/board/ShapeTraceEntries.java b/src/main/java/board/ShapeTraceEntries.java similarity index 97% rename from board/ShapeTraceEntries.java rename to src/main/java/board/ShapeTraceEntries.java index e745526..2ca8338 100644 --- a/board/ShapeTraceEntries.java +++ b/src/main/java/board/ShapeTraceEntries.java @@ -1,967 +1,976 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - */ - -package board; - -import geometry.planar.ConvexShape; -import geometry.planar.FloatPoint; -import geometry.planar.Line; -import geometry.planar.Point; -import geometry.planar.Polyline; -import geometry.planar.TileShape; - -import java.util.Collection; -import java.util.Iterator; - - - -/** - * Auxiliary class used by the shove functions - * - * @author Alfons Wirtz - */ - -public class ShapeTraceEntries -{ - /** - * Used for shoving traces and vias out of the input shape. - * p_from_side.no is the side of p_shape, from where the shove comes. - * if p_from_side.no < 0, it will be calculated internally. - */ - ShapeTraceEntries(TileShape p_shape, int p_layer, int[] p_own_net_nos, int p_cl_type, - CalcFromSide p_from_side, RoutingBoard p_board) - { - shape = p_shape; - layer = p_layer; - own_net_nos = p_own_net_nos; - cl_class = p_cl_type; - from_side = p_from_side; - board = p_board; - list_anchor = null; - trace_piece_count = 0; - max_stack_level = 0; - shove_via_list = new java.util.LinkedList(); - } - - /** - * Stores traces and vias in p_item_list. - * Returns false, if p_item_list contains obstacles, - * which cannot be shoved aside. - * If p_is_pad_check. the check is for vias, otherwise it is for traces. - * If p_copper_sharing_allowed, overlaps with traces or pads of the own net are allowed. - */ - boolean store_items(Collection p_item_list, boolean p_is_pad_check, boolean p_copper_sharing_allowed) - { - Iterator it = p_item_list.iterator(); - while(it.hasNext()) - { - Item curr_item = it.next(); - - if (!p_is_pad_check && curr_item instanceof ViaObstacleArea || curr_item instanceof ComponentObstacleArea) - { - continue; - } - boolean contains_own_net = curr_item.shares_net_no(this.own_net_nos); - if (curr_item instanceof ConductionArea && - (contains_own_net || !((ConductionArea)curr_item).get_is_obstacle())) - { - continue; - } - if (curr_item.is_shove_fixed() && !contains_own_net) - { - this.found_obstacle = curr_item; - return false; - } - if (curr_item instanceof Via) - { - if (p_is_pad_check || !contains_own_net) - { - shove_via_list.add((Via) curr_item); - } - } - else if (curr_item instanceof PolylineTrace) - { - PolylineTrace curr_trace = (PolylineTrace) curr_item; - - if (!store_trace(curr_trace)) - { - return false; - } - } - else - { - if (contains_own_net) - { - if (!p_copper_sharing_allowed) - { - this.found_obstacle = curr_item; - return false; - } - if (p_is_pad_check && !((curr_item instanceof Pin) && ((Pin)curr_item).drill_allowed())) - { - this.found_obstacle = curr_item; - return false; - } - } - else - { - this.found_obstacle = curr_item; - return false; - } - } - } - search_from_side(); - resort(); - if (!calculate_stack_levels()) - { - return false; - } - return true; - } - - - /** - * calculates the next substitute trace piece. - * Returns null at he end of the substitute trace list. - */ - PolylineTrace next_substitute_trace_piece() - { - - EntryPoint[] entries = pop_piece(); - if (entries == null) - { - return null; - } - PolylineTrace curr_trace = entries[0].trace; - TileShape offset_shape; - ShapeSearchTree search_tree = this.board.search_tree_manager.get_default_tree(); - if (search_tree.is_clearance_compensation_used()) - { - double curr_offset = curr_trace.get_compensated_half_width(search_tree) + c_offset_add; - offset_shape = (TileShape)shape.offset(curr_offset); - } - else - { - // enlarge the shape in 2 steps for symmetry reasons - offset_shape = (TileShape)shape.offset(curr_trace.get_half_width()); - double cl_offset = board.clearance_value(curr_trace.clearance_class_no(), cl_class, layer) + c_offset_add; - offset_shape = (TileShape) offset_shape.offset(cl_offset); - } - int edge_count = shape.border_line_count(); - int edge_diff = entries[1].edge_no - entries[0].edge_no; - - // calculate the polyline of the substitute trace - - Line [] piece_lines = new Line[edge_diff + 3]; - // start with the intersecting line of the trace at the start entry. - piece_lines[0] = entries[0].trace.polyline().arr[entries[0].trace_line_no]; - // end with the intersecting line of the trace at the end entry - piece_lines[piece_lines.length - 1] = - entries[1].trace.polyline().arr[entries[1].trace_line_no]; - // fill the interiour lines of piece_lines with the appropriate edge - // lines of the offset shape - int curr_edge_no = entries[0].edge_no % edge_count; - for (int i = 1; i < piece_lines.length - 1; ++i) - { - piece_lines [i] = offset_shape.border_line(curr_edge_no); - if (curr_edge_no == edge_count - 1) - { - curr_edge_no = 0; - } - else - { - ++curr_edge_no; - } - } - Polyline piece_polyline = new Polyline(piece_lines); - if (piece_polyline.is_empty()) - { - // no valid trace piece, return the next one - return next_substitute_trace_piece(); - } - return new PolylineTrace(piece_polyline, this.layer, - curr_trace.get_half_width(), curr_trace.net_no_arr, - curr_trace.clearance_class_no(), 0, 0, FixedState.UNFIXED, this.board); - } - - /** - * returns the maximum recursion depth for shoving the obstacle traces - */ - int stack_depth() - { - return max_stack_level; - } - - /** - * returns the number of substitute trace pieces. - */ - int substitute_trace_count() - { - return trace_piece_count; - } - - /** - * Looks if an unconnected endpoint of a trace of a foreign net - * is contained in the interiour of the shape. - */ - public boolean trace_tails_in_shape() - { - return this.shape_contains_trace_tails; - } - - /** - * Cuts out all traces in p_item_list out of the stored shape. - * Traces with net number p_except_net_no are ignored - */ - void cutout_traces(Collection p_item_list) - { - Iterator it = p_item_list.iterator(); - while (it.hasNext()) - { - Item curr_item = it.next(); - if (curr_item instanceof PolylineTrace && !curr_item.shares_net_no(this.own_net_nos)) - { - cutout_trace((PolylineTrace) curr_item, this.shape, this.cl_class); - } - } - } - - /** - * Returns the item responsible for the failing, if the shove algorithm failed. - */ - Item get_found_obstacle() - { - return this.found_obstacle; - } - - public static void cutout_trace(PolylineTrace p_trace, ConvexShape p_shape, int p_cl_class) - { - if (!p_trace.is_on_the_board()) - { - System.out.println("ShapeTraceEntries.cutout_trace : trace is deleted"); - return; - } - ConvexShape offset_shape; - BasicBoard board = p_trace.board; - ShapeSearchTree search_tree = board.search_tree_manager.get_default_tree(); - if (search_tree.is_clearance_compensation_used()) - { - double curr_offset = p_trace.get_compensated_half_width(search_tree) + c_offset_add; - offset_shape = p_shape.offset(curr_offset); - } - else - { - // enlarge the shape in 2 steps for symmetry reasons - double cl_offset = board.clearance_value(p_trace.clearance_class_no(), - p_cl_class, p_trace.get_layer()) + c_offset_add; - offset_shape = p_shape.offset(p_trace.get_half_width()); - offset_shape = offset_shape.offset(cl_offset); - } - Polyline trace_lines = p_trace.polyline(); - Polyline [] pieces = offset_shape.cutout(trace_lines); - if (pieces.length == 1 && pieces[0] == trace_lines) - { - // nothing cut off - return; - } - if (pieces.length == 2 && offset_shape.is_outside(pieces[0].first_corner()) - && offset_shape.is_outside(pieces[1].last_corner())) - { - fast_cutout_trace(p_trace, pieces[0], pieces[1]); - } - else - { - board.remove_item(p_trace); - for (int i = 0; i < pieces.length; ++i) - { - board.insert_trace_without_cleaning(pieces[i], p_trace.get_layer(), - p_trace.get_half_width(), p_trace.net_no_arr, p_trace.clearance_class_no(), FixedState.UNFIXED); - } - } - } - - /** Optimized function handling the performance critical standard cutout case */ - private static void fast_cutout_trace(PolylineTrace p_trace, Polyline p_start_piece, Polyline p_end_piece) - { - BasicBoard board = p_trace.board; - board.additional_update_after_change(p_trace); - board.item_list.save_for_undo(p_trace); - PolylineTrace start_piece = new PolylineTrace(p_start_piece, p_trace.get_layer(), p_trace.get_half_width(), - p_trace.net_no_arr, p_trace.clearance_class_no(), 0, 0, FixedState.UNFIXED, board); - start_piece.board = board; - board.item_list.insert(start_piece); - start_piece.set_on_the_board(true); - - PolylineTrace end_piece = new PolylineTrace(p_end_piece, p_trace.get_layer(), p_trace.get_half_width(), - p_trace.net_no_arr, p_trace.clearance_class_no(), 0, 0, FixedState.UNFIXED, board); - end_piece.board = board; - board.item_list.insert(end_piece); - end_piece.set_on_the_board(true); - - board.search_tree_manager.reuse_entries_after_cutout(p_trace, start_piece, end_piece); - board.remove_item(p_trace); - - board.communication.observers.notify_new(start_piece); - board.communication.observers.notify_new(end_piece); - } - - - /** Stores all intersection points of p_trace - * with the border of the internal shape enlarged by the - * half width and the clearance of the corresponding trace pen. - */ - private boolean store_trace( PolylineTrace p_trace) - { - ShapeSearchTree search_tree = this.board.search_tree_manager.get_default_tree(); - TileShape offset_shape; - if (search_tree.is_clearance_compensation_used()) - { - double curr_offset = p_trace.get_compensated_half_width(search_tree) + c_offset_add; - offset_shape = (TileShape)shape.offset(curr_offset); - } - else - { - // enlarge the shape in 2 steps for symmetry reasons - double cl_offset = board.clearance_value(p_trace.clearance_class_no(), - this.cl_class, p_trace.get_layer()) + c_offset_add; - offset_shape = (TileShape)shape.offset(p_trace.get_half_width()); - offset_shape = (TileShape) offset_shape.offset(cl_offset); - } - - // using enlarge here instead offset causes problems because of a - // comparison in the constructor of class EntryPoint - int [][] entries = offset_shape.entrance_points(p_trace.polyline()); - for (int i = 0; i < entries.length; ++i) - { - int [] entry_tuple = entries[i]; - FloatPoint entry_approx = - p_trace.polyline().arr[entry_tuple[0]]. - intersection_approx(offset_shape.border_line(entry_tuple[1])); - insert_entry_point(p_trace, entry_tuple[0],entry_tuple[1], entry_approx); - } - - // Look, if an end point of the trace lies in the interiour of - // the shape. This may be the case, if a via touches the shape - - if (!p_trace.shares_net_no(own_net_nos)) - { - if (!(p_trace.nets_normal())) - { - return false; - } - Point end_corner = p_trace.first_corner(); - Collection contact_list; - for (int i = 0; i < 2; ++i) - { - if (offset_shape.contains(end_corner)) - { - if (i == 0) - { - contact_list = p_trace.get_start_contacts(); - } - else - { - contact_list = p_trace.get_end_contacts(); - } - int contact_count = 0; - boolean store_end_corner = true; - - // check for contact object, which is not shovable - Iterator it = contact_list.iterator(); - while (it.hasNext()) - { - Item contact_item = it.next(); - if (!contact_item.is_route()) - { - this.found_obstacle = contact_item; - return false; - } - if (contact_item instanceof Trace) - { - - if (contact_item.is_shove_fixed() || ((Trace)contact_item).get_half_width() != p_trace.get_half_width() || - contact_item.clearance_class_no() != p_trace.clearance_class_no()) - { - if (offset_shape.contains_inside(end_corner)) - { - this.found_obstacle = contact_item; - return false; - } - } - } - else if (contact_item instanceof Via) - { - TileShape via_shape = ((Via) contact_item).get_tile_shape_on_layer(layer); - - double via_trace_diff = via_shape.smallest_radius() - p_trace.get_compensated_half_width(search_tree); - if (!search_tree.is_clearance_compensation_used()) - { - int via_clearance = board.clearance_value(contact_item.clearance_class_no(), this.cl_class, this.layer); - int trace_clearance = board.clearance_value(p_trace.clearance_class_no(), this.cl_class, this.layer); - if (trace_clearance > via_clearance) - { - via_trace_diff += via_clearance - trace_clearance; - } - } - if (via_trace_diff < 0) - { - // the via is smaller than the trace - this.found_obstacle = contact_item; - return false; - } - - if (via_trace_diff == 0 && !offset_shape.contains_inside(end_corner)) - { - // the via need not to be shoved - store_end_corner = false; - } - } - ++contact_count; - } - if (contact_count == 1 && store_end_corner) - { - Point projection = offset_shape.nearest_border_point(end_corner); - { - int projection_side = offset_shape.contains_on_border_line_no(projection); - int trace_line_segment_no; - // the following may not be correct because the trace may not conntain a suitable - // line for the construction oof the end line of the substitute trace. - if (i == 0) - { - trace_line_segment_no = 0; - } - else - { - trace_line_segment_no = p_trace.polyline().arr.length - 1; - } - - if (projection_side >= 0) - { - insert_entry_point(p_trace, trace_line_segment_no, projection_side, projection.to_float()); - } - } - } - else if (contact_count == 0 && offset_shape.contains_inside(end_corner)) - { - shape_contains_trace_tails = true; - } - } - end_corner = p_trace.last_corner(); - } - } - this.found_obstacle = p_trace; - return true; - } - - private void search_from_side() - { - if (this.from_side != null && this.from_side.no >= 0) - { - return; // from side is already legal - } - EntryPoint curr_node = this.list_anchor; - int curr_fromside_no = 0; - FloatPoint curr_entry_approx = null; - while (curr_node != null) - { - if (curr_node.trace.shares_net_no(this.own_net_nos)) - { - curr_fromside_no = curr_node.edge_no; - curr_entry_approx = curr_node.entry_approx; - break; - } - curr_node = curr_node.next; - } - this.from_side = new CalcFromSide(curr_fromside_no, curr_entry_approx); - } - - /** - * resorts the intersection points according to from_side_no and - * removes redundant points - */ - private void resort() - { - int edge_count = this.shape.border_line_count(); - if (this.from_side.no < 0 || from_side.no >= edge_count) - { - System.out.println("ShapeTraceEntries.resort: from side not calculated"); - return; - } - // resort the intersection points, so that they start in the - // middle of from_side. - FloatPoint compare_corner_1 = shape.corner_approx(this.from_side.no); - FloatPoint compare_corner_2; - if (from_side.no == edge_count - 1) - { - compare_corner_2 = shape.corner_approx(0); - } - else - { - compare_corner_2 = shape.corner_approx(from_side.no + 1); - } - double from_point_dist = 0; - FloatPoint from_point_projection = null; - if (from_side.border_intersection != null) - { - from_point_projection = from_side.border_intersection.projection_approx(shape.border_line(from_side.no)); - from_point_dist = from_point_projection.distance_square(compare_corner_1); - if (from_point_dist >= - compare_corner_1.distance_square(compare_corner_2)) - { - from_side = new CalcFromSide(from_side.no, null); - } - } - // search the first intersection point between the side middle - // and compare_corner_2 - EntryPoint curr = list_anchor; - EntryPoint prev = null; - - while (curr != null) - { - if (curr.edge_no > this.from_side.no) - { - break; - } - if (curr.edge_no == from_side.no) - { - if (from_side.border_intersection != null) - { - FloatPoint curr_projection = curr.entry_approx.projection_approx(shape.border_line(from_side.no)); - if ( curr_projection.distance_square(compare_corner_1) >= from_point_dist - && curr_projection.distance_square(from_point_projection) <= - curr_projection.distance_square(compare_corner_1)) - { - break; - } - } - else - { - if (curr.entry_approx.distance_square(compare_corner_2) - <= curr.entry_approx.distance_square(compare_corner_1)) - { - break; - } - } - } - prev = curr; - curr = prev.next; - } - if (curr != null && curr != list_anchor) - { - EntryPoint new_anchor = curr; - - while (curr != null) - { - prev = curr; - curr = prev.next; - } - prev.next = list_anchor; - curr = list_anchor; - while (curr != new_anchor) - { - // add edge_count to curr.side to differentiate points - // before and after the middle of from_side - curr.edge_no += edge_count; - prev = curr; - curr = prev.next; - } - prev.next = null; - list_anchor = new_anchor; - } - // remove intersections between two other intersections of the same - // connected set, so that only first and last intersection is kept. - if (list_anchor == null) - { - return; - } - prev = list_anchor; - int[] prev_net_nos = prev.trace.net_no_arr; - - curr = list_anchor.next; - int[] curr_net_nos; - EntryPoint next; - - if (curr != null) - { - curr_net_nos = curr.trace.net_no_arr; - next = curr.next; - } - else - { - next = null; - curr_net_nos = new int[0]; - } - EntryPoint before_prev = null; - while (next != null) - { - int[] next_net_nos = next.trace.net_no_arr; - if (net_nos_equal(prev_net_nos, curr_net_nos) && net_nos_equal(curr_net_nos, next_net_nos)) - { - prev.next = next; - } - else - { - before_prev = prev; - prev = curr; - prev_net_nos = curr_net_nos; - } - curr_net_nos = next_net_nos; - curr = next; - next = curr.next; - } - - // remove nodes of own net at start and end of the list - if (curr != null && net_nos_equal(curr_net_nos, own_net_nos)) - { - prev.next = null; - if (net_nos_equal(prev_net_nos, own_net_nos)) - { - if (before_prev != null) - { - before_prev.next = null; - } - else - { - list_anchor = null; - } - } - } - - if (list_anchor != null && list_anchor.trace.nets_equal(own_net_nos)) - { - list_anchor = list_anchor.next; - - if (list_anchor != null && list_anchor.trace.nets_equal(own_net_nos)) - { - list_anchor = list_anchor.next; - } - } - } - - private boolean calculate_stack_levels() - { - if (list_anchor == null) - { - return true; - } - EntryPoint curr_entry = list_anchor; - int[] curr_net_nos = curr_entry.trace.net_no_arr; - int curr_level; - if (net_nos_equal(curr_net_nos, this.own_net_nos)) - { - // ignore own net when calculating the stack level - curr_level = 0; - } - else - { - curr_level = 1; - } - - while (curr_entry != null) - { - if (curr_entry.stack_level < 0) // not yet calculated - { - ++trace_piece_count; - curr_entry.stack_level = curr_level; - if (curr_level > max_stack_level) - { - if (max_stack_level > 1) - { - this.found_obstacle = curr_entry.trace; - } - max_stack_level = curr_level; - } - } - - // set stack level for all entries of the current net; - EntryPoint check_entry = curr_entry.next; - int index_of_next_foreign_set = 0; - int index_of_last_occurance_of_set = 0; - int next_index = 0; - EntryPoint last_own_entry = null; - EntryPoint first_foreign_entry = null; - - while (check_entry != null) - { - ++next_index; - int[] check_net_nos = check_entry.trace.net_no_arr; - if (net_nos_equal(check_net_nos, curr_net_nos)) - { - index_of_last_occurance_of_set = next_index; - last_own_entry = check_entry; - check_entry.stack_level = curr_entry.stack_level; - } - - else if (index_of_next_foreign_set == 0) - { - // first occurance of a foreign connected set - index_of_next_foreign_set = next_index; - first_foreign_entry = check_entry; - } - check_entry = check_entry.next; - } - EntryPoint next_entry = null; - - if (next_index != 0) - { - if (index_of_next_foreign_set != 0 - && index_of_next_foreign_set < index_of_last_occurance_of_set) - // raise level - { - next_entry = first_foreign_entry; - if (next_entry.stack_level >= 0) // already calculated - { - // stack property failes - return false; - } - ++curr_level; - } - else - { - if (index_of_last_occurance_of_set != 0) - { - next_entry = last_own_entry; - } - else - { - next_entry = first_foreign_entry; - if (next_entry.stack_level >= 0) // already calculated - { - --curr_level; - if (next_entry.stack_level != curr_level) - { - return false; - } - } - } - } - curr_net_nos = next_entry.trace.net_no_arr; - // remove all entries between curr_entry and next_entry, because - // they are irrelevant; - check_entry = curr_entry.next; - while (check_entry != next_entry) - { - check_entry = check_entry.next; - } - curr_entry.next = next_entry; - curr_entry = next_entry; - } - else - { - curr_entry = null; - } - } - if (curr_level != 1) - { - System.out.println( - "ShapeTraceEntries.calculate_stack_levels: curr_level inconsistent"); - return false; - } - return true; - } - - /** - * Pops the next piece with minimal level from the imtersection list - * Returns null, if the stack is empty. - * The returned array has 2 elements. The first is the first entry point, - * and the second is the last entry point of the minimal level. - */ - private EntryPoint [] pop_piece() - { - if (list_anchor == null) - { - if (this.trace_piece_count != 0) - { - System.out.println("ShapeTraceEntries: trace_piece_count is inconsistent"); - } - return null; - } - EntryPoint first = list_anchor; - EntryPoint prev_first = null; - - while (first != null) - { - if (first.stack_level == this.max_stack_level) - { - break; - } - prev_first = first; - first = first.next; - } - if (first == null) - { - System.out.println("ShapeTraceEntries: max_stack_level not found"); - return null; - } - EntryPoint [] result = new EntryPoint [2]; - result[0] = first; - EntryPoint last = first; - EntryPoint after_last = first.next; - - while (after_last != null) - { - if (after_last.stack_level != max_stack_level || - !after_last.trace.nets_equal( first.trace)) - { - break; - } - last = after_last; - after_last = last.next; - } - result[1] = last; - - // remove the nodes from first to last inclusive - - if (prev_first != null) - { - prev_first.next = after_last; - } - else - { - list_anchor = after_last; - } - - // recalculate max_stack_level; - max_stack_level = 0; - EntryPoint curr = list_anchor; - while (curr != null) - { - if (curr.stack_level > max_stack_level) - { - max_stack_level = curr.stack_level; - } - curr = curr.next; - } - --trace_piece_count; - if (first.trace.nets_equal(this.own_net_nos)) - { - // own net is ignored and nay occur only at the lowest level - result = pop_piece(); - } - return result; - } - - private void insert_entry_point(PolylineTrace p_trace, int p_trace_line_no, - int p_edge_no, FloatPoint p_entry_approx) - { - EntryPoint new_entry = new EntryPoint(p_trace, p_trace_line_no, p_edge_no, p_entry_approx); - EntryPoint curr_prev = null; - EntryPoint curr_next = list_anchor; - // insert the new entry into the sorted list - while (curr_next != null) - { - if (curr_next.edge_no > new_entry.edge_no) - { - break; - } - if (curr_next.edge_no == new_entry.edge_no) - { - FloatPoint prev_corner = shape.corner_approx(p_edge_no); - FloatPoint next_corner; - if (p_edge_no == shape.border_line_count() - 1) - { - next_corner = shape.corner_approx(0); - } - else - { - next_corner = shape.corner_approx(new_entry.edge_no + 1); - } - if( prev_corner.scalar_product(p_entry_approx, next_corner) - <= prev_corner.scalar_product(curr_next.entry_approx, next_corner)) - // the projection of the line from prev_corner to p_entry_approx - // onto the line from prev_corner to next_corner is smaller - // than the projection of the line from prev_corner to - // next.entry_approx onto the same line. - { - break; - } - } - curr_prev = curr_next; - curr_next = curr_next.next; - } - new_entry.next = curr_next; - if (curr_prev != null) - { - curr_prev.next = new_entry; - } - else - { - list_anchor = new_entry; - } - } - - final Collection shove_via_list; - private final TileShape shape; - private final int layer; - private final int[] own_net_nos; - private final int cl_class; - private CalcFromSide from_side; - private final RoutingBoard board; - private EntryPoint list_anchor; - private int trace_piece_count; - private int max_stack_level; - private boolean shape_contains_trace_tails = false; - private Item found_obstacle = null; - private static final double c_offset_add = 1; - - /** - * Information about an entry point of p_trace into the shape. - * The entry points are sorted around the border of the shape - */ - private static class EntryPoint - { - EntryPoint(PolylineTrace p_trace, int p_trace_line_no, int p_edge_no, - FloatPoint p_entry_approx) - { - trace = p_trace; - edge_no = p_edge_no; - trace_line_no = p_trace_line_no; - entry_approx = p_entry_approx; - stack_level = -1; //not yet calculated - } - - final PolylineTrace trace; - final int trace_line_no; - int edge_no; - final FloatPoint entry_approx; - int stack_level; - EntryPoint next; - } - - static private boolean net_nos_equal(int[] p_net_nos_1, int [] p_net_nos_2) - { - if (p_net_nos_1.length != p_net_nos_2.length) - { - return false; - } - for (int curr_net_no_1 : p_net_nos_1) - { - boolean net_no_found = false; - for (int curr_net_no_2 : p_net_nos_2) - { - if (curr_net_no_1 == curr_net_no_2) - { - net_no_found = true; - } - } - if (!net_no_found) - { - return false; - } - } - return true; - } -} \ No newline at end of file +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + */ + +package board; + +import geometry.planar.ConvexShape; +import geometry.planar.FloatPoint; +import geometry.planar.Line; +import geometry.planar.Point; +import geometry.planar.Polyline; +import geometry.planar.TileShape; + +import java.util.Collection; +import java.util.Iterator; + + + +/** + * Auxiliary class used by the shove functions + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class ShapeTraceEntries +{ + /** + * Used for shoving traces and vias out of the input shape. + * p_from_side.no is the side of p_shape, from where the shove comes. + * if p_from_side.no < 0, it will be calculated internally. + */ + ShapeTraceEntries(TileShape p_shape, int p_layer, int[] p_own_net_nos, int p_cl_type, + CalcFromSide p_from_side, RoutingBoard p_board) + { + shape = p_shape; + layer = p_layer; + own_net_nos = p_own_net_nos; + cl_class = p_cl_type; + from_side = p_from_side; + board = p_board; + list_anchor = null; + trace_piece_count = 0; + max_stack_level = 0; + shove_via_list = new java.util.LinkedList(); + } + + /** + * Stores traces and vias in p_item_list. + * Returns false, if p_item_list contains obstacles, + * which cannot be shoved aside. + * If p_is_pad_check. the check is for vias, otherwise it is for traces. + * If p_copper_sharing_allowed, overlaps with traces or pads of the own net are allowed. + */ + boolean store_items(Collection p_item_list, boolean p_is_pad_check, boolean p_copper_sharing_allowed) + { + Iterator it = p_item_list.iterator(); + while(it.hasNext()) + { + Item curr_item = it.next(); + + if (!p_is_pad_check && curr_item instanceof ViaObstacleArea || curr_item instanceof ComponentObstacleArea) + { + continue; + } + boolean contains_own_net = curr_item.shares_net_no(this.own_net_nos); + if (curr_item instanceof ConductionArea && + (contains_own_net || !((ConductionArea)curr_item).get_is_obstacle())) + { + continue; + } + if (curr_item.is_shove_fixed() && !contains_own_net) + { + this.found_obstacle = curr_item; + return false; + } + if (curr_item instanceof Via) + { + if (p_is_pad_check || !contains_own_net) + { + shove_via_list.add((Via) curr_item); + } + } + else if (curr_item instanceof PolylineTrace) + { + PolylineTrace curr_trace = (PolylineTrace) curr_item; + + if (!store_trace(curr_trace)) + { + return false; + } + } + else + { + if (contains_own_net) + { + if (!p_copper_sharing_allowed) + { + this.found_obstacle = curr_item; + return false; + } + if (p_is_pad_check && !((curr_item instanceof Pin) && ((Pin)curr_item).drill_allowed())) + { + this.found_obstacle = curr_item; + return false; + } + } + else + { + this.found_obstacle = curr_item; + return false; + } + } + } + search_from_side(); + resort(); + if (!calculate_stack_levels()) + { + return false; + } + return true; + } + + + /** + * calculates the next substitute trace piece. + * Returns null at he end of the substitute trace list. + */ + PolylineTrace next_substitute_trace_piece() + { + + EntryPoint[] entries = pop_piece(); + if (entries == null) + { + return null; + } + PolylineTrace curr_trace = entries[0].trace; + TileShape offset_shape; + ShapeSearchTree search_tree = this.board.search_tree_manager.get_default_tree(); + if (search_tree.is_clearance_compensation_used()) + { + double curr_offset = curr_trace.get_compensated_half_width(search_tree) + c_offset_add; + offset_shape = (TileShape)shape.offset(curr_offset); + } + else + { + // enlarge the shape in 2 steps for symmetry reasons + offset_shape = (TileShape)shape.offset(curr_trace.get_half_width()); + double cl_offset = board.clearance_value(curr_trace.clearance_class_no(), cl_class, layer) + c_offset_add; + offset_shape = (TileShape) offset_shape.offset(cl_offset); + } + int edge_count = shape.border_line_count(); + int edge_diff = entries[1].edge_no - entries[0].edge_no; + + // calculate the polyline of the substitute trace + + Line [] piece_lines = new Line[edge_diff + 3]; + // start with the intersecting line of the trace at the start entry. + piece_lines[0] = entries[0].trace.polyline().arr[entries[0].trace_line_no]; + // end with the intersecting line of the trace at the end entry + piece_lines[piece_lines.length - 1] = + entries[1].trace.polyline().arr[entries[1].trace_line_no]; + // fill the interiour lines of piece_lines with the appropriate edge + // lines of the offset shape + int curr_edge_no = entries[0].edge_no % edge_count; + for (int i = 1; i < piece_lines.length - 1; ++i) + { + piece_lines [i] = offset_shape.border_line(curr_edge_no); + if (curr_edge_no == edge_count - 1) + { + curr_edge_no = 0; + } + else + { + ++curr_edge_no; + } + } + Polyline piece_polyline = new Polyline(piece_lines); + if (piece_polyline.is_empty()) + { + // no valid trace piece, return the next one + return next_substitute_trace_piece(); + } + return new PolylineTrace(piece_polyline, this.layer, + curr_trace.get_half_width(), curr_trace.net_no_arr, + curr_trace.clearance_class_no(), 0, 0, FixedState.UNFIXED, this.board); + } + + /** + * returns the maximum recursion depth for shoving the obstacle traces + */ + int stack_depth() + { + return max_stack_level; + } + + /** + * returns the number of substitute trace pieces. + */ + int substitute_trace_count() + { + return trace_piece_count; + } + + /** + * Looks if an unconnected endpoint of a trace of a foreign net + * is contained in the interiour of the shape. + * + * @return a boolean. + */ + public boolean trace_tails_in_shape() + { + return this.shape_contains_trace_tails; + } + + /** + * Cuts out all traces in p_item_list out of the stored shape. + * Traces with net number p_except_net_no are ignored + */ + void cutout_traces(Collection p_item_list) + { + Iterator it = p_item_list.iterator(); + while (it.hasNext()) + { + Item curr_item = it.next(); + if (curr_item instanceof PolylineTrace && !curr_item.shares_net_no(this.own_net_nos)) + { + cutout_trace((PolylineTrace) curr_item, this.shape, this.cl_class); + } + } + } + + /** + * Returns the item responsible for the failing, if the shove algorithm failed. + */ + Item get_found_obstacle() + { + return this.found_obstacle; + } + + /** + *

cutout_trace.

+ * + * @param p_trace a {@link board.PolylineTrace} object. + * @param p_shape a {@link geometry.planar.ConvexShape} object. + * @param p_cl_class a int. + */ + public static void cutout_trace(PolylineTrace p_trace, ConvexShape p_shape, int p_cl_class) + { + if (!p_trace.is_on_the_board()) + { + System.out.println("ShapeTraceEntries.cutout_trace : trace is deleted"); + return; + } + ConvexShape offset_shape; + BasicBoard board = p_trace.board; + ShapeSearchTree search_tree = board.search_tree_manager.get_default_tree(); + if (search_tree.is_clearance_compensation_used()) + { + double curr_offset = p_trace.get_compensated_half_width(search_tree) + c_offset_add; + offset_shape = p_shape.offset(curr_offset); + } + else + { + // enlarge the shape in 2 steps for symmetry reasons + double cl_offset = board.clearance_value(p_trace.clearance_class_no(), + p_cl_class, p_trace.get_layer()) + c_offset_add; + offset_shape = p_shape.offset(p_trace.get_half_width()); + offset_shape = offset_shape.offset(cl_offset); + } + Polyline trace_lines = p_trace.polyline(); + Polyline [] pieces = offset_shape.cutout(trace_lines); + if (pieces.length == 1 && pieces[0] == trace_lines) + { + // nothing cut off + return; + } + if (pieces.length == 2 && offset_shape.is_outside(pieces[0].first_corner()) + && offset_shape.is_outside(pieces[1].last_corner())) + { + fast_cutout_trace(p_trace, pieces[0], pieces[1]); + } + else + { + board.remove_item(p_trace); + for (int i = 0; i < pieces.length; ++i) + { + board.insert_trace_without_cleaning(pieces[i], p_trace.get_layer(), + p_trace.get_half_width(), p_trace.net_no_arr, p_trace.clearance_class_no(), FixedState.UNFIXED); + } + } + } + + /** Optimized function handling the performance critical standard cutout case */ + private static void fast_cutout_trace(PolylineTrace p_trace, Polyline p_start_piece, Polyline p_end_piece) + { + BasicBoard board = p_trace.board; + board.additional_update_after_change(p_trace); + board.item_list.save_for_undo(p_trace); + PolylineTrace start_piece = new PolylineTrace(p_start_piece, p_trace.get_layer(), p_trace.get_half_width(), + p_trace.net_no_arr, p_trace.clearance_class_no(), 0, 0, FixedState.UNFIXED, board); + start_piece.board = board; + board.item_list.insert(start_piece); + start_piece.set_on_the_board(true); + + PolylineTrace end_piece = new PolylineTrace(p_end_piece, p_trace.get_layer(), p_trace.get_half_width(), + p_trace.net_no_arr, p_trace.clearance_class_no(), 0, 0, FixedState.UNFIXED, board); + end_piece.board = board; + board.item_list.insert(end_piece); + end_piece.set_on_the_board(true); + + board.search_tree_manager.reuse_entries_after_cutout(p_trace, start_piece, end_piece); + board.remove_item(p_trace); + + board.communication.observers.notify_new(start_piece); + board.communication.observers.notify_new(end_piece); + } + + + /** Stores all intersection points of p_trace + * with the border of the internal shape enlarged by the + * half width and the clearance of the corresponding trace pen. + */ + private boolean store_trace( PolylineTrace p_trace) + { + ShapeSearchTree search_tree = this.board.search_tree_manager.get_default_tree(); + TileShape offset_shape; + if (search_tree.is_clearance_compensation_used()) + { + double curr_offset = p_trace.get_compensated_half_width(search_tree) + c_offset_add; + offset_shape = (TileShape)shape.offset(curr_offset); + } + else + { + // enlarge the shape in 2 steps for symmetry reasons + double cl_offset = board.clearance_value(p_trace.clearance_class_no(), + this.cl_class, p_trace.get_layer()) + c_offset_add; + offset_shape = (TileShape)shape.offset(p_trace.get_half_width()); + offset_shape = (TileShape) offset_shape.offset(cl_offset); + } + + // using enlarge here instead offset causes problems because of a + // comparison in the constructor of class EntryPoint + int [][] entries = offset_shape.entrance_points(p_trace.polyline()); + for (int i = 0; i < entries.length; ++i) + { + int [] entry_tuple = entries[i]; + FloatPoint entry_approx = + p_trace.polyline().arr[entry_tuple[0]]. + intersection_approx(offset_shape.border_line(entry_tuple[1])); + insert_entry_point(p_trace, entry_tuple[0],entry_tuple[1], entry_approx); + } + + // Look, if an end point of the trace lies in the interiour of + // the shape. This may be the case, if a via touches the shape + + if (!p_trace.shares_net_no(own_net_nos)) + { + if (!(p_trace.nets_normal())) + { + return false; + } + Point end_corner = p_trace.first_corner(); + Collection contact_list; + for (int i = 0; i < 2; ++i) + { + if (offset_shape.contains(end_corner)) + { + if (i == 0) + { + contact_list = p_trace.get_start_contacts(); + } + else + { + contact_list = p_trace.get_end_contacts(); + } + int contact_count = 0; + boolean store_end_corner = true; + + // check for contact object, which is not shovable + Iterator it = contact_list.iterator(); + while (it.hasNext()) + { + Item contact_item = it.next(); + if (!contact_item.is_route()) + { + this.found_obstacle = contact_item; + return false; + } + if (contact_item instanceof Trace) + { + + if (contact_item.is_shove_fixed() || ((Trace)contact_item).get_half_width() != p_trace.get_half_width() || + contact_item.clearance_class_no() != p_trace.clearance_class_no()) + { + if (offset_shape.contains_inside(end_corner)) + { + this.found_obstacle = contact_item; + return false; + } + } + } + else if (contact_item instanceof Via) + { + TileShape via_shape = ((Via) contact_item).get_tile_shape_on_layer(layer); + + double via_trace_diff = via_shape.smallest_radius() - p_trace.get_compensated_half_width(search_tree); + if (!search_tree.is_clearance_compensation_used()) + { + int via_clearance = board.clearance_value(contact_item.clearance_class_no(), this.cl_class, this.layer); + int trace_clearance = board.clearance_value(p_trace.clearance_class_no(), this.cl_class, this.layer); + if (trace_clearance > via_clearance) + { + via_trace_diff += via_clearance - trace_clearance; + } + } + if (via_trace_diff < 0) + { + // the via is smaller than the trace + this.found_obstacle = contact_item; + return false; + } + + if (via_trace_diff == 0 && !offset_shape.contains_inside(end_corner)) + { + // the via need not to be shoved + store_end_corner = false; + } + } + ++contact_count; + } + if (contact_count == 1 && store_end_corner) + { + Point projection = offset_shape.nearest_border_point(end_corner); + { + int projection_side = offset_shape.contains_on_border_line_no(projection); + int trace_line_segment_no; + // the following may not be correct because the trace may not conntain a suitable + // line for the construction oof the end line of the substitute trace. + if (i == 0) + { + trace_line_segment_no = 0; + } + else + { + trace_line_segment_no = p_trace.polyline().arr.length - 1; + } + + if (projection_side >= 0) + { + insert_entry_point(p_trace, trace_line_segment_no, projection_side, projection.to_float()); + } + } + } + else if (contact_count == 0 && offset_shape.contains_inside(end_corner)) + { + shape_contains_trace_tails = true; + } + } + end_corner = p_trace.last_corner(); + } + } + this.found_obstacle = p_trace; + return true; + } + + private void search_from_side() + { + if (this.from_side != null && this.from_side.no >= 0) + { + return; // from side is already legal + } + EntryPoint curr_node = this.list_anchor; + int curr_fromside_no = 0; + FloatPoint curr_entry_approx = null; + while (curr_node != null) + { + if (curr_node.trace.shares_net_no(this.own_net_nos)) + { + curr_fromside_no = curr_node.edge_no; + curr_entry_approx = curr_node.entry_approx; + break; + } + curr_node = curr_node.next; + } + this.from_side = new CalcFromSide(curr_fromside_no, curr_entry_approx); + } + + /** + * resorts the intersection points according to from_side_no and + * removes redundant points + */ + private void resort() + { + int edge_count = this.shape.border_line_count(); + if (this.from_side.no < 0 || from_side.no >= edge_count) + { + System.out.println("ShapeTraceEntries.resort: from side not calculated"); + return; + } + // resort the intersection points, so that they start in the + // middle of from_side. + FloatPoint compare_corner_1 = shape.corner_approx(this.from_side.no); + FloatPoint compare_corner_2; + if (from_side.no == edge_count - 1) + { + compare_corner_2 = shape.corner_approx(0); + } + else + { + compare_corner_2 = shape.corner_approx(from_side.no + 1); + } + double from_point_dist = 0; + FloatPoint from_point_projection = null; + if (from_side.border_intersection != null) + { + from_point_projection = from_side.border_intersection.projection_approx(shape.border_line(from_side.no)); + from_point_dist = from_point_projection.distance_square(compare_corner_1); + if (from_point_dist >= + compare_corner_1.distance_square(compare_corner_2)) + { + from_side = new CalcFromSide(from_side.no, null); + } + } + // search the first intersection point between the side middle + // and compare_corner_2 + EntryPoint curr = list_anchor; + EntryPoint prev = null; + + while (curr != null) + { + if (curr.edge_no > this.from_side.no) + { + break; + } + if (curr.edge_no == from_side.no) + { + if (from_side.border_intersection != null) + { + FloatPoint curr_projection = curr.entry_approx.projection_approx(shape.border_line(from_side.no)); + if ( curr_projection.distance_square(compare_corner_1) >= from_point_dist + && curr_projection.distance_square(from_point_projection) <= + curr_projection.distance_square(compare_corner_1)) + { + break; + } + } + else + { + if (curr.entry_approx.distance_square(compare_corner_2) + <= curr.entry_approx.distance_square(compare_corner_1)) + { + break; + } + } + } + prev = curr; + curr = prev.next; + } + if (curr != null && curr != list_anchor) + { + EntryPoint new_anchor = curr; + + while (curr != null) + { + prev = curr; + curr = prev.next; + } + prev.next = list_anchor; + curr = list_anchor; + while (curr != new_anchor) + { + // add edge_count to curr.side to differentiate points + // before and after the middle of from_side + curr.edge_no += edge_count; + prev = curr; + curr = prev.next; + } + prev.next = null; + list_anchor = new_anchor; + } + // remove intersections between two other intersections of the same + // connected set, so that only first and last intersection is kept. + if (list_anchor == null) + { + return; + } + prev = list_anchor; + int[] prev_net_nos = prev.trace.net_no_arr; + + curr = list_anchor.next; + int[] curr_net_nos; + EntryPoint next; + + if (curr != null) + { + curr_net_nos = curr.trace.net_no_arr; + next = curr.next; + } + else + { + next = null; + curr_net_nos = new int[0]; + } + EntryPoint before_prev = null; + while (next != null) + { + int[] next_net_nos = next.trace.net_no_arr; + if (net_nos_equal(prev_net_nos, curr_net_nos) && net_nos_equal(curr_net_nos, next_net_nos)) + { + prev.next = next; + } + else + { + before_prev = prev; + prev = curr; + prev_net_nos = curr_net_nos; + } + curr_net_nos = next_net_nos; + curr = next; + next = curr.next; + } + + // remove nodes of own net at start and end of the list + if (curr != null && net_nos_equal(curr_net_nos, own_net_nos)) + { + prev.next = null; + if (net_nos_equal(prev_net_nos, own_net_nos)) + { + if (before_prev != null) + { + before_prev.next = null; + } + else + { + list_anchor = null; + } + } + } + + if (list_anchor != null && list_anchor.trace.nets_equal(own_net_nos)) + { + list_anchor = list_anchor.next; + + if (list_anchor != null && list_anchor.trace.nets_equal(own_net_nos)) + { + list_anchor = list_anchor.next; + } + } + } + + private boolean calculate_stack_levels() + { + if (list_anchor == null) + { + return true; + } + EntryPoint curr_entry = list_anchor; + int[] curr_net_nos = curr_entry.trace.net_no_arr; + int curr_level; + if (net_nos_equal(curr_net_nos, this.own_net_nos)) + { + // ignore own net when calculating the stack level + curr_level = 0; + } + else + { + curr_level = 1; + } + + while (curr_entry != null) + { + if (curr_entry.stack_level < 0) // not yet calculated + { + ++trace_piece_count; + curr_entry.stack_level = curr_level; + if (curr_level > max_stack_level) + { + if (max_stack_level > 1) + { + this.found_obstacle = curr_entry.trace; + } + max_stack_level = curr_level; + } + } + + // set stack level for all entries of the current net; + EntryPoint check_entry = curr_entry.next; + int index_of_next_foreign_set = 0; + int index_of_last_occurance_of_set = 0; + int next_index = 0; + EntryPoint last_own_entry = null; + EntryPoint first_foreign_entry = null; + + while (check_entry != null) + { + ++next_index; + int[] check_net_nos = check_entry.trace.net_no_arr; + if (net_nos_equal(check_net_nos, curr_net_nos)) + { + index_of_last_occurance_of_set = next_index; + last_own_entry = check_entry; + check_entry.stack_level = curr_entry.stack_level; + } + + else if (index_of_next_foreign_set == 0) + { + // first occurance of a foreign connected set + index_of_next_foreign_set = next_index; + first_foreign_entry = check_entry; + } + check_entry = check_entry.next; + } + EntryPoint next_entry = null; + + if (next_index != 0) + { + if (index_of_next_foreign_set != 0 + && index_of_next_foreign_set < index_of_last_occurance_of_set) + // raise level + { + next_entry = first_foreign_entry; + if (next_entry.stack_level >= 0) // already calculated + { + // stack property failes + return false; + } + ++curr_level; + } + else + { + if (index_of_last_occurance_of_set != 0) + { + next_entry = last_own_entry; + } + else + { + next_entry = first_foreign_entry; + if (next_entry.stack_level >= 0) // already calculated + { + --curr_level; + if (next_entry.stack_level != curr_level) + { + return false; + } + } + } + } + curr_net_nos = next_entry.trace.net_no_arr; + // remove all entries between curr_entry and next_entry, because + // they are irrelevant; + check_entry = curr_entry.next; + while (check_entry != next_entry) + { + check_entry = check_entry.next; + } + curr_entry.next = next_entry; + curr_entry = next_entry; + } + else + { + curr_entry = null; + } + } + if (curr_level != 1) + { + System.out.println( + "ShapeTraceEntries.calculate_stack_levels: curr_level inconsistent"); + return false; + } + return true; + } + + /** + * Pops the next piece with minimal level from the imtersection list + * Returns null, if the stack is empty. + * The returned array has 2 elements. The first is the first entry point, + * and the second is the last entry point of the minimal level. + */ + private EntryPoint [] pop_piece() + { + if (list_anchor == null) + { + if (this.trace_piece_count != 0) + { + System.out.println("ShapeTraceEntries: trace_piece_count is inconsistent"); + } + return null; + } + EntryPoint first = list_anchor; + EntryPoint prev_first = null; + + while (first != null) + { + if (first.stack_level == this.max_stack_level) + { + break; + } + prev_first = first; + first = first.next; + } + if (first == null) + { + System.out.println("ShapeTraceEntries: max_stack_level not found"); + return null; + } + EntryPoint [] result = new EntryPoint [2]; + result[0] = first; + EntryPoint last = first; + EntryPoint after_last = first.next; + + while (after_last != null) + { + if (after_last.stack_level != max_stack_level || + !after_last.trace.nets_equal( first.trace)) + { + break; + } + last = after_last; + after_last = last.next; + } + result[1] = last; + + // remove the nodes from first to last inclusive + + if (prev_first != null) + { + prev_first.next = after_last; + } + else + { + list_anchor = after_last; + } + + // recalculate max_stack_level; + max_stack_level = 0; + EntryPoint curr = list_anchor; + while (curr != null) + { + if (curr.stack_level > max_stack_level) + { + max_stack_level = curr.stack_level; + } + curr = curr.next; + } + --trace_piece_count; + if (first.trace.nets_equal(this.own_net_nos)) + { + // own net is ignored and nay occur only at the lowest level + result = pop_piece(); + } + return result; + } + + private void insert_entry_point(PolylineTrace p_trace, int p_trace_line_no, + int p_edge_no, FloatPoint p_entry_approx) + { + EntryPoint new_entry = new EntryPoint(p_trace, p_trace_line_no, p_edge_no, p_entry_approx); + EntryPoint curr_prev = null; + EntryPoint curr_next = list_anchor; + // insert the new entry into the sorted list + while (curr_next != null) + { + if (curr_next.edge_no > new_entry.edge_no) + { + break; + } + if (curr_next.edge_no == new_entry.edge_no) + { + FloatPoint prev_corner = shape.corner_approx(p_edge_no); + FloatPoint next_corner; + if (p_edge_no == shape.border_line_count() - 1) + { + next_corner = shape.corner_approx(0); + } + else + { + next_corner = shape.corner_approx(new_entry.edge_no + 1); + } + if( prev_corner.scalar_product(p_entry_approx, next_corner) + <= prev_corner.scalar_product(curr_next.entry_approx, next_corner)) + // the projection of the line from prev_corner to p_entry_approx + // onto the line from prev_corner to next_corner is smaller + // than the projection of the line from prev_corner to + // next.entry_approx onto the same line. + { + break; + } + } + curr_prev = curr_next; + curr_next = curr_next.next; + } + new_entry.next = curr_next; + if (curr_prev != null) + { + curr_prev.next = new_entry; + } + else + { + list_anchor = new_entry; + } + } + + final Collection shove_via_list; + private final TileShape shape; + private final int layer; + private final int[] own_net_nos; + private final int cl_class; + private CalcFromSide from_side; + private final RoutingBoard board; + private EntryPoint list_anchor; + private int trace_piece_count; + private int max_stack_level; + private boolean shape_contains_trace_tails = false; + private Item found_obstacle = null; + private static final double c_offset_add = 1; + + /** + * Information about an entry point of p_trace into the shape. + * The entry points are sorted around the border of the shape + */ + private static class EntryPoint + { + EntryPoint(PolylineTrace p_trace, int p_trace_line_no, int p_edge_no, + FloatPoint p_entry_approx) + { + trace = p_trace; + edge_no = p_edge_no; + trace_line_no = p_trace_line_no; + entry_approx = p_entry_approx; + stack_level = -1; //not yet calculated + } + + final PolylineTrace trace; + final int trace_line_no; + int edge_no; + final FloatPoint entry_approx; + int stack_level; + EntryPoint next; + } + + static private boolean net_nos_equal(int[] p_net_nos_1, int [] p_net_nos_2) + { + if (p_net_nos_1.length != p_net_nos_2.length) + { + return false; + } + for (int curr_net_no_1 : p_net_nos_1) + { + boolean net_no_found = false; + for (int curr_net_no_2 : p_net_nos_2) + { + if (curr_net_no_1 == curr_net_no_2) + { + net_no_found = true; + } + } + if (!net_no_found) + { + return false; + } + } + return true; + } +} diff --git a/board/ShoveTraceAlgo.java b/src/main/java/board/ShoveTraceAlgo.java similarity index 95% rename from board/ShoveTraceAlgo.java rename to src/main/java/board/ShoveTraceAlgo.java index d49e9dc..c53bac3 100644 --- a/board/ShoveTraceAlgo.java +++ b/src/main/java/board/ShoveTraceAlgo.java @@ -1,831 +1,871 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - */ -package board; - -import datastructures.TimeLimit; - -import geometry.planar.ConvexShape; -import geometry.planar.Direction; -import geometry.planar.FloatPoint; -import geometry.planar.IntBox; -import geometry.planar.Line; -import geometry.planar.Point; -import geometry.planar.IntPoint; -import geometry.planar.Vector; -import geometry.planar.Polyline; -import geometry.planar.TileShape; -import geometry.planar.LineSegment; - -import java.util.Collection; -import java.util.Iterator; -import java.util.Set; - -/** - * Contains internal auxiliary functions of class RoutingBoard - * for shoving traces - * - * @author Alfons Wirtz - */ -public class ShoveTraceAlgo -{ - - public ShoveTraceAlgo(RoutingBoard p_board) - { - board = p_board; - } - - /** - * Checks if a shove with the input parameters is possible without clearance violations - * p_dir is used internally to prevent the check from bouncing back. - * Returns false, if the shove failed. - */ - public boolean check(TileShape p_trace_shape, CalcFromSide p_from_side, - Direction p_dir, int p_layer, int[] p_net_no_arr, - int p_cl_type, int p_max_recursion_depth, int p_max_via_recursion_depth, - int p_max_spring_over_recursion_depth, TimeLimit p_time_limit) - { - if (p_time_limit != null && p_time_limit.limit_exceeded()) - { - return false; - } - - if (p_trace_shape.is_empty()) - { - System.out.println("ShoveTraceAux.check: p_trace_shape is empty"); - return true; - } - if (!p_trace_shape.is_contained_in(board.get_bounding_box())) - { - this.board.set_shove_failing_obstacle(board.get_outline()); - return false; - } - ShapeTraceEntries shape_entries = - new ShapeTraceEntries(p_trace_shape, p_layer, p_net_no_arr, p_cl_type, p_from_side, board); - ShapeSearchTree search_tree = this.board.search_tree_manager.get_default_tree(); - Collection obstacles = - search_tree.overlapping_items_with_clearance(p_trace_shape, p_layer, new int[0], p_cl_type); - obstacles.removeAll(get_ignore_items_at_tie_pins(p_trace_shape, p_layer, p_net_no_arr)); - boolean obstacles_shovable = shape_entries.store_items(obstacles, false, true); - if (!obstacles_shovable) - { - this.board.set_shove_failing_obstacle(shape_entries.get_found_obstacle()); - return false; - } - int trace_piece_count = shape_entries.substitute_trace_count(); - - if (shape_entries.stack_depth() > 1) - { - this.board.set_shove_failing_obstacle(shape_entries.get_found_obstacle()); - return false; - } - double shape_radius = 0.5 * p_trace_shape.bounding_box().min_width(); - - // check, if the obstacle vias can be shoved - - - for (Via curr_shove_via : shape_entries.shove_via_list) - { - if (curr_shove_via.shares_net_no(p_net_no_arr)) - { - continue; - } - if (p_max_via_recursion_depth <= 0) - { - this.board.set_shove_failing_obstacle(curr_shove_via); - return false; - } - FloatPoint curr_shove_via_center = curr_shove_via.get_center().to_float(); - IntPoint[] try_via_centers = - MoveDrillItemAlgo.try_shove_via_points(p_trace_shape, p_layer, curr_shove_via, p_cl_type, - true, board); - - double max_dist = 0.5 * curr_shove_via.get_shape_on_layer(p_layer).bounding_box().max_width() + shape_radius; - double max_dist_square = max_dist * max_dist; - boolean shove_via_ok = false; - for (int i = 0; i < try_via_centers.length; ++i) - { - if (i == 0 || curr_shove_via_center.distance_square(try_via_centers[i].to_float()) <= max_dist_square) - { - Vector delta = try_via_centers[i].difference_by(curr_shove_via.get_center()); - Collection ignore_items = new java.util.LinkedList(); - if (MoveDrillItemAlgo.check(curr_shove_via, delta, p_max_recursion_depth, - p_max_via_recursion_depth - 1, ignore_items, this.board, p_time_limit)) - { - shove_via_ok = true; - break; - } - } - } - if (!shove_via_ok) - { - return false; - } - } - - if (trace_piece_count == 0) - { - return true; - } - if (p_max_recursion_depth <= 0) - { - this.board.set_shove_failing_obstacle(shape_entries.get_found_obstacle()); - return false; - } - - boolean is_orthogonal_mode = p_trace_shape instanceof IntBox; - for (;;) - { - PolylineTrace curr_substitute_trace = - shape_entries.next_substitute_trace_piece(); - if (curr_substitute_trace == null) - { - break; - } - if (p_max_spring_over_recursion_depth > 0) - { - Polyline new_polyline = spring_over(curr_substitute_trace.polyline(), - curr_substitute_trace.get_compensated_half_width(search_tree), p_layer, curr_substitute_trace.net_no_arr, - curr_substitute_trace.clearance_class_no(), false, p_max_spring_over_recursion_depth, null); - if (new_polyline == null) - { - // spring_over did not work - return false; - } - if (new_polyline != curr_substitute_trace.polyline()) - { - // spring_over changed something - --p_max_spring_over_recursion_depth; - curr_substitute_trace.change(new_polyline); - } - } - for (int i = 0; i < curr_substitute_trace.tile_shape_count(); ++i) - { - Direction curr_dir = curr_substitute_trace.polyline().arr[i + 1].direction(); - boolean is_in_front = p_dir == null || p_dir.equals(curr_dir); - if (is_in_front) - { - CalcShapeAndFromSide curr = - new CalcShapeAndFromSide(curr_substitute_trace, i, is_orthogonal_mode, true); - if (!this.check(curr.shape, curr.from_side, curr_dir, p_layer, curr_substitute_trace.net_no_arr, - curr_substitute_trace.clearance_class_no(), - p_max_recursion_depth - 1, p_max_via_recursion_depth, - p_max_spring_over_recursion_depth, p_time_limit)) - { - return false; - } - } - } - } - return true; - } - - /** - * Checks if a shove with the input parameters is possible without clearance violations - * The result is the maximum lenght of a trace from the start of the line segment to the end of - * the line segment, for wich the algoritm succeedes. - * If the algorithm succeedes completely, the result will be equal to Integer.MAX_VALUE. - */ - public static double check(RoutingBoard p_board, LineSegment p_line_segment, boolean p_shove_to_the_left, int p_layer, int[] p_net_no_arr, int p_trace_half_width, - int p_cl_type, int p_max_recursion_depth, int p_max_via_recursion_depth) - { - ShapeSearchTree search_tree = p_board.search_tree_manager.get_default_tree(); - if (search_tree.is_clearance_compensation_used()) - { - p_trace_half_width += search_tree.clearance_compensation_value(p_cl_type, p_layer); - } - TileShape[] trace_shapes = p_line_segment.to_polyline().offset_shapes(p_trace_half_width); - if (trace_shapes.length != 1) - { - System.out.println("ShoveTraceAlgo.check: trace_shape count 1 expected"); - return 0; - } - - TileShape trace_shape = trace_shapes[0]; - if (trace_shape.is_empty()) - { - System.out.println("ShoveTraceAlgo.check: trace_shape is empty"); - return 0; - } - if (!trace_shape.is_contained_in(p_board.get_bounding_box())) - { - return 0; - } - CalcFromSide from_side = new CalcFromSide(p_line_segment, trace_shape, p_shove_to_the_left); - ShapeTraceEntries shape_entries = - new ShapeTraceEntries(trace_shape, p_layer, p_net_no_arr, p_cl_type, from_side, p_board); - Collection obstacles = - search_tree.overlapping_items_with_clearance(trace_shape, p_layer, new int[0], p_cl_type); - boolean obstacles_shovable = shape_entries.store_items(obstacles, false, true); - if (!obstacles_shovable || shape_entries.trace_tails_in_shape()) - { - return 0; - } - int trace_piece_count = shape_entries.substitute_trace_count(); - - if (shape_entries.stack_depth() > 1) - { - return 0; - } - - FloatPoint start_corner_appprox = p_line_segment.start_point_approx(); - FloatPoint end_corner_appprox = p_line_segment.end_point_approx(); - double segment_length = end_corner_appprox.distance(start_corner_appprox); - - rules.ClearanceMatrix cl_matrix = p_board.rules.clearance_matrix; - - double result = Integer.MAX_VALUE; - - // check, if the obstacle vias can be shoved - - for (Via curr_shove_via : shape_entries.shove_via_list) - { - if (curr_shove_via.shares_net_no(p_net_no_arr)) - { - continue; - } - boolean shove_via_ok = false; - if (p_max_via_recursion_depth > 0) - { - - IntPoint[] new_via_center = - MoveDrillItemAlgo.try_shove_via_points(trace_shape, p_layer, curr_shove_via, p_cl_type, - false, p_board); - - if (new_via_center.length <= 0) - { - return 0; - } - Vector delta = new_via_center[0].difference_by(curr_shove_via.get_center()); - Collection ignore_items = new java.util.LinkedList(); - shove_via_ok = MoveDrillItemAlgo.check(curr_shove_via, delta, p_max_recursion_depth, - p_max_via_recursion_depth - 1, ignore_items, p_board, null); - } - - if (!shove_via_ok) - { - FloatPoint via_center_appprox = curr_shove_via.get_center().to_float(); - double projection = start_corner_appprox.scalar_product(end_corner_appprox, via_center_appprox); - projection /= segment_length; - IntBox via_box = curr_shove_via.get_tree_shape_on_layer(search_tree, p_layer).bounding_box(); - double via_radius = 0.5 * via_box.max_width(); - double curr_ok_lenght = projection - via_radius - p_trace_half_width; - if (!search_tree.is_clearance_compensation_used()) - { - curr_ok_lenght -= cl_matrix.value(p_cl_type, curr_shove_via.clearance_class_no(), p_layer); - } - if (curr_ok_lenght <= 0) - { - return 0; - } - result = Math.min(result, curr_ok_lenght); - } - } - if (trace_piece_count == 0) - { - return result; - } - if (p_max_recursion_depth <= 0) - { - return 0; - } - - Direction line_direction = p_line_segment.get_line().direction(); - for (;;) - { - PolylineTrace curr_substitute_trace = - shape_entries.next_substitute_trace_piece(); - if (curr_substitute_trace == null) - { - break; - } - for (int i = 0; i < curr_substitute_trace.tile_shape_count(); ++i) - { - LineSegment curr_line_segment = new LineSegment(curr_substitute_trace.polyline(), i + 1); - if (p_shove_to_the_left) - { - // swap the line segmment to get the corredct shove length - // in case it is smmaller than the length of the whole line segmment. - curr_line_segment = curr_line_segment.opposite(); - } - boolean is_in_front = curr_line_segment.get_line().direction().equals(line_direction); - if (is_in_front) - { - double shove_ok_length = check(p_board, curr_line_segment, p_shove_to_the_left, p_layer, curr_substitute_trace.net_no_arr, - curr_substitute_trace.get_half_width(), curr_substitute_trace.clearance_class_no(), - p_max_recursion_depth - 1, p_max_via_recursion_depth); - if (shove_ok_length < Integer.MAX_VALUE) - { - if (shove_ok_length <= 0) - { - return 0; - } - double projection = - Math.min(start_corner_appprox.scalar_product(end_corner_appprox, curr_line_segment.start_point_approx()), - start_corner_appprox.scalar_product(end_corner_appprox, curr_line_segment.end_point_approx())); - projection /= segment_length; - double curr_ok_length = shove_ok_length + projection - p_trace_half_width - curr_substitute_trace.get_half_width(); - if (search_tree.is_clearance_compensation_used()) - { - curr_ok_length -= search_tree.clearance_compensation_value(curr_substitute_trace.clearance_class_no(), p_layer); - } - else - { - curr_ok_length -= cl_matrix.value(p_cl_type, curr_substitute_trace.clearance_class_no(), p_layer); - } - if (curr_ok_length <= 0) - { - return 0; - } - result = Math.min(curr_ok_length, result); - } - break; - } - } - } - return result; - } - - /** - * Puts in a trace segment with the input parameters and - * shoves obstacles out of the way. If the shove does not work, - * the database may be damaged. To prevent this, call check first. - */ - public boolean insert(TileShape p_trace_shape, CalcFromSide p_from_side, int p_layer, int[] p_net_no_arr, - int p_cl_type, Collection p_ignore_items, - int p_max_recursion_depth, int p_max_via_recursion_depth, int p_max_spring_over_recursion_depth) - { - if (p_trace_shape.is_empty()) - { - System.out.println("ShoveTraceAux.insert: p_trace_shape is empty"); - return true; - } - if (!p_trace_shape.is_contained_in(board.get_bounding_box())) - { - this.board.set_shove_failing_obstacle(board.get_outline()); - return false; - } - if (!MoveDrillItemAlgo.shove_vias(p_trace_shape, p_from_side, p_layer, p_net_no_arr, p_cl_type, - p_ignore_items, p_max_recursion_depth, p_max_via_recursion_depth, true, this.board)) - { - return false; - } - ShapeTraceEntries shape_entries = - new ShapeTraceEntries(p_trace_shape, p_layer, p_net_no_arr, p_cl_type, p_from_side, board); - ShapeSearchTree search_tree = this.board.search_tree_manager.get_default_tree(); - Collection obstacles = - search_tree.overlapping_items_with_clearance(p_trace_shape, p_layer, new int[0], p_cl_type); - obstacles.removeAll(get_ignore_items_at_tie_pins(p_trace_shape, p_layer, p_net_no_arr)); - boolean obstacles_shovable = shape_entries.store_items(obstacles, false, true); - if (!shape_entries.shove_via_list.isEmpty()) - { - obstacles_shovable = false; - this.board.set_shove_failing_obstacle(shape_entries.shove_via_list.iterator().next()); - return false; - } - if (!obstacles_shovable) - { - this.board.set_shove_failing_obstacle(shape_entries.get_found_obstacle()); - return false; - } - int trace_piece_count = shape_entries.substitute_trace_count(); - if (trace_piece_count == 0) - { - return true; - } - if (p_max_recursion_depth <= 0) - { - this.board.set_shove_failing_obstacle(shape_entries.get_found_obstacle()); - return false; - } - boolean tails_exist_before = board.contains_trace_tails(obstacles, p_net_no_arr); - shape_entries.cutout_traces(obstacles); - boolean is_orthogonal_mode = p_trace_shape instanceof IntBox; - for (;;) - { - PolylineTrace curr_substitute_trace = - shape_entries.next_substitute_trace_piece(); - if (curr_substitute_trace == null) - { - break; - } - if (curr_substitute_trace.first_corner().equals(curr_substitute_trace.last_corner())) - { - continue; - } - if (p_max_spring_over_recursion_depth > 0) - { - Polyline new_polyline = spring_over(curr_substitute_trace.polyline(), - curr_substitute_trace.get_compensated_half_width(search_tree), p_layer, curr_substitute_trace.net_no_arr, - curr_substitute_trace.clearance_class_no(), false, p_max_spring_over_recursion_depth, null); - - if (new_polyline == null) - { - // spring_over did not work - return false; - } - if (new_polyline != curr_substitute_trace.polyline()) - { - // spring_over changed something - --p_max_spring_over_recursion_depth; - curr_substitute_trace.change(new_polyline); - } - } - int[] curr_net_no_arr = curr_substitute_trace.net_no_arr; - for (int i = 0; i < curr_substitute_trace.tile_shape_count(); ++i) - { - CalcShapeAndFromSide curr = - new CalcShapeAndFromSide(curr_substitute_trace, i, is_orthogonal_mode, false); - if (!this.insert(curr.shape, curr.from_side, p_layer, curr_net_no_arr, curr_substitute_trace.clearance_class_no(), - p_ignore_items, p_max_recursion_depth - 1, p_max_via_recursion_depth, p_max_spring_over_recursion_depth)) - { - return false; - } - } - for (int i = 0; i < curr_substitute_trace.corner_count(); ++i) - { - board.join_changed_area( - curr_substitute_trace.polyline().corner_approx(i), p_layer); - } - Point[] end_corners = null; - if (!tails_exist_before) - { - end_corners = new Point[2]; - end_corners[0] = curr_substitute_trace.first_corner(); - end_corners[1] = curr_substitute_trace.last_corner(); - } - board.insert_item(curr_substitute_trace); - curr_substitute_trace.normalize(board.changed_area.get_area(p_layer)); - if (!tails_exist_before) - { - for (int i = 0; i < 2; ++i) - { - Trace tail = board.get_trace_tail(end_corners[i], p_layer, curr_net_no_arr); - if (tail != null) - { - board.remove_items(tail.get_connection_items(Item.StopConnectionOption.VIA), false); - for (int curr_net_no : curr_net_no_arr) - { - board.combine_traces(curr_net_no); - } - } - } - } - } - return true; - } - - Collection get_ignore_items_at_tie_pins(TileShape p_trace_shape, int p_layer, int[] p_net_no_arr) - { - Collection overlaps = this.board.overlapping_objects(p_trace_shape, p_layer); - Set result = new java.util.TreeSet(); - for (SearchTreeObject curr_object : overlaps) - { - if (curr_object instanceof Pin) - { - Pin curr_pin = (Pin) curr_object; - if (curr_pin.shares_net_no(p_net_no_arr)) - { - result.addAll(curr_pin.get_all_contacts(p_layer)); - } - } - } - return result; - } - - /** - * Checks, if there are obstacle in the way of p_polyline and tries - * to wrap the polyline trace around these obstacles in counterclock sense. - * Returns null, if that is not possible. - * Returns p_polyline, if there were no obstacles - * If p_contact_pins != null, all pins not contained in p_contact_pins are - * regarded as obstacles, even if they are of the own net. - */ - private Polyline spring_over(Polyline p_polyline, int p_half_width, - int p_layer, int[] p_net_no_arr, int p_cl_type, boolean p_over_connected_pins, - int p_recursion_depth, Set p_contact_pins) - { - Item found_obstacle = null; - IntBox found_obstacle_bounding_box = null; - ShapeSearchTree search_tree = this.board.search_tree_manager.get_default_tree(); - int[] check_net_no_arr; - if (p_contact_pins == null) - { - check_net_no_arr = p_net_no_arr; - } - else - { - check_net_no_arr = new int[0]; - } - for (int i = 0; i < p_polyline.arr.length - 2; ++i) - { - TileShape curr_shape = p_polyline.offset_shape(p_half_width, i); - Collection obstacles = search_tree.overlapping_items_with_clearance(curr_shape, p_layer, check_net_no_arr, p_cl_type); - Iterator it = obstacles.iterator(); - while (it.hasNext()) - { - Item curr_item = it.next(); - boolean is_obstacle; - if (curr_item.shares_net_no(p_net_no_arr)) - { - // to avoid acid traps - is_obstacle = curr_item instanceof Pin && p_contact_pins != null && - !p_contact_pins.contains(curr_item); - } - else if (curr_item instanceof ConductionArea) - { - is_obstacle = ((ConductionArea) curr_item).get_is_obstacle(); - } - else if (curr_item instanceof ViaObstacleArea || curr_item instanceof ComponentObstacleArea) - { - is_obstacle = false; - } - else if (curr_item instanceof PolylineTrace) - { - if (curr_item.is_shove_fixed()) - { - is_obstacle = true; - if (curr_item instanceof PolylineTrace) - { - // check for a shove fixed trace exit stub, which has to be be ignored at a tie pin. - Collection curr_contacts = curr_item.get_normal_contacts(); - for (Item curr_contact : curr_contacts) - { - if (curr_contact.shares_net_no(p_net_no_arr)) - { - is_obstacle = false; - } - } - } - } - else - { - // a unfixed trace can be pushed aside eventually - is_obstacle = false; - } - } - else - { - // a unfixed via can be pushed aside eventually - is_obstacle = !curr_item.is_route(); - } - - if (is_obstacle) - { - if (found_obstacle == null) - { - found_obstacle = curr_item; - found_obstacle_bounding_box = curr_item.bounding_box(); - } - else if (found_obstacle != curr_item) - { - // check, if 1 obstacle is contained in the other obstacle and take - // the bigger obstacle in this case. - // That may happen in case of fixed vias inside of pins. - IntBox curr_item_bounding_box = curr_item.bounding_box(); - if (found_obstacle_bounding_box.intersects(curr_item_bounding_box)) - { - if (curr_item_bounding_box.contains(found_obstacle_bounding_box)) - { - found_obstacle = curr_item; - found_obstacle_bounding_box = curr_item_bounding_box; - } - else if (!found_obstacle_bounding_box.contains(curr_item_bounding_box)) - { - return null; - } - } - } - } - } - if (found_obstacle != null) - { - break; - } - } - if (found_obstacle == null) - { - // no obstacle in the way, nothing to do - return p_polyline; - } - - - - - - - - - - - if (p_recursion_depth <= 0 || found_obstacle instanceof BoardOutline || (found_obstacle instanceof Trace && !found_obstacle.is_shove_fixed())) - { - this.board.set_shove_failing_obstacle(found_obstacle); - return null; - } - boolean try_spring_over = true; - if (!p_over_connected_pins) - { - // Check if the obstacle has a trace contact on p_layer - Collection contacts_on_layer = found_obstacle.get_all_contacts(p_layer); - for (Item curr_contact : contacts_on_layer) - { - if (curr_contact instanceof Trace) - { - try_spring_over = false; - break; - } - } - } - ConvexShape obstacle_shape = null; - if (try_spring_over) - { - if (found_obstacle instanceof ObstacleArea || found_obstacle instanceof Trace) - { - if (found_obstacle.tree_shape_count(search_tree) == 1) - { - obstacle_shape = found_obstacle.get_tree_shape(search_tree, 0); - } - else - { - try_spring_over = false; - } - } - else if (found_obstacle instanceof DrillItem) - { - DrillItem found_drill_item = (DrillItem) found_obstacle; - obstacle_shape = (found_drill_item.get_tree_shape_on_layer(search_tree, p_layer)); - } - } - if (!try_spring_over) - { - this.board.set_shove_failing_obstacle(found_obstacle); - return null; - } - TileShape offset_shape; - if (search_tree.is_clearance_compensation_used()) - { - int offset = p_half_width + 1; - offset_shape = (TileShape) obstacle_shape.enlarge(offset); - } - else - { - // enlarge the shape in 2 steps for symmetry reasons - int offset = p_half_width + 1; - double half_cl_offset = 0.5 * board.clearance_value(found_obstacle.clearance_class_no(), p_cl_type, p_layer); - offset_shape = (TileShape) obstacle_shape.enlarge(offset + half_cl_offset); - offset_shape = (TileShape) offset_shape.enlarge(half_cl_offset); - } - if (this.board.rules.get_trace_angle_restriction() == AngleRestriction.NINETY_DEGREE) - { - offset_shape = offset_shape.bounding_box(); - } - else if (this.board.rules.get_trace_angle_restriction() == AngleRestriction.FORTYFIVE_DEGREE) - { - offset_shape = offset_shape.bounding_octagon(); - } - - - - - - if (offset_shape.contains_inside(p_polyline.first_corner()) || offset_shape.contains_inside(p_polyline.last_corner())) - { - // can happen with clearance compensation off because of asymmetry in calculations with the offset shapes - this.board.set_shove_failing_obstacle(found_obstacle); - return null; - } - int[][] entries = offset_shape.entrance_points(p_polyline); - if (entries.length == 0) - { - return p_polyline; // no obstacle - } - - if (entries.length < - 2) - { - this.board.set_shove_failing_obstacle(found_obstacle); - return null; - } - Polyline[] pieces = offset_shape.cutout(p_polyline); // build a circuit around the offset_shape in counter clock sense - // from the first intersection point to the second intersection point - int first_intersection_side_no = entries[0][1]; - int last_intersection_side_no = entries[entries.length - 1][1]; - int first_intersection_line_no = entries[0][0]; - int last_intersection_line_no = entries[entries.length - 1][0]; - int side_diff = last_intersection_side_no - first_intersection_side_no; - if (side_diff < - 0) - { - side_diff += offset_shape.border_line_count(); - } - else if (side_diff == 0) - { - FloatPoint compare_corner = offset_shape.corner_approx(first_intersection_side_no); - FloatPoint first_intersection = p_polyline.arr[first_intersection_line_no].intersection_approx(offset_shape.border_line(first_intersection_side_no)); - FloatPoint second_intersection = p_polyline.arr[last_intersection_line_no].intersection_approx(offset_shape.border_line(last_intersection_side_no)); - if (compare_corner.distance(second_intersection) < compare_corner.distance(first_intersection)) - { - side_diff += offset_shape.border_line_count(); - } - } - Line[] substitute_lines = new Line[side_diff + 3]; - substitute_lines[0] = p_polyline.arr[first_intersection_line_no]; - int curr_edge_line_no = first_intersection_side_no; - - for (int i = 1; - i <= side_diff + 1; - ++i) - { - substitute_lines[i] = offset_shape.border_line(curr_edge_line_no); - if (curr_edge_line_no == offset_shape.border_line_count() - 1) - { - curr_edge_line_no = 0; - } - else - { - ++curr_edge_line_no; - } - } - substitute_lines[side_diff + 2] = p_polyline.arr[last_intersection_line_no]; - Polyline substitute_polyline = new Polyline(substitute_lines); - Polyline result = substitute_polyline; - - - - - - if (pieces.length > 0) - { - result = pieces[0].combine(substitute_polyline); - } - if (pieces.length > 1) - { - result = result.combine(pieces[1]); - } - return spring_over(result, p_half_width, p_layer, p_net_no_arr, p_cl_type, p_over_connected_pins, - p_recursion_depth - 1, p_contact_pins); - } - - /** - * Checks, if there are obstacle in the way of p_polyline and tries - * to wrap the polyline trace around these obstacles. - * Returns null, if that is not possible. - * Returns p_polyline, if there were no obstacles - * This function looks contrary to the previous function for the shortest - * way around the obstaccles. - * If p_contact_pins != null, all pins not contained in p_contact_pins are - * regarded as obstacles, even if they are of the own net. - */ - Polyline spring_over_obstacles( - Polyline p_polyline, int p_half_width, int p_layer, int[] p_net_no_arr, - int p_cl_type, Set p_contact_pins) - { - final int c_max_spring_over_recursion_depth = 20; - Polyline counter_clock_wise_result = spring_over(p_polyline, p_half_width, p_layer, p_net_no_arr, p_cl_type, - true, c_max_spring_over_recursion_depth, p_contact_pins); - if (counter_clock_wise_result == p_polyline) - { - return p_polyline; // no obstacle - } - - Polyline clock_wise_result = spring_over(p_polyline.reverse(), p_half_width, p_layer, p_net_no_arr, p_cl_type, - true, c_max_spring_over_recursion_depth, p_contact_pins); - Polyline result = null; - if (clock_wise_result != null && counter_clock_wise_result != null) - { - if (clock_wise_result.length_approx() <= counter_clock_wise_result.length_approx()) - { - result = clock_wise_result.reverse(); - } - else - { - result = counter_clock_wise_result; - } - - } - else if (clock_wise_result != null) - { - result = clock_wise_result.reverse(); - } - else if (counter_clock_wise_result != null) - { - result = counter_clock_wise_result; - } - - return result; - } - private final RoutingBoard board; -} \ No newline at end of file +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + */ +package board; + +import datastructures.TimeLimit; + +import geometry.planar.ConvexShape; +import geometry.planar.Direction; +import geometry.planar.FloatPoint; +import geometry.planar.IntBox; +import geometry.planar.Line; +import geometry.planar.Point; +import geometry.planar.IntPoint; +import geometry.planar.Vector; +import geometry.planar.Polyline; +import geometry.planar.TileShape; +import geometry.planar.LineSegment; + +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; + +/** + * Contains internal auxiliary functions of class RoutingBoard + * for shoving traces + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class ShoveTraceAlgo +{ + + /** + *

Constructor for ShoveTraceAlgo.

+ * + * @param p_board a {@link board.RoutingBoard} object. + */ + public ShoveTraceAlgo(RoutingBoard p_board) + { + board = p_board; + } + + /** + * Checks if a shove with the input parameters is possible without clearance violations + * p_dir is used internally to prevent the check from bouncing back. + * Returns false, if the shove failed. + * + * @param p_trace_shape a {@link geometry.planar.TileShape} object. + * @param p_from_side a {@link board.CalcFromSide} object. + * @param p_dir a {@link geometry.planar.Direction} object. + * @param p_layer a int. + * @param p_net_no_arr an array of int. + * @param p_cl_type a int. + * @param p_max_recursion_depth a int. + * @param p_max_via_recursion_depth a int. + * @param p_max_spring_over_recursion_depth a int. + * @param p_time_limit a {@link datastructures.TimeLimit} object. + * @return a boolean. + */ + public boolean check(TileShape p_trace_shape, CalcFromSide p_from_side, + Direction p_dir, int p_layer, int[] p_net_no_arr, + int p_cl_type, int p_max_recursion_depth, int p_max_via_recursion_depth, + int p_max_spring_over_recursion_depth, TimeLimit p_time_limit) + { + if (p_time_limit != null && p_time_limit.limit_exceeded()) + { + return false; + } + + if (p_trace_shape.is_empty()) + { + System.out.println("ShoveTraceAux.check: p_trace_shape is empty"); + return true; + } + if (!p_trace_shape.is_contained_in(board.get_bounding_box())) + { + this.board.set_shove_failing_obstacle(board.get_outline()); + return false; + } + ShapeTraceEntries shape_entries = + new ShapeTraceEntries(p_trace_shape, p_layer, p_net_no_arr, p_cl_type, p_from_side, board); + ShapeSearchTree search_tree = this.board.search_tree_manager.get_default_tree(); + Collection obstacles = + search_tree.overlapping_items_with_clearance(p_trace_shape, p_layer, new int[0], p_cl_type); + obstacles.removeAll(get_ignore_items_at_tie_pins(p_trace_shape, p_layer, p_net_no_arr)); + boolean obstacles_shovable = shape_entries.store_items(obstacles, false, true); + if (!obstacles_shovable) + { + this.board.set_shove_failing_obstacle(shape_entries.get_found_obstacle()); + return false; + } + int trace_piece_count = shape_entries.substitute_trace_count(); + + if (shape_entries.stack_depth() > 1) + { + this.board.set_shove_failing_obstacle(shape_entries.get_found_obstacle()); + return false; + } + double shape_radius = 0.5 * p_trace_shape.bounding_box().min_width(); + + // check, if the obstacle vias can be shoved + + + for (Via curr_shove_via : shape_entries.shove_via_list) + { + if (curr_shove_via.shares_net_no(p_net_no_arr)) + { + continue; + } + if (p_max_via_recursion_depth <= 0) + { + this.board.set_shove_failing_obstacle(curr_shove_via); + return false; + } + FloatPoint curr_shove_via_center = curr_shove_via.get_center().to_float(); + IntPoint[] try_via_centers = + MoveDrillItemAlgo.try_shove_via_points(p_trace_shape, p_layer, curr_shove_via, p_cl_type, + true, board); + + double max_dist = 0.5 * curr_shove_via.get_shape_on_layer(p_layer).bounding_box().max_width() + shape_radius; + double max_dist_square = max_dist * max_dist; + boolean shove_via_ok = false; + for (int i = 0; i < try_via_centers.length; ++i) + { + if (i == 0 || curr_shove_via_center.distance_square(try_via_centers[i].to_float()) <= max_dist_square) + { + Vector delta = try_via_centers[i].difference_by(curr_shove_via.get_center()); + Collection ignore_items = new java.util.LinkedList(); + if (MoveDrillItemAlgo.check(curr_shove_via, delta, p_max_recursion_depth, + p_max_via_recursion_depth - 1, ignore_items, this.board, p_time_limit)) + { + shove_via_ok = true; + break; + } + } + } + if (!shove_via_ok) + { + return false; + } + } + + if (trace_piece_count == 0) + { + return true; + } + if (p_max_recursion_depth <= 0) + { + this.board.set_shove_failing_obstacle(shape_entries.get_found_obstacle()); + return false; + } + + boolean is_orthogonal_mode = p_trace_shape instanceof IntBox; + for (;;) + { + PolylineTrace curr_substitute_trace = + shape_entries.next_substitute_trace_piece(); + if (curr_substitute_trace == null) + { + break; + } + if (p_max_spring_over_recursion_depth > 0) + { + Polyline new_polyline = spring_over(curr_substitute_trace.polyline(), + curr_substitute_trace.get_compensated_half_width(search_tree), p_layer, curr_substitute_trace.net_no_arr, + curr_substitute_trace.clearance_class_no(), false, p_max_spring_over_recursion_depth, null); + if (new_polyline == null) + { + // spring_over did not work + return false; + } + if (new_polyline != curr_substitute_trace.polyline()) + { + // spring_over changed something + --p_max_spring_over_recursion_depth; + curr_substitute_trace.change(new_polyline); + } + } + for (int i = 0; i < curr_substitute_trace.tile_shape_count(); ++i) + { + Direction curr_dir = curr_substitute_trace.polyline().arr[i + 1].direction(); + boolean is_in_front = p_dir == null || p_dir.equals(curr_dir); + if (is_in_front) + { + CalcShapeAndFromSide curr = + new CalcShapeAndFromSide(curr_substitute_trace, i, is_orthogonal_mode, true); + if (!this.check(curr.shape, curr.from_side, curr_dir, p_layer, curr_substitute_trace.net_no_arr, + curr_substitute_trace.clearance_class_no(), + p_max_recursion_depth - 1, p_max_via_recursion_depth, + p_max_spring_over_recursion_depth, p_time_limit)) + { + return false; + } + } + } + } + return true; + } + + /** + * Checks if a shove with the input parameters is possible without clearance violations + * The result is the maximum lenght of a trace from the start of the line segment to the end of + * the line segment, for wich the algoritm succeedes. + * If the algorithm succeedes completely, the result will be equal to Integer.MAX_VALUE. + * + * @param p_board a {@link board.RoutingBoard} object. + * @param p_line_segment a {@link geometry.planar.LineSegment} object. + * @param p_shove_to_the_left a boolean. + * @param p_layer a int. + * @param p_net_no_arr an array of int. + * @param p_trace_half_width a int. + * @param p_cl_type a int. + * @param p_max_recursion_depth a int. + * @param p_max_via_recursion_depth a int. + * @return a double. + */ + public static double check(RoutingBoard p_board, LineSegment p_line_segment, boolean p_shove_to_the_left, int p_layer, int[] p_net_no_arr, int p_trace_half_width, + int p_cl_type, int p_max_recursion_depth, int p_max_via_recursion_depth) + { + ShapeSearchTree search_tree = p_board.search_tree_manager.get_default_tree(); + if (search_tree.is_clearance_compensation_used()) + { + p_trace_half_width += search_tree.clearance_compensation_value(p_cl_type, p_layer); + } + TileShape[] trace_shapes = p_line_segment.to_polyline().offset_shapes(p_trace_half_width); + if (trace_shapes.length != 1) + { + System.out.println("ShoveTraceAlgo.check: trace_shape count 1 expected"); + return 0; + } + + TileShape trace_shape = trace_shapes[0]; + if (trace_shape.is_empty()) + { + System.out.println("ShoveTraceAlgo.check: trace_shape is empty"); + return 0; + } + if (!trace_shape.is_contained_in(p_board.get_bounding_box())) + { + return 0; + } + CalcFromSide from_side = new CalcFromSide(p_line_segment, trace_shape, p_shove_to_the_left); + ShapeTraceEntries shape_entries = + new ShapeTraceEntries(trace_shape, p_layer, p_net_no_arr, p_cl_type, from_side, p_board); + Collection obstacles = + search_tree.overlapping_items_with_clearance(trace_shape, p_layer, new int[0], p_cl_type); + boolean obstacles_shovable = shape_entries.store_items(obstacles, false, true); + if (!obstacles_shovable || shape_entries.trace_tails_in_shape()) + { + return 0; + } + int trace_piece_count = shape_entries.substitute_trace_count(); + + if (shape_entries.stack_depth() > 1) + { + return 0; + } + + FloatPoint start_corner_appprox = p_line_segment.start_point_approx(); + FloatPoint end_corner_appprox = p_line_segment.end_point_approx(); + double segment_length = end_corner_appprox.distance(start_corner_appprox); + + rules.ClearanceMatrix cl_matrix = p_board.rules.clearance_matrix; + + double result = Integer.MAX_VALUE; + + // check, if the obstacle vias can be shoved + + for (Via curr_shove_via : shape_entries.shove_via_list) + { + if (curr_shove_via.shares_net_no(p_net_no_arr)) + { + continue; + } + boolean shove_via_ok = false; + if (p_max_via_recursion_depth > 0) + { + + IntPoint[] new_via_center = + MoveDrillItemAlgo.try_shove_via_points(trace_shape, p_layer, curr_shove_via, p_cl_type, + false, p_board); + + if (new_via_center.length <= 0) + { + return 0; + } + Vector delta = new_via_center[0].difference_by(curr_shove_via.get_center()); + Collection ignore_items = new java.util.LinkedList(); + shove_via_ok = MoveDrillItemAlgo.check(curr_shove_via, delta, p_max_recursion_depth, + p_max_via_recursion_depth - 1, ignore_items, p_board, null); + } + + if (!shove_via_ok) + { + FloatPoint via_center_appprox = curr_shove_via.get_center().to_float(); + double projection = start_corner_appprox.scalar_product(end_corner_appprox, via_center_appprox); + projection /= segment_length; + IntBox via_box = curr_shove_via.get_tree_shape_on_layer(search_tree, p_layer).bounding_box(); + double via_radius = 0.5 * via_box.max_width(); + double curr_ok_lenght = projection - via_radius - p_trace_half_width; + if (!search_tree.is_clearance_compensation_used()) + { + curr_ok_lenght -= cl_matrix.value(p_cl_type, curr_shove_via.clearance_class_no(), p_layer); + } + if (curr_ok_lenght <= 0) + { + return 0; + } + result = Math.min(result, curr_ok_lenght); + } + } + if (trace_piece_count == 0) + { + return result; + } + if (p_max_recursion_depth <= 0) + { + return 0; + } + + Direction line_direction = p_line_segment.get_line().direction(); + for (;;) + { + PolylineTrace curr_substitute_trace = + shape_entries.next_substitute_trace_piece(); + if (curr_substitute_trace == null) + { + break; + } + for (int i = 0; i < curr_substitute_trace.tile_shape_count(); ++i) + { + LineSegment curr_line_segment = new LineSegment(curr_substitute_trace.polyline(), i + 1); + if (p_shove_to_the_left) + { + // swap the line segmment to get the corredct shove length + // in case it is smmaller than the length of the whole line segmment. + curr_line_segment = curr_line_segment.opposite(); + } + boolean is_in_front = curr_line_segment.get_line().direction().equals(line_direction); + if (is_in_front) + { + double shove_ok_length = check(p_board, curr_line_segment, p_shove_to_the_left, p_layer, curr_substitute_trace.net_no_arr, + curr_substitute_trace.get_half_width(), curr_substitute_trace.clearance_class_no(), + p_max_recursion_depth - 1, p_max_via_recursion_depth); + if (shove_ok_length < Integer.MAX_VALUE) + { + if (shove_ok_length <= 0) + { + return 0; + } + double projection = + Math.min(start_corner_appprox.scalar_product(end_corner_appprox, curr_line_segment.start_point_approx()), + start_corner_appprox.scalar_product(end_corner_appprox, curr_line_segment.end_point_approx())); + projection /= segment_length; + double curr_ok_length = shove_ok_length + projection - p_trace_half_width - curr_substitute_trace.get_half_width(); + if (search_tree.is_clearance_compensation_used()) + { + curr_ok_length -= search_tree.clearance_compensation_value(curr_substitute_trace.clearance_class_no(), p_layer); + } + else + { + curr_ok_length -= cl_matrix.value(p_cl_type, curr_substitute_trace.clearance_class_no(), p_layer); + } + if (curr_ok_length <= 0) + { + return 0; + } + result = Math.min(curr_ok_length, result); + } + break; + } + } + } + return result; + } + + /** + * Puts in a trace segment with the input parameters and + * shoves obstacles out of the way. If the shove does not work, + * the database may be damaged. To prevent this, call check first. + * + * @param p_trace_shape a {@link geometry.planar.TileShape} object. + * @param p_from_side a {@link board.CalcFromSide} object. + * @param p_layer a int. + * @param p_net_no_arr an array of int. + * @param p_cl_type a int. + * @param p_ignore_items a {@link java.util.Collection} object. + * @param p_max_recursion_depth a int. + * @param p_max_via_recursion_depth a int. + * @param p_max_spring_over_recursion_depth a int. + * @return a boolean. + */ + public boolean insert(TileShape p_trace_shape, CalcFromSide p_from_side, int p_layer, int[] p_net_no_arr, + int p_cl_type, Collection p_ignore_items, + int p_max_recursion_depth, int p_max_via_recursion_depth, int p_max_spring_over_recursion_depth) + { + if (p_trace_shape.is_empty()) + { + System.out.println("ShoveTraceAux.insert: p_trace_shape is empty"); + return true; + } + if (!p_trace_shape.is_contained_in(board.get_bounding_box())) + { + this.board.set_shove_failing_obstacle(board.get_outline()); + return false; + } + if (!MoveDrillItemAlgo.shove_vias(p_trace_shape, p_from_side, p_layer, p_net_no_arr, p_cl_type, + p_ignore_items, p_max_recursion_depth, p_max_via_recursion_depth, true, this.board)) + { + return false; + } + ShapeTraceEntries shape_entries = + new ShapeTraceEntries(p_trace_shape, p_layer, p_net_no_arr, p_cl_type, p_from_side, board); + ShapeSearchTree search_tree = this.board.search_tree_manager.get_default_tree(); + Collection obstacles = + search_tree.overlapping_items_with_clearance(p_trace_shape, p_layer, new int[0], p_cl_type); + obstacles.removeAll(get_ignore_items_at_tie_pins(p_trace_shape, p_layer, p_net_no_arr)); + boolean obstacles_shovable = shape_entries.store_items(obstacles, false, true); + if (!shape_entries.shove_via_list.isEmpty()) + { + obstacles_shovable = false; + this.board.set_shove_failing_obstacle(shape_entries.shove_via_list.iterator().next()); + return false; + } + if (!obstacles_shovable) + { + this.board.set_shove_failing_obstacle(shape_entries.get_found_obstacle()); + return false; + } + int trace_piece_count = shape_entries.substitute_trace_count(); + if (trace_piece_count == 0) + { + return true; + } + if (p_max_recursion_depth <= 0) + { + this.board.set_shove_failing_obstacle(shape_entries.get_found_obstacle()); + return false; + } + boolean tails_exist_before = board.contains_trace_tails(obstacles, p_net_no_arr); + shape_entries.cutout_traces(obstacles); + boolean is_orthogonal_mode = p_trace_shape instanceof IntBox; + for (;;) + { + PolylineTrace curr_substitute_trace = + shape_entries.next_substitute_trace_piece(); + if (curr_substitute_trace == null) + { + break; + } + if (curr_substitute_trace.first_corner().equals(curr_substitute_trace.last_corner())) + { + continue; + } + if (p_max_spring_over_recursion_depth > 0) + { + Polyline new_polyline = spring_over(curr_substitute_trace.polyline(), + curr_substitute_trace.get_compensated_half_width(search_tree), p_layer, curr_substitute_trace.net_no_arr, + curr_substitute_trace.clearance_class_no(), false, p_max_spring_over_recursion_depth, null); + + if (new_polyline == null) + { + // spring_over did not work + return false; + } + if (new_polyline != curr_substitute_trace.polyline()) + { + // spring_over changed something + --p_max_spring_over_recursion_depth; + curr_substitute_trace.change(new_polyline); + } + } + int[] curr_net_no_arr = curr_substitute_trace.net_no_arr; + for (int i = 0; i < curr_substitute_trace.tile_shape_count(); ++i) + { + CalcShapeAndFromSide curr = + new CalcShapeAndFromSide(curr_substitute_trace, i, is_orthogonal_mode, false); + if (!this.insert(curr.shape, curr.from_side, p_layer, curr_net_no_arr, curr_substitute_trace.clearance_class_no(), + p_ignore_items, p_max_recursion_depth - 1, p_max_via_recursion_depth, p_max_spring_over_recursion_depth)) + { + return false; + } + } + for (int i = 0; i < curr_substitute_trace.corner_count(); ++i) + { + board.join_changed_area( + curr_substitute_trace.polyline().corner_approx(i), p_layer); + } + Point[] end_corners = null; + if (!tails_exist_before) + { + end_corners = new Point[2]; + end_corners[0] = curr_substitute_trace.first_corner(); + end_corners[1] = curr_substitute_trace.last_corner(); + } + board.insert_item(curr_substitute_trace); + curr_substitute_trace.normalize(board.changed_area.get_area(p_layer)); + if (!tails_exist_before) + { + for (int i = 0; i < 2; ++i) + { + Trace tail = board.get_trace_tail(end_corners[i], p_layer, curr_net_no_arr); + if (tail != null) + { + board.remove_items(tail.get_connection_items(Item.StopConnectionOption.VIA), false); + for (int curr_net_no : curr_net_no_arr) + { + board.combine_traces(curr_net_no); + } + } + } + } + } + return true; + } + + Collection get_ignore_items_at_tie_pins(TileShape p_trace_shape, int p_layer, int[] p_net_no_arr) + { + Collection overlaps = this.board.overlapping_objects(p_trace_shape, p_layer); + Set result = new java.util.TreeSet(); + for (SearchTreeObject curr_object : overlaps) + { + if (curr_object instanceof Pin) + { + Pin curr_pin = (Pin) curr_object; + if (curr_pin.shares_net_no(p_net_no_arr)) + { + result.addAll(curr_pin.get_all_contacts(p_layer)); + } + } + } + return result; + } + + /** + * Checks, if there are obstacle in the way of p_polyline and tries + * to wrap the polyline trace around these obstacles in counterclock sense. + * Returns null, if that is not possible. + * Returns p_polyline, if there were no obstacles + * If p_contact_pins != null, all pins not contained in p_contact_pins are + * regarded as obstacles, even if they are of the own net. + */ + private Polyline spring_over(Polyline p_polyline, int p_half_width, + int p_layer, int[] p_net_no_arr, int p_cl_type, boolean p_over_connected_pins, + int p_recursion_depth, Set p_contact_pins) + { + Item found_obstacle = null; + IntBox found_obstacle_bounding_box = null; + ShapeSearchTree search_tree = this.board.search_tree_manager.get_default_tree(); + int[] check_net_no_arr; + if (p_contact_pins == null) + { + check_net_no_arr = p_net_no_arr; + } + else + { + check_net_no_arr = new int[0]; + } + for (int i = 0; i < p_polyline.arr.length - 2; ++i) + { + TileShape curr_shape = p_polyline.offset_shape(p_half_width, i); + Collection obstacles = search_tree.overlapping_items_with_clearance(curr_shape, p_layer, check_net_no_arr, p_cl_type); + Iterator it = obstacles.iterator(); + while (it.hasNext()) + { + Item curr_item = it.next(); + boolean is_obstacle; + if (curr_item.shares_net_no(p_net_no_arr)) + { + // to avoid acid traps + is_obstacle = curr_item instanceof Pin && p_contact_pins != null && + !p_contact_pins.contains(curr_item); + } + else if (curr_item instanceof ConductionArea) + { + is_obstacle = ((ConductionArea) curr_item).get_is_obstacle(); + } + else if (curr_item instanceof ViaObstacleArea || curr_item instanceof ComponentObstacleArea) + { + is_obstacle = false; + } + else if (curr_item instanceof PolylineTrace) + { + if (curr_item.is_shove_fixed()) + { + is_obstacle = true; + if (curr_item instanceof PolylineTrace) + { + // check for a shove fixed trace exit stub, which has to be be ignored at a tie pin. + Collection curr_contacts = curr_item.get_normal_contacts(); + for (Item curr_contact : curr_contacts) + { + if (curr_contact.shares_net_no(p_net_no_arr)) + { + is_obstacle = false; + } + } + } + } + else + { + // a unfixed trace can be pushed aside eventually + is_obstacle = false; + } + } + else + { + // a unfixed via can be pushed aside eventually + is_obstacle = !curr_item.is_route(); + } + + if (is_obstacle) + { + if (found_obstacle == null) + { + found_obstacle = curr_item; + found_obstacle_bounding_box = curr_item.bounding_box(); + } + else if (found_obstacle != curr_item) + { + // check, if 1 obstacle is contained in the other obstacle and take + // the bigger obstacle in this case. + // That may happen in case of fixed vias inside of pins. + IntBox curr_item_bounding_box = curr_item.bounding_box(); + if (found_obstacle_bounding_box.intersects(curr_item_bounding_box)) + { + if (curr_item_bounding_box.contains(found_obstacle_bounding_box)) + { + found_obstacle = curr_item; + found_obstacle_bounding_box = curr_item_bounding_box; + } + else if (!found_obstacle_bounding_box.contains(curr_item_bounding_box)) + { + return null; + } + } + } + } + } + if (found_obstacle != null) + { + break; + } + } + if (found_obstacle == null) + { + // no obstacle in the way, nothing to do + return p_polyline; + } + + + + + + + + + + + if (p_recursion_depth <= 0 || found_obstacle instanceof BoardOutline || (found_obstacle instanceof Trace && !found_obstacle.is_shove_fixed())) + { + this.board.set_shove_failing_obstacle(found_obstacle); + return null; + } + boolean try_spring_over = true; + if (!p_over_connected_pins) + { + // Check if the obstacle has a trace contact on p_layer + Collection contacts_on_layer = found_obstacle.get_all_contacts(p_layer); + for (Item curr_contact : contacts_on_layer) + { + if (curr_contact instanceof Trace) + { + try_spring_over = false; + break; + } + } + } + ConvexShape obstacle_shape = null; + if (try_spring_over) + { + if (found_obstacle instanceof ObstacleArea || found_obstacle instanceof Trace) + { + if (found_obstacle.tree_shape_count(search_tree) == 1) + { + obstacle_shape = found_obstacle.get_tree_shape(search_tree, 0); + } + else + { + try_spring_over = false; + } + } + else if (found_obstacle instanceof DrillItem) + { + DrillItem found_drill_item = (DrillItem) found_obstacle; + obstacle_shape = (found_drill_item.get_tree_shape_on_layer(search_tree, p_layer)); + } + } + if (!try_spring_over) + { + this.board.set_shove_failing_obstacle(found_obstacle); + return null; + } + TileShape offset_shape; + if (search_tree.is_clearance_compensation_used()) + { + int offset = p_half_width + 1; + offset_shape = (TileShape) obstacle_shape.enlarge(offset); + } + else + { + // enlarge the shape in 2 steps for symmetry reasons + int offset = p_half_width + 1; + double half_cl_offset = 0.5 * board.clearance_value(found_obstacle.clearance_class_no(), p_cl_type, p_layer); + offset_shape = (TileShape) obstacle_shape.enlarge(offset + half_cl_offset); + offset_shape = (TileShape) offset_shape.enlarge(half_cl_offset); + } + if (this.board.rules.get_trace_angle_restriction() == AngleRestriction.NINETY_DEGREE) + { + offset_shape = offset_shape.bounding_box(); + } + else if (this.board.rules.get_trace_angle_restriction() == AngleRestriction.FORTYFIVE_DEGREE) + { + offset_shape = offset_shape.bounding_octagon(); + } + + + + + + if (offset_shape.contains_inside(p_polyline.first_corner()) || offset_shape.contains_inside(p_polyline.last_corner())) + { + // can happen with clearance compensation off because of asymmetry in calculations with the offset shapes + this.board.set_shove_failing_obstacle(found_obstacle); + return null; + } + int[][] entries = offset_shape.entrance_points(p_polyline); + if (entries.length == 0) + { + return p_polyline; // no obstacle + } + + if (entries.length < + 2) + { + this.board.set_shove_failing_obstacle(found_obstacle); + return null; + } + Polyline[] pieces = offset_shape.cutout(p_polyline); // build a circuit around the offset_shape in counter clock sense + // from the first intersection point to the second intersection point + int first_intersection_side_no = entries[0][1]; + int last_intersection_side_no = entries[entries.length - 1][1]; + int first_intersection_line_no = entries[0][0]; + int last_intersection_line_no = entries[entries.length - 1][0]; + int side_diff = last_intersection_side_no - first_intersection_side_no; + if (side_diff < + 0) + { + side_diff += offset_shape.border_line_count(); + } + else if (side_diff == 0) + { + FloatPoint compare_corner = offset_shape.corner_approx(first_intersection_side_no); + FloatPoint first_intersection = p_polyline.arr[first_intersection_line_no].intersection_approx(offset_shape.border_line(first_intersection_side_no)); + FloatPoint second_intersection = p_polyline.arr[last_intersection_line_no].intersection_approx(offset_shape.border_line(last_intersection_side_no)); + if (compare_corner.distance(second_intersection) < compare_corner.distance(first_intersection)) + { + side_diff += offset_shape.border_line_count(); + } + } + Line[] substitute_lines = new Line[side_diff + 3]; + substitute_lines[0] = p_polyline.arr[first_intersection_line_no]; + int curr_edge_line_no = first_intersection_side_no; + + for (int i = 1; + i <= side_diff + 1; + ++i) + { + substitute_lines[i] = offset_shape.border_line(curr_edge_line_no); + if (curr_edge_line_no == offset_shape.border_line_count() - 1) + { + curr_edge_line_no = 0; + } + else + { + ++curr_edge_line_no; + } + } + substitute_lines[side_diff + 2] = p_polyline.arr[last_intersection_line_no]; + Polyline substitute_polyline = new Polyline(substitute_lines); + Polyline result = substitute_polyline; + + + + + + if (pieces.length > 0) + { + result = pieces[0].combine(substitute_polyline); + } + if (pieces.length > 1) + { + result = result.combine(pieces[1]); + } + return spring_over(result, p_half_width, p_layer, p_net_no_arr, p_cl_type, p_over_connected_pins, + p_recursion_depth - 1, p_contact_pins); + } + + /** + * Checks, if there are obstacle in the way of p_polyline and tries + * to wrap the polyline trace around these obstacles. + * Returns null, if that is not possible. + * Returns p_polyline, if there were no obstacles + * This function looks contrary to the previous function for the shortest + * way around the obstaccles. + * If p_contact_pins != null, all pins not contained in p_contact_pins are + * regarded as obstacles, even if they are of the own net. + */ + Polyline spring_over_obstacles( + Polyline p_polyline, int p_half_width, int p_layer, int[] p_net_no_arr, + int p_cl_type, Set p_contact_pins) + { + final int c_max_spring_over_recursion_depth = 20; + Polyline counter_clock_wise_result = spring_over(p_polyline, p_half_width, p_layer, p_net_no_arr, p_cl_type, + true, c_max_spring_over_recursion_depth, p_contact_pins); + if (counter_clock_wise_result == p_polyline) + { + return p_polyline; // no obstacle + } + + Polyline clock_wise_result = spring_over(p_polyline.reverse(), p_half_width, p_layer, p_net_no_arr, p_cl_type, + true, c_max_spring_over_recursion_depth, p_contact_pins); + Polyline result = null; + if (clock_wise_result != null && counter_clock_wise_result != null) + { + if (clock_wise_result.length_approx() <= counter_clock_wise_result.length_approx()) + { + result = clock_wise_result.reverse(); + } + else + { + result = counter_clock_wise_result; + } + + } + else if (clock_wise_result != null) + { + result = clock_wise_result.reverse(); + } + else if (counter_clock_wise_result != null) + { + result = counter_clock_wise_result; + } + + return result; + } + private final RoutingBoard board; +} diff --git a/board/TestLevel.java b/src/main/java/board/TestLevel.java similarity index 88% rename from board/TestLevel.java rename to src/main/java/board/TestLevel.java index 808fb6e..c77e831 100644 --- a/board/TestLevel.java +++ b/src/main/java/board/TestLevel.java @@ -1,33 +1,34 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * TestLevel.java - * - * Created on 20. April 2006, 07:32 - * - */ - -package board; - -/** - * If > RELEASE, some features may be used, which are still in experimental state. - * Also warnings for debugging may be printed depending on the test_level. - * - * @author alfons - */ -public enum TestLevel -{ - RELEASE_VERSION, TEST_VERSION, CRITICAL_DEBUGGING_OUTPUT, ALL_DEBUGGING_OUTPUT -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * TestLevel.java + * + * Created on 20. April 2006, 07:32 + * + */ + +package board; + +/** + * {@code If > RELEASE}, some features may be used, which are still in experimental state. + * Also warnings for debugging may be printed depending on the test_level. + * + * @author alfons + * @version $Id: $Id + */ +public enum TestLevel +{ + RELEASE_VERSION, TEST_VERSION, CRITICAL_DEBUGGING_OUTPUT, ALL_DEBUGGING_OUTPUT +} diff --git a/board/Trace.java b/src/main/java/board/Trace.java similarity index 87% rename from board/Trace.java rename to src/main/java/board/Trace.java index 167d134..8233a59 100644 --- a/board/Trace.java +++ b/src/main/java/board/Trace.java @@ -1,549 +1,657 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - */ - -package board; - -import geometry.planar.FloatPoint; -import geometry.planar.IntOctagon; -import geometry.planar.Point; -import geometry.planar.TileShape; - -import java.util.Collection; -import java.util.Iterator; -import java.util.Set; -import java.util.TreeSet; - - -/** - * - * Class describing functionality required for traces in the plane. - * - * @author Alfons Wirtz - */ - -public abstract class Trace extends Item implements Connectable, java.io.Serializable -{ - - Trace(int p_layer, int p_half_width, int[] p_net_no_arr, int p_clearance_type, - int p_id_no, int p_group_no, FixedState p_fixed_state, BasicBoard p_board) - { - super(p_net_no_arr, p_clearance_type, p_id_no, p_group_no, p_fixed_state, p_board); - half_width = p_half_width ; - p_layer = Math.max(p_layer, 0); - if (p_board != null) - { - p_layer = Math.min(p_layer, p_board.get_layer_count() - 1); - } - layer = p_layer; - } - - /** - * returns the first corner of the trace - */ - public abstract Point first_corner(); - - /** - * returns the last corner of the trace - */ - public abstract Point last_corner(); - - public int first_layer() - { - return this.layer; - } - - public int last_layer() - { - return this.layer; - } - - public int get_layer() - { - return this.layer; - } - - public void set_layer(int p_layer) - { - this.layer = p_layer; - } - - public int get_half_width() - { - return half_width; - } - - /** - * Returns the length of this trace. - */ - public abstract double get_length(); - - /** - * Returns the half with enlarged by the clearance compensation value for the tree - * with id number p_ttree_id_no - * Equals get_half_width(), if no clearance compensation is used in this tree. - */ - public int get_compensated_half_width(ShapeSearchTree p_search_tree) - { - int result = this.half_width + p_search_tree.clearance_compensation_value(clearance_class_no(), this.layer); - return result; - } - - public boolean is_obstacle(Item p_other) - { - if (p_other == this || p_other instanceof ViaObstacleArea || p_other instanceof ComponentObstacleArea) - { - return false; - } - if (p_other instanceof ConductionArea && !((ConductionArea) p_other).get_is_obstacle()) - { - return false; - } - if (!p_other.shares_net(this)) - { - return true; - } - return false; - } - - /** - * Get a list of all items with a connection point on the layer - * of this trace equal to its first corner. - */ - public Set get_start_contacts() - { - return get_normal_contacts(first_corner(), false); - } - - /** - * Get a list of all items with a connection point on the layer - * of this trace equal to its last corner. - */ - public Set get_end_contacts() - { - return get_normal_contacts(last_corner(), false); - } - - public Point normal_contact_point(Item p_other) - { - return p_other.normal_contact_point(this); - } - - public Set get_normal_contacts() - { - Set result = new TreeSet(); - Point start_corner = this.first_corner(); - if (start_corner != null) - { - result.addAll(get_normal_contacts(start_corner, false)); - } - Point end_corner = this.last_corner(); - if (end_corner != null) - { - result.addAll(get_normal_contacts(end_corner, false)); - } - return result; - } - - public boolean is_route() - { - return !is_user_fixed() && this.net_count() > 0; - } - - /** - * Returns true, if this trace is not contacted at its first or at its last point. - */ - public boolean is_tail() - { - Collection contact_list = this.get_start_contacts(); - if (contact_list.size() == 0) - { - return true; - } - contact_list = this.get_end_contacts(); - return (contact_list.size() == 0); - } - - - public java.awt.Color[] get_draw_colors(boardgraphics.GraphicsContext p_graphics_context) - { - return p_graphics_context.get_trace_colors(this.is_user_fixed()); - } - - public int get_draw_priority() - { - return boardgraphics.Drawable.MAX_DRAW_PRIORITY; - } - - public double get_draw_intensity(boardgraphics.GraphicsContext p_graphics_context) - { - return p_graphics_context.get_trace_color_intensity(); - } - - /** - * Get a list of all items having a connection point at p_point - * on the layer of this trace. - * If p_ignore_net is false, only contacts to items sharing a net with this trace - * are calculated. This is the normal case. - */ - public Set get_normal_contacts(Point p_point, boolean p_ignore_net) - { - if (p_point == null || !(p_point.equals(this.first_corner()) || p_point.equals(this.last_corner()))) - { - return new TreeSet(); - } - TileShape search_shape = TileShape.get_instance(p_point); - Set overlaps = board.overlapping_objects(search_shape, this.layer); - Set result = new TreeSet (); - for (SearchTreeObject curr_ob : overlaps) - { - if (!(curr_ob instanceof Item)) - { - continue; - } - Item curr_item = (Item) curr_ob; - if (curr_item != this && curr_item.shares_layer(this) && (p_ignore_net || curr_item.shares_net(this))) - { - if (curr_item instanceof Trace) - { - Trace curr_trace = (Trace) curr_item; - if (p_point.equals(curr_trace.first_corner()) - || p_point.equals(curr_trace.last_corner())) - { - result.add(curr_item); - } - } - else if (curr_item instanceof DrillItem) - { - DrillItem curr_drill_item = (DrillItem) curr_item; - if(p_point.equals(curr_drill_item.get_center())) - { - result.add(curr_item); - } - } - else if (curr_item instanceof ConductionArea) - { - ConductionArea curr_area = (ConductionArea) curr_item; - if (curr_area.get_area().contains(p_point)) - { - result.add(curr_item); - } - } - } - } - return result; - } - - Point normal_contact_point(DrillItem p_drill_item) - { - return p_drill_item.normal_contact_point(this); - } - - Point normal_contact_point(Trace p_other) - { - if (this.layer != p_other.layer) - { - return null; - } - boolean contact_at_first_corner = - this.first_corner().equals(p_other.first_corner()) - || this.first_corner().equals(p_other.last_corner()); - boolean contact_at_last_corner = - this.last_corner().equals(p_other.first_corner()) - || this.last_corner().equals(p_other.last_corner()); - Point result; - if (!(contact_at_first_corner || contact_at_last_corner) - || contact_at_first_corner && contact_at_last_corner) - { - // no contact point or more than 1 contact point - result = null; - } - else if (contact_at_first_corner) - { - result = this.first_corner(); - } - else // contact at last corner - { - result = this.last_corner(); - } - return result; - } - - public boolean is_drillable(int p_net_no) - { - return this.contains_net(p_net_no); - } - - /** - * looks, if this trace is connectet to the same object - * at its start and its end point - */ - public boolean is_overlap() - { - Set start_contacts = this.get_start_contacts(); - Set end_contacts = this.get_end_contacts(); - Iterator it = end_contacts.iterator(); - while (it.hasNext()) - { - if (start_contacts.contains(it.next())) - { - return true; - } - } - return false; - } - - /** - * Returns true, if it is not allowed to change the location of this item by the push algorithm. - */ - public boolean is_shove_fixed() - { - if (super.is_shove_fixed()) - { - return true; - } - - // check, if the trace belongs to a net, which is not shovable. - rules.Nets nets = this.board.rules.nets; - for (int curr_net_no : this.net_no_arr) - { - if (rules.Nets.is_normal_net_no(curr_net_no)) - { - if (nets.get(curr_net_no).get_class().is_shove_fixed()) - { - return true; - } - } - } - return false; - } - - /** - * returns the endpoint of this trace with the shortest distance - * to p_from_point - */ - public Point nearest_end_point(Point p_from_point) - { - Point p1 = first_corner(); - Point p2 = last_corner(); - FloatPoint from_point = p_from_point.to_float(); - double d1 = from_point.distance(p1.to_float()); - double d2 = from_point.distance(p2.to_float()); - Point result; - if (d1 < d2) - { - result = p1; - } - else - { - result = p2; - } - return result; - } - - /** - * Checks, if this trace can be reached by other items via more than one path - */ - public boolean is_cycle() - { - if (this.is_overlap()) - { - return true; - } - Set visited_items = new TreeSet(); - Collection start_contacts = this.get_start_contacts(); - // a cycle exists if through expanding the start contact we reach - // this trace again via an end contact - for (Item curr_contact : start_contacts) - { - // make shure, that all direct neighbours are - // expanded from here, to block coming back to - // this trace via a start contact. - visited_items.add(curr_contact); - } - boolean ignore_areas = false; - if (this.net_no_arr.length > 0) - { - rules.Net curr_net = this.board.rules.nets.get(this.net_no_arr[0]); - if (curr_net != null && curr_net.get_class() != null) - { - ignore_areas = curr_net.get_class().get_ignore_cycles_with_areas(); - } - } - for (Item curr_contact : start_contacts) - { - if (curr_contact.is_cycle_recu(visited_items, this, this, ignore_areas)) - { - return true; - } - } - return false; - } - - public int shape_layer(int p_index) - { - return layer; - } - - public Point[] get_ratsnest_corners() - { - // Use only uncontacted enpoints of the trace. - // Otherwise the allocated memory in the calculation of the incompletes might become very big. - int stub_count = 0; - boolean stub_at_start = false; - boolean stub_at_end = false; - if (get_start_contacts().isEmpty()) - { - ++stub_count; - stub_at_start = true; - } - if (get_end_contacts().isEmpty()) - { - ++stub_count; - stub_at_end = true; - } - Point[] result = new Point[stub_count]; - int stub_no = 0; - if (stub_at_start) - { - result[stub_no] = first_corner(); - ++stub_no; - } - if (stub_at_end) - { - result[stub_no] = last_corner(); - } - for (int i = 0; i < result.length; ++i) - { - if (result[i] == null) - { - return new Point[0];// Trace is inconsistent - } - } - return result; - } - - - /** - * checks, that the connection restrictions to the contact pins - * are satisfied. If p_at_start, the start of this trace is checked, - * else the end. Returns false, if a pin is at that end, where - * the connection is checked and the connection is not ok. - */ - public abstract boolean check_connection_to_pin(boolean p_at_start); - - public boolean is_selected_by_filter(ItemSelectionFilter p_filter) - { - if (!this.is_selected_by_fixed_filter(p_filter)) - { - return false; - } - return p_filter.is_selected(ItemSelectionFilter.SelectableChoices.TRACES); - } - - - /** - * Looks up touching pins at the first corner and the last corner of the trace. - * Used to avoid acid traps. - */ - Set touching_pins_at_end_corners() - { - Set result = new TreeSet(); - if (this.board == null) - { - return result; - } - Point curr_end_point = this.first_corner(); - for (int i = 0; i < 2; ++i) - { - IntOctagon curr_oct = curr_end_point.surrounding_octagon(); - curr_oct = curr_oct.enlarge(this.half_width); - Set curr_overlaps = this.board.overlapping_items_with_clearance(curr_oct, this.layer, new int[0], this.clearance_class_no()); - for (Item curr_item : curr_overlaps) - { - if ((curr_item instanceof Pin) && curr_item.shares_net(this)) - { - result.add((Pin)curr_item); - } - } - curr_end_point = this.last_corner(); - } - return result; - } - - public void print_info(ObjectInfoPanel p_window, java.util.Locale p_locale) - { - java.util.ResourceBundle resources = - java.util.ResourceBundle.getBundle("board.resources.ObjectInfoPanel", p_locale); - p_window.append_bold(resources.getString("trace")); - p_window.append(" " + resources.getString("from")); - p_window.append(this.first_corner().to_float()); - p_window.append(resources.getString("to")); - p_window.append(this.last_corner().to_float()); - p_window.append(resources.getString("on_layer") + " "); - p_window.append(this.board.layer_structure.arr[this.layer].name); - p_window.append(", " + resources.getString("width") + " "); - p_window.append(2 * this.half_width); - p_window.append(", " + resources.getString("length") + " "); - p_window.append(this.get_length()); - this.print_connectable_item_info(p_window, p_locale); - p_window.newline(); - } - - public boolean validate() - { - boolean result = super.validate(); - - if (this.first_corner().equals(this.last_corner())) - { - System.out.println("Trace.validate: first and last corner are equal"); - result = false; - } - return result; - } - - - /** - * looks, if this trace can be combined with other traces . - * Returns true, if somthing has been combined. - */ - abstract boolean combine(); - - /** - * Looks up traces intersecting with this trace and splits them at the intersection points. - * In case of an overlaps, the traces are split at their first and their last common point. - * Returns the pieces resulting from splitting. - * If nothing is split, the result will contain just this Trace. - * If p_clip_shape != null, the split may be resticted to p_clip_shape. - */ - public abstract Collection split(IntOctagon p_clip_shape); - - /** - * Splits this trace into two at p_point. - * Returns the 2 pieces of the splitted trace, or null if nothing was splitted because for example - * p_point is not located on this trace. - */ - public abstract Trace[] split(Point p_point); - - /** - * Tries to make this trace shorter according to its rules. - * Returns true if the geometry of the trace was changed. - */ - public abstract boolean pull_tight(PullTightAlgo p_pull_tight_algo); - - - private final int half_width ; // half width of the trace pen - private int layer ; // board layer of the trace -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + */ + +package board; + +import geometry.planar.FloatPoint; +import geometry.planar.IntOctagon; +import geometry.planar.Point; +import geometry.planar.TileShape; + +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; +import java.util.TreeSet; + + +/** + * + * Class describing functionality required for traces in the plane. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public abstract class Trace extends Item implements Connectable, java.io.Serializable +{ + + Trace(int p_layer, int p_half_width, int[] p_net_no_arr, int p_clearance_type, + int p_id_no, int p_group_no, FixedState p_fixed_state, BasicBoard p_board) + { + super(p_net_no_arr, p_clearance_type, p_id_no, p_group_no, p_fixed_state, p_board); + half_width = p_half_width ; + p_layer = Math.max(p_layer, 0); + if (p_board != null) + { + p_layer = Math.min(p_layer, p_board.get_layer_count() - 1); + } + layer = p_layer; + } + + /** + * returns the first corner of the trace + * + * @return a {@link geometry.planar.Point} object. + */ + public abstract Point first_corner(); + + /** + * returns the last corner of the trace + * + * @return a {@link geometry.planar.Point} object. + */ + public abstract Point last_corner(); + + /** + *

first_layer.

+ * + * @return a int. + */ + public int first_layer() + { + return this.layer; + } + + /** + *

last_layer.

+ * + * @return a int. + */ + public int last_layer() + { + return this.layer; + } + + /** + *

get_layer.

+ * + * @return a int. + */ + public int get_layer() + { + return this.layer; + } + + /** + *

set_layer.

+ * + * @param p_layer a int. + */ + public void set_layer(int p_layer) + { + this.layer = p_layer; + } + + /** + *

get_half_width.

+ * + * @return a int. + */ + public int get_half_width() + { + return half_width; + } + + /** + * Returns the length of this trace. + * + * @return a double. + */ + public abstract double get_length(); + + /** + * Returns the half with enlarged by the clearance compensation value for the tree + * with id number p_ttree_id_no + * Equals get_half_width(), if no clearance compensation is used in this tree. + * + * @param p_search_tree a {@link board.ShapeSearchTree} object. + * @return a int. + */ + public int get_compensated_half_width(ShapeSearchTree p_search_tree) + { + int result = this.half_width + p_search_tree.clearance_compensation_value(clearance_class_no(), this.layer); + return result; + } + + /** + *

is_obstacle.

+ * + * @param p_other a {@link board.Item} object. + * @return a boolean. + */ + public boolean is_obstacle(Item p_other) + { + if (p_other == this || p_other instanceof ViaObstacleArea || p_other instanceof ComponentObstacleArea) + { + return false; + } + if (p_other instanceof ConductionArea && !((ConductionArea) p_other).get_is_obstacle()) + { + return false; + } + if (!p_other.shares_net(this)) + { + return true; + } + return false; + } + + /** + * Get a list of all items with a connection point on the layer + * of this trace equal to its first corner. + * + * @return a {@link java.util.Set} object. + */ + public Set get_start_contacts() + { + return get_normal_contacts(first_corner(), false); + } + + /** + * Get a list of all items with a connection point on the layer + * of this trace equal to its last corner. + * + * @return a {@link java.util.Set} object. + */ + public Set get_end_contacts() + { + return get_normal_contacts(last_corner(), false); + } + + /** + *

normal_contact_point.

+ * + * @param p_other a {@link board.Item} object. + * @return a {@link geometry.planar.Point} object. + */ + public Point normal_contact_point(Item p_other) + { + return p_other.normal_contact_point(this); + } + + /** + *

get_normal_contacts.

+ * + * @return a {@link java.util.Set} object. + */ + public Set get_normal_contacts() + { + Set result = new TreeSet(); + Point start_corner = this.first_corner(); + if (start_corner != null) + { + result.addAll(get_normal_contacts(start_corner, false)); + } + Point end_corner = this.last_corner(); + if (end_corner != null) + { + result.addAll(get_normal_contacts(end_corner, false)); + } + return result; + } + + /** + *

is_route.

+ * + * @return a boolean. + */ + public boolean is_route() + { + return !is_user_fixed() && this.net_count() > 0; + } + + /** + * Returns true, if this trace is not contacted at its first or at its last point. + * + * @return a boolean. + */ + public boolean is_tail() + { + Collection contact_list = this.get_start_contacts(); + if (contact_list.size() == 0) + { + return true; + } + contact_list = this.get_end_contacts(); + return (contact_list.size() == 0); + } + + + /** {@inheritDoc} */ + public java.awt.Color[] get_draw_colors(boardgraphics.GraphicsContext p_graphics_context) + { + return p_graphics_context.get_trace_colors(this.is_user_fixed()); + } + + /** + *

get_draw_priority.

+ * + * @return a int. + */ + public int get_draw_priority() + { + return boardgraphics.Drawable.MAX_DRAW_PRIORITY; + } + + /** {@inheritDoc} */ + public double get_draw_intensity(boardgraphics.GraphicsContext p_graphics_context) + { + return p_graphics_context.get_trace_color_intensity(); + } + + /** + * Get a list of all items having a connection point at p_point + * on the layer of this trace. + * If p_ignore_net is false, only contacts to items sharing a net with this trace + * are calculated. This is the normal case. + * + * @param p_point a {@link geometry.planar.Point} object. + * @param p_ignore_net a boolean. + * @return a {@link java.util.Set} object. + */ + public Set get_normal_contacts(Point p_point, boolean p_ignore_net) + { + if (p_point == null || !(p_point.equals(this.first_corner()) || p_point.equals(this.last_corner()))) + { + return new TreeSet(); + } + TileShape search_shape = TileShape.get_instance(p_point); + Set overlaps = board.overlapping_objects(search_shape, this.layer); + Set result = new TreeSet (); + for (SearchTreeObject curr_ob : overlaps) + { + if (!(curr_ob instanceof Item)) + { + continue; + } + Item curr_item = (Item) curr_ob; + if (curr_item != this && curr_item.shares_layer(this) && (p_ignore_net || curr_item.shares_net(this))) + { + if (curr_item instanceof Trace) + { + Trace curr_trace = (Trace) curr_item; + if (p_point.equals(curr_trace.first_corner()) + || p_point.equals(curr_trace.last_corner())) + { + result.add(curr_item); + } + } + else if (curr_item instanceof DrillItem) + { + DrillItem curr_drill_item = (DrillItem) curr_item; + if(p_point.equals(curr_drill_item.get_center())) + { + result.add(curr_item); + } + } + else if (curr_item instanceof ConductionArea) + { + ConductionArea curr_area = (ConductionArea) curr_item; + if (curr_area.get_area().contains(p_point)) + { + result.add(curr_item); + } + } + } + } + return result; + } + + Point normal_contact_point(DrillItem p_drill_item) + { + return p_drill_item.normal_contact_point(this); + } + + Point normal_contact_point(Trace p_other) + { + if (this.layer != p_other.layer) + { + return null; + } + boolean contact_at_first_corner = + this.first_corner().equals(p_other.first_corner()) + || this.first_corner().equals(p_other.last_corner()); + boolean contact_at_last_corner = + this.last_corner().equals(p_other.first_corner()) + || this.last_corner().equals(p_other.last_corner()); + Point result; + if (!(contact_at_first_corner || contact_at_last_corner) + || contact_at_first_corner && contact_at_last_corner) + { + // no contact point or more than 1 contact point + result = null; + } + else if (contact_at_first_corner) + { + result = this.first_corner(); + } + else // contact at last corner + { + result = this.last_corner(); + } + return result; + } + + /** {@inheritDoc} */ + public boolean is_drillable(int p_net_no) + { + return this.contains_net(p_net_no); + } + + /** + * looks, if this trace is connectet to the same object + * at its start and its end point + * + * @return a boolean. + */ + public boolean is_overlap() + { + Set start_contacts = this.get_start_contacts(); + Set end_contacts = this.get_end_contacts(); + Iterator it = end_contacts.iterator(); + while (it.hasNext()) + { + if (start_contacts.contains(it.next())) + { + return true; + } + } + return false; + } + + /** + * Returns true, if it is not allowed to change the location of this item by the push algorithm. + * + * @return a boolean. + */ + public boolean is_shove_fixed() + { + if (super.is_shove_fixed()) + { + return true; + } + + // check, if the trace belongs to a net, which is not shovable. + rules.Nets nets = this.board.rules.nets; + for (int curr_net_no : this.net_no_arr) + { + if (rules.Nets.is_normal_net_no(curr_net_no)) + { + if (nets.get(curr_net_no).get_class().is_shove_fixed()) + { + return true; + } + } + } + return false; + } + + /** + * returns the endpoint of this trace with the shortest distance + * to p_from_point + * + * @param p_from_point a {@link geometry.planar.Point} object. + * @return a {@link geometry.planar.Point} object. + */ + public Point nearest_end_point(Point p_from_point) + { + Point p1 = first_corner(); + Point p2 = last_corner(); + FloatPoint from_point = p_from_point.to_float(); + double d1 = from_point.distance(p1.to_float()); + double d2 = from_point.distance(p2.to_float()); + Point result; + if (d1 < d2) + { + result = p1; + } + else + { + result = p2; + } + return result; + } + + /** + * Checks, if this trace can be reached by other items via more than one path + * + * @return a boolean. + */ + public boolean is_cycle() + { + if (this.is_overlap()) + { + return true; + } + Set visited_items = new TreeSet(); + Collection start_contacts = this.get_start_contacts(); + // a cycle exists if through expanding the start contact we reach + // this trace again via an end contact + for (Item curr_contact : start_contacts) + { + // make shure, that all direct neighbours are + // expanded from here, to block coming back to + // this trace via a start contact. + visited_items.add(curr_contact); + } + boolean ignore_areas = false; + if (this.net_no_arr.length > 0) + { + rules.Net curr_net = this.board.rules.nets.get(this.net_no_arr[0]); + if (curr_net != null && curr_net.get_class() != null) + { + ignore_areas = curr_net.get_class().get_ignore_cycles_with_areas(); + } + } + for (Item curr_contact : start_contacts) + { + if (curr_contact.is_cycle_recu(visited_items, this, this, ignore_areas)) + { + return true; + } + } + return false; + } + + /** {@inheritDoc} */ + public int shape_layer(int p_index) + { + return layer; + } + + /** + *

get_ratsnest_corners.

+ * + * @return an array of {@link geometry.planar.Point} objects. + */ + public Point[] get_ratsnest_corners() + { + // Use only uncontacted enpoints of the trace. + // Otherwise the allocated memory in the calculation of the incompletes might become very big. + int stub_count = 0; + boolean stub_at_start = false; + boolean stub_at_end = false; + if (get_start_contacts().isEmpty()) + { + ++stub_count; + stub_at_start = true; + } + if (get_end_contacts().isEmpty()) + { + ++stub_count; + stub_at_end = true; + } + Point[] result = new Point[stub_count]; + int stub_no = 0; + if (stub_at_start) + { + result[stub_no] = first_corner(); + ++stub_no; + } + if (stub_at_end) + { + result[stub_no] = last_corner(); + } + for (int i = 0; i < result.length; ++i) + { + if (result[i] == null) + { + return new Point[0];// Trace is inconsistent + } + } + return result; + } + + + /** + * checks, that the connection restrictions to the contact pins + * are satisfied. If p_at_start, the start of this trace is checked, + * else the end. Returns false, if a pin is at that end, where + * the connection is checked and the connection is not ok. + * + * @param p_at_start a boolean. + * @return a boolean. + */ + public abstract boolean check_connection_to_pin(boolean p_at_start); + + /** {@inheritDoc} */ + public boolean is_selected_by_filter(ItemSelectionFilter p_filter) + { + if (!this.is_selected_by_fixed_filter(p_filter)) + { + return false; + } + return p_filter.is_selected(ItemSelectionFilter.SelectableChoices.TRACES); + } + + + /** + * Looks up touching pins at the first corner and the last corner of the trace. + * Used to avoid acid traps. + */ + Set touching_pins_at_end_corners() + { + Set result = new TreeSet(); + if (this.board == null) + { + return result; + } + Point curr_end_point = this.first_corner(); + for (int i = 0; i < 2; ++i) + { + IntOctagon curr_oct = curr_end_point.surrounding_octagon(); + curr_oct = curr_oct.enlarge(this.half_width); + Set curr_overlaps = this.board.overlapping_items_with_clearance(curr_oct, this.layer, new int[0], this.clearance_class_no()); + for (Item curr_item : curr_overlaps) + { + if ((curr_item instanceof Pin) && curr_item.shares_net(this)) + { + result.add((Pin)curr_item); + } + } + curr_end_point = this.last_corner(); + } + return result; + } + + /** {@inheritDoc} */ + public void print_info(ObjectInfoPanel p_window, java.util.Locale p_locale) + { + java.util.ResourceBundle resources = + java.util.ResourceBundle.getBundle("board.resources.ObjectInfoPanel", p_locale); + p_window.append_bold(resources.getString("trace")); + p_window.append(" " + resources.getString("from")); + p_window.append(this.first_corner().to_float()); + p_window.append(resources.getString("to")); + p_window.append(this.last_corner().to_float()); + p_window.append(resources.getString("on_layer") + " "); + p_window.append(this.board.layer_structure.arr[this.layer].name); + p_window.append(", " + resources.getString("width") + " "); + p_window.append(2 * this.half_width); + p_window.append(", " + resources.getString("length") + " "); + p_window.append(this.get_length()); + this.print_connectable_item_info(p_window, p_locale); + p_window.newline(); + } + + /** + *

validate.

+ * + * @return a boolean. + */ + public boolean validate() + { + boolean result = super.validate(); + + if (this.first_corner().equals(this.last_corner())) + { + System.out.println("Trace.validate: first and last corner are equal"); + result = false; + } + return result; + } + + + /** + * looks, if this trace can be combined with other traces . + * Returns true, if somthing has been combined. + */ + abstract boolean combine(); + + /** + * Looks up traces intersecting with this trace and splits them at the intersection points. + * In case of an overlaps, the traces are split at their first and their last common point. + * Returns the pieces resulting from splitting. + * If nothing is split, the result will contain just this Trace. + * If p_clip_shape != null, the split may be resticted to p_clip_shape. + * + * @param p_clip_shape a {@link geometry.planar.IntOctagon} object. + * @return a {@link java.util.Collection} object. + */ + public abstract Collection split(IntOctagon p_clip_shape); + + /** + * Splits this trace into two at p_point. + * Returns the 2 pieces of the splitted trace, or null if nothing was splitted because for example + * p_point is not located on this trace. + * + * @param p_point a {@link geometry.planar.Point} object. + * @return an array of {@link board.Trace} objects. + */ + public abstract Trace[] split(Point p_point); + + /** + * Tries to make this trace shorter according to its rules. + * Returns true if the geometry of the trace was changed. + * + * @param p_pull_tight_algo a {@link board.PullTightAlgo} object. + * @return a boolean. + */ + public abstract boolean pull_tight(PullTightAlgo p_pull_tight_algo); + + + private final int half_width ; // half width of the trace pen + private int layer ; // board layer of the trace +} diff --git a/board/Unit.java b/src/main/java/board/Unit.java similarity index 90% rename from board/Unit.java rename to src/main/java/board/Unit.java index efc0618..7ca85dd 100644 --- a/board/Unit.java +++ b/src/main/java/board/Unit.java @@ -24,6 +24,7 @@ * Enum for the userunits inch, mil or millimeter. * * @author Alfons Wirtz + * @version $Id: $Id */ public enum Unit implements java.io.Serializable { @@ -58,7 +59,14 @@ public String toString() } }; - /** Scales p_value from p_from_unit to p_to_unit */ + /** + * Scales p_value from p_from_unit to p_to_unit + * + * @param p_value a double. + * @param p_from_unit a {@link board.Unit} object. + * @param p_to_unit a {@link board.Unit} object. + * @return a double. + */ public static double scale(double p_value, Unit p_from_unit, Unit p_to_unit) { double result; @@ -132,6 +140,9 @@ else if(p_to_unit == MM) /** * Return the unit corresponding to the input string, * or null, if the input string is different from mil, inch and mm. + * + * @param p_string a {@link java.lang.String} object. + * @return a {@link board.Unit} object. */ public static Unit from_string(String p_string) { @@ -159,5 +170,6 @@ else if (p_string.compareToIgnoreCase("um") == 0) return result; } + /** Constant INCH_TO_MM=25.4 */ public static final double INCH_TO_MM = 25.4; } diff --git a/board/Via.java b/src/main/java/board/Via.java similarity index 85% rename from board/Via.java rename to src/main/java/board/Via.java index e406784..a78b401 100644 --- a/board/Via.java +++ b/src/main/java/board/Via.java @@ -35,11 +35,24 @@ * padstack. * * @author Alfons Wirtz + * @version $Id: $Id */ public class Via extends DrillItem implements java.io.Serializable { - /** Creates a new instance of Via with the input parameters*/ + /** + * Creates a new instance of Via with the input parameters + * + * @param p_padstack a {@link library.Padstack} object. + * @param p_center a {@link geometry.planar.Point} object. + * @param p_net_no_arr an array of int. + * @param p_clearance_type a int. + * @param p_id_no a int. + * @param p_group_no a int. + * @param p_fixed_state a {@link board.FixedState} object. + * @param p_attach_allowed a boolean. + * @param p_board a {@link board.BasicBoard} object. + */ public Via(Padstack p_padstack, Point p_center, int[] p_net_no_arr, int p_clearance_type, int p_id_no, int p_group_no, FixedState p_fixed_state, boolean p_attach_allowed, BasicBoard p_board) { @@ -48,12 +61,14 @@ public Via(Padstack p_padstack, Point p_center, int[] p_net_no_arr, int p_cleara this.attach_allowed = p_attach_allowed; } + /** {@inheritDoc} */ public Item copy(int p_id_no) { return new Via(padstack, get_center(), net_no_arr, clearance_class_no(), p_id_no, get_component_no(), get_fixed_state(), attach_allowed, board); } + /** {@inheritDoc} */ public Shape get_shape(int p_index) { if (padstack == null) @@ -83,21 +98,42 @@ public Shape get_shape(int p_index) return this.precalculated_shapes[p_index]; } + /** + *

get_padstack.

+ * + * @return a {@link library.Padstack} object. + */ public Padstack get_padstack() { return padstack; } + /** + *

set_padstack.

+ * + * @param p_padstack a {@link library.Padstack} object. + */ public void set_padstack(Padstack p_padstack) { padstack = p_padstack; } + /** + *

is_route.

+ * + * @return a boolean. + */ public boolean is_route() { return !is_user_fixed() && this.net_count() > 0; } + /** + *

is_obstacle.

+ * + * @param p_other a {@link board.Item} object. + * @return a boolean. + */ public boolean is_obstacle(Item p_other) { if (p_other == this || p_other instanceof ComponentObstacleArea) @@ -125,6 +161,8 @@ public boolean is_obstacle(Item p_other) /** * Checks, if the Via has contacts on at most 1 layer. + * + * @return a boolean. */ public boolean is_tail() { @@ -148,6 +186,7 @@ public boolean is_tail() return true; } + /** {@inheritDoc} */ public void change_placement_side(IntPoint p_pole) { if (this.board == null) @@ -164,6 +203,12 @@ public void change_placement_side(IntPoint p_pole) clear_derived_data(); } + /** + *

get_autoroute_drill_info.

+ * + * @param p_autoroute_tree a {@link board.ShapeSearchTree} object. + * @return a {@link autoroute.ExpansionDrill} object. + */ public autoroute.ExpansionDrill get_autoroute_drill_info(ShapeSearchTree p_autoroute_tree) { if (this.autoroute_drill_info == null) @@ -181,6 +226,9 @@ public autoroute.ExpansionDrill get_autoroute_drill_info(ShapeSearchTree p_autor return this.autoroute_drill_info; } + /** + *

clear_derived_data.

+ */ public void clear_derived_data() { super.clear_derived_data(); @@ -188,12 +236,16 @@ public void clear_derived_data() this.autoroute_drill_info = null; } + /** + *

clear_autoroute_info.

+ */ public void clear_autoroute_info() { super.clear_autoroute_info(); this.autoroute_drill_info = null; } + /** {@inheritDoc} */ public boolean is_selected_by_filter(ItemSelectionFilter p_filter) { if (!this.is_selected_by_fixed_filter(p_filter)) @@ -203,6 +255,7 @@ public boolean is_selected_by_filter(ItemSelectionFilter p_filter) return p_filter.is_selected(ItemSelectionFilter.SelectableChoices.VIAS); } + /** {@inheritDoc} */ public java.awt.Color[] get_draw_colors(boardgraphics.GraphicsContext p_graphics_context) { java.awt.Color[] result; @@ -224,6 +277,7 @@ else if (this.first_layer() >= this.last_layer()) return result; } + /** {@inheritDoc} */ public double get_draw_intensity(boardgraphics.GraphicsContext p_graphics_context) { double result; @@ -245,6 +299,7 @@ else if (this.first_layer() >= this.last_layer()) return result; } + /** {@inheritDoc} */ public void print_info(ObjectInfoPanel p_window, java.util.Locale p_locale) { java.util.ResourceBundle resources = @@ -258,6 +313,7 @@ public void print_info(ObjectInfoPanel p_window, java.util.Locale p_locale) p_window.newline(); } + /** {@inheritDoc} */ public boolean write(java.io.ObjectOutputStream p_stream) { try diff --git a/board/ViaObstacleArea.java b/src/main/java/board/ViaObstacleArea.java similarity index 95% rename from board/ViaObstacleArea.java rename to src/main/java/board/ViaObstacleArea.java index 1298edd..8355d45 100644 --- a/board/ViaObstacleArea.java +++ b/src/main/java/board/ViaObstacleArea.java @@ -27,6 +27,7 @@ * Describes Areas on the board, where vias are not allowed. * * @author alfons + * @version $Id: $Id */ public class ViaObstacleArea extends ObstacleArea { @@ -50,6 +51,7 @@ public class ViaObstacleArea extends ObstacleArea this(p_area, p_layer, p_translation, p_rotation_in_degree, p_side_changed, new int[0], p_clearance_type, p_id_no, p_group_no, p_name, p_fixed_state, p_board); } + /** {@inheritDoc} */ public Item copy(int p_id_no) { int [] copied_net_nos = new int[net_no_arr.length]; @@ -59,6 +61,7 @@ public Item copy(int p_id_no) this.name, get_fixed_state(), board); } + /** {@inheritDoc} */ public boolean is_obstacle(Item p_other) { if (p_other.shares_net(this)) @@ -68,11 +71,13 @@ public boolean is_obstacle(Item p_other) return p_other instanceof Via; } + /** {@inheritDoc} */ public boolean is_trace_obstacle(int p_net_no) { return false; } + /** {@inheritDoc} */ public boolean is_selected_by_filter(ItemSelectionFilter p_filter) { if (!this.is_selected_by_fixed_filter(p_filter)) @@ -82,6 +87,7 @@ public boolean is_selected_by_filter(ItemSelectionFilter p_filter) return p_filter.is_selected(ItemSelectionFilter.SelectableChoices.VIA_KEEPOUT); } + /** {@inheritDoc} */ public void print_info(ObjectInfoPanel p_window, java.util.Locale p_locale) { java.util.ResourceBundle resources = @@ -93,11 +99,13 @@ public void print_info(ObjectInfoPanel p_window, java.util.Locale p_locale) p_window.newline(); } + /** {@inheritDoc} */ public java.awt.Color[] get_draw_colors(boardgraphics.GraphicsContext p_graphics_context) { return p_graphics_context.get_via_obstacle_colors(); } + /** {@inheritDoc} */ public double get_draw_intensity(boardgraphics.GraphicsContext p_graphics_context) { return p_graphics_context.get_via_obstacle_color_intensity(); diff --git a/board/package.html b/src/main/java/board/package.html similarity index 100% rename from board/package.html rename to src/main/java/board/package.html diff --git a/boardgraphics/ColorIntensityTable.java b/src/main/java/boardgraphics/ColorIntensityTable.java similarity index 89% rename from boardgraphics/ColorIntensityTable.java rename to src/main/java/boardgraphics/ColorIntensityTable.java index 654d11a..99c6535 100644 --- a/boardgraphics/ColorIntensityTable.java +++ b/src/main/java/boardgraphics/ColorIntensityTable.java @@ -25,6 +25,7 @@ * The values are between 0 (invisible) and 1 (full intensity). * * @author alfons + * @version $Id: $Id */ public class ColorIntensityTable implements java.io.Serializable { @@ -51,6 +52,8 @@ public ColorIntensityTable() /** * Copy constructor. + * + * @param p_color_intesity_table a {@link boardgraphics.ColorIntensityTable} object. */ public ColorIntensityTable(ColorIntensityTable p_color_intesity_table) { @@ -61,6 +64,12 @@ public ColorIntensityTable(ColorIntensityTable p_color_intesity_table) } } + /** + *

get_value.

+ * + * @param p_no a int. + * @return a double. + */ public double get_value(int p_no) { if (p_no < 0 || p_no >= ObjectNames.values().length) @@ -71,6 +80,12 @@ public double get_value(int p_no) return arr[p_no]; } + /** + *

set_value.

+ * + * @param p_no a int. + * @param p_value a double. + */ public void set_value(int p_no, double p_value) { if (p_no < 0 || p_no >= ObjectNames.values().length) diff --git a/boardgraphics/ColorTableModel.java b/src/main/java/boardgraphics/ColorTableModel.java similarity index 76% rename from boardgraphics/ColorTableModel.java rename to src/main/java/boardgraphics/ColorTableModel.java index 67d1b23..4bb868a 100644 --- a/boardgraphics/ColorTableModel.java +++ b/src/main/java/boardgraphics/ColorTableModel.java @@ -25,16 +25,30 @@ * Abstract class to store colors used for drawing the board. * * @author Alfons Wirtz + * @version $Id: $Id */ public abstract class ColorTableModel extends AbstractTableModel { + /** + *

Constructor for ColorTableModel.

+ * + * @param p_row_count a int. + * @param p_locale a {@link java.util.Locale} object. + */ protected ColorTableModel(int p_row_count, java.util.Locale p_locale) { this.data = new Object[p_row_count] []; this.locale = p_locale; } + /** + *

Constructor for ColorTableModel.

+ * + * @param p_stream a {@link java.io.ObjectInputStream} object. + * @throws java.io.IOException if any. + * @throws java.lang.ClassNotFoundException if any. + */ protected ColorTableModel(java.io.ObjectInputStream p_stream) throws java.io.IOException, java.lang.ClassNotFoundException { @@ -42,16 +56,23 @@ protected ColorTableModel(java.io.ObjectInputStream p_stream) this.locale = (java.util.Locale) p_stream.readObject(); } + /** + *

getRowCount.

+ * + * @return a int. + */ public int getRowCount() { return data.length; } + /** {@inheritDoc} */ public Object getValueAt(int p_row, int p_col) { return data[p_row][p_col]; } + /** {@inheritDoc} */ public void setValueAt(Object p_value, int p_row, int p_col) { data[p_row][p_col] = p_value; @@ -59,6 +80,8 @@ public void setValueAt(Object p_value, int p_row, int p_col) } /** + * {@inheritDoc} + * * JTable uses this method to determine the default renderer/ * editor for each cell. If we didn't implement this method, * then the last column would contain text ("true"/"false"), @@ -70,6 +93,12 @@ public Class getColumnClass(int p_c) } + /** + *

write_object.

+ * + * @param p_stream a {@link java.io.ObjectOutputStream} object. + * @throws java.io.IOException if any. + */ protected void write_object(java.io.ObjectOutputStream p_stream) throws java.io.IOException { diff --git a/boardgraphics/CoordinateTransform.java b/src/main/java/boardgraphics/CoordinateTransform.java similarity index 88% rename from boardgraphics/CoordinateTransform.java rename to src/main/java/boardgraphics/CoordinateTransform.java index 77dfc7a..e9e85cd 100644 --- a/boardgraphics/CoordinateTransform.java +++ b/src/main/java/boardgraphics/CoordinateTransform.java @@ -1,299 +1,343 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - */ - -package boardgraphics; - -import geometry.planar.FloatPoint; -import geometry.planar.IntBox; -import geometry.planar.Limits; - -import java.awt.Dimension; -import java.awt.geom.Point2D; - -/** - * Transformation function between the board and the screen coordinate systems. - * - * @author Alfons Wirtz - */ - - -public class CoordinateTransform implements java.io.Serializable -{ - public CoordinateTransform(IntBox p_design_box, Dimension p_panel_bounds ) - { - this.screen_bounds = p_panel_bounds; - this.design_box = p_design_box; - this.rotation_pole = p_design_box.centre_of_gravity(); - - int min_ll = Math.min(p_design_box.ll.x, p_design_box.ll.y); - int max_ur = Math.max(p_design_box.ur.x, p_design_box.ur.y); - if (Math.max(Math.abs(min_ll), Math.abs(max_ur)) <= 0.3 * Limits.CRIT_INT) - { - // create an offset to p_design_box to enable deep zoom out - double design_offset = Math.max(p_design_box.width(), p_design_box.height()); - design_box_with_offset = p_design_box.offset(design_offset); - } - else - { - // no offset because of danger of integer overflow - design_box_with_offset = p_design_box; - } - - double x_scale_factor = screen_bounds.getWidth()/design_box_with_offset.width(); - double y_scale_factor = screen_bounds.getHeight()/design_box_with_offset.height(); - - scale_factor = Math.min(x_scale_factor, y_scale_factor) ; - display_x_offset = scale_factor * design_box_with_offset.ll.x; - display_y_offset = scale_factor * design_box_with_offset.ll.y ; - } - - /** Copy constructor */ - public CoordinateTransform(CoordinateTransform p_coordinate_transform) - { - this.screen_bounds = new Dimension(p_coordinate_transform.screen_bounds); - this.design_box = new IntBox(p_coordinate_transform.design_box.ll, p_coordinate_transform.design_box.ur); - this.rotation_pole = new FloatPoint(p_coordinate_transform.rotation_pole.x, p_coordinate_transform.rotation_pole.y); - this.design_box_with_offset = new IntBox(p_coordinate_transform.design_box_with_offset.ll, p_coordinate_transform.design_box_with_offset.ur); - this.scale_factor = p_coordinate_transform.scale_factor; - this.display_x_offset = p_coordinate_transform.display_x_offset; - this.display_y_offset = p_coordinate_transform.display_y_offset; - this.mirror_left_right = p_coordinate_transform.mirror_left_right; - this.mirror_top_bottom = p_coordinate_transform.mirror_top_bottom; - this.rotation = p_coordinate_transform.rotation; - } - - /** - * scale a value from the board to the screen coordinate system - */ - public double board_to_screen(double p_val) - { - return p_val * scale_factor ; - } - - /** - * scale a value the screen to the board coordinate system - */ - public double screen_to_board(double p_val) - { - return p_val / scale_factor; - } - - - /** - * transform a geometry.planar.FloatPoint to a java.awt.geom.Point2D - */ - public Point2D board_to_screen(FloatPoint p_point) - { - FloatPoint rotated_point = p_point.rotate(this.rotation, this.rotation_pole); - - double x, y; - if (this.mirror_left_right) - { - x = (design_box_with_offset.width() - rotated_point.x - 1) * scale_factor + display_x_offset; - } - else - { - x = rotated_point.x * scale_factor - display_x_offset; - } - if (this.mirror_top_bottom) - { - y = (design_box_with_offset.height() - rotated_point.y - 1) * scale_factor + display_y_offset; - } - else - { - y = rotated_point.y * scale_factor - display_y_offset; - } - return new Point2D.Double(x, y); - } - - /** - * Transform a java.awt.geom.Point2D to a geometry.planar.FloatPoint - */ - public FloatPoint screen_to_board(Point2D p_point) - { - double x, y; - if (this.mirror_left_right) - { - x = design_box_with_offset.width() -(p_point.getX() - display_x_offset) / scale_factor - 1; - } - else - { - x = (p_point.getX() + display_x_offset)/ scale_factor; - } - if (this.mirror_top_bottom) - { - y = design_box_with_offset.height() -(p_point.getY() - display_y_offset) / scale_factor - 1; - } - else - { - y = (p_point.getY() + display_y_offset)/ scale_factor; - } - FloatPoint result = new FloatPoint(x, y); - return result.rotate(-this.rotation, this.rotation_pole); - } - - /** - * Transforms an angle in radian on the board to an angle on the screen. - */ - public double board_to_screen_angle(double p_angle) - { - double result = p_angle + this.rotation; - if (this.mirror_left_right) - { - result = Math.PI - result; - } - if (this.mirror_top_bottom) - { - result = -result; - } - while (result >= 2 * Math.PI) - { - result -= 2 * Math.PI; - } - while (result < 0) - { - result += 2 * Math.PI; - } - return result; - } - - /** - * Transform a geometry.planar.IntBox to a java.awt.Rectangle - * If the internal rotation is not a multiple of Pi/2, a bounding rectangle of the - * rotated rectangular shape is returned. - */ - public java.awt.Rectangle board_to_screen(IntBox p_box) - { - Point2D corner_1 = board_to_screen(p_box.ll.to_float()); - Point2D corner_2 = board_to_screen(p_box.ur.to_float()); - double ll_x = Math.min(corner_1.getX(), corner_2.getX()); - double ll_y = Math.min(corner_1.getY(), corner_2.getY()); - double dx = Math.abs(corner_2.getX() - corner_1.getX()); - double dy = Math.abs(corner_2.getY() - corner_1.getY()); - java.awt.Rectangle result = - new java.awt. Rectangle((int) Math.floor(ll_x), (int) Math.floor(ll_y), - (int) Math.ceil(dx), (int) Math.ceil(dy)); - return result; - } - - /** - * Transform a java.awt.Rectangle to a geometry.planar.IntBox - * If the internal rotation is not a multiple of Pi/2, a bounding box of the - * rotated rectangular shape is returned. - */ - public IntBox screen_to_board(java.awt.Rectangle p_rect) - { - FloatPoint corner_1 = screen_to_board(new Point2D.Double(p_rect.getX(), p_rect.getY())); - FloatPoint corner_2 = screen_to_board(new Point2D.Double(p_rect.getX() + p_rect.getWidth(), - p_rect.getY() + p_rect.getHeight())); - int llx = (int) Math.floor(Math.min(corner_1.x, corner_2.x)); - int lly = (int) Math.floor(Math.min(corner_1.y, corner_2.y)); - int urx = (int) Math.ceil(Math.max(corner_1.x, corner_2.x)); - int ury = (int) Math.ceil(Math.max(corner_1.y, corner_2.y)); - return new IntBox(llx, lly, urx, ury); - } - - /** - * If p_value is true, the left side and the right side of the board will be swapped. - */ - public void set_mirror_left_right(boolean p_value) - { - mirror_left_right = p_value; - } - - /** - * Returns, if the left side and the right side of the board are swapped. - */ - public boolean is_mirror_left_right() - { - return mirror_left_right; - } - - /** - * If p_value is true, the top side and the botton side of the board will be swapped. - */ - public void set_mirror_top_bottom(boolean p_value) - { - // Because the origin of display is the upper left corner, the internal value - // will be opposite to the input value of this function. - mirror_top_bottom = !p_value; - } - - /** - * Returns, if the top side and the botton side of the board are swapped. - */ - public boolean is_mirror_top_bottom() - { - // Because the origin of display is the upper left corner, the internal value - // is opposite to the result of this function. - return !mirror_top_bottom; - } - - /** - * Sets the rotation of the displayed board to p_value. - */ - public void set_rotation(double p_value) - { - rotation = p_value; - } - - /** - * Returns the rotation of the displayed board. - */ - public double get_rotation() - { - return rotation; - } - - /** - * Returns the internal rotation snapped to the nearest multiple of 90 degree. - * The result will be 0, 1, 2 or 3. - */ - public int get_90_degree_rotation() - { - int multiple = (int) Math.round(Math.toDegrees(rotation) / 90.0); - while (multiple < 0) - { - multiple += 4; - } - while (multiple >= 4) - { - multiple -= 4; - } - return multiple; - } - - final IntBox design_box; - final IntBox design_box_with_offset ; - final Dimension screen_bounds ; - private final double scale_factor ; - private final double display_x_offset; - private final double display_y_offset; - - /** - * Left side and right side of the board are swapped. - */ - private boolean mirror_left_right = false; - - /** - * Top side and bottom side of the board are swapped. - */ - private boolean mirror_top_bottom = true; - - private double rotation = 0; - - private FloatPoint rotation_pole; -} \ No newline at end of file +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + */ + +package boardgraphics; + +import geometry.planar.FloatPoint; +import geometry.planar.IntBox; +import geometry.planar.Limits; + +import java.awt.Dimension; +import java.awt.geom.Point2D; + +/** + * Transformation function between the board and the screen coordinate systems. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class CoordinateTransform implements java.io.Serializable +{ + /** + *

Constructor for CoordinateTransform.

+ * + * @param p_design_box a {@link geometry.planar.IntBox} object. + * @param p_panel_bounds a java$awt$Dimension object. + */ + public CoordinateTransform(IntBox p_design_box, Dimension p_panel_bounds ) + { + this.screen_bounds = p_panel_bounds; + this.design_box = p_design_box; + this.rotation_pole = p_design_box.centre_of_gravity(); + + int min_ll = Math.min(p_design_box.ll.x, p_design_box.ll.y); + int max_ur = Math.max(p_design_box.ur.x, p_design_box.ur.y); + if (Math.max(Math.abs(min_ll), Math.abs(max_ur)) <= 0.3 * Limits.CRIT_INT) + { + // create an offset to p_design_box to enable deep zoom out + double design_offset = Math.max(p_design_box.width(), p_design_box.height()); + design_box_with_offset = p_design_box.offset(design_offset); + } + else + { + // no offset because of danger of integer overflow + design_box_with_offset = p_design_box; + } + + double x_scale_factor = screen_bounds.getWidth()/design_box_with_offset.width(); + double y_scale_factor = screen_bounds.getHeight()/design_box_with_offset.height(); + + scale_factor = Math.min(x_scale_factor, y_scale_factor) ; + display_x_offset = scale_factor * design_box_with_offset.ll.x; + display_y_offset = scale_factor * design_box_with_offset.ll.y ; + } + + /** + * Copy constructor + * + * @param p_coordinate_transform a {@link boardgraphics.CoordinateTransform} object. + */ + public CoordinateTransform(CoordinateTransform p_coordinate_transform) + { + this.screen_bounds = new Dimension(p_coordinate_transform.screen_bounds); + this.design_box = new IntBox(p_coordinate_transform.design_box.ll, p_coordinate_transform.design_box.ur); + this.rotation_pole = new FloatPoint(p_coordinate_transform.rotation_pole.x, p_coordinate_transform.rotation_pole.y); + this.design_box_with_offset = new IntBox(p_coordinate_transform.design_box_with_offset.ll, p_coordinate_transform.design_box_with_offset.ur); + this.scale_factor = p_coordinate_transform.scale_factor; + this.display_x_offset = p_coordinate_transform.display_x_offset; + this.display_y_offset = p_coordinate_transform.display_y_offset; + this.mirror_left_right = p_coordinate_transform.mirror_left_right; + this.mirror_top_bottom = p_coordinate_transform.mirror_top_bottom; + this.rotation = p_coordinate_transform.rotation; + } + + /** + * scale a value from the board to the screen coordinate system + * + * @param p_val a double. + * @return a double. + */ + public double board_to_screen(double p_val) + { + return p_val * scale_factor ; + } + + /** + * scale a value the screen to the board coordinate system + * + * @param p_val a double. + * @return a double. + */ + public double screen_to_board(double p_val) + { + return p_val / scale_factor; + } + + + /** + * transform a geometry.planar.FloatPoint to a java.awt.geom.Point2D + * + * @param p_point a {@link geometry.planar.FloatPoint} object. + * @return a java$awt$geom$Point2D object. + */ + public Point2D board_to_screen(FloatPoint p_point) + { + FloatPoint rotated_point = p_point.rotate(this.rotation, this.rotation_pole); + + double x, y; + if (this.mirror_left_right) + { + x = (design_box_with_offset.width() - rotated_point.x - 1) * scale_factor + display_x_offset; + } + else + { + x = rotated_point.x * scale_factor - display_x_offset; + } + if (this.mirror_top_bottom) + { + y = (design_box_with_offset.height() - rotated_point.y - 1) * scale_factor + display_y_offset; + } + else + { + y = rotated_point.y * scale_factor - display_y_offset; + } + return new Point2D.Double(x, y); + } + + /** + * Transform a java.awt.geom.Point2D to a geometry.planar.FloatPoint + * + * @param p_point a java$awt$geom$Point2D object. + * @return a {@link geometry.planar.FloatPoint} object. + */ + public FloatPoint screen_to_board(Point2D p_point) + { + double x, y; + if (this.mirror_left_right) + { + x = design_box_with_offset.width() -(p_point.getX() - display_x_offset) / scale_factor - 1; + } + else + { + x = (p_point.getX() + display_x_offset)/ scale_factor; + } + if (this.mirror_top_bottom) + { + y = design_box_with_offset.height() -(p_point.getY() - display_y_offset) / scale_factor - 1; + } + else + { + y = (p_point.getY() + display_y_offset)/ scale_factor; + } + FloatPoint result = new FloatPoint(x, y); + return result.rotate(-this.rotation, this.rotation_pole); + } + + /** + * Transforms an angle in radian on the board to an angle on the screen. + * + * @param p_angle a double. + * @return a double. + */ + public double board_to_screen_angle(double p_angle) + { + double result = p_angle + this.rotation; + if (this.mirror_left_right) + { + result = Math.PI - result; + } + if (this.mirror_top_bottom) + { + result = -result; + } + while (result >= 2 * Math.PI) + { + result -= 2 * Math.PI; + } + while (result < 0) + { + result += 2 * Math.PI; + } + return result; + } + + /** + * Transform a geometry.planar.IntBox to a java.awt.Rectangle + * If the internal rotation is not a multiple of Pi/2, a bounding rectangle of the + * rotated rectangular shape is returned. + * + * @param p_box a {@link geometry.planar.IntBox} object. + * @return a java$awt$Rectangle object. + */ + public java.awt.Rectangle board_to_screen(IntBox p_box) + { + Point2D corner_1 = board_to_screen(p_box.ll.to_float()); + Point2D corner_2 = board_to_screen(p_box.ur.to_float()); + double ll_x = Math.min(corner_1.getX(), corner_2.getX()); + double ll_y = Math.min(corner_1.getY(), corner_2.getY()); + double dx = Math.abs(corner_2.getX() - corner_1.getX()); + double dy = Math.abs(corner_2.getY() - corner_1.getY()); + java.awt.Rectangle result = + new java.awt. Rectangle((int) Math.floor(ll_x), (int) Math.floor(ll_y), + (int) Math.ceil(dx), (int) Math.ceil(dy)); + return result; + } + + /** + * Transform a java.awt.Rectangle to a geometry.planar.IntBox + * If the internal rotation is not a multiple of Pi/2, a bounding box of the + * rotated rectangular shape is returned. + * + * @param p_rect a java$awt$Rectangle object. + * @return a {@link geometry.planar.IntBox} object. + */ + public IntBox screen_to_board(java.awt.Rectangle p_rect) + { + FloatPoint corner_1 = screen_to_board(new Point2D.Double(p_rect.getX(), p_rect.getY())); + FloatPoint corner_2 = screen_to_board(new Point2D.Double(p_rect.getX() + p_rect.getWidth(), + p_rect.getY() + p_rect.getHeight())); + int llx = (int) Math.floor(Math.min(corner_1.x, corner_2.x)); + int lly = (int) Math.floor(Math.min(corner_1.y, corner_2.y)); + int urx = (int) Math.ceil(Math.max(corner_1.x, corner_2.x)); + int ury = (int) Math.ceil(Math.max(corner_1.y, corner_2.y)); + return new IntBox(llx, lly, urx, ury); + } + + /** + * If p_value is true, the left side and the right side of the board will be swapped. + * + * @param p_value a boolean. + */ + public void set_mirror_left_right(boolean p_value) + { + mirror_left_right = p_value; + } + + /** + * Returns, if the left side and the right side of the board are swapped. + * + * @return a boolean. + */ + public boolean is_mirror_left_right() + { + return mirror_left_right; + } + + /** + * If p_value is true, the top side and the botton side of the board will be swapped. + * + * @param p_value a boolean. + */ + public void set_mirror_top_bottom(boolean p_value) + { + // Because the origin of display is the upper left corner, the internal value + // will be opposite to the input value of this function. + mirror_top_bottom = !p_value; + } + + /** + * Returns, if the top side and the botton side of the board are swapped. + * + * @return a boolean. + */ + public boolean is_mirror_top_bottom() + { + // Because the origin of display is the upper left corner, the internal value + // is opposite to the result of this function. + return !mirror_top_bottom; + } + + /** + * Sets the rotation of the displayed board to p_value. + * + * @param p_value a double. + */ + public void set_rotation(double p_value) + { + rotation = p_value; + } + + /** + * Returns the rotation of the displayed board. + * + * @return a double. + */ + public double get_rotation() + { + return rotation; + } + + /** + * Returns the internal rotation snapped to the nearest multiple of 90 degree. + * The result will be 0, 1, 2 or 3. + * + * @return a int. + */ + public int get_90_degree_rotation() + { + int multiple = (int) Math.round(Math.toDegrees(rotation) / 90.0); + while (multiple < 0) + { + multiple += 4; + } + while (multiple >= 4) + { + multiple -= 4; + } + return multiple; + } + + final IntBox design_box; + final IntBox design_box_with_offset ; + final Dimension screen_bounds ; + private final double scale_factor ; + private final double display_x_offset; + private final double display_y_offset; + + /** + * Left side and right side of the board are swapped. + */ + private boolean mirror_left_right = false; + + /** + * Top side and bottom side of the board are swapped. + */ + private boolean mirror_top_bottom = true; + + private double rotation = 0; + + private FloatPoint rotation_pole; +} diff --git a/boardgraphics/Drawable.java b/src/main/java/boardgraphics/Drawable.java similarity index 65% rename from boardgraphics/Drawable.java rename to src/main/java/boardgraphics/Drawable.java index ec17e6a..db81d52 100644 --- a/boardgraphics/Drawable.java +++ b/src/main/java/boardgraphics/Drawable.java @@ -1,64 +1,87 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - */ - -package boardgraphics; - -import java.awt.Color; -import java.awt.Graphics; - -/** - * items to be drawn by the functions in GraphicsContext - * must implement this interface - * - * @author Alfons Wirtz - */ - -public interface Drawable -{ - /** - * Draws this item to the device provided in p_graphics_context. - * p_color_arr is an array of dimenssion layer_count. - * p_intensity is a number between between 0 and 1. - */ - void draw(Graphics p_g, GraphicsContext p_graphics_context, Color[] p_color_arr, double p_intensity); - - /** - * Draws this item to the device provided in p_graphics_context. - * It is drawn on each layer with the same color p_color. - * p_intensity is a number between 0 and 1. - */ - void draw(Graphics p_g, GraphicsContext p_graphics_context, Color p_color, double p_intensity); - - /** - * Returns the priority for drawing an item. - * Items with higher priority are drawn later than items with lower priority. - */ - int get_draw_priority(); - - /** - * Gets the drawing intensity in the alpha blending for this item. - */ - double get_draw_intensity(GraphicsContext p_graphics_context); - - /** - * gets the draw colors for this object from p_graphics_context - */ - Color[] get_draw_colors(GraphicsContext p_graphics_context); - - static final int MIN_DRAW_PRIORITY = 1; - static final int MIDDLE_DRAW_PRIORITY = 3; - static final int MAX_DRAW_PRIORITY = 3; -} \ No newline at end of file +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + */ + +package boardgraphics; + +import java.awt.Color; +import java.awt.Graphics; + +/** + * items to be drawn by the functions in GraphicsContext + * must implement this interface + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public interface Drawable +{ + /** + * Draws this item to the device provided in p_graphics_context. + * p_color_arr is an array of dimenssion layer_count. + * p_intensity is a number between between 0 and 1. + * + * @param p_g a {@link java.awt.Graphics} object. + * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object. + * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object. + * @param p_color_arr an array of {@link java.awt.Color} objects. + * @param p_intensity a double. + */ + void draw(Graphics p_g, GraphicsContext p_graphics_context, Color[] p_color_arr, double p_intensity); + + /** + * Draws this item to the device provided in p_graphics_context. + * It is drawn on each layer with the same color p_color. + * p_intensity is a number between 0 and 1. + * + * @param p_g a {@link java.awt.Graphics} object. + * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object. + * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object. + * @param p_color a {@link java.awt.Color} object. + * @param p_intensity a double. + */ + void draw(Graphics p_g, GraphicsContext p_graphics_context, Color p_color, double p_intensity); + + /** + * Returns the priority for drawing an item. + * Items with higher priority are drawn later than items with lower priority. + * + * @return a int. + */ + int get_draw_priority(); + + /** + * Gets the drawing intensity in the alpha blending for this item. + * + * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object. + * @return a double. + */ + double get_draw_intensity(GraphicsContext p_graphics_context); + + /** + * gets the draw colors for this object from p_graphics_context + * + * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object. + * @return an array of {@link java.awt.Color} objects. + */ + Color[] get_draw_colors(GraphicsContext p_graphics_context); + + /** Constant MIN_DRAW_PRIORITY=1 */ + static final int MIN_DRAW_PRIORITY = 1; + /** Constant MIDDLE_DRAW_PRIORITY=3 */ + static final int MIDDLE_DRAW_PRIORITY = 3; + /** Constant MAX_DRAW_PRIORITY=3 */ + static final int MAX_DRAW_PRIORITY = 3; +} diff --git a/boardgraphics/GraphicsContext.java b/src/main/java/boardgraphics/GraphicsContext.java similarity index 78% rename from boardgraphics/GraphicsContext.java rename to src/main/java/boardgraphics/GraphicsContext.java index 87f792c..463eab2 100644 --- a/boardgraphics/GraphicsContext.java +++ b/src/main/java/boardgraphics/GraphicsContext.java @@ -1,854 +1,1149 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - */ - -package boardgraphics; - -import geometry.planar.Area; -import geometry.planar.Circle; -import geometry.planar.Ellipse; -import geometry.planar.FloatPoint; -import geometry.planar.IntBox; -import geometry.planar.PolylineShape; -import geometry.planar.Shape; -import geometry.planar.TileShape; - -import java.awt.AlphaComposite; -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Polygon; -import java.awt.Rectangle; -import java.awt.RenderingHints; -import java.awt.geom.Ellipse2D; -import java.awt.geom.GeneralPath; -import java.awt.geom.Line2D; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.awt.geom.AffineTransform; - - -/** - * Context for drawing items in the board package to the screen. - * - * @author Alfons Wirtz - */ - - -public class GraphicsContext implements java.io.Serializable -{ - public GraphicsContext( IntBox p_design_bounds, - Dimension p_panel_bounds, board.LayerStructure p_layer_structure, java.util.Locale p_locale) - { - coordinate_transform = new CoordinateTransform(p_design_bounds, p_panel_bounds); - item_color_table = new ItemColorTableModel(p_layer_structure, p_locale); - other_color_table = new OtherColorTableModel(p_locale); - color_intensity_table = new ColorIntensityTable(); - layer_visibility_arr = new double [p_layer_structure.arr.length]; - for (int i = 0; i < layer_visibility_arr.length; ++i) - { - if (p_layer_structure.arr[i].is_signal) - { - layer_visibility_arr [i] = 1; - } - else - { - layer_visibility_arr [i] = 0; - } - } - } - - /** - * Copy constructor - */ - public GraphicsContext(GraphicsContext p_graphics_context) - { - this.coordinate_transform = new CoordinateTransform(p_graphics_context.coordinate_transform); - this.item_color_table = new ItemColorTableModel(p_graphics_context.item_color_table); - this.other_color_table = new OtherColorTableModel(p_graphics_context.other_color_table); - this.color_intensity_table = new ColorIntensityTable(p_graphics_context.color_intensity_table); - this.layer_visibility_arr = p_graphics_context.copy_layer_visibility_arr(); - } - - /** - * Changes the bounds of the board design to p_design_bounds. - * Useful when components are still placed outside the boaed. - */ - public void change_design_bounds(IntBox p_new_design_bounds) - { - if (p_new_design_bounds.equals(this.coordinate_transform.design_box)) - { - return; - } - Dimension screen_bounds = this.coordinate_transform.screen_bounds; - this.coordinate_transform = new CoordinateTransform(p_new_design_bounds, screen_bounds); - } - - /** - * changes the size of the panel to p_new_bounds - */ - public void change_panel_size(Dimension p_new_bounds) - { - if (coordinate_transform == null) - { - return; - } - IntBox design_box = coordinate_transform.design_box; - boolean left_right_swapped = coordinate_transform.is_mirror_left_right(); - boolean top_bottom_swapped = coordinate_transform.is_mirror_top_bottom(); - double rotation = coordinate_transform.get_rotation(); - coordinate_transform = new CoordinateTransform(design_box, p_new_bounds); - coordinate_transform.set_mirror_left_right(left_right_swapped); - coordinate_transform.set_mirror_top_bottom(top_bottom_swapped); - coordinate_transform.set_rotation(rotation); - } - - /** - * draws a polygon with corners p_points - */ - public void draw(FloatPoint[] p_points, double p_half_width, Color p_color, Graphics p_g, double p_translucency_factor) - { - if (p_color == null) - { - return; - } - Graphics2D g2 = (Graphics2D)p_g; - Rectangle clip_shape = (Rectangle)p_g.getClip() ; - // the class member update_box cannot be used here, because - // the dirty rectangle is internally enlarged by the system. - // Therefore we can not improve the performance by using an - // update octagon instead of a box. - IntBox clip_box = coordinate_transform.screen_to_board(clip_shape); - double scaled_width = coordinate_transform.board_to_screen(p_half_width); - - init_draw_graphics(g2, p_color, (float)scaled_width*2); - set_translucency(g2, p_translucency_factor); - - GeneralPath draw_path = null; - if (!show_line_segments) - { - draw_path = new GeneralPath(); - } - - for(int i= 0; i<(p_points.length-1); i++) - { - if (line_outside_update_box(p_points[i], p_points[i + 1], - p_half_width + update_offset, clip_box)) - { - // this check should be unnessersary here, - // the system should do it in the draw(line) function - continue; - } - Point2D p1 = coordinate_transform.board_to_screen(p_points[i]) ; - Point2D p2 = coordinate_transform.board_to_screen(p_points[i+1]) ; - Line2D line = new Line2D.Double(p1, p2) ; - - if (show_line_segments) - { - g2.draw(line); - } - else - { - draw_path.append(line, false); - } - } - if (!show_line_segments) - { - g2.draw(draw_path); - } - } - - /* - * draws the boundary of a circle - */ - public void draw_circle(FloatPoint p_center, double p_radius, double p_draw_half_width, - Color p_color, Graphics p_g, double p_translucency_factor) - { - if (p_color == null) - { - return; - } - Graphics2D g2 = (Graphics2D)p_g; - Point2D center = coordinate_transform.board_to_screen(p_center); - - double radius = coordinate_transform.board_to_screen(p_radius); - double diameter = 2 * radius; - float draw_width = (float)(2 * coordinate_transform.board_to_screen(p_draw_half_width)); - Ellipse2D circle = - new Ellipse2D.Double(center.getX() - radius,center.getY() - radius, diameter, diameter); - set_translucency(g2, p_translucency_factor); - init_draw_graphics(g2, p_color, draw_width); - g2.draw(circle); - } - - /* - * draws a rectangle - */ - public void draw_rectangle(FloatPoint p_corner1, FloatPoint p_corner2, - double p_draw_half_width, Color p_color, Graphics p_g, double p_translucency_factor) - { - if (p_color == null) - { - return; - } - Graphics2D g2 = (Graphics2D)p_g ; - Point2D corner1 = coordinate_transform.board_to_screen(p_corner1) ; - Point2D corner2 = coordinate_transform.board_to_screen(p_corner2) ; - - double xmin = Math.min(corner1.getX(), corner2.getX()) ; - double ymin = Math.min(corner1.getY(), corner2.getY()) ; - - float draw_width = (float)(2 * coordinate_transform.board_to_screen(p_draw_half_width)) ; - double width = Math.abs(corner2.getX() - corner1.getX()) ; - double height = Math.abs(corner2.getY() - corner1.getY()) ; - Rectangle2D rectangle = new Rectangle2D.Double(xmin, ymin, width, height) ; - set_translucency(g2, p_translucency_factor); - init_draw_graphics(g2, p_color, draw_width) ; - g2.draw(rectangle) ; - } - - /** - * Draws the boundary of p_shape. - */ - public void draw_boundary(Shape p_shape, double p_draw_half_width, Color p_color, Graphics p_g, double p_translucency_factor) - { - if (p_shape instanceof PolylineShape) - { - FloatPoint[] draw_corners = p_shape.corner_approx_arr(); - if (draw_corners.length <= 1) - { - return; - } - FloatPoint[] closed_draw_corners = new FloatPoint[draw_corners.length + 1]; - System.arraycopy(draw_corners, 0, closed_draw_corners, 0, draw_corners.length); - closed_draw_corners[closed_draw_corners.length - 1] = draw_corners [0]; - this.draw( closed_draw_corners, p_draw_half_width, p_color, p_g, p_translucency_factor); - } - else if (p_shape instanceof Circle) - { - Circle curr_circle = (Circle) p_shape; - this.draw_circle(curr_circle.center.to_float(), curr_circle.radius, p_draw_half_width, - p_color, p_g, p_translucency_factor); - } - } - - /** - * Draws the boundary of p_area. - */ - public void draw_boundary(Area p_area, double p_draw_half_width, Color p_color, Graphics p_g, double p_translucency_factor) - { - draw_boundary(p_area.get_border(), p_draw_half_width, p_color, p_g, p_translucency_factor); - Shape[] holes = p_area.get_holes(); - for (int i = 0; i < holes.length; ++i) - { - draw_boundary(holes[i], p_draw_half_width, p_color, p_g, p_translucency_factor); - } - } - - /** - * Draws the interiour of a circle - */ - public void fill_circle(Circle p_circle, Graphics p_g, Color p_color, double p_translucency_factor) - { - if (p_color == null) - { - return; - } - Point2D center = coordinate_transform.board_to_screen(p_circle.center.to_float()); - double radius = coordinate_transform.board_to_screen(p_circle.radius); - if (!point_near_rectangle(center.getX(), center.getY(), (Rectangle)p_g.getClip(), radius)) - { - return; - } - double diameter = 2 * radius; - Ellipse2D circle = - new Ellipse2D.Double(center.getX() - radius,center.getY() - radius, diameter, diameter); - Graphics2D g2 = (Graphics2D)p_g; - g2.setColor(p_color); - set_translucency(g2, p_translucency_factor); - g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - g2.fill(circle); - } - - /** - * Draws the interiour of an ellipse. - */ - public void fill_ellipse(Ellipse p_ellipse, Graphics p_g, Color p_color, double p_translucency_factor) - { - Ellipse [] ellipse_arr = new Ellipse[1]; - ellipse_arr[0] = p_ellipse; - fill_ellipse_arr(ellipse_arr, p_g, p_color, p_translucency_factor); - } - - - /** - * Draws the interiour of an array of ellipses. - * Ellipses contained in an other ellipse are treated as holes. - */ - public void fill_ellipse_arr(Ellipse [] p_ellipse_arr, Graphics p_g, Color p_color, double p_translucency_factor) - { - if (p_color == null || p_ellipse_arr.length <= 0) - { - return; - } - GeneralPath draw_path = new GeneralPath(GeneralPath.WIND_EVEN_ODD); - for (Ellipse curr_ellipse : p_ellipse_arr) - { - Point2D center = coordinate_transform.board_to_screen(curr_ellipse.center); - double bigger_radius = coordinate_transform.board_to_screen(curr_ellipse.bigger_radius); - if (!point_near_rectangle(center.getX(), center.getY(), (Rectangle)p_g.getClip(), bigger_radius)) - { - continue; - } - double smaller_radius = coordinate_transform.board_to_screen(curr_ellipse.smaller_radius); - Ellipse2D draw_ellipse = - new Ellipse2D.Double(center.getX() - bigger_radius,center.getY() - smaller_radius, - 2 * bigger_radius, 2 * smaller_radius); - double rotation = coordinate_transform.board_to_screen_angle(curr_ellipse.rotation); - AffineTransform affine_transform = new AffineTransform(); - affine_transform.rotate(rotation, center.getX(), center.getY()); - java.awt.Shape rotated_ellipse = affine_transform.createTransformedShape(draw_ellipse); - draw_path.append(rotated_ellipse, false); - } - Graphics2D g2 = (Graphics2D)p_g; - g2.setColor(p_color); - set_translucency(g2, p_translucency_factor); - g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - g2.fill(draw_path); - } - - /** - * Checks, if the distance of the point with coordinates p_x, p_y to p_rect ist at most p_dist. - */ - private boolean point_near_rectangle(double p_x, double p_y, Rectangle p_rect, double p_dist) - { - if (p_x < p_rect.x - p_dist) - { - return false; - } - if (p_y < p_rect.y - p_dist) - { - return false; - } - if (p_x > p_rect.x + p_rect.width + p_dist) - { - return false; - } - if (p_y > p_rect.y + p_rect.height + p_dist) - { - return false; - } - return true; - } - - /** - * Fill the interior of the polygon shape represented by p_points. - */ - public void fill_shape(FloatPoint[] p_points, Graphics p_g, Color p_color, double p_translucency_factor) - { - if (p_color == null) - { - return; - } - Graphics2D g2 = (Graphics2D)p_g; - Polygon draw_polygon = new Polygon(); - for(int i= 0; i < p_points.length; i++) - { - Point2D curr_corner = coordinate_transform.board_to_screen(p_points[i]); - draw_polygon.addPoint((int)Math.round(curr_corner.getX()), - (int)Math.round(curr_corner.getY())); - } - g2.setColor(p_color); - set_translucency(g2, p_translucency_factor); - g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - g2.fill(draw_polygon); - } - - /** - * Fill the interiour of a list of polygons. - * Used for example with an area consisting of a border polygon and some holes. - */ - public void fill_area(FloatPoint[][] p_point_lists, Graphics p_g, Color p_color, double p_translucency_factor) - { - if (p_color == null) - { - return; - } - GeneralPath draw_path = new GeneralPath(GeneralPath.WIND_EVEN_ODD); - for (int j = 0; j < p_point_lists.length; ++j) - { - Polygon draw_polygon = new Polygon(); - FloatPoint[] curr_point_list = p_point_lists[j]; - for(int i= 0; i < curr_point_list.length; i++) - { - Point2D curr_corner = coordinate_transform.board_to_screen(curr_point_list[i]); - draw_polygon.addPoint((int)Math.round(curr_corner.getX()), - (int)Math.round(curr_corner.getY())); - } - draw_path.append(draw_polygon, false); - } - Graphics2D g2 = (Graphics2D)p_g; - g2.setColor(p_color); - set_translucency(g2, p_translucency_factor); - g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - g2.fill(draw_path); - } - - /** - * draws the interiour of an item of class geometry.planar.Area - */ - public void fill_area(Area p_area, Graphics p_g, Color p_color, double p_translucency_factor) - { - if (p_color == null || p_area.is_empty()) - { - return; - } - if (p_area instanceof Circle) - { - fill_circle((Circle) p_area, p_g, p_color, p_translucency_factor); - } - else - { - PolylineShape border = (PolylineShape) p_area.get_border(); - if (!border.is_bounded()) - { - System.out.println("GraphicsContext.fill_area: shape not bounded"); - return; - } - Rectangle clip_shape = (Rectangle)p_g.getClip() ; - IntBox clip_box = coordinate_transform.screen_to_board(clip_shape); - if (!border.bounding_box().intersects(clip_box)) - { - return; - } - Shape [] holes = p_area.get_holes(); - - FloatPoint[] [] draw_polygons = new FloatPoint [holes.length + 1][]; - for (int j = 0; j < draw_polygons.length; ++j) - { - PolylineShape curr_draw_shape; - if (j == 0) - { - curr_draw_shape = border; - } - else - { - curr_draw_shape = (PolylineShape) holes[j - 1]; - } - draw_polygons[j] = new FloatPoint [curr_draw_shape.border_line_count() + 1]; - FloatPoint curr_draw_polygon[] = draw_polygons[j]; - for (int i = 0; i < curr_draw_polygon.length - 1; ++i) - { - curr_draw_polygon[i] = curr_draw_shape.corner_approx(i); - } - // close the polygon - curr_draw_polygon[curr_draw_polygon.length - 1] = curr_draw_polygon[0]; - } - fill_area(draw_polygons, p_g, p_color, p_translucency_factor) ; - } - if (show_area_division) - { - TileShape[] tiles = p_area.split_to_convex(); - for (int i = 0; i < tiles.length; ++i) - { - FloatPoint[] corners = new FloatPoint [tiles[i].border_line_count() + 1]; - TileShape curr_tile = tiles[i]; - for (int j = 0; j < corners.length - 1; ++j) - { - corners[j]= curr_tile.corner_approx(j); - } - corners[corners.length - 1] = corners[0]; - draw(corners, 1, java.awt.Color.white, p_g, 0.7); - } - } - } - - public Color get_background_color() - { - return other_color_table.get_background_color(); - } - - public Color get_hilight_color() - { - return other_color_table.get_hilight_color(); - } - - public Color get_incomplete_color() - { - return other_color_table.get_incomplete_color(); - } - - public Color get_outline_color() - { - return other_color_table.get_outline_color(); - } - - public Color get_component_color(boolean p_front) - { - return other_color_table.get_component_color(p_front); - } - - public Color get_violations_color() - { - return other_color_table.get_violations_color(); - } - - public Color get_length_matching_area_color() - { - return other_color_table.get_length_matching_area_color(); - } - - public Color[] get_trace_colors(boolean p_fixed) - { - - return item_color_table.get_trace_colors(p_fixed); - } - - public Color[] get_via_colors(boolean p_fixed) - { - return item_color_table.get_via_colors(p_fixed); - } - - public Color[] get_pin_colors() - { - return item_color_table.get_pin_colors(); - } - - public Color[] get_conduction_colors() - { - return item_color_table.get_conduction_colors(); - } - - public Color[] get_obstacle_colors() - { - return item_color_table.get_obstacle_colors(); - } - - public Color[] get_via_obstacle_colors() - { - return item_color_table.get_via_obstacle_colors(); - } - - public Color[] get_place_obstacle_colors() - { - return item_color_table.get_place_obstacle_colors(); - } - - public double get_trace_color_intensity() - { - return color_intensity_table.get_value(ColorIntensityTable.ObjectNames.TRACES.ordinal()); - } - - public double get_via_color_intensity() - { - return color_intensity_table.get_value(ColorIntensityTable.ObjectNames.VIAS.ordinal()); - } - - public double get_pin_color_intensity() - { - return color_intensity_table.get_value(ColorIntensityTable.ObjectNames.PINS.ordinal()); - } - - public double get_conduction_color_intensity() - { - return color_intensity_table.get_value(ColorIntensityTable.ObjectNames.CONDUCTION_AREAS.ordinal()); - } - - public double get_obstacle_color_intensity() - { - return color_intensity_table.get_value(ColorIntensityTable.ObjectNames.KEEPOUTS.ordinal()); - } - - public double get_via_obstacle_color_intensity() - { - return color_intensity_table.get_value(ColorIntensityTable.ObjectNames.VIA_KEEPOUTS.ordinal()); - } - - public double get_place_obstacle_color_intensity() - { - return color_intensity_table.get_value(ColorIntensityTable.ObjectNames.PLACE_KEEPOUTS.ordinal()); - } - - public double get_component_outline_color_intensity() - { - return color_intensity_table.get_value(ColorIntensityTable.ObjectNames.COMPONENT_OUTLINES.ordinal()); - } - - public double get_hilight_color_intensity() - { - return color_intensity_table.get_value(ColorIntensityTable.ObjectNames.HILIGHT.ordinal()); - } - - public double get_incomplete_color_intensity() - { - return color_intensity_table.get_value(ColorIntensityTable.ObjectNames.INCOMPLETES.ordinal()); - } - - public double get_length_matching_area_color_intensity() - { - return color_intensity_table.get_value(ColorIntensityTable.ObjectNames.LENGTH_MATCHING_AREAS.ordinal()); - } - - public void set_trace_color_intensity(double p_value) - { - color_intensity_table.set_value(ColorIntensityTable.ObjectNames.TRACES.ordinal(), p_value); - } - - public void set_via_color_intensity(double p_value) - { - color_intensity_table.set_value(ColorIntensityTable.ObjectNames.VIAS.ordinal(), p_value); - } - - public void set_pin_color_intensity(double p_value) - { - color_intensity_table.set_value(ColorIntensityTable.ObjectNames.PINS.ordinal(), p_value); - } - - public void set_conduction_color_intensity(double p_value) - { - color_intensity_table.set_value(ColorIntensityTable.ObjectNames.CONDUCTION_AREAS.ordinal(), p_value); - } - - public void set_obstacle_color_intensity(double p_value) - { - color_intensity_table.set_value(ColorIntensityTable.ObjectNames.KEEPOUTS.ordinal(), p_value); - } - - public void set_via_obstacle_color_intensity(double p_value) - { - color_intensity_table.set_value(ColorIntensityTable.ObjectNames.VIA_KEEPOUTS.ordinal(), p_value); - } - - public void set_hilight_color_intensity(double p_value) - { - color_intensity_table.set_value(ColorIntensityTable.ObjectNames.HILIGHT.ordinal(), p_value); - } - - public void set_incomplete_color_intensity(double p_value) - { - color_intensity_table.set_value(ColorIntensityTable.ObjectNames.INCOMPLETES.ordinal(), p_value); - } - - public void set_length_matching_area_color_intensity(double p_value) - { - color_intensity_table.set_value(ColorIntensityTable.ObjectNames.LENGTH_MATCHING_AREAS.ordinal(), p_value); - } - - public java.awt.Dimension get_panel_size() - { - return coordinate_transform.screen_bounds; - } - - /** - * Returns the center of the design on the screen. - */ - public Point2D get_design_center() - { - FloatPoint center = coordinate_transform.design_box_with_offset.centre_of_gravity(); - return coordinate_transform.board_to_screen(center); - } - - /** - * Returns the bounding box of the design in screen coordinates. - */ - public java.awt.Rectangle get_design_bounds() - { - return coordinate_transform.board_to_screen(coordinate_transform.design_box); - } - - /** - * Sets the factor for automatic layer dimming. - * Values are between 0 and 1. If 1, there is no automatic layer dimming. - */ - public void set_auto_layer_dim_factor(double p_value) - { - auto_layer_dim_factor = p_value; - } - - /** gets the factor for automatic layer dimming */ - public double get_auto_layer_dim_factor() - { - return this.auto_layer_dim_factor; - } - - /** Sets the layer, which will be excluded from automatic layer dimming. */ - public void set_fully_visible_layer(int p_layer_no) - { - fully_visible_layer = p_layer_no; - } - - /** - * Gets the visibility factor of the input layer. - * The result is between 0 and 1. - * If the result is 0, the layer is invisible, - * if the result is 1, the layer is fully visible. - */ - public double get_layer_visibility(int p_layer_no) - { - double result; - if (p_layer_no == this.fully_visible_layer) - { - result = layer_visibility_arr[p_layer_no]; - } - else - { - result = this.auto_layer_dim_factor * layer_visibility_arr[p_layer_no]; - } - return result; - } - - /** - * Gets the visibility factor of the input layer without the aoutomatic layer dimming. - */ - public double get_raw_layer_visibility(int p_layer_no) - { - return layer_visibility_arr[p_layer_no]; - } - - /** - * Gets the visibility factor of the input layer. - * The value is expected between 0 and 1. - * If the value is 0, the layer is invisible, - * if the value is 1, the layer is fully visible. - * - */ - public void set_layer_visibility(int p_layer_no, double p_value) - { - layer_visibility_arr[p_layer_no] = Math.max(0, Math.min(p_value, 1)); - } - - public void set_layer_visibility_arr(double [] p_layer_visibility_arr) - { - this.layer_visibility_arr = p_layer_visibility_arr; - } - - - public double[] copy_layer_visibility_arr() - { - double[] result = new double [this.layer_visibility_arr.length]; - System.arraycopy(this.layer_visibility_arr, 0, result, 0, this.layer_visibility_arr.length); - return result; - } - - /** Returns the number of layers on the board */ - public int layer_count() - { - return layer_visibility_arr.length; - } - - /** - * filter lines, which cannot touch the update_box to improve the - * performance of the draw function by avoiding unnessesary calls - * of draw (line) - */ - private boolean line_outside_update_box(FloatPoint p_1, - FloatPoint p_2, double p_update_offset, IntBox p_update_box) - { - if (p_1 == null || p_2 == null) - { - return true; - } - if (Math.max(p_1.x, p_2.x) < p_update_box.ll.x - p_update_offset) - { - return true; - } - if (Math.max(p_1.y, p_2.y) < p_update_box.ll.y - p_update_offset ) - { - return true; - } - if (Math.min(p_1.x, p_2.x) > p_update_box.ur.x + p_update_offset) - { - return true; - } - if (Math.min(p_1.y, p_2.y) > p_update_box.ur.y + p_update_offset) - { - return true; - } - return false; - } - - /** - * initialise some values in p_graphics - */ - private static void init_draw_graphics(Graphics2D p_graphics, Color p_color, float p_width) - { - BasicStroke bs = new BasicStroke(Math.max(p_width, 0), BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND); - p_graphics.setStroke(bs); - p_graphics.setColor(p_color); - p_graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - } - - private static void set_translucency(Graphics2D p_g2, double p_factor) - { - AlphaComposite curr_alpha_composite; - if (p_factor >= 0) - { - curr_alpha_composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) p_factor); - } - else - { - curr_alpha_composite = AlphaComposite.getInstance(AlphaComposite.DST_OVER, (float) -p_factor); - } - p_g2.setComposite(curr_alpha_composite); - } - - /** - * Writes an instance of this class to a file. - */ - private void writeObject(java.io.ObjectOutputStream p_stream) - throws java.io.IOException - { - p_stream.defaultWriteObject(); - item_color_table.write_object(p_stream); - other_color_table.write_object(p_stream); - } - - /** Reads an instance of this class from a file */ - private void readObject(java.io.ObjectInputStream p_stream) - throws java.io.IOException, java.lang.ClassNotFoundException - { - p_stream.defaultReadObject(); - this.item_color_table = new ItemColorTableModel(p_stream); - this.other_color_table = new OtherColorTableModel(p_stream); - } - - public transient ItemColorTableModel item_color_table; - public transient OtherColorTableModel other_color_table; - public ColorIntensityTable color_intensity_table; - - - public CoordinateTransform coordinate_transform = null; - - /** layer_visibility_arr[i] is between 0 and 1, for each layer i, 0 is invisible and 1 fully visible. */ - private double [] layer_visibility_arr; - - - /** - * The factor for autoomatic layer dimming of layers different from the current layer. - * Values are between 0 and 1. If 1, there is no automatic layer dimming. - */ - private double auto_layer_dim_factor = 0.7; - - /** The layer, which is not automatically dimmed. */ - private int fully_visible_layer = 0; - - private static final int update_offset = 10000; - - private static final boolean show_line_segments = false; - private static final boolean show_area_division = false; - -} \ No newline at end of file +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + */ + +package boardgraphics; + +import geometry.planar.Area; +import geometry.planar.Circle; +import geometry.planar.Ellipse; +import geometry.planar.FloatPoint; +import geometry.planar.IntBox; +import geometry.planar.PolylineShape; +import geometry.planar.Shape; +import geometry.planar.TileShape; + +import java.awt.AlphaComposite; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.geom.Ellipse2D; +import java.awt.geom.GeneralPath; +import java.awt.geom.Line2D; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.geom.AffineTransform; + + +/** + * Context for drawing items in the board package to the screen. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class GraphicsContext implements java.io.Serializable +{ + /** + *

Constructor for GraphicsContext.

+ * + * @param p_design_bounds a {@link geometry.planar.IntBox} object. + * @param p_panel_bounds a {@link java.awt.Dimension} object. + * @param p_layer_structure a {@link board.LayerStructure} object. + * @param p_locale a {@link java.util.Locale} object. + */ + public GraphicsContext( IntBox p_design_bounds, + Dimension p_panel_bounds, board.LayerStructure p_layer_structure, java.util.Locale p_locale) + { + coordinate_transform = new CoordinateTransform(p_design_bounds, p_panel_bounds); + item_color_table = new ItemColorTableModel(p_layer_structure, p_locale); + other_color_table = new OtherColorTableModel(p_locale); + color_intensity_table = new ColorIntensityTable(); + layer_visibility_arr = new double [p_layer_structure.arr.length]; + for (int i = 0; i < layer_visibility_arr.length; ++i) + { + if (p_layer_structure.arr[i].is_signal) + { + layer_visibility_arr [i] = 1; + } + else + { + layer_visibility_arr [i] = 0; + } + } + } + + /** + * Copy constructor + * + * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object. + */ + public GraphicsContext(GraphicsContext p_graphics_context) + { + this.coordinate_transform = new CoordinateTransform(p_graphics_context.coordinate_transform); + this.item_color_table = new ItemColorTableModel(p_graphics_context.item_color_table); + this.other_color_table = new OtherColorTableModel(p_graphics_context.other_color_table); + this.color_intensity_table = new ColorIntensityTable(p_graphics_context.color_intensity_table); + this.layer_visibility_arr = p_graphics_context.copy_layer_visibility_arr(); + } + + /** + * Changes the bounds of the board design to p_design_bounds. + * Useful when components are still placed outside the boaed. + * + * @param p_new_design_bounds a {@link geometry.planar.IntBox} object. + */ + public void change_design_bounds(IntBox p_new_design_bounds) + { + if (p_new_design_bounds.equals(this.coordinate_transform.design_box)) + { + return; + } + Dimension screen_bounds = this.coordinate_transform.screen_bounds; + this.coordinate_transform = new CoordinateTransform(p_new_design_bounds, screen_bounds); + } + + /** + * changes the size of the panel to p_new_bounds + * + * @param p_new_bounds a {@link java.awt.Dimension} object. + */ + public void change_panel_size(Dimension p_new_bounds) + { + if (coordinate_transform == null) + { + return; + } + IntBox design_box = coordinate_transform.design_box; + boolean left_right_swapped = coordinate_transform.is_mirror_left_right(); + boolean top_bottom_swapped = coordinate_transform.is_mirror_top_bottom(); + double rotation = coordinate_transform.get_rotation(); + coordinate_transform = new CoordinateTransform(design_box, p_new_bounds); + coordinate_transform.set_mirror_left_right(left_right_swapped); + coordinate_transform.set_mirror_top_bottom(top_bottom_swapped); + coordinate_transform.set_rotation(rotation); + } + + /** + * draws a polygon with corners p_points + * + * @param p_points an array of {@link geometry.planar.FloatPoint} objects. + * @param p_half_width a double. + * @param p_color a {@link java.awt.Color} object. + * @param p_g a {@link java.awt.Graphics} object. + * @param p_translucency_factor a double. + */ + public void draw(FloatPoint[] p_points, double p_half_width, Color p_color, Graphics p_g, double p_translucency_factor) + { + if (p_color == null) + { + return; + } + Graphics2D g2 = (Graphics2D)p_g; + Rectangle clip_shape = (Rectangle)p_g.getClip() ; + // the class member update_box cannot be used here, because + // the dirty rectangle is internally enlarged by the system. + // Therefore we can not improve the performance by using an + // update octagon instead of a box. + IntBox clip_box = coordinate_transform.screen_to_board(clip_shape); + double scaled_width = coordinate_transform.board_to_screen(p_half_width); + + init_draw_graphics(g2, p_color, (float)scaled_width*2); + set_translucency(g2, p_translucency_factor); + + GeneralPath draw_path = null; + if (!show_line_segments) + { + draw_path = new GeneralPath(); + } + + for(int i= 0; i<(p_points.length-1); i++) + { + if (line_outside_update_box(p_points[i], p_points[i + 1], + p_half_width + update_offset, clip_box)) + { + // this check should be unnessersary here, + // the system should do it in the draw(line) function + continue; + } + Point2D p1 = coordinate_transform.board_to_screen(p_points[i]) ; + Point2D p2 = coordinate_transform.board_to_screen(p_points[i+1]) ; + Line2D line = new Line2D.Double(p1, p2) ; + + if (show_line_segments) + { + g2.draw(line); + } + else + { + draw_path.append(line, false); + } + } + if (!show_line_segments) + { + g2.draw(draw_path); + } + } + + /* + * draws the boundary of a circle + */ + /** + *

draw_circle.

+ * + * @param p_center a {@link geometry.planar.FloatPoint} object. + * @param p_radius a double. + * @param p_draw_half_width a double. + * @param p_color a {@link java.awt.Color} object. + * @param p_g a {@link java.awt.Graphics} object. + * @param p_translucency_factor a double. + */ + public void draw_circle(FloatPoint p_center, double p_radius, double p_draw_half_width, + Color p_color, Graphics p_g, double p_translucency_factor) + { + if (p_color == null) + { + return; + } + Graphics2D g2 = (Graphics2D)p_g; + Point2D center = coordinate_transform.board_to_screen(p_center); + + double radius = coordinate_transform.board_to_screen(p_radius); + double diameter = 2 * radius; + float draw_width = (float)(2 * coordinate_transform.board_to_screen(p_draw_half_width)); + Ellipse2D circle = + new Ellipse2D.Double(center.getX() - radius,center.getY() - radius, diameter, diameter); + set_translucency(g2, p_translucency_factor); + init_draw_graphics(g2, p_color, draw_width); + g2.draw(circle); + } + + /* + * draws a rectangle + */ + /** + *

draw_rectangle.

+ * + * @param p_corner1 a {@link geometry.planar.FloatPoint} object. + * @param p_corner2 a {@link geometry.planar.FloatPoint} object. + * @param p_draw_half_width a double. + * @param p_color a {@link java.awt.Color} object. + * @param p_g a {@link java.awt.Graphics} object. + * @param p_translucency_factor a double. + */ + public void draw_rectangle(FloatPoint p_corner1, FloatPoint p_corner2, + double p_draw_half_width, Color p_color, Graphics p_g, double p_translucency_factor) + { + if (p_color == null) + { + return; + } + Graphics2D g2 = (Graphics2D)p_g ; + Point2D corner1 = coordinate_transform.board_to_screen(p_corner1) ; + Point2D corner2 = coordinate_transform.board_to_screen(p_corner2) ; + + double xmin = Math.min(corner1.getX(), corner2.getX()) ; + double ymin = Math.min(corner1.getY(), corner2.getY()) ; + + float draw_width = (float)(2 * coordinate_transform.board_to_screen(p_draw_half_width)) ; + double width = Math.abs(corner2.getX() - corner1.getX()) ; + double height = Math.abs(corner2.getY() - corner1.getY()) ; + Rectangle2D rectangle = new Rectangle2D.Double(xmin, ymin, width, height) ; + set_translucency(g2, p_translucency_factor); + init_draw_graphics(g2, p_color, draw_width) ; + g2.draw(rectangle) ; + } + + /** + * Draws the boundary of p_shape. + * + * @param p_shape a {@link geometry.planar.Shape} object. + * @param p_draw_half_width a double. + * @param p_color a {@link java.awt.Color} object. + * @param p_g a {@link java.awt.Graphics} object. + * @param p_translucency_factor a double. + */ + public void draw_boundary(Shape p_shape, double p_draw_half_width, Color p_color, Graphics p_g, double p_translucency_factor) + { + if (p_shape instanceof PolylineShape) + { + FloatPoint[] draw_corners = p_shape.corner_approx_arr(); + if (draw_corners.length <= 1) + { + return; + } + FloatPoint[] closed_draw_corners = new FloatPoint[draw_corners.length + 1]; + System.arraycopy(draw_corners, 0, closed_draw_corners, 0, draw_corners.length); + closed_draw_corners[closed_draw_corners.length - 1] = draw_corners [0]; + this.draw( closed_draw_corners, p_draw_half_width, p_color, p_g, p_translucency_factor); + } + else if (p_shape instanceof Circle) + { + Circle curr_circle = (Circle) p_shape; + this.draw_circle(curr_circle.center.to_float(), curr_circle.radius, p_draw_half_width, + p_color, p_g, p_translucency_factor); + } + } + + /** + * Draws the boundary of p_area. + * + * @param p_area a {@link geometry.planar.Area} object. + * @param p_draw_half_width a double. + * @param p_color a {@link java.awt.Color} object. + * @param p_g a {@link java.awt.Graphics} object. + * @param p_translucency_factor a double. + */ + public void draw_boundary(Area p_area, double p_draw_half_width, Color p_color, Graphics p_g, double p_translucency_factor) + { + draw_boundary(p_area.get_border(), p_draw_half_width, p_color, p_g, p_translucency_factor); + Shape[] holes = p_area.get_holes(); + for (int i = 0; i < holes.length; ++i) + { + draw_boundary(holes[i], p_draw_half_width, p_color, p_g, p_translucency_factor); + } + } + + /** + * Draws the interiour of a circle + * + * @param p_circle a {@link geometry.planar.Circle} object. + * @param p_g a {@link java.awt.Graphics} object. + * @param p_color a {@link java.awt.Color} object. + * @param p_translucency_factor a double. + */ + public void fill_circle(Circle p_circle, Graphics p_g, Color p_color, double p_translucency_factor) + { + if (p_color == null) + { + return; + } + Point2D center = coordinate_transform.board_to_screen(p_circle.center.to_float()); + double radius = coordinate_transform.board_to_screen(p_circle.radius); + if (!point_near_rectangle(center.getX(), center.getY(), (Rectangle)p_g.getClip(), radius)) + { + return; + } + double diameter = 2 * radius; + Ellipse2D circle = + new Ellipse2D.Double(center.getX() - radius,center.getY() - radius, diameter, diameter); + Graphics2D g2 = (Graphics2D)p_g; + g2.setColor(p_color); + set_translucency(g2, p_translucency_factor); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2.fill(circle); + } + + /** + * Draws the interiour of an ellipse. + * + * @param p_ellipse a {@link geometry.planar.Ellipse} object. + * @param p_g a {@link java.awt.Graphics} object. + * @param p_color a {@link java.awt.Color} object. + * @param p_translucency_factor a double. + */ + public void fill_ellipse(Ellipse p_ellipse, Graphics p_g, Color p_color, double p_translucency_factor) + { + Ellipse [] ellipse_arr = new Ellipse[1]; + ellipse_arr[0] = p_ellipse; + fill_ellipse_arr(ellipse_arr, p_g, p_color, p_translucency_factor); + } + + + /** + * Draws the interiour of an array of ellipses. + * Ellipses contained in an other ellipse are treated as holes. + * + * @param p_ellipse_arr an array of {@link geometry.planar.Ellipse} objects. + * @param p_g a {@link java.awt.Graphics} object. + * @param p_color a {@link java.awt.Color} object. + * @param p_translucency_factor a double. + */ + public void fill_ellipse_arr(Ellipse [] p_ellipse_arr, Graphics p_g, Color p_color, double p_translucency_factor) + { + if (p_color == null || p_ellipse_arr.length <= 0) + { + return; + } + GeneralPath draw_path = new GeneralPath(GeneralPath.WIND_EVEN_ODD); + for (Ellipse curr_ellipse : p_ellipse_arr) + { + Point2D center = coordinate_transform.board_to_screen(curr_ellipse.center); + double bigger_radius = coordinate_transform.board_to_screen(curr_ellipse.bigger_radius); + if (!point_near_rectangle(center.getX(), center.getY(), (Rectangle)p_g.getClip(), bigger_radius)) + { + continue; + } + double smaller_radius = coordinate_transform.board_to_screen(curr_ellipse.smaller_radius); + Ellipse2D draw_ellipse = + new Ellipse2D.Double(center.getX() - bigger_radius,center.getY() - smaller_radius, + 2 * bigger_radius, 2 * smaller_radius); + double rotation = coordinate_transform.board_to_screen_angle(curr_ellipse.rotation); + AffineTransform affine_transform = new AffineTransform(); + affine_transform.rotate(rotation, center.getX(), center.getY()); + java.awt.Shape rotated_ellipse = affine_transform.createTransformedShape(draw_ellipse); + draw_path.append(rotated_ellipse, false); + } + Graphics2D g2 = (Graphics2D)p_g; + g2.setColor(p_color); + set_translucency(g2, p_translucency_factor); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2.fill(draw_path); + } + + /** + * Checks, if the distance of the point with coordinates p_x, p_y to p_rect ist at most p_dist. + */ + private boolean point_near_rectangle(double p_x, double p_y, Rectangle p_rect, double p_dist) + { + if (p_x < p_rect.x - p_dist) + { + return false; + } + if (p_y < p_rect.y - p_dist) + { + return false; + } + if (p_x > p_rect.x + p_rect.width + p_dist) + { + return false; + } + if (p_y > p_rect.y + p_rect.height + p_dist) + { + return false; + } + return true; + } + + /** + * Fill the interior of the polygon shape represented by p_points. + * + * @param p_points an array of {@link geometry.planar.FloatPoint} objects. + * @param p_g a {@link java.awt.Graphics} object. + * @param p_color a {@link java.awt.Color} object. + * @param p_translucency_factor a double. + */ + public void fill_shape(FloatPoint[] p_points, Graphics p_g, Color p_color, double p_translucency_factor) + { + if (p_color == null) + { + return; + } + Graphics2D g2 = (Graphics2D)p_g; + Polygon draw_polygon = new Polygon(); + for(int i= 0; i < p_points.length; i++) + { + Point2D curr_corner = coordinate_transform.board_to_screen(p_points[i]); + draw_polygon.addPoint((int)Math.round(curr_corner.getX()), + (int)Math.round(curr_corner.getY())); + } + g2.setColor(p_color); + set_translucency(g2, p_translucency_factor); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2.fill(draw_polygon); + } + + /** + * Fill the interiour of a list of polygons. + * Used for example with an area consisting of a border polygon and some holes. + * + * @param p_point_lists an array of {@link geometry.planar.FloatPoint} objects. + * @param p_g a {@link java.awt.Graphics} object. + * @param p_color a {@link java.awt.Color} object. + * @param p_translucency_factor a double. + */ + public void fill_area(FloatPoint[][] p_point_lists, Graphics p_g, Color p_color, double p_translucency_factor) + { + if (p_color == null) + { + return; + } + GeneralPath draw_path = new GeneralPath(GeneralPath.WIND_EVEN_ODD); + for (int j = 0; j < p_point_lists.length; ++j) + { + Polygon draw_polygon = new Polygon(); + FloatPoint[] curr_point_list = p_point_lists[j]; + for(int i= 0; i < curr_point_list.length; i++) + { + Point2D curr_corner = coordinate_transform.board_to_screen(curr_point_list[i]); + draw_polygon.addPoint((int)Math.round(curr_corner.getX()), + (int)Math.round(curr_corner.getY())); + } + draw_path.append(draw_polygon, false); + } + Graphics2D g2 = (Graphics2D)p_g; + g2.setColor(p_color); + set_translucency(g2, p_translucency_factor); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2.fill(draw_path); + } + + /** + * draws the interiour of an item of class geometry.planar.Area + * + * @param p_area a {@link geometry.planar.Area} object. + * @param p_g a {@link java.awt.Graphics} object. + * @param p_color a {@link java.awt.Color} object. + * @param p_translucency_factor a double. + */ + public void fill_area(Area p_area, Graphics p_g, Color p_color, double p_translucency_factor) + { + if (p_color == null || p_area.is_empty()) + { + return; + } + if (p_area instanceof Circle) + { + fill_circle((Circle) p_area, p_g, p_color, p_translucency_factor); + } + else + { + PolylineShape border = (PolylineShape) p_area.get_border(); + if (!border.is_bounded()) + { + System.out.println("GraphicsContext.fill_area: shape not bounded"); + return; + } + Rectangle clip_shape = (Rectangle)p_g.getClip() ; + IntBox clip_box = coordinate_transform.screen_to_board(clip_shape); + if (!border.bounding_box().intersects(clip_box)) + { + return; + } + Shape [] holes = p_area.get_holes(); + + FloatPoint[] [] draw_polygons = new FloatPoint [holes.length + 1][]; + for (int j = 0; j < draw_polygons.length; ++j) + { + PolylineShape curr_draw_shape; + if (j == 0) + { + curr_draw_shape = border; + } + else + { + curr_draw_shape = (PolylineShape) holes[j - 1]; + } + draw_polygons[j] = new FloatPoint [curr_draw_shape.border_line_count() + 1]; + FloatPoint curr_draw_polygon[] = draw_polygons[j]; + for (int i = 0; i < curr_draw_polygon.length - 1; ++i) + { + curr_draw_polygon[i] = curr_draw_shape.corner_approx(i); + } + // close the polygon + curr_draw_polygon[curr_draw_polygon.length - 1] = curr_draw_polygon[0]; + } + fill_area(draw_polygons, p_g, p_color, p_translucency_factor) ; + } + if (show_area_division) + { + TileShape[] tiles = p_area.split_to_convex(); + for (int i = 0; i < tiles.length; ++i) + { + FloatPoint[] corners = new FloatPoint [tiles[i].border_line_count() + 1]; + TileShape curr_tile = tiles[i]; + for (int j = 0; j < corners.length - 1; ++j) + { + corners[j]= curr_tile.corner_approx(j); + } + corners[corners.length - 1] = corners[0]; + draw(corners, 1, java.awt.Color.white, p_g, 0.7); + } + } + } + + /** + *

get_background_color.

+ * + * @return a {@link java.awt.Color} object. + */ + public Color get_background_color() + { + return other_color_table.get_background_color(); + } + + /** + *

get_hilight_color.

+ * + * @return a {@link java.awt.Color} object. + */ + public Color get_hilight_color() + { + return other_color_table.get_hilight_color(); + } + + /** + *

get_incomplete_color.

+ * + * @return a {@link java.awt.Color} object. + */ + public Color get_incomplete_color() + { + return other_color_table.get_incomplete_color(); + } + + /** + *

get_outline_color.

+ * + * @return a {@link java.awt.Color} object. + */ + public Color get_outline_color() + { + return other_color_table.get_outline_color(); + } + + /** + *

get_component_color.

+ * + * @param p_front a boolean. + * @return a {@link java.awt.Color} object. + */ + public Color get_component_color(boolean p_front) + { + return other_color_table.get_component_color(p_front); + } + + /** + *

get_violations_color.

+ * + * @return a {@link java.awt.Color} object. + */ + public Color get_violations_color() + { + return other_color_table.get_violations_color(); + } + + /** + *

get_length_matching_area_color.

+ * + * @return a {@link java.awt.Color} object. + */ + public Color get_length_matching_area_color() + { + return other_color_table.get_length_matching_area_color(); + } + + /** + *

get_trace_colors.

+ * + * @param p_fixed a boolean. + * @return an array of {@link java.awt.Color} objects. + */ + public Color[] get_trace_colors(boolean p_fixed) + { + + return item_color_table.get_trace_colors(p_fixed); + } + + /** + *

get_via_colors.

+ * + * @param p_fixed a boolean. + * @return an array of {@link java.awt.Color} objects. + */ + public Color[] get_via_colors(boolean p_fixed) + { + return item_color_table.get_via_colors(p_fixed); + } + + /** + *

get_pin_colors.

+ * + * @return an array of {@link java.awt.Color} objects. + */ + public Color[] get_pin_colors() + { + return item_color_table.get_pin_colors(); + } + + /** + *

get_conduction_colors.

+ * + * @return an array of {@link java.awt.Color} objects. + */ + public Color[] get_conduction_colors() + { + return item_color_table.get_conduction_colors(); + } + + /** + *

get_obstacle_colors.

+ * + * @return an array of {@link java.awt.Color} objects. + */ + public Color[] get_obstacle_colors() + { + return item_color_table.get_obstacle_colors(); + } + + /** + *

get_via_obstacle_colors.

+ * + * @return an array of {@link java.awt.Color} objects. + */ + public Color[] get_via_obstacle_colors() + { + return item_color_table.get_via_obstacle_colors(); + } + + /** + *

get_place_obstacle_colors.

+ * + * @return an array of {@link java.awt.Color} objects. + */ + public Color[] get_place_obstacle_colors() + { + return item_color_table.get_place_obstacle_colors(); + } + + /** + *

get_trace_color_intensity.

+ * + * @return a double. + */ + public double get_trace_color_intensity() + { + return color_intensity_table.get_value(ColorIntensityTable.ObjectNames.TRACES.ordinal()); + } + + /** + *

get_via_color_intensity.

+ * + * @return a double. + */ + public double get_via_color_intensity() + { + return color_intensity_table.get_value(ColorIntensityTable.ObjectNames.VIAS.ordinal()); + } + + /** + *

get_pin_color_intensity.

+ * + * @return a double. + */ + public double get_pin_color_intensity() + { + return color_intensity_table.get_value(ColorIntensityTable.ObjectNames.PINS.ordinal()); + } + + /** + *

get_conduction_color_intensity.

+ * + * @return a double. + */ + public double get_conduction_color_intensity() + { + return color_intensity_table.get_value(ColorIntensityTable.ObjectNames.CONDUCTION_AREAS.ordinal()); + } + + /** + *

get_obstacle_color_intensity.

+ * + * @return a double. + */ + public double get_obstacle_color_intensity() + { + return color_intensity_table.get_value(ColorIntensityTable.ObjectNames.KEEPOUTS.ordinal()); + } + + /** + *

get_via_obstacle_color_intensity.

+ * + * @return a double. + */ + public double get_via_obstacle_color_intensity() + { + return color_intensity_table.get_value(ColorIntensityTable.ObjectNames.VIA_KEEPOUTS.ordinal()); + } + + /** + *

get_place_obstacle_color_intensity.

+ * + * @return a double. + */ + public double get_place_obstacle_color_intensity() + { + return color_intensity_table.get_value(ColorIntensityTable.ObjectNames.PLACE_KEEPOUTS.ordinal()); + } + + /** + *

get_component_outline_color_intensity.

+ * + * @return a double. + */ + public double get_component_outline_color_intensity() + { + return color_intensity_table.get_value(ColorIntensityTable.ObjectNames.COMPONENT_OUTLINES.ordinal()); + } + + /** + *

get_hilight_color_intensity.

+ * + * @return a double. + */ + public double get_hilight_color_intensity() + { + return color_intensity_table.get_value(ColorIntensityTable.ObjectNames.HILIGHT.ordinal()); + } + + /** + *

get_incomplete_color_intensity.

+ * + * @return a double. + */ + public double get_incomplete_color_intensity() + { + return color_intensity_table.get_value(ColorIntensityTable.ObjectNames.INCOMPLETES.ordinal()); + } + + /** + *

get_length_matching_area_color_intensity.

+ * + * @return a double. + */ + public double get_length_matching_area_color_intensity() + { + return color_intensity_table.get_value(ColorIntensityTable.ObjectNames.LENGTH_MATCHING_AREAS.ordinal()); + } + + /** + *

set_trace_color_intensity.

+ * + * @param p_value a double. + */ + public void set_trace_color_intensity(double p_value) + { + color_intensity_table.set_value(ColorIntensityTable.ObjectNames.TRACES.ordinal(), p_value); + } + + /** + *

set_via_color_intensity.

+ * + * @param p_value a double. + */ + public void set_via_color_intensity(double p_value) + { + color_intensity_table.set_value(ColorIntensityTable.ObjectNames.VIAS.ordinal(), p_value); + } + + /** + *

set_pin_color_intensity.

+ * + * @param p_value a double. + */ + public void set_pin_color_intensity(double p_value) + { + color_intensity_table.set_value(ColorIntensityTable.ObjectNames.PINS.ordinal(), p_value); + } + + /** + *

set_conduction_color_intensity.

+ * + * @param p_value a double. + */ + public void set_conduction_color_intensity(double p_value) + { + color_intensity_table.set_value(ColorIntensityTable.ObjectNames.CONDUCTION_AREAS.ordinal(), p_value); + } + + /** + *

set_obstacle_color_intensity.

+ * + * @param p_value a double. + */ + public void set_obstacle_color_intensity(double p_value) + { + color_intensity_table.set_value(ColorIntensityTable.ObjectNames.KEEPOUTS.ordinal(), p_value); + } + + /** + *

set_via_obstacle_color_intensity.

+ * + * @param p_value a double. + */ + public void set_via_obstacle_color_intensity(double p_value) + { + color_intensity_table.set_value(ColorIntensityTable.ObjectNames.VIA_KEEPOUTS.ordinal(), p_value); + } + + /** + *

set_hilight_color_intensity.

+ * + * @param p_value a double. + */ + public void set_hilight_color_intensity(double p_value) + { + color_intensity_table.set_value(ColorIntensityTable.ObjectNames.HILIGHT.ordinal(), p_value); + } + + /** + *

set_incomplete_color_intensity.

+ * + * @param p_value a double. + */ + public void set_incomplete_color_intensity(double p_value) + { + color_intensity_table.set_value(ColorIntensityTable.ObjectNames.INCOMPLETES.ordinal(), p_value); + } + + /** + *

set_length_matching_area_color_intensity.

+ * + * @param p_value a double. + */ + public void set_length_matching_area_color_intensity(double p_value) + { + color_intensity_table.set_value(ColorIntensityTable.ObjectNames.LENGTH_MATCHING_AREAS.ordinal(), p_value); + } + + /** + *

get_panel_size.

+ * + * @return a java$awt$Dimension object. + */ + public java.awt.Dimension get_panel_size() + { + return coordinate_transform.screen_bounds; + } + + /** + * Returns the center of the design on the screen. + * + * @return a java$awt$geom$Point2D object. + */ + public Point2D get_design_center() + { + FloatPoint center = coordinate_transform.design_box_with_offset.centre_of_gravity(); + return coordinate_transform.board_to_screen(center); + } + + /** + * Returns the bounding box of the design in screen coordinates. + * + * @return a java$awt$Rectangle object. + */ + public java.awt.Rectangle get_design_bounds() + { + return coordinate_transform.board_to_screen(coordinate_transform.design_box); + } + + /** + * Sets the factor for automatic layer dimming. + * Values are between 0 and 1. If 1, there is no automatic layer dimming. + * + * @param p_value a double. + */ + public void set_auto_layer_dim_factor(double p_value) + { + auto_layer_dim_factor = p_value; + } + + /** + * gets the factor for automatic layer dimming + * + * @return a double. + */ + public double get_auto_layer_dim_factor() + { + return this.auto_layer_dim_factor; + } + + /** + * Sets the layer, which will be excluded from automatic layer dimming. + * + * @param p_layer_no a int. + */ + public void set_fully_visible_layer(int p_layer_no) + { + fully_visible_layer = p_layer_no; + } + + /** + * Gets the visibility factor of the input layer. + * The result is between 0 and 1. + * If the result is 0, the layer is invisible, + * if the result is 1, the layer is fully visible. + * + * @param p_layer_no a int. + * @return a double. + */ + public double get_layer_visibility(int p_layer_no) + { + double result; + if (p_layer_no == this.fully_visible_layer) + { + result = layer_visibility_arr[p_layer_no]; + } + else + { + result = this.auto_layer_dim_factor * layer_visibility_arr[p_layer_no]; + } + return result; + } + + /** + * Gets the visibility factor of the input layer without the aoutomatic layer dimming. + * + * @param p_layer_no a int. + * @return a double. + */ + public double get_raw_layer_visibility(int p_layer_no) + { + return layer_visibility_arr[p_layer_no]; + } + + /** + * Gets the visibility factor of the input layer. + * The value is expected between 0 and 1. + * If the value is 0, the layer is invisible, + * if the value is 1, the layer is fully visible. + * + * @param p_layer_no a int. + * @param p_value a double. + */ + public void set_layer_visibility(int p_layer_no, double p_value) + { + layer_visibility_arr[p_layer_no] = Math.max(0, Math.min(p_value, 1)); + } + + /** + *

set_layer_visibility_arr.

+ * + * @param p_layer_visibility_arr an array of double. + */ + public void set_layer_visibility_arr(double [] p_layer_visibility_arr) + { + this.layer_visibility_arr = p_layer_visibility_arr; + } + + + /** + *

copy_layer_visibility_arr.

+ * + * @return an array of double. + */ + public double[] copy_layer_visibility_arr() + { + double[] result = new double [this.layer_visibility_arr.length]; + System.arraycopy(this.layer_visibility_arr, 0, result, 0, this.layer_visibility_arr.length); + return result; + } + + /** + * Returns the number of layers on the board + * + * @return a int. + */ + public int layer_count() + { + return layer_visibility_arr.length; + } + + /** + * filter lines, which cannot touch the update_box to improve the + * performance of the draw function by avoiding unnessesary calls + * of draw (line) + */ + private boolean line_outside_update_box(FloatPoint p_1, + FloatPoint p_2, double p_update_offset, IntBox p_update_box) + { + if (p_1 == null || p_2 == null) + { + return true; + } + if (Math.max(p_1.x, p_2.x) < p_update_box.ll.x - p_update_offset) + { + return true; + } + if (Math.max(p_1.y, p_2.y) < p_update_box.ll.y - p_update_offset ) + { + return true; + } + if (Math.min(p_1.x, p_2.x) > p_update_box.ur.x + p_update_offset) + { + return true; + } + if (Math.min(p_1.y, p_2.y) > p_update_box.ur.y + p_update_offset) + { + return true; + } + return false; + } + + /** + * initialise some values in p_graphics + */ + private static void init_draw_graphics(Graphics2D p_graphics, Color p_color, float p_width) + { + BasicStroke bs = new BasicStroke(Math.max(p_width, 0), BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND); + p_graphics.setStroke(bs); + p_graphics.setColor(p_color); + p_graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + } + + private static void set_translucency(Graphics2D p_g2, double p_factor) + { + AlphaComposite curr_alpha_composite; + if (p_factor >= 0) + { + curr_alpha_composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) p_factor); + } + else + { + curr_alpha_composite = AlphaComposite.getInstance(AlphaComposite.DST_OVER, (float) -p_factor); + } + p_g2.setComposite(curr_alpha_composite); + } + + /** + * Writes an instance of this class to a file. + */ + private void writeObject(java.io.ObjectOutputStream p_stream) + throws java.io.IOException + { + p_stream.defaultWriteObject(); + item_color_table.write_object(p_stream); + other_color_table.write_object(p_stream); + } + + /** Reads an instance of this class from a file */ + private void readObject(java.io.ObjectInputStream p_stream) + throws java.io.IOException, java.lang.ClassNotFoundException + { + p_stream.defaultReadObject(); + this.item_color_table = new ItemColorTableModel(p_stream); + this.other_color_table = new OtherColorTableModel(p_stream); + } + + public transient ItemColorTableModel item_color_table; + public transient OtherColorTableModel other_color_table; + public ColorIntensityTable color_intensity_table; + + + public CoordinateTransform coordinate_transform = null; + + /** layer_visibility_arr[i] is between 0 and 1, for each layer i, 0 is invisible and 1 fully visible. */ + private double [] layer_visibility_arr; + + + /** + * The factor for autoomatic layer dimming of layers different from the current layer. + * Values are between 0 and 1. If 1, there is no automatic layer dimming. + */ + private double auto_layer_dim_factor = 0.7; + + /** The layer, which is not automatically dimmed. */ + private int fully_visible_layer = 0; + + private static final int update_offset = 10000; + + private static final boolean show_line_segments = false; + private static final boolean show_area_division = false; + +} diff --git a/boardgraphics/ItemColorTableModel.java b/src/main/java/boardgraphics/ItemColorTableModel.java similarity index 86% rename from boardgraphics/ItemColorTableModel.java rename to src/main/java/boardgraphics/ItemColorTableModel.java index 49110a6..b50f276 100644 --- a/boardgraphics/ItemColorTableModel.java +++ b/src/main/java/boardgraphics/ItemColorTableModel.java @@ -26,10 +26,17 @@ * Stores the layer dependent colors used for drawing for the items on the board. * * @author Alfons Wirtz + * @version $Id: $Id */ public class ItemColorTableModel extends ColorTableModel implements java.io.Serializable { + /** + *

Constructor for ItemColorTableModel.

+ * + * @param p_layer_structure a {@link board.LayerStructure} object. + * @param p_locale a {@link java.util.Locale} object. + */ public ItemColorTableModel(board.LayerStructure p_layer_structure, java.util.Locale p_locale) { super(p_layer_structure.arr.length, p_locale); @@ -111,6 +118,13 @@ else if (remainder % different_inner_colors == 5) } } + /** + *

Constructor for ItemColorTableModel.

+ * + * @param p_stream a {@link java.io.ObjectInputStream} object. + * @throws java.io.IOException if any. + * @throws java.lang.ClassNotFoundException if any. + */ public ItemColorTableModel(java.io.ObjectInputStream p_stream) throws java.io.IOException, java.lang.ClassNotFoundException { @@ -119,6 +133,8 @@ public ItemColorTableModel(java.io.ObjectInputStream p_stream) /** * Copy construcror. + * + * @param p_item_color_model a {@link boardgraphics.ItemColorTableModel} object. */ public ItemColorTableModel(ItemColorTableModel p_item_color_model) { @@ -130,16 +146,27 @@ public ItemColorTableModel(ItemColorTableModel p_item_color_model) } } + /** + *

getColumnCount.

+ * + * @return a int. + */ public int getColumnCount() { return ColumnNames.values().length; } + /** + *

getRowCount.

+ * + * @return a int. + */ public int getRowCount() { return data.length; } + /** {@inheritDoc} */ public String getColumnName(int p_col) { java.util.ResourceBundle resources = @@ -147,6 +174,7 @@ public String getColumnName(int p_col) return resources.getString(ColumnNames.values()[p_col].toString()); } + /** {@inheritDoc} */ public void setValueAt(Object p_value, int p_row, int p_col) { super.setValueAt(p_value, p_row, p_col); @@ -154,6 +182,8 @@ public void setValueAt(Object p_value, int p_row, int p_col) } /** + * {@inheritDoc} + * * Don't need to implement this method unless your table's * editable. */ @@ -246,6 +276,12 @@ Color[] get_place_obstacle_colors() } + /** + *

set_trace_colors.

+ * + * @param p_color_arr an array of {@link java.awt.Color} objects. + * @param p_fixed a boolean. + */ public void set_trace_colors(Color[] p_color_arr, boolean p_fixed) { if (p_fixed) @@ -258,6 +294,12 @@ public void set_trace_colors(Color[] p_color_arr, boolean p_fixed) } } + /** + *

set_via_colors.

+ * + * @param p_color_arr an array of {@link java.awt.Color} objects. + * @param p_fixed a boolean. + */ public void set_via_colors(Color[] p_color_arr, boolean p_fixed) { if (p_fixed) @@ -270,26 +312,51 @@ public void set_via_colors(Color[] p_color_arr, boolean p_fixed) } } + /** + *

set_pin_colors.

+ * + * @param p_color_arr an array of {@link java.awt.Color} objects. + */ public void set_pin_colors(Color[] p_color_arr) { set_colors(ColumnNames.PINS.ordinal(), p_color_arr); } + /** + *

set_conduction_colors.

+ * + * @param p_color_arr an array of {@link java.awt.Color} objects. + */ public void set_conduction_colors(Color[] p_color_arr) { set_colors(ColumnNames.CONDUCTION_AREAS.ordinal(), p_color_arr); } + /** + *

set_keepout_colors.

+ * + * @param p_color_arr an array of {@link java.awt.Color} objects. + */ public void set_keepout_colors(Color[] p_color_arr) { set_colors(ColumnNames.KEEPOUTS.ordinal(), p_color_arr); } + /** + *

set_via_keepout_colors.

+ * + * @param p_color_arr an array of {@link java.awt.Color} objects. + */ public void set_via_keepout_colors(Color[] p_color_arr) { set_colors(ColumnNames.VIA_KEEPOUTS.ordinal(), p_color_arr); } + /** + *

set_place_keepout_colors.

+ * + * @param p_color_arr an array of {@link java.awt.Color} objects. + */ public void set_place_keepout_colors(Color[] p_color_arr) { set_colors(ColumnNames.PLACE_KEEPOUTS.ordinal(), p_color_arr); diff --git a/boardgraphics/ItemDrawInfo.java b/src/main/java/boardgraphics/ItemDrawInfo.java similarity index 85% rename from boardgraphics/ItemDrawInfo.java rename to src/main/java/boardgraphics/ItemDrawInfo.java index 364b8dd..db18ebf 100644 --- a/boardgraphics/ItemDrawInfo.java +++ b/src/main/java/boardgraphics/ItemDrawInfo.java @@ -26,11 +26,17 @@ * Information for drawing an item on the screen. * * @author alfons + * @version $Id: $Id */ public class ItemDrawInfo { - /** Creates a new instance of ItemDrawInfo */ + /** + * Creates a new instance of ItemDrawInfo + * + * @param p_layer_color an array of {@link java.awt.Color} objects. + * @param p_intensity a double. + */ public ItemDrawInfo(Color[] p_layer_color, double p_intensity) { layer_color = p_layer_color; diff --git a/boardgraphics/OtherColorTableModel.java b/src/main/java/boardgraphics/OtherColorTableModel.java similarity index 69% rename from boardgraphics/OtherColorTableModel.java rename to src/main/java/boardgraphics/OtherColorTableModel.java index a6c4f1d..4714bb9 100644 --- a/boardgraphics/OtherColorTableModel.java +++ b/src/main/java/boardgraphics/OtherColorTableModel.java @@ -26,10 +26,16 @@ * Stores the colors used for the background and highlighting. * * @author Alfons Wirtz + * @version $Id: $Id */ public class OtherColorTableModel extends ColorTableModel implements java.io.Serializable { + /** + *

Constructor for OtherColorTableModel.

+ * + * @param p_locale a {@link java.util.Locale} object. + */ public OtherColorTableModel(java.util.Locale p_locale) { super(1, p_locale); @@ -45,6 +51,13 @@ public OtherColorTableModel(java.util.Locale p_locale) curr_row[ColumnNames.LENGTH_MATCHING_AREA.ordinal()] = Color.green; } + /** + *

Constructor for OtherColorTableModel.

+ * + * @param p_stream a {@link java.io.ObjectInputStream} object. + * @throws java.io.IOException if any. + * @throws java.lang.ClassNotFoundException if any. + */ public OtherColorTableModel(java.io.ObjectInputStream p_stream) throws java.io.IOException, java.lang.ClassNotFoundException { @@ -53,6 +66,8 @@ public OtherColorTableModel(java.io.ObjectInputStream p_stream) /** * Copy construcror. + * + * @param p_item_color_model a {@link boardgraphics.OtherColorTableModel} object. */ public OtherColorTableModel(OtherColorTableModel p_item_color_model) { @@ -65,11 +80,17 @@ public OtherColorTableModel(OtherColorTableModel p_item_color_model) } + /** + *

getColumnCount.

+ * + * @return a int. + */ public int getColumnCount() { return ColumnNames.values().length; } + /** {@inheritDoc} */ public String getColumnName(int p_col) { java.util.ResourceBundle resources = @@ -77,36 +98,68 @@ public String getColumnName(int p_col) return resources.getString(ColumnNames.values()[p_col].toString()); } + /** {@inheritDoc} */ public boolean isCellEditable(int p_row, int p_col) { return true; } + /** + *

get_background_color.

+ * + * @return a {@link java.awt.Color} object. + */ public Color get_background_color() { return (Color)(data[0][ColumnNames.BACKGROUND.ordinal()]); } + /** + *

get_hilight_color.

+ * + * @return a {@link java.awt.Color} object. + */ public Color get_hilight_color() { return (Color) (data[0][ColumnNames.HIGHLIGHT.ordinal()]); } + /** + *

get_incomplete_color.

+ * + * @return a {@link java.awt.Color} object. + */ public Color get_incomplete_color() { return (Color) (data[0][ColumnNames.INCOMPLETES.ordinal()]); } + /** + *

get_outline_color.

+ * + * @return a {@link java.awt.Color} object. + */ public Color get_outline_color() { return (Color) (data[0][ColumnNames.OUTLINE.ordinal()]); } + /** + *

get_violations_color.

+ * + * @return a {@link java.awt.Color} object. + */ public Color get_violations_color() { return (Color) (data[0][ColumnNames.VIOLATIONS.ordinal()]); } + /** + *

get_component_color.

+ * + * @param p_front a boolean. + * @return a {@link java.awt.Color} object. + */ public Color get_component_color(boolean p_front) { Color result; @@ -121,36 +174,72 @@ public Color get_component_color(boolean p_front) return result; } + /** + *

get_length_matching_area_color.

+ * + * @return a {@link java.awt.Color} object. + */ public Color get_length_matching_area_color() { return (Color) (data[0][ColumnNames.LENGTH_MATCHING_AREA.ordinal()]); } + /** + *

set_background_color.

+ * + * @param p_color a {@link java.awt.Color} object. + */ public void set_background_color(Color p_color) { data[0][ColumnNames.BACKGROUND.ordinal()] = p_color; } + /** + *

set_hilight_color.

+ * + * @param p_color a {@link java.awt.Color} object. + */ public void set_hilight_color(Color p_color) { data[0][ColumnNames.HIGHLIGHT.ordinal()] = p_color; } + /** + *

set_incomplete_color.

+ * + * @param p_color a {@link java.awt.Color} object. + */ public void set_incomplete_color(Color p_color) { data[0][ColumnNames.INCOMPLETES.ordinal()] = p_color; } + /** + *

set_violations_color.

+ * + * @param p_color a {@link java.awt.Color} object. + */ public void set_violations_color(Color p_color) { data[0][ColumnNames.VIOLATIONS.ordinal()] = p_color; } + /** + *

set_outline_color.

+ * + * @param p_color a {@link java.awt.Color} object. + */ public void set_outline_color(Color p_color) { data[0][ColumnNames.OUTLINE.ordinal()] = p_color; } + /** + *

set_component_color.

+ * + * @param p_color a {@link java.awt.Color} object. + * @param p_front a boolean. + */ public void set_component_color(Color p_color, boolean p_front) { if (p_front) @@ -163,6 +252,11 @@ public void set_component_color(Color p_color, boolean p_front) } } + /** + *

set_length_matching_area_color.

+ * + * @param p_color a {@link java.awt.Color} object. + */ public void set_length_matching_area_color(Color p_color) { data[0][ColumnNames.LENGTH_MATCHING_AREA.ordinal()] = p_color; diff --git a/boardgraphics/package.html b/src/main/java/boardgraphics/package.html similarity index 100% rename from boardgraphics/package.html rename to src/main/java/boardgraphics/package.html diff --git a/datastructures/ArrayStack.java b/src/main/java/datastructures/ArrayStack.java similarity index 92% rename from datastructures/ArrayStack.java rename to src/main/java/datastructures/ArrayStack.java index e4dc794..790460a 100644 --- a/datastructures/ArrayStack.java +++ b/src/main/java/datastructures/ArrayStack.java @@ -1,90 +1,97 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * ArrayStack.java - * - * Created on 11. Maerz 2006, 06:52 - * - */ - -package datastructures; - -@SuppressWarnings("unchecked") - -/** - * Implementation of a stack as an array. - * - * @author Alfons Wirtz - */ -public class ArrayStack -{ - /** - * Creates a new instance of ArrayStack with an initial maximal capacity for p_max_stack_depth elements. - */ - public ArrayStack(int p_max_stack_depth) - { - node_arr = (p_element_type [] ) new Object [p_max_stack_depth]; - } - - /** - * Sets the stack to empty. - */ - public void reset() - { - level = -1; - } - - /** - * Pushed p_element onto the stack. - */ - public void push(p_element_type p_element) - { - - ++level; - - if (level >= node_arr.length) - { - reallocate(); - } - - node_arr[level] = p_element; - } - - /** - * Pops the next element from the top of the stack. - * Returns null, if the stack is exhausted. - */ - public p_element_type pop() - { - if (level < 0) - { - return null; - } - p_element_type result = node_arr[level]; - --level; - return result; - } - - private void reallocate() - { - p_element_type [] new_arr = (p_element_type [] ) new Object[4 * this.node_arr.length]; - System.arraycopy(node_arr, 0, new_arr, 0, node_arr.length); - this.node_arr = new_arr; - } - - private int level = -1; - - private p_element_type[] node_arr ; -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * ArrayStack.java + * + * Created on 11. Maerz 2006, 06:52 + * + */ + +package datastructures; + +@SuppressWarnings("unchecked") + +/** + * Implementation of a stack as an array. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class ArrayStack +{ + /** + * Creates a new instance of ArrayStack with an initial maximal capacity for p_max_stack_depth elements. + * + * @param p_max_stack_depth a int. + */ + public ArrayStack(int p_max_stack_depth) + { + node_arr = (p_element_type [] ) new Object [p_max_stack_depth]; + } + + /** + * Sets the stack to empty. + */ + public void reset() + { + level = -1; + } + + /** + * Pushed p_element onto the stack. + * + * @param p_element a p_element_type object. + */ + public void push(p_element_type p_element) + { + + ++level; + + if (level >= node_arr.length) + { + reallocate(); + } + + node_arr[level] = p_element; + } + + /** + * Pops the next element from the top of the stack. + * Returns null, if the stack is exhausted. + * + * @return a p_element_type object. + */ + public p_element_type pop() + { + if (level < 0) + { + return null; + } + p_element_type result = node_arr[level]; + --level; + return result; + } + + private void reallocate() + { + p_element_type [] new_arr = (p_element_type [] ) new Object[4 * this.node_arr.length]; + System.arraycopy(node_arr, 0, new_arr, 0, node_arr.length); + this.node_arr = new_arr; + } + + private int level = -1; + + private p_element_type[] node_arr ; +} diff --git a/datastructures/BigIntAux.java b/src/main/java/datastructures/BigIntAux.java similarity index 87% rename from datastructures/BigIntAux.java rename to src/main/java/datastructures/BigIntAux.java index dc88a26..2f5a6db 100644 --- a/datastructures/BigIntAux.java +++ b/src/main/java/datastructures/BigIntAux.java @@ -1,145 +1,159 @@ -/* - * This file contains a copy of the method binaryGcd in the class java.math.MutableBigInteger. - * The reason is, that binaryGcD is not public and we needed to call it from outside the java.math package. - * There is no aim to violate any copyright. - * - * - * BigIntAux.java - * - * Created on 5. January 2003, 11:26 - */ - -package datastructures; - -import java.math.BigInteger; - -/** - * - * Auxiliary functions with BigInteger Parameters - - * @author Alfons Wirtz - */ - -public class BigIntAux -{ - /** - * calculates the determinant of the vectors - * (p_x_1, p_y_1) and (p_x_2, p_y_2) - */ - public static final BigInteger determinant (BigInteger p_x_1, BigInteger p_y_1, - BigInteger p_x_2, BigInteger p_y_2) - { - BigInteger tmp1 = p_x_1.multiply(p_y_2); - BigInteger tmp2 = p_x_2.multiply(p_y_1); - return tmp1.subtract(tmp2); - } - - - /** - * auxiliary function to implement addition and translation in the - * classes RationalVector and RationalPoint - */ - public static final BigInteger[] add_rational_coordinates(BigInteger[] p_first, - BigInteger [] p_second) - { - BigInteger[] result = new BigInteger[3]; - if (p_first[2].equals(p_second[2])) - // both rational numbers have the same denominator - { - result[2] = p_first[2]; - result[0] = p_first[0].add(p_second[0]); - result[1] = p_first[1].add(p_second[1]); - } - else - // multiply both denominators for the new denominator - // to be on the save side: - // taking the leat common multiple whould be optimal - { - result[2] = p_first[2].multiply(p_second[2]); - BigInteger tmp_1 = p_first[0].multiply(p_second[2]); - BigInteger tmp_2 = p_second[0].multiply(p_first[2]); - result[0] = tmp_1.add(tmp_2); - tmp_1 = p_first[1].multiply(p_second[2]); - tmp_2 = p_second[1].multiply(p_first[2]); - result[1] = tmp_1.add(tmp_2); - } - return result; - } - - // the following function binaryGcd is copied from private parts of java.math - // because we need it public. - - /* - * trailingZeroTable[i] is the number of trailing zero bits in the binary - * representaion of i. - */ - final static byte trailingZeroTable[] = { - -25, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, - 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, - 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, - 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, - 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, - 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, - 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, - 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, - 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, - 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, - 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, - 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, - 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, - 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, - 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, - 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0}; - - /** - * Calculate GCD of a and b interpreted as unsigned integers. - */ - public static final int binaryGcd(int a, int b) { - if (b==0) - return a; - if (a==0) - return b; - - int x; - int aZeros = 0; - while ((x = a & 0xff) == 0) { - a >>>= 8; - aZeros += 8; - } - int y = trailingZeroTable[x]; - aZeros += y; - a >>>= y; - - int bZeros = 0; - while ((x = b & 0xff) == 0) { - b >>>= 8; - bZeros += 8; - } - y = trailingZeroTable[x]; - bZeros += y; - b >>>= y; - - int t = (aZeros < bZeros ? aZeros : bZeros); - - while (a != b) { - if ((a+0x80000000) > (b+0x80000000)) { // a > b as unsigned - a -= b; - - while ((x = a & 0xff) == 0) - a >>>= 8; - a >>>= trailingZeroTable[x]; - } else { - b -= a; - - while ((x = b & 0xff) == 0) - b >>>= 8; - b >>>= trailingZeroTable[x]; - } - } - return a<>>= 8; + aZeros += 8; + } + int y = trailingZeroTable[x]; + aZeros += y; + a >>>= y; + + int bZeros = 0; + while ((x = b & 0xff) == 0) { + b >>>= 8; + bZeros += 8; + } + y = trailingZeroTable[x]; + bZeros += y; + b >>>= y; + + int t = (aZeros < bZeros ? aZeros : bZeros); + + while (a != b) { + if ((a+0x80000000) > (b+0x80000000)) { // a > b as unsigned + a -= b; + + while ((x = a & 0xff) == 0) + a >>>= 8; + a >>>= trailingZeroTable[x]; + } else { + b -= a; + + while ((x = b & 0xff) == 0) + b >>>= 8; + b >>>= trailingZeroTable[x]; + } + } + return a<getDescription.

+ * + * @return a {@link java.lang.String} object. + */ public String getDescription() { String message = "files with the extensions"; @@ -51,6 +61,7 @@ else if (i < extensions.length -2) return message; } + /** {@inheritDoc} */ public boolean accept(java.io.File p_file) { if (p_file.isDirectory()) diff --git a/datastructures/IdNoGenerator.java b/src/main/java/datastructures/IdNoGenerator.java similarity index 92% rename from datastructures/IdNoGenerator.java rename to src/main/java/datastructures/IdNoGenerator.java index 677f790..d220468 100644 --- a/datastructures/IdNoGenerator.java +++ b/src/main/java/datastructures/IdNoGenerator.java @@ -24,16 +24,21 @@ * Interface for creatiing unique identification number. * * @author Alfons Wirtz + * @version $Id: $Id */ public interface IdNoGenerator { /** * Create a new unique identification number. + * + * @return a int. */ int new_no(); /** * Return the maximum generated id number so far. + * + * @return a int. */ int max_generated_no(); } diff --git a/datastructures/IdentifierType.java b/src/main/java/datastructures/IdentifierType.java similarity index 89% rename from datastructures/IdentifierType.java rename to src/main/java/datastructures/IdentifierType.java index bbb524d..700a5e4 100644 --- a/datastructures/IdentifierType.java +++ b/src/main/java/datastructures/IdentifierType.java @@ -26,12 +26,16 @@ * Describes legal identifiers together with the character used for string quotes. * * @author alfons + * @version $Id: $Id */ public class IdentifierType { /** * Defines the reserved characters and the string for quoting identifiers containing * reserved characters for a new instance of Identifier. + * + * @param p_reserved_chars an array of {@link java.lang.String} objects. + * @param p_string_quote a {@link java.lang.String} object. */ public IdentifierType(String [] p_reserved_chars, String p_string_quote) { @@ -41,6 +45,9 @@ public IdentifierType(String [] p_reserved_chars, String p_string_quote) /** * Writes p_name after puttiong it into quotes, if it contains reserved characters or blanks. + * + * @param p_name a {@link java.lang.String} object. + * @param p_file a {@link java.io.OutputStreamWriter} object. */ public void write(String p_name, OutputStreamWriter p_file) { diff --git a/datastructures/IndentFileWriter.java b/src/main/java/datastructures/IndentFileWriter.java similarity index 93% rename from datastructures/IndentFileWriter.java rename to src/main/java/datastructures/IndentFileWriter.java index 8f01d43..0fc5c42 100644 --- a/datastructures/IndentFileWriter.java +++ b/src/main/java/datastructures/IndentFileWriter.java @@ -24,11 +24,16 @@ * Handles the indenting of scopes while writing to an output text file. * * @author alfons + * @version $Id: $Id */ public class IndentFileWriter extends java.io.OutputStreamWriter { - /** Creates a new instance of IndentFileWriter */ + /** + * Creates a new instance of IndentFileWriter + * + * @param p_stream a {@link java.io.OutputStream} object. + */ public IndentFileWriter(java.io.OutputStream p_stream) { super(p_stream); diff --git a/datastructures/MinAreaTree.java b/src/main/java/datastructures/MinAreaTree.java similarity index 96% rename from datastructures/MinAreaTree.java rename to src/main/java/datastructures/MinAreaTree.java index 92932a6..75d5b2a 100644 --- a/datastructures/MinAreaTree.java +++ b/src/main/java/datastructures/MinAreaTree.java @@ -37,6 +37,7 @@ * The algorithm would of course also work for higher dimensions. * * @author Alfons Wirtz + * @version $Id: $Id */ public class MinAreaTree extends ShapeTree { @@ -44,6 +45,8 @@ public class MinAreaTree extends ShapeTree /** * Constructor with a fixed set of directions defining the keys and and * the surrounding shapes + * + * @param p_directions a {@link geometry.planar.ShapeBoundingDirections} object. */ public MinAreaTree(ShapeBoundingDirections p_directions) { @@ -52,6 +55,9 @@ public MinAreaTree(ShapeBoundingDirections p_directions) /** * Calculates the objects in this tree, which overlap with p_shape + * + * @param p_shape a {@link geometry.planar.RegularTileShape} object. + * @return a {@link java.util.Set} object. */ public Set overlaps(RegularTileShape p_shape) { @@ -166,6 +172,8 @@ private final Leaf position_locate(TreeNode p_curr_node, Leaf p_leaf_to_insert) /** * removes an entry from this tree + * + * @param p_leaf a Leaf object. */ public void remove_leaf(Leaf p_leaf) { diff --git a/datastructures/Observers.java b/src/main/java/datastructures/Observers.java similarity index 81% rename from datastructures/Observers.java rename to src/main/java/datastructures/Observers.java index 5ef1bed..fc7cf0d 100644 --- a/datastructures/Observers.java +++ b/src/main/java/datastructures/Observers.java @@ -24,32 +24,45 @@ * Interface to observe changes on objects for syncronisatiation purposes. * * @author Alfons Wirtz + * @version $Id: $Id */ public interface Observers { /** * Tell the observers the deletion p_object. + * + * @param p_object a ObjectType object. */ void notify_deleted(ObjectType p_object); /** * Notify the observers, that they can syncronize the changes on p_object. + * + * @param p_object a ObjectType object. */ void notify_changed(ObjectType p_object); /** * Enable the observers to syncronize the new created item. + * + * @param p_object a ObjectType object. */ void notify_new(ObjectType p_object); - /** Starts notifying the observers */ + /** + * Starts notifying the observers + */ void activate(); - /** Ends notifying the observers */ + /** + * Ends notifying the observers + */ void deactivate(); /** * Returns, if the observer is activated. + * + * @return a boolean. */ boolean is_active(); } diff --git a/datastructures/PlanarDelaunayTriangulation.java b/src/main/java/datastructures/PlanarDelaunayTriangulation.java similarity index 99% rename from datastructures/PlanarDelaunayTriangulation.java rename to src/main/java/datastructures/PlanarDelaunayTriangulation.java index ce76d8c..8e9a8b9 100644 --- a/datastructures/PlanarDelaunayTriangulation.java +++ b/src/main/java/datastructures/PlanarDelaunayTriangulation.java @@ -41,11 +41,16 @@ * from M. de Berg, M. van Kreveld, M Overmars and O Schwarzkopf. * * @author Alfons Wirtz + * @version $Id: $Id */ public class PlanarDelaunayTriangulation { - /** Creates a new instance of PlanarDelaunayTriangulation from p_object_list. */ + /** + * Creates a new instance of PlanarDelaunayTriangulation from p_object_list. + * + * @param p_object_list a java$util$Collection object. + */ public PlanarDelaunayTriangulation(Collection p_object_list) { List corner_list = new LinkedList(); @@ -103,6 +108,8 @@ public PlanarDelaunayTriangulation(Collection get_edge_lines() { @@ -294,6 +301,8 @@ else if (p_edge.right_triangle.opposite_corner(p_edge) == p_corner) /** * Checks the consistancy of the triangles in this triagulation. * Used for debugging purposes. + * + * @return a boolean. */ public boolean validate() { diff --git a/datastructures/ShapeTree.java b/src/main/java/datastructures/ShapeTree.java similarity index 90% rename from datastructures/ShapeTree.java rename to src/main/java/datastructures/ShapeTree.java index 07078ec..b1e42bd 100644 --- a/datastructures/ShapeTree.java +++ b/src/main/java/datastructures/ShapeTree.java @@ -31,11 +31,16 @@ * Objects to be stored in the tree must implement the interface ShapeTree.Storable. * * @author Alfons Wirtz + * @version $Id: $Id */ public abstract class ShapeTree { - /** Creates a new instance of ShapeTree */ + /** + * Creates a new instance of ShapeTree + * + * @param p_directions a {@link geometry.planar.ShapeBoundingDirections} object. + */ public ShapeTree(ShapeBoundingDirections p_directions) { bounding_directions = p_directions ; @@ -46,6 +51,8 @@ public ShapeTree(ShapeBoundingDirections p_directions) /** * Inserts all shapes of p_obj into the tree + * + * @param p_obj a {@link datastructures.ShapeTree.Storable} object. */ public void insert(ShapeTree.Storable p_obj) { @@ -64,6 +71,10 @@ public void insert(ShapeTree.Storable p_obj) /** * Insert a shape - creates a new node with a bounding shape + * + * @param p_object a {@link datastructures.ShapeTree.Storable} object. + * @param p_index a int. + * @return a {@link datastructures.ShapeTree.Leaf} object. */ protected Leaf insert(ShapeTree.Storable p_object, int p_index) { @@ -86,7 +97,11 @@ protected Leaf insert(ShapeTree.Storable p_object, int p_index) } - /** Inserts the leaves of this tree into an array. */ + /** + * Inserts the leaves of this tree into an array. + * + * @return an array of {@link datastructures.ShapeTree.Leaf} objects. + */ public Leaf[] to_array() { Leaf [] result = new Leaf[this.leaf_count]; @@ -130,6 +145,8 @@ public Leaf[] to_array() /** * removes all entries of p_obj in the tree. + * + * @param p_entries an array of {@link datastructures.ShapeTree.Leaf} objects. */ public void remove(Leaf [] p_entries) { @@ -143,14 +160,22 @@ public void remove(Leaf [] p_entries) } } - /** Returns the number of entries stored in the tree. */ + /** + * Returns the number of entries stored in the tree. + * + * @return a int. + */ public int size() { return leaf_count; } - /** Outputs some statistic information about the tree. */ + /** + * Outputs some statistic information about the tree. + * + * @param p_message a {@link java.lang.String} object. + */ public void statistics(String p_message) { Leaf[] leaf_arr = this.to_array(); diff --git a/datastructures/Signum.java b/src/main/java/datastructures/Signum.java similarity index 85% rename from datastructures/Signum.java rename to src/main/java/datastructures/Signum.java index 19118d9..772b7dc 100644 --- a/datastructures/Signum.java +++ b/src/main/java/datastructures/Signum.java @@ -1,115 +1,127 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - */ - -package datastructures; - -/** - * - * Implements the mathematical signum function. - * - - * @author Alfons Wirtz - */ - -public class Signum -{ - public static final Signum POSITIVE = new Signum ("positive"); - public static final Signum NEGATIVE = new Signum ("negative"); - public static final Signum ZERO = new Signum ("zero"); - - /** - * Returns the signum of p_value. - * Values are Signum.POSITIVE, Signum.NEGATIVE and Signum.ZERO - */ - public static final Signum of (double p_value) - { - Signum result; - - if (p_value > 0) - { - result = POSITIVE; - } - else if (p_value < 0) - { - result = NEGATIVE; - } - else - { - result = ZERO; - } - return result; - } - - /** - * Returns the signum of p_value as an int. - * Values are +1, 0 and -1 - */ - public static final int as_int (double p_value) - { - int result; - - if (p_value > 0) - { - result = 1; - } - else if (p_value < 0) - { - result = -1; - } - else - { - result = 0; - } - return result; - } - - /** - * Returns the string of this instance - */ - public String to_string () - { - return name; - } - - /** - * Returns the opposite Signum of this Signum - */ - public final Signum negate() - { - Signum result; - if (this == POSITIVE) - { - result = NEGATIVE; - } - else if (this == NEGATIVE) - { - result = POSITIVE; - } - else - { - result = this; - } - return result; - } - - - private Signum(String p_name) - { - name = p_name; - } - - private final String name; -} \ No newline at end of file +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + */ + +package datastructures; + +/** + * + * Implements the mathematical signum function. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class Signum +{ + /** Constant POSITIVE */ + public static final Signum POSITIVE = new Signum ("positive"); + /** Constant NEGATIVE */ + public static final Signum NEGATIVE = new Signum ("negative"); + /** Constant ZERO */ + public static final Signum ZERO = new Signum ("zero"); + + /** + * Returns the signum of p_value. + * Values are Signum.POSITIVE, Signum.NEGATIVE and Signum.ZERO + * + * @param p_value a double. + * @return a {@link datastructures.Signum} object. + */ + public static final Signum of (double p_value) + { + Signum result; + + if (p_value > 0) + { + result = POSITIVE; + } + else if (p_value < 0) + { + result = NEGATIVE; + } + else + { + result = ZERO; + } + return result; + } + + /** + * Returns the signum of p_value as an int. + * Values are +1, 0 and -1 + * + * @param p_value a double. + * @return a int. + */ + public static final int as_int (double p_value) + { + int result; + + if (p_value > 0) + { + result = 1; + } + else if (p_value < 0) + { + result = -1; + } + else + { + result = 0; + } + return result; + } + + /** + * Returns the string of this instance + * + * @return a {@link java.lang.String} object. + */ + public String to_string () + { + return name; + } + + /** + * Returns the opposite Signum of this Signum + * + * @return a {@link datastructures.Signum} object. + */ + public final Signum negate() + { + Signum result; + if (this == POSITIVE) + { + result = NEGATIVE; + } + else if (this == NEGATIVE) + { + result = POSITIVE; + } + else + { + result = this; + } + return result; + } + + + private Signum(String p_name) + { + name = p_name; + } + + private final String name; +} diff --git a/datastructures/Stoppable.java b/src/main/java/datastructures/Stoppable.java similarity index 94% rename from datastructures/Stoppable.java rename to src/main/java/datastructures/Stoppable.java index 6653bd6..c3a07f4 100644 --- a/datastructures/Stoppable.java +++ b/src/main/java/datastructures/Stoppable.java @@ -1,40 +1,43 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * Stoppable.java - * - * Created on 7. Maerz 2006, 09:46 - * - */ - -package datastructures; - -/** - * Interface for stoppable threads. - * - * @author alfons - */ -public interface Stoppable -{ - /** - * Requests this thread to be stopped. - */ - void request_stop(); - - /** - * Returns true, if this thread is requested to be stopped. - */ - boolean is_stop_requested(); -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * Stoppable.java + * + * Created on 7. Maerz 2006, 09:46 + * + */ + +package datastructures; + +/** + * Interface for stoppable threads. + * + * @author alfons + * @version $Id: $Id + */ +public interface Stoppable +{ + /** + * Requests this thread to be stopped. + */ + void request_stop(); + + /** + * Returns true, if this thread is requested to be stopped. + * + * @return a boolean. + */ + boolean is_stop_requested(); +} diff --git a/datastructures/TimeLimit.java b/src/main/java/datastructures/TimeLimit.java similarity index 92% rename from datastructures/TimeLimit.java rename to src/main/java/datastructures/TimeLimit.java index 806579a..d0d18bb 100644 --- a/datastructures/TimeLimit.java +++ b/src/main/java/datastructures/TimeLimit.java @@ -1,65 +1,73 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * TimeLimit.java - * - * Created on 15. Maerz 2006, 09:27 - * - */ - -package datastructures; - -/** - * Class used to cancel a performance critical algorithm after a time limit is exceeded. - * @author Alfons Wirtz - */ -public class TimeLimit -{ - - /** - * Creates a new instance with a time limit of p_milli_seconds milli seconds - */ - public TimeLimit(int p_milli_seconds) - { - this.time_limit = p_milli_seconds; - this.time_stamp = (new java.util.Date()).getTime(); - } - - /** - * Returns true, if the time limit provided in the constructor of this class is exceeded. - */ - public boolean limit_exceeded() - { - long curr_time = (new java.util.Date()).getTime(); - return (curr_time - this.time_stamp > this.time_limit); - } - - /** - * Multiplies this TimeLimit by p_factor. - */ - public void muultiply(double p_factor) - { - if (p_factor <= 0) - { - return; - } - double new_limit = (p_factor * this.time_limit); - new_limit = Math.min(new_limit, Integer.MAX_VALUE); - this.time_limit = (int) new_limit; - } - - private final long time_stamp; - private int time_limit; -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * TimeLimit.java + * + * Created on 15. Maerz 2006, 09:27 + * + */ + +package datastructures; + +/** + * Class used to cancel a performance critical algorithm after a time limit is exceeded. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class TimeLimit +{ + + /** + * Creates a new instance with a time limit of p_milli_seconds milli seconds + * + * @param p_milli_seconds a int. + */ + public TimeLimit(int p_milli_seconds) + { + this.time_limit = p_milli_seconds; + this.time_stamp = (new java.util.Date()).getTime(); + } + + /** + * Returns true, if the time limit provided in the constructor of this class is exceeded. + * + * @return a boolean. + */ + public boolean limit_exceeded() + { + long curr_time = (new java.util.Date()).getTime(); + return (curr_time - this.time_stamp > this.time_limit); + } + + /** + * Multiplies this TimeLimit by p_factor. + * + * @param p_factor a double. + */ + public void muultiply(double p_factor) + { + if (p_factor <= 0) + { + return; + } + double new_limit = (p_factor * this.time_limit); + new_limit = Math.min(new_limit, Integer.MAX_VALUE); + this.time_limit = (int) new_limit; + } + + private final long time_stamp; + private int time_limit; +} diff --git a/datastructures/UndoableObjects.java b/src/main/java/datastructures/UndoableObjects.java similarity index 93% rename from datastructures/UndoableObjects.java rename to src/main/java/datastructures/UndoableObjects.java index 23e7f97..7437525 100644 --- a/datastructures/UndoableObjects.java +++ b/src/main/java/datastructures/UndoableObjects.java @@ -31,11 +31,14 @@ * The algorithm works only for objects containing no references. * * @author Alfons Wirtz + * @version $Id: $Id */ public class UndoableObjects implements java.io.Serializable { - /** Creates a new instance of UndoableObjectsList */ + /** + * Creates a new instance of UndoableObjectsList + */ public UndoableObjects() { stack_level = 0; @@ -46,6 +49,8 @@ public UndoableObjects() /** * Returns an iterator for sequential reading of the object list. * Use it together with this.read_object(). + * + * @return a {@link java.util.Iterator} object. */ public Iterator start_read_object() { @@ -57,6 +62,9 @@ public Iterator start_read_object() * Reads the next object in this list. * Returns null, if the list is exhausted. * p_it must be created by start_read_object. + * + * @param p_it a {@link java.util.Iterator} object. + * @return a {@link datastructures.UndoableObjects.Storable} object. */ public UndoableObjects.Storable read_object(Iterator p_it) { @@ -74,6 +82,8 @@ public UndoableObjects.Storable read_object(Iterator p_it) /** * Adds p_object to the UndoableObjectsList. + * + * @param p_object a {@link datastructures.UndoableObjects.Storable} object. */ public void insert(UndoableObjects.Storable p_object) { @@ -85,6 +95,9 @@ public void insert(UndoableObjects.Storable p_object) /** * Removes p_object from the top level of the UndoableObjectsList. * Returns false, if p_object was not found in the list. + * + * @param p_object a {@link datastructures.UndoableObjects.Storable} object. + * @return a boolean. */ public boolean delete(UndoableObjects.Storable p_object) { @@ -145,6 +158,10 @@ public void generate_snapshot() * Outputs the cancelled and the restored objects (if != null) to enable * the calling function to take additional actions needed for these objects. * Returns false, if no more undo is possible + * + * @param p_cancelled_objects a {@link java.util.Collection} object. + * @param p_restored_objects a {@link java.util.Collection} object. + * @return a boolean. */ public boolean undo(Collection p_cancelled_objects, Collection p_restored_objects) { @@ -196,6 +213,10 @@ public boolean undo(Collection p_cancelled_objects, Co * Outputs the cancelled and the restored objects (if != null) to enable * the calling function to take additional actions needed for these objects. * Returns false, if no more redo is possible. + * + * @param p_cancelled_objects a {@link java.util.Collection} object. + * @param p_restored_objects a {@link java.util.Collection} object. + * @return a boolean. */ public boolean redo(Collection p_cancelled_objects, Collection p_restored_objects) { @@ -260,6 +281,8 @@ else if (curr_node.level == this.stack_level) * Removes the top snapshot from the undo stack, so that its situation cannot be * restored any more. * Returns false, if no more snapshot could be popped. + * + * @return a boolean. */ public boolean pop_snapshot() { @@ -316,6 +339,8 @@ else if (curr_deleted_node.undo_object != null) /** * Must be callel before p_object will be modified after a snapshot * for the first time, if it may have existed before that snapshot. + * + * @param p_object a {@link datastructures.UndoableObjects.Storable} object. */ public void save_for_undo(UndoableObjects.Storable p_object) { diff --git a/datastructures/package.html b/src/main/java/datastructures/package.html similarity index 100% rename from datastructures/package.html rename to src/main/java/datastructures/package.html diff --git a/designformats/specctra/AutorouteSettings.java b/src/main/java/designformats/specctra/AutorouteSettings.java similarity index 97% rename from designformats/specctra/AutorouteSettings.java rename to src/main/java/designformats/specctra/AutorouteSettings.java index 38c2f35..28909ff 100644 --- a/designformats/specctra/AutorouteSettings.java +++ b/src/main/java/designformats/specctra/AutorouteSettings.java @@ -1,324 +1,326 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * AutorouteSettings.java - * - * Created on 1. Maerz 2007, 07:10 - * - */ -package designformats.specctra; - -import datastructures.IndentFileWriter; -import datastructures.IdentifierType; - -/** - * - * @author Alfons Wirtz - */ -public class AutorouteSettings -{ - - static interactive.AutorouteSettings read_scope(Scanner p_scanner, LayerStructure p_layer_structure) - { - interactive.AutorouteSettings result = new interactive.AutorouteSettings(p_layer_structure.arr.length); - boolean with_fanout = false; - boolean with_autoroute = true; - boolean with_postroute = true; - Object next_token = null; - for (;;) - { - Object prev_token = next_token; - try - { - next_token = p_scanner.next_token(); - } catch (java.io.IOException e) - { - System.out.println("AutorouteSettings.read_scope: IO error scanning file"); - return null; - } - if (next_token == null) - { - System.out.println("AutorouteSettings.read_scope: unexpected end of file"); - return null; - } - if (next_token == Keyword.CLOSED_BRACKET) - { - // end of scope - break; - } - if (prev_token == Keyword.OPEN_BRACKET) - { - if (next_token == Keyword.FANOUT) - { - with_fanout = DsnFile.read_on_off_scope(p_scanner); - } - else if (next_token == Keyword.AUTOROUTE) - { - with_autoroute = DsnFile.read_on_off_scope(p_scanner); - } - else if (next_token == Keyword.POSTROUTE) - { - with_postroute = DsnFile.read_on_off_scope(p_scanner); - } - else if (next_token == Keyword.VIAS) - { - result.set_vias_allowed(DsnFile.read_on_off_scope(p_scanner)); - } - else if (next_token == Keyword.VIA_COSTS) - { - result.set_via_costs(DsnFile.read_integer_scope(p_scanner)); - } - else if (next_token == Keyword.PLANE_VIA_COSTS) - { - result.set_plane_via_costs(DsnFile.read_integer_scope(p_scanner)); - } - else if (next_token == Keyword.START_RIPUP_COSTS) - { - result.set_start_ripup_costs(DsnFile.read_integer_scope(p_scanner)); - } - else if (next_token == Keyword.START_PASS_NO) - { - result.set_pass_no(DsnFile.read_integer_scope(p_scanner)); - } - else if (next_token == Keyword.LAYER_RULE) - { - result = read_layer_rule(p_scanner, p_layer_structure, result); - if (result == null) - { - return null; - } - } - else - { - ScopeKeyword.skip_scope(p_scanner); - } - } - } - result.set_with_fanout(with_fanout); - result.set_with_autoroute(with_autoroute); - result.set_with_postroute(with_postroute); - return result; - } - - static interactive.AutorouteSettings read_layer_rule(Scanner p_scanner, LayerStructure p_layer_structure, - interactive.AutorouteSettings p_settings) - { - p_scanner.yybegin(SpecctraFileScanner.NAME); - Object next_token; - try - { - next_token = p_scanner.next_token(); - } catch (java.io.IOException e) - { - System.out.println("AutorouteSettings.read_layer_rule: IO error scanning file"); - return null; - } - if (!(next_token instanceof String)) - { - System.out.println("AutorouteSettings.read_layer_rule: String expected"); - return null; - } - int layer_no = p_layer_structure.get_no((String) next_token); - if (layer_no < 0) - { - System.out.println("AutorouteSettings.read_layer_rule: layer not found"); - return null; - } - for (;;) - { - Object prev_token = next_token; - try - { - next_token = p_scanner.next_token(); - } catch (java.io.IOException e) - { - System.out.println("AutorouteSettings.read_layer_rule: IO error scanning file"); - return null; - } - if (next_token == null) - { - System.out.println("AutorouteSettings.read_layer_rule: unexpected end of file"); - return null; - } - if (next_token == Keyword.CLOSED_BRACKET) - { - // end of scope - break; - } - if (prev_token == Keyword.OPEN_BRACKET) - { - if (next_token == Keyword.ACTIVE) - { - p_settings.set_layer_active(layer_no, DsnFile.read_on_off_scope(p_scanner)); - } - else if (next_token == Keyword.PREFERRED_DIRECTION) - { - try - { - boolean pref_dir_is_horizontal = true; - next_token = p_scanner.next_token(); - if (next_token == Keyword.VERTICAL) - { - pref_dir_is_horizontal = false; - } - else if (next_token != Keyword.HORIZONTAL) - { - System.out.println("AutorouteSettings.read_layer_rule: unexpected key word"); - return null; - } - p_settings.set_preferred_direction_is_horizontal(layer_no, pref_dir_is_horizontal); - next_token = p_scanner.next_token(); - if (next_token != Keyword.CLOSED_BRACKET) - { - System.out.println("AutorouteSettings.read_layer_rule: uclosing bracket expected"); - return null; - } - } catch (java.io.IOException e) - { - System.out.println("AutorouteSettings.read_layer_rule: IO error scanning file"); - return null; - } - } - else if (next_token == Keyword.PREFERRED_DIRECTION_TRACE_COSTS) - { - p_settings.set_preferred_direction_trace_costs(layer_no, DsnFile.read_float_scope(p_scanner)); - } - else if (next_token == Keyword.AGAINST_PREFERRED_DIRECTION_TRACE_COSTS) - { - p_settings.set_against_preferred_direction_trace_costs(layer_no, DsnFile.read_float_scope(p_scanner)); - } - else - { - ScopeKeyword.skip_scope(p_scanner); - } - } - } - return p_settings; - } - - static void write_scope(IndentFileWriter p_file, interactive.AutorouteSettings p_settings, - board.LayerStructure p_layer_structure, IdentifierType p_identifier_type) throws java.io.IOException - { - p_file.start_scope(); - p_file.write("autoroute_settings"); - p_file.new_line(); - p_file.write("(fanout "); - if (p_settings.get_with_fanout()) - { - p_file.write("on)"); - } - else - { - p_file.write("off)"); - } - p_file.new_line(); - p_file.write("(autoroute "); - if (p_settings.get_with_autoroute()) - { - p_file.write("on)"); - } - else - { - p_file.write("off)"); - } - p_file.new_line(); - p_file.write("(postroute "); - if (p_settings.get_with_postroute()) - { - p_file.write("on)"); - } - else - { - p_file.write("off)"); - } - p_file.new_line(); - p_file.write("(vias "); - if (p_settings.get_vias_allowed()) - { - p_file.write("on)"); - } - else - { - p_file.write("off)"); - } - p_file.new_line(); - p_file.write("(via_costs "); - { - Integer via_costs = p_settings.get_via_costs(); - p_file.write(via_costs.toString()); - } - p_file.write(")"); - p_file.new_line(); - p_file.write("(plane_via_costs "); - { - Integer via_costs = p_settings.get_plane_via_costs(); - p_file.write(via_costs.toString()); - } - p_file.write(")"); - p_file.new_line(); - p_file.write("(start_ripup_costs "); - { - Integer ripup_costs = p_settings.get_start_ripup_costs(); - p_file.write(ripup_costs.toString()); - } - p_file.write(")"); - p_file.new_line(); - p_file.write("(start_pass_no "); - { - Integer pass_no = p_settings.get_pass_no(); - p_file.write(pass_no.toString()); - } - p_file.write(")"); - for (int i = 0; i < p_layer_structure.arr.length; ++i) - { - board.Layer curr_layer = p_layer_structure.arr[i]; - p_file.start_scope(); - p_file.write("layer_rule "); - p_identifier_type.write(curr_layer.name, p_file); - p_file.new_line(); - p_file.write("(active "); - if (p_settings.get_layer_active(i)) - { - p_file.write("on)"); - } - else - { - p_file.write("off)"); - } - p_file.new_line(); - p_file.write("(preferred_direction "); - if (p_settings.get_preferred_direction_is_horizontal(i)) - { - p_file.write("horizontal)"); - } - else - { - p_file.write("vertical)"); - } - p_file.new_line(); - p_file.write("(preferred_direction_trace_costs "); - Float trace_costs = (float) p_settings.get_preferred_direction_trace_costs(i); - p_file.write(trace_costs.toString()); - p_file.write(")"); - p_file.new_line(); - p_file.write("(against_preferred_direction_trace_costs "); - trace_costs = (float) p_settings.get_against_preferred_direction_trace_costs(i); - p_file.write(trace_costs.toString()); - p_file.write(")"); - p_file.end_scope(); - } - p_file.end_scope(); - } -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * AutorouteSettings.java + * + * Created on 1. Maerz 2007, 07:10 + * + */ +package designformats.specctra; + +import datastructures.IndentFileWriter; +import datastructures.IdentifierType; + +/** + *

AutorouteSettings class.

+ * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class AutorouteSettings +{ + + static interactive.AutorouteSettings read_scope(Scanner p_scanner, LayerStructure p_layer_structure) + { + interactive.AutorouteSettings result = new interactive.AutorouteSettings(p_layer_structure.arr.length); + boolean with_fanout = false; + boolean with_autoroute = true; + boolean with_postroute = true; + Object next_token = null; + for (;;) + { + Object prev_token = next_token; + try + { + next_token = p_scanner.next_token(); + } catch (java.io.IOException e) + { + System.out.println("AutorouteSettings.read_scope: IO error scanning file"); + return null; + } + if (next_token == null) + { + System.out.println("AutorouteSettings.read_scope: unexpected end of file"); + return null; + } + if (next_token == Keyword.CLOSED_BRACKET) + { + // end of scope + break; + } + if (prev_token == Keyword.OPEN_BRACKET) + { + if (next_token == Keyword.FANOUT) + { + with_fanout = DsnFile.read_on_off_scope(p_scanner); + } + else if (next_token == Keyword.AUTOROUTE) + { + with_autoroute = DsnFile.read_on_off_scope(p_scanner); + } + else if (next_token == Keyword.POSTROUTE) + { + with_postroute = DsnFile.read_on_off_scope(p_scanner); + } + else if (next_token == Keyword.VIAS) + { + result.set_vias_allowed(DsnFile.read_on_off_scope(p_scanner)); + } + else if (next_token == Keyword.VIA_COSTS) + { + result.set_via_costs(DsnFile.read_integer_scope(p_scanner)); + } + else if (next_token == Keyword.PLANE_VIA_COSTS) + { + result.set_plane_via_costs(DsnFile.read_integer_scope(p_scanner)); + } + else if (next_token == Keyword.START_RIPUP_COSTS) + { + result.set_start_ripup_costs(DsnFile.read_integer_scope(p_scanner)); + } + else if (next_token == Keyword.START_PASS_NO) + { + result.set_pass_no(DsnFile.read_integer_scope(p_scanner)); + } + else if (next_token == Keyword.LAYER_RULE) + { + result = read_layer_rule(p_scanner, p_layer_structure, result); + if (result == null) + { + return null; + } + } + else + { + ScopeKeyword.skip_scope(p_scanner); + } + } + } + result.set_with_fanout(with_fanout); + result.set_with_autoroute(with_autoroute); + result.set_with_postroute(with_postroute); + return result; + } + + static interactive.AutorouteSettings read_layer_rule(Scanner p_scanner, LayerStructure p_layer_structure, + interactive.AutorouteSettings p_settings) + { + p_scanner.yybegin(SpecctraFileScanner.NAME); + Object next_token; + try + { + next_token = p_scanner.next_token(); + } catch (java.io.IOException e) + { + System.out.println("AutorouteSettings.read_layer_rule: IO error scanning file"); + return null; + } + if (!(next_token instanceof String)) + { + System.out.println("AutorouteSettings.read_layer_rule: String expected"); + return null; + } + int layer_no = p_layer_structure.get_no((String) next_token); + if (layer_no < 0) + { + System.out.println("AutorouteSettings.read_layer_rule: layer not found"); + return null; + } + for (;;) + { + Object prev_token = next_token; + try + { + next_token = p_scanner.next_token(); + } catch (java.io.IOException e) + { + System.out.println("AutorouteSettings.read_layer_rule: IO error scanning file"); + return null; + } + if (next_token == null) + { + System.out.println("AutorouteSettings.read_layer_rule: unexpected end of file"); + return null; + } + if (next_token == Keyword.CLOSED_BRACKET) + { + // end of scope + break; + } + if (prev_token == Keyword.OPEN_BRACKET) + { + if (next_token == Keyword.ACTIVE) + { + p_settings.set_layer_active(layer_no, DsnFile.read_on_off_scope(p_scanner)); + } + else if (next_token == Keyword.PREFERRED_DIRECTION) + { + try + { + boolean pref_dir_is_horizontal = true; + next_token = p_scanner.next_token(); + if (next_token == Keyword.VERTICAL) + { + pref_dir_is_horizontal = false; + } + else if (next_token != Keyword.HORIZONTAL) + { + System.out.println("AutorouteSettings.read_layer_rule: unexpected key word"); + return null; + } + p_settings.set_preferred_direction_is_horizontal(layer_no, pref_dir_is_horizontal); + next_token = p_scanner.next_token(); + if (next_token != Keyword.CLOSED_BRACKET) + { + System.out.println("AutorouteSettings.read_layer_rule: uclosing bracket expected"); + return null; + } + } catch (java.io.IOException e) + { + System.out.println("AutorouteSettings.read_layer_rule: IO error scanning file"); + return null; + } + } + else if (next_token == Keyword.PREFERRED_DIRECTION_TRACE_COSTS) + { + p_settings.set_preferred_direction_trace_costs(layer_no, DsnFile.read_float_scope(p_scanner)); + } + else if (next_token == Keyword.AGAINST_PREFERRED_DIRECTION_TRACE_COSTS) + { + p_settings.set_against_preferred_direction_trace_costs(layer_no, DsnFile.read_float_scope(p_scanner)); + } + else + { + ScopeKeyword.skip_scope(p_scanner); + } + } + } + return p_settings; + } + + static void write_scope(IndentFileWriter p_file, interactive.AutorouteSettings p_settings, + board.LayerStructure p_layer_structure, IdentifierType p_identifier_type) throws java.io.IOException + { + p_file.start_scope(); + p_file.write("autoroute_settings"); + p_file.new_line(); + p_file.write("(fanout "); + if (p_settings.get_with_fanout()) + { + p_file.write("on)"); + } + else + { + p_file.write("off)"); + } + p_file.new_line(); + p_file.write("(autoroute "); + if (p_settings.get_with_autoroute()) + { + p_file.write("on)"); + } + else + { + p_file.write("off)"); + } + p_file.new_line(); + p_file.write("(postroute "); + if (p_settings.get_with_postroute()) + { + p_file.write("on)"); + } + else + { + p_file.write("off)"); + } + p_file.new_line(); + p_file.write("(vias "); + if (p_settings.get_vias_allowed()) + { + p_file.write("on)"); + } + else + { + p_file.write("off)"); + } + p_file.new_line(); + p_file.write("(via_costs "); + { + Integer via_costs = p_settings.get_via_costs(); + p_file.write(via_costs.toString()); + } + p_file.write(")"); + p_file.new_line(); + p_file.write("(plane_via_costs "); + { + Integer via_costs = p_settings.get_plane_via_costs(); + p_file.write(via_costs.toString()); + } + p_file.write(")"); + p_file.new_line(); + p_file.write("(start_ripup_costs "); + { + Integer ripup_costs = p_settings.get_start_ripup_costs(); + p_file.write(ripup_costs.toString()); + } + p_file.write(")"); + p_file.new_line(); + p_file.write("(start_pass_no "); + { + Integer pass_no = p_settings.get_pass_no(); + p_file.write(pass_no.toString()); + } + p_file.write(")"); + for (int i = 0; i < p_layer_structure.arr.length; ++i) + { + board.Layer curr_layer = p_layer_structure.arr[i]; + p_file.start_scope(); + p_file.write("layer_rule "); + p_identifier_type.write(curr_layer.name, p_file); + p_file.new_line(); + p_file.write("(active "); + if (p_settings.get_layer_active(i)) + { + p_file.write("on)"); + } + else + { + p_file.write("off)"); + } + p_file.new_line(); + p_file.write("(preferred_direction "); + if (p_settings.get_preferred_direction_is_horizontal(i)) + { + p_file.write("horizontal)"); + } + else + { + p_file.write("vertical)"); + } + p_file.new_line(); + p_file.write("(preferred_direction_trace_costs "); + Float trace_costs = (float) p_settings.get_preferred_direction_trace_costs(i); + p_file.write(trace_costs.toString()); + p_file.write(")"); + p_file.new_line(); + p_file.write("(against_preferred_direction_trace_costs "); + trace_costs = (float) p_settings.get_against_preferred_direction_trace_costs(i); + p_file.write(trace_costs.toString()); + p_file.write(")"); + p_file.end_scope(); + } + p_file.end_scope(); + } +} diff --git a/designformats/specctra/Circle.java b/src/main/java/designformats/specctra/Circle.java similarity index 86% rename from designformats/specctra/Circle.java rename to src/main/java/designformats/specctra/Circle.java index 81c08e8..f4549bd 100644 --- a/designformats/specctra/Circle.java +++ b/src/main/java/designformats/specctra/Circle.java @@ -28,6 +28,7 @@ * Class for reading and writing circle scopes from dsn-files. * * @author alfons + * @version $Id: $Id */ public class Circle extends Shape { @@ -37,6 +38,9 @@ public class Circle extends Shape * p_coor [0] is the radius of the circle, * p_coor [1] is the x coordinate of the circle, * p_coor [2] is the y coordinate of the circle. + * + * @param p_layer a {@link designformats.specctra.Layer} object. + * @param p_coor an array of double. */ public Circle(Layer p_layer, double [] p_coor) { @@ -44,6 +48,14 @@ public Circle(Layer p_layer, double [] p_coor) coor = p_coor; } + /** + *

Constructor for Circle.

+ * + * @param p_layer a {@link designformats.specctra.Layer} object. + * @param p_radius a double. + * @param p_center_x a double. + * @param p_center_y a double. + */ public Circle(Layer p_layer, double p_radius, double p_center_x, double p_center_y) { super(p_layer); @@ -53,6 +65,7 @@ public Circle(Layer p_layer, double p_radius, double p_center_x, double p_center coor[2] = p_center_y; } + /** {@inheritDoc} */ public geometry.planar.Shape transform_to_board(CoordinateTransform p_coordinate_transform) { double [] location = new double[2]; @@ -63,6 +76,7 @@ public geometry.planar.Shape transform_to_board(CoordinateTransform p_coordinate return new geometry.planar.Circle(center, radius); } + /** {@inheritDoc} */ public geometry.planar.Shape transform_to_board_rel(CoordinateTransform p_coordinate_transform) { int [] new_coor = new int[3]; @@ -74,6 +88,11 @@ public geometry.planar.Shape transform_to_board_rel(CoordinateTransform p_coordi return new geometry.planar.Circle(new IntPoint(new_coor[1], new_coor[2]), new_coor[0]); } + /** + *

bounding_box.

+ * + * @return a {@link designformats.specctra.Rectangle} object. + */ public Rectangle bounding_box() { double[] bounds = new double[4]; @@ -84,6 +103,7 @@ public Rectangle bounding_box() return new Rectangle(layer, bounds); } + /** {@inheritDoc} */ public void write_scope(IndentFileWriter p_file, IdentifierType p_identifier_type) throws java.io.IOException { p_file.new_line(); @@ -97,6 +117,7 @@ public void write_scope(IndentFileWriter p_file, IdentifierType p_identifier_typ p_file.write(")"); } + /** {@inheritDoc} */ public void write_scope_int(IndentFileWriter p_file, IdentifierType p_identifier_type) throws java.io.IOException { p_file.new_line(); diff --git a/designformats/specctra/Circuit.java b/src/main/java/designformats/specctra/Circuit.java similarity index 96% rename from designformats/specctra/Circuit.java rename to src/main/java/designformats/specctra/Circuit.java index f2c126b..546373d 100644 --- a/designformats/specctra/Circuit.java +++ b/src/main/java/designformats/specctra/Circuit.java @@ -22,14 +22,19 @@ package designformats.specctra; /** + *

Circuit class.

* * @author Alfons Wirtz + * @version $Id: $Id */ public class Circuit { /** * Currently only the length matching rule is read from a circuit scope. * If the scope does not contain a length matching rule, nulll is returned. + * + * @param p_scanner a {@link designformats.specctra.Scanner} object. + * @return a {@link designformats.specctra.Circuit.ReadScopeResult} object. */ public static ReadScopeResult read_scope( Scanner p_scanner) { diff --git a/designformats/specctra/Component.java b/src/main/java/designformats/specctra/Component.java similarity index 96% rename from designformats/specctra/Component.java rename to src/main/java/designformats/specctra/Component.java index 7e35641..3b51527 100644 --- a/designformats/specctra/Component.java +++ b/src/main/java/designformats/specctra/Component.java @@ -25,17 +25,22 @@ * Handels the placement bata of a library component. * * @author alfons + * @version $Id: $Id */ public class Component extends ScopeKeyword { - /** Creates a new instance of Component */ + /** + * Creates a new instance of Component + */ public Component() { super("component"); } /** + * {@inheritDoc} + * * Overwrites the function read_scope in ScopeKeyword */ public boolean read_scope(ReadScopeParameter p_par) @@ -59,6 +64,10 @@ public boolean read_scope(ReadScopeParameter p_par) /** * Used also when reading a session file. + * + * @param p_scanner a {@link designformats.specctra.Scanner} object. + * @return a {@link designformats.specctra.ComponentPlacement} object. + * @throws java.io.IOException if any. */ public static ComponentPlacement read_scope(Scanner p_scanner) throws java.io.IOException { @@ -88,6 +97,13 @@ public static ComponentPlacement read_scope(Scanner p_scanner) throws java.io.IO return component_placement; } + /** + *

write_scope.

+ * + * @param p_par a {@link designformats.specctra.WriteScopeParameter} object. + * @param p_component a {@link board.Component} object. + * @throws java.io.IOException if any. + */ public static void write_scope(WriteScopeParameter p_par, board.Component p_component) throws java.io.IOException { diff --git a/designformats/specctra/ComponentPlacement.java b/src/main/java/designformats/specctra/ComponentPlacement.java similarity index 95% rename from designformats/specctra/ComponentPlacement.java rename to src/main/java/designformats/specctra/ComponentPlacement.java index 3633c2e..83ed3f0 100644 --- a/designformats/specctra/ComponentPlacement.java +++ b/src/main/java/designformats/specctra/ComponentPlacement.java @@ -28,11 +28,16 @@ * Describes the placement data of a library component * * @author alfons + * @version $Id: $Id */ public class ComponentPlacement { - /** Creates a new instance of ComponentPlacement */ + /** + * Creates a new instance of ComponentPlacement + * + * @param p_lib_name a {@link java.lang.String} object. + */ public ComponentPlacement(String p_lib_name) { lib_name = p_lib_name; diff --git a/designformats/specctra/CoordinateTransform.java b/src/main/java/designformats/specctra/CoordinateTransform.java similarity index 83% rename from designformats/specctra/CoordinateTransform.java rename to src/main/java/designformats/specctra/CoordinateTransform.java index 1c291e5..f62ee72 100644 --- a/designformats/specctra/CoordinateTransform.java +++ b/src/main/java/designformats/specctra/CoordinateTransform.java @@ -30,6 +30,7 @@ * Computes transformations between a specctra dsn-file coordinates and board coordinates. * * @author Alfons Wirtz + * @version $Id: $Id */ public class CoordinateTransform implements java.io.Serializable { @@ -38,6 +39,10 @@ public class CoordinateTransform implements java.io.Serializable * Creates a new instance of CoordinateTransform. * The base point of the dsn coordinate system will be translated to zero in the board * coordinate system. + * + * @param p_scale_factor a double. + * @param p_base_x a double. + * @param p_base_y a double. */ public CoordinateTransform(double p_scale_factor, double p_base_x, double p_base_y) { @@ -48,6 +53,9 @@ public CoordinateTransform(double p_scale_factor, double p_base_x, double p_base /** * Scale a value from the board to the dsn coordinate system + * + * @param p_val a double. + * @return a double. */ public double board_to_dsn(double p_val) { @@ -56,6 +64,9 @@ public double board_to_dsn(double p_val) /** * Scale a value from the dsn to the board coordinate system + * + * @param p_val a double. + * @return a double. */ public double dsn_to_board(double p_val) { @@ -65,6 +76,9 @@ public double dsn_to_board(double p_val) /** * Transforms a geometry.planar.FloatPoint to a tuple of doubles * in the dsn coordinate system. + * + * @param p_point a {@link geometry.planar.FloatPoint} object. + * @return an array of double. */ public double[] board_to_dsn(FloatPoint p_point) { @@ -77,6 +91,9 @@ public double[] board_to_dsn(FloatPoint p_point) /** * Transforms a geometry.planar.FloatPoint to a tuple of doubles * in the dsn coordinate system in relative (vector) coordinates. + * + * @param p_point a {@link geometry.planar.FloatPoint} object. + * @return an array of double. */ public double[] board_to_dsn_rel(FloatPoint p_point) { @@ -89,6 +106,9 @@ public double[] board_to_dsn_rel(FloatPoint p_point) /** * Transforms an array of n geometry.planar.FloatPoints to * an array of 2*n doubles in the dsn coordinate system. + * + * @param p_points an array of {@link geometry.planar.FloatPoint} objects. + * @return an array of double. */ public double [] board_to_dsn(FloatPoint [] p_points) { @@ -104,6 +124,9 @@ public double[] board_to_dsn_rel(FloatPoint p_point) /** * Transforms an array of n geometry.planar.Lines to * an array of 4*n doubles in the dsn coordinate system. + * + * @param p_lines an array of {@link geometry.planar.Line} objects. + * @return an array of double. */ public double [] board_to_dsn(Line [] p_lines) { @@ -123,6 +146,9 @@ public double[] board_to_dsn_rel(FloatPoint p_point) /** * Transforms an array of n geometry.planar.FloatPoints to * an array of 2*n doubles in the dsn coordinate system in relative (vector) coordinates. + * + * @param p_points an array of {@link geometry.planar.FloatPoint} objects. + * @return an array of double. */ public double [] board_to_dsn_rel(FloatPoint [] p_points) { @@ -138,6 +164,9 @@ public double[] board_to_dsn_rel(FloatPoint p_point) /** * Transforms a geometry.planar.Vector to a tuple of doubles * in the dsn coordinate system. + * + * @param p_vector a {@link geometry.planar.Vector} object. + * @return an array of double. */ public double[] board_to_dsn(Vector p_vector) { @@ -150,6 +179,9 @@ public double[] board_to_dsn(Vector p_vector) /** * Transforms a dsn tuple to a geometry.planar.FloatPoint + * + * @param p_tuple an array of double. + * @return a {@link geometry.planar.FloatPoint} object. */ public FloatPoint dsn_to_board(double [] p_tuple) { @@ -160,6 +192,9 @@ public FloatPoint dsn_to_board(double [] p_tuple) /** * Transforms a dsn tuple to a geometry.planar.FloatPoint in relative (vector) coordinates. + * + * @param p_tuple an array of double. + * @return a {@link geometry.planar.FloatPoint} object. */ public FloatPoint dsn_to_board_rel(double [] p_tuple) { @@ -170,6 +205,9 @@ public FloatPoint dsn_to_board_rel(double [] p_tuple) /** * Transforms a geometry.planar.Intbox to the coordinates of a Rectangle. + * + * @param p_box a {@link geometry.planar.IntBox} object. + * @return an array of double. */ public double [] board_to_dsn(IntBox p_box) { @@ -183,6 +221,9 @@ public FloatPoint dsn_to_board_rel(double [] p_tuple) /** * Transforms a geometry.planar.Intbox to a Rectangle in relative (vector) coordinates. + * + * @param p_box a {@link geometry.planar.IntBox} object. + * @return an array of double. */ public double [] board_to_dsn_rel(IntBox p_box) { @@ -196,6 +237,10 @@ public FloatPoint dsn_to_board_rel(double [] p_tuple) /** * Transforms a board shape to a dsn shape. + * + * @param p_board_shape a {@link geometry.planar.Shape} object. + * @param p_layer a {@link designformats.specctra.Layer} object. + * @return a {@link designformats.specctra.Shape} object. */ public Shape board_to_dsn(geometry.planar.Shape p_board_shape, Layer p_layer) { @@ -227,6 +272,10 @@ else if (p_board_shape instanceof geometry.planar.Circle) /** * Transforms the relative (vector) coordinates of a geometry.planar.Shape to a specctra dsn shape. + * + * @param p_board_shape a {@link geometry.planar.Shape} object. + * @param p_layer a {@link designformats.specctra.Layer} object. + * @return a {@link designformats.specctra.Shape} object. */ public Shape board_to_dsn_rel(geometry.planar.Shape p_board_shape, Layer p_layer) { diff --git a/designformats/specctra/DsnFile.java b/src/main/java/designformats/specctra/DsnFile.java similarity index 93% rename from designformats/specctra/DsnFile.java rename to src/main/java/designformats/specctra/DsnFile.java index 70009fa..2249855 100644 --- a/designformats/specctra/DsnFile.java +++ b/src/main/java/designformats/specctra/DsnFile.java @@ -28,6 +28,7 @@ * Class for reading and writing dsn-files. * * @author alfons + * @version $Id: $Id */ public class DsnFile { @@ -43,6 +44,13 @@ public enum ReadResult * The parameters p_item_observers and p_item_id_no_generator are used, * in case the board is embedded into a host system. * Returns false, if an error occured. + * + * @param p_input_stream a {@link java.io.InputStream} object. + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_observers a {@link board.BoardObservers} object. + * @param p_item_id_no_generator a {@link datastructures.IdNoGenerator} object. + * @param p_test_level a {@link board.TestLevel} object. + * @return a {@link designformats.specctra.DsnFile.ReadResult} object. */ public static ReadResult read(java.io.InputStream p_input_stream, interactive.BoardHandling p_board_handling, board.BoardObservers p_observers, datastructures.IdNoGenerator p_item_id_no_generator, TestLevel p_test_level) @@ -226,6 +234,12 @@ else if (autoroute_settings.get_layer_active(i)) * Returns false, if the write failed. * If p_compat_mode is true, only standard speecctra dsn scopes are written, so that any * host system with an specctra interface can read them. + * + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_file a {@link java.io.OutputStream} object. + * @param p_design_name a {@link java.lang.String} object. + * @param p_compat_mode a boolean. + * @return a boolean. */ public static boolean write(interactive.BoardHandling p_board_handling, java.io.OutputStream p_file, String p_design_name, boolean p_compat_mode) { @@ -370,6 +384,12 @@ else if (next_token instanceof Integer) } } + /** + *

read_string_scope.

+ * + * @param p_scanner a {@link designformats.specctra.Scanner} object. + * @return a {@link java.lang.String} object. + */ public static String read_string_scope(Scanner p_scanner) { try @@ -396,6 +416,12 @@ public static String read_string_scope(Scanner p_scanner) } } + /** + *

read_string_list_scope.

+ * + * @param p_scanner a {@link designformats.specctra.Scanner} object. + * @return a {@link java.util.Collection} object. + */ public static java.util.Collection read_string_list_scope(Scanner p_scanner) { java.util.Collection result = new java.util.LinkedList(); diff --git a/designformats/specctra/Keyword.java b/src/main/java/designformats/specctra/Keyword.java similarity index 64% rename from designformats/specctra/Keyword.java rename to src/main/java/designformats/specctra/Keyword.java index 52da218..85816dd 100644 --- a/designformats/specctra/Keyword.java +++ b/src/main/java/designformats/specctra/Keyword.java @@ -23,6 +23,7 @@ * Enumeration class for keywords of the specctra dsn file format * * @author alfons + * @version $Id: $Id */ public class Keyword { @@ -33,113 +34,218 @@ public class Keyword * ScopeKeywords with an inividual read_scope method are defined in an extra class, */ public static final Keyword ABSOLUTE = new Keyword("absolute"); + /** Constant ACTIVE */ public static final Keyword ACTIVE = new Keyword("active"); + /** Constant AGAINST_PREFERRED_DIRECTION_TRACE_COSTS */ public static final Keyword AGAINST_PREFERRED_DIRECTION_TRACE_COSTS = new Keyword("against_preferred_direction_trace_costs"); + /** Constant ATTACH */ public static final Keyword ATTACH = new Keyword("attach"); + /** Constant AUTOROUTE */ public static final Keyword AUTOROUTE = new Keyword("autoroute"); + /** Constant AUTOROUTE_SETTINGS */ public static final Keyword AUTOROUTE_SETTINGS = new Keyword("autoroute_settings"); + /** Constant BACK */ public static final Keyword BACK = new Keyword("back"); + /** Constant BOUNDARY */ public static final Keyword BOUNDARY = new Keyword("boundary"); + /** Constant CIRCUIT */ public static final Keyword CIRCUIT = new Keyword("circuit"); + /** Constant CIRCLE */ public static final Keyword CIRCLE = new Keyword("circle"); + /** Constant CLASS */ public static final Keyword CLASS = new Keyword("class"); + /** Constant CLASS_CLASS */ public static final Keyword CLASS_CLASS = new Keyword("class_class"); + /** Constant CLASSES */ public static final Keyword CLASSES = new Keyword("classes"); + /** Constant COMPONENT_SCOPE */ public static final ScopeKeyword COMPONENT_SCOPE = new Component(); + /** Constant CONSTANT */ public static final Keyword CONSTANT = new Keyword("constant"); + /** Constant CONTROL */ public static final Keyword CONTROL = new Keyword("control"); + /** Constant CLEARANCE */ public static final Keyword CLEARANCE = new Keyword("clearance"); + /** Constant CLEARANCE_CLASS */ public static final Keyword CLEARANCE_CLASS = new Keyword("clearance_class"); + /** Constant CLOSED_BRACKET */ public static final Keyword CLOSED_BRACKET = new Keyword(")"); + /** Constant FANOUT */ public static final Keyword FANOUT = new Keyword("fanout"); + /** Constant FLIP_STYLE */ public static final Keyword FLIP_STYLE = new Keyword("flip_style"); + /** Constant FIX */ public static final Keyword FIX = new Keyword("fix"); + /** Constant FORTYFIVE_DEGREE */ public static final Keyword FORTYFIVE_DEGREE = new Keyword("fortyfive_degree"); + /** Constant FROMTO */ public static final Keyword FROMTO = new Keyword("fromto"); + /** Constant FRONT */ public static final Keyword FRONT = new Keyword("front"); + /** Constant GENERATED_BY_FREEROUTE */ public static final Keyword GENERATED_BY_FREEROUTE = new Keyword("generated_by_freeroute"); + /** Constant HORIZONTAL */ public static final Keyword HORIZONTAL = new Keyword("horizontal"); + /** Constant HOST_CAD */ public static final Keyword HOST_CAD = new Keyword("host_cad"); + /** Constant HOST_VERSION */ public static final Keyword HOST_VERSION = new Keyword("host_version"); + /** Constant IMAGE */ public static final Keyword IMAGE = new Keyword("image"); + /** Constant KEEPOUT */ public static final Keyword KEEPOUT = new Keyword("keepout"); + /** Constant LAYER */ public static final Keyword LAYER = new Keyword("layer"); + /** Constant LAYER_RULE */ public static final Keyword LAYER_RULE = new Keyword("layer_rule"); + /** Constant LENGTH */ public static final Keyword LENGTH = new Keyword("length"); + /** Constant LIBRARY_SCOPE */ public static final ScopeKeyword LIBRARY_SCOPE = new Library(); + /** Constant LOCK_TYPE */ public static final Keyword LOCK_TYPE = new Keyword("lock_type"); + /** Constant LOGICAL_PART */ public static final Keyword LOGICAL_PART = new Keyword("logical_part"); + /** Constant LOGICAL_PART_MAPPING */ public static final Keyword LOGICAL_PART_MAPPING = new Keyword("logical_part_mapping"); + /** Constant NET */ public static final Keyword NET = new Keyword("net"); + /** Constant NETWORK_OUT */ public static final Keyword NETWORK_OUT = new Keyword("network_out"); + /** Constant NETWORK_SCOPE */ public static final ScopeKeyword NETWORK_SCOPE = new Network(); + /** Constant NINETY_DEGREE */ public static final Keyword NINETY_DEGREE = new Keyword("ninety_degree"); + /** Constant NONE */ public static final Keyword NONE = new Keyword("none"); + /** Constant NORMAL */ public static final Keyword NORMAL = new Keyword("normal"); + /** Constant OFF */ public static final Keyword OFF = new Keyword("off"); + /** Constant ON */ public static final Keyword ON = new Keyword("on"); + /** Constant OPEN_BRACKET */ public static final Keyword OPEN_BRACKET = new Keyword("("); + /** Constant ORDER */ public static final Keyword ORDER = new Keyword("order"); + /** Constant OUTLINE */ public static final Keyword OUTLINE = new Keyword("outline"); + /** Constant PADSTACK */ public static final Keyword PADSTACK = new Keyword("padstack"); + /** Constant PART_LIBRARY_SCOPE */ public static final ScopeKeyword PART_LIBRARY_SCOPE = new PartLibrary(); + /** Constant PARSER_SCOPE */ public static final ScopeKeyword PARSER_SCOPE = new Parser(); + /** Constant PCB_SCOPE */ public static final ScopeKeyword PCB_SCOPE = new ScopeKeyword("pcb"); + /** Constant PIN */ public static final Keyword PIN = new Keyword("pin"); + /** Constant PINS */ public static final Keyword PINS = new Keyword("pins"); + /** Constant PLACE */ public static final Keyword PLACE = new Keyword("place"); + /** Constant PLACE_CONTROL */ public static final ScopeKeyword PLACE_CONTROL = new PlaceControl(); + /** Constant PLACE_KEEPOUT */ public static final Keyword PLACE_KEEPOUT = new Keyword("place_keepout"); + /** Constant PLACEMENT_SCOPE */ public static final ScopeKeyword PLACEMENT_SCOPE = new Placement(); + /** Constant PLANE_SCOPE */ public static final ScopeKeyword PLANE_SCOPE = new Plane(); + /** Constant PLANE_VIA_COSTS */ public static final Keyword PLANE_VIA_COSTS = new Keyword("plane_via_costs"); + /** Constant PREFERRED_DIRECTION */ public static final Keyword PREFERRED_DIRECTION = new Keyword("preferred_direction"); + /** Constant PREFERRED_DIRECTION_TRACE_COSTS */ public static final Keyword PREFERRED_DIRECTION_TRACE_COSTS = new Keyword("preferred_direction_trace_costs"); + /** Constant SNAP_ANGLE */ public static final Keyword SNAP_ANGLE = new Keyword("snap_angle"); + /** Constant POLYGON */ public static final Keyword POLYGON = new Keyword("polygon"); + /** Constant POLYGON_PATH */ public static final Keyword POLYGON_PATH = new Keyword("polygon_path"); + /** Constant POLYLINE_PATH */ public static final Keyword POLYLINE_PATH = new Keyword("polyline_path"); + /** Constant POSITION */ public static final Keyword POSITION = new Keyword("position"); + /** Constant POSTROUTE */ public static final Keyword POSTROUTE = new Keyword("postroute"); + /** Constant POWER */ public static final Keyword POWER = new Keyword("power"); + /** Constant PULL_TIGHT */ public static final Keyword PULL_TIGHT = new Keyword("pull_tight"); + /** Constant RECTANGLE */ public static final Keyword RECTANGLE = new Keyword("rectangle"); + /** Constant RESOLUTION_SCOPE */ public static final Keyword RESOLUTION_SCOPE = new Resolution(); + /** Constant ROTATE */ public static final Keyword ROTATE = new Keyword("rotate"); + /** Constant ROTATE_FIRST */ public static final Keyword ROTATE_FIRST = new Keyword("rotate_first"); + /** Constant ROUTES */ public static final Keyword ROUTES = new Keyword("routes"); + /** Constant RULE */ public static final Keyword RULE = new Keyword("rule"); + /** Constant RULES */ public static final Keyword RULES = new Keyword("rules"); + /** Constant SESSION */ public static final Keyword SESSION = new Keyword("session"); + /** Constant SHAPE */ public static final Keyword SHAPE = new Keyword("shape"); + /** Constant SHOVE_FIXED */ public static final Keyword SHOVE_FIXED = new Keyword("shove_fixed"); + /** Constant SIDE */ public static final Keyword SIDE = new Keyword("side"); + /** Constant SIGNAL */ public static final Keyword SIGNAL = new Keyword("signal"); + /** Constant SPARE */ public static final Keyword SPARE = new Keyword("spare"); + /** Constant START_PASS_NO */ public static final Keyword START_PASS_NO = new Keyword("start_pass_no"); + /** Constant START_RIPUP_COSTS */ public static final Keyword START_RIPUP_COSTS = new Keyword("start_ripup_costs"); + /** Constant STRING_QUOTE */ public static final Keyword STRING_QUOTE = new Keyword("string_quote"); + /** Constant STRUCTURE_SCOPE */ public static final ScopeKeyword STRUCTURE_SCOPE = new Structure(); + /** Constant TYPE */ public static final Keyword TYPE = new Keyword("type"); + /** Constant USE_LAYER */ public static final Keyword USE_LAYER = new Keyword("use_layer"); + /** Constant USE_NET */ public static final Keyword USE_NET = new Keyword("use_net"); + /** Constant USE_VIA */ public static final Keyword USE_VIA = new Keyword("use_via"); + /** Constant VERTICAL */ public static final Keyword VERTICAL = new Keyword("vertical"); + /** Constant VIA */ public static final Keyword VIA = new Keyword("via"); + /** Constant VIAS */ public static final Keyword VIAS = new Keyword("vias"); + /** Constant VIA_AT_SMD */ public static final Keyword VIA_AT_SMD = new Keyword("via_at_smd"); + /** Constant VIA_COSTS */ public static final Keyword VIA_COSTS = new Keyword("via_costs"); + /** Constant VIA_KEEPOUT */ public static final Keyword VIA_KEEPOUT = new Keyword("via_keepout"); + /** Constant VIA_RULE */ public static final Keyword VIA_RULE = new Keyword("via_rule"); + /** Constant WIDTH */ public static final Keyword WIDTH = new Keyword("width"); + /** Constant WINDOW */ public static final Keyword WINDOW = new Keyword("window"); + /** Constant WIRE */ public static final Keyword WIRE = new Keyword("wire"); + /** Constant WIRING_SCOPE */ public static final ScopeKeyword WIRING_SCOPE = new Wiring(); + /** Constant WRITE_RESOLUTION */ public static final Keyword WRITE_RESOLUTION = new Keyword("write_resolution"); /** * Returns the name string of this Keyword. * The name is used for debugging purposes. + * + * @return a {@link java.lang.String} object. */ public String get_name() { @@ -147,7 +253,11 @@ public String get_name() } private final String name; - /** prevents creating more instances */ + /** + * prevents creating more instances + * + * @param p_name a {@link java.lang.String} object. + */ protected Keyword(String p_name) { name = p_name; diff --git a/designformats/specctra/Layer.java b/src/main/java/designformats/specctra/Layer.java similarity index 85% rename from designformats/specctra/Layer.java rename to src/main/java/designformats/specctra/Layer.java index 45658f2..3cded8e 100644 --- a/designformats/specctra/Layer.java +++ b/src/main/java/designformats/specctra/Layer.java @@ -28,6 +28,7 @@ * Describes a layer in a Specctra dsn file. * * @author alfons + * @version $Id: $Id */ public class Layer { @@ -43,6 +44,11 @@ public class Layer * If p_is_signal, the layer is a signal layer, otherwise it is a powerground layer. * For Layer objects describing more than 1 layer the number is -1. * p_net_names is a list of nets for this layer, if the layer is a power plane. + * + * @param p_name a {@link java.lang.String} object. + * @param p_no a int. + * @param p_is_signal a boolean. + * @param p_net_names a {@link java.util.Collection} object. */ public Layer(String p_name, int p_no, boolean p_is_signal, Collection p_net_names) { @@ -58,6 +64,10 @@ public Layer(String p_name, int p_no, boolean p_is_signal, Collection p_ * and ending at the solder side. * If p_is_signal, the layer is a signal layer, otherwise it is a powerground layer. * For Layer objects describing more than 1 layer the number is -1. + * + * @param p_name a {@link java.lang.String} object. + * @param p_no a int. + * @param p_is_signal a boolean. */ public Layer(String p_name, int p_no, boolean p_is_signal) { @@ -69,6 +79,11 @@ public Layer(String p_name, int p_no, boolean p_is_signal) /** * Writes a layer scope in the stucture scope. + * + * @param p_par a {@link designformats.specctra.WriteScopeParameter} object. + * @param p_layer_no a int. + * @param p_write_rule a boolean. + * @throws java.io.IOException if any. */ public static void write_scope(WriteScopeParameter p_par, int p_layer_no, boolean p_write_rule) throws java.io.IOException diff --git a/designformats/specctra/LayerStructure.java b/src/main/java/designformats/specctra/LayerStructure.java similarity index 84% rename from designformats/specctra/LayerStructure.java rename to src/main/java/designformats/specctra/LayerStructure.java index 202bb81..6af52f7 100644 --- a/designformats/specctra/LayerStructure.java +++ b/src/main/java/designformats/specctra/LayerStructure.java @@ -26,11 +26,16 @@ * Describes a layer structure read from a dsn file. * * @author alfons + * @version $Id: $Id */ public class LayerStructure { - /** Creates a new instance of LayerStructure from a list of layers*/ + /** + * Creates a new instance of LayerStructure from a list of layers + * + * @param p_layer_list a {@link java.util.Collection} object. + */ public LayerStructure(Collection p_layer_list) { arr = new Layer[p_layer_list.size()]; @@ -43,6 +48,8 @@ public LayerStructure(Collection p_layer_list) /** * Creates a dsn-LayerStructure from a board LayerStructure. + * + * @param p_board_layer_structure a {@link board.LayerStructure} object. */ public LayerStructure(board.LayerStructure p_board_layer_structure) { @@ -57,6 +64,9 @@ public LayerStructure(board.LayerStructure p_board_layer_structure) /** * returns the number of the layer with the name p_name, * -1, if no layer with name p_name exists. + * + * @param p_name a {@link java.lang.String} object. + * @return a int. */ public int get_no(String p_name) { @@ -79,6 +89,11 @@ public int get_no(String p_name) return -1; } + /** + *

signal_layer_count.

+ * + * @return a int. + */ public int signal_layer_count() { int result = 0; @@ -94,6 +109,9 @@ public int signal_layer_count() /** * Returns, if the net with name p_net_name contains a powwer plane. + * + * @param p_net_name a {@link java.lang.String} object. + * @return a boolean. */ public boolean contains_plane(String p_net_name) { diff --git a/designformats/specctra/Library.java b/src/main/java/designformats/specctra/Library.java similarity index 97% rename from designformats/specctra/Library.java rename to src/main/java/designformats/specctra/Library.java index 5ad97c5..553317c 100644 --- a/designformats/specctra/Library.java +++ b/src/main/java/designformats/specctra/Library.java @@ -34,16 +34,20 @@ * Class for reading and writing library scopes from dsn-files. * * @author Alfons Wirtz + * @version $Id: $Id */ public class Library extends ScopeKeyword { - /** Creates a new instance of Library */ + /** + * Creates a new instance of Library + */ public Library() { super("library"); } + /** {@inheritDoc} */ public boolean read_scope(ReadScopeParameter p_par) { board.RoutingBoard board = p_par.board_handling.get_routing_board(); @@ -203,6 +207,12 @@ else if (next_token == Keyword.IMAGE) return true; } + /** + *

write_scope.

+ * + * @param p_par a {@link designformats.specctra.WriteScopeParameter} object. + * @throws java.io.IOException if any. + */ public static void write_scope(WriteScopeParameter p_par) throws java.io.IOException { p_par.file.start_scope(); @@ -218,6 +228,13 @@ public static void write_scope(WriteScopeParameter p_par) throws java.io.IOExcep p_par.file.end_scope(); } + /** + *

write_padstack_scope.

+ * + * @param p_par a {@link designformats.specctra.WriteScopeParameter} object. + * @param p_padstack a {@link library.Padstack} object. + * @throws java.io.IOException if any. + */ public static void write_padstack_scope(WriteScopeParameter p_par, library.Padstack p_padstack) throws java.io.IOException { // search the layer range of the padstack diff --git a/designformats/specctra/Net.java b/src/main/java/designformats/specctra/Net.java similarity index 80% rename from designformats/specctra/Net.java rename to src/main/java/designformats/specctra/Net.java index 8ea45af..623d35b 100644 --- a/designformats/specctra/Net.java +++ b/src/main/java/designformats/specctra/Net.java @@ -33,16 +33,29 @@ * Class for reading and writing net scopes from dsn-files. * * @author alfons + * @version $Id: $Id */ public class Net { - /** Creates a new instance of Net */ + /** + * Creates a new instance of Net + * + * @param p_net_id a {@link designformats.specctra.Net.Id} object. + */ public Net(Id p_net_id) { id = p_net_id; } + /** + *

write_scope.

+ * + * @param p_par a {@link designformats.specctra.WriteScopeParameter} object. + * @param p_net a {@link rules.Net} object. + * @param p_pin_list a {@link java.util.Collection} object. + * @throws java.io.IOException if any. + */ public static void write_scope(WriteScopeParameter p_par, rules.Net p_net, Collection p_pin_list) throws java.io.IOException { p_par.file.start_scope(); @@ -63,6 +76,14 @@ public static void write_scope(WriteScopeParameter p_par, rules.Net p_net, Colle p_par.file.end_scope(); } + /** + *

write_net_id.

+ * + * @param p_net a {@link rules.Net} object. + * @param p_file a {@link datastructures.IndentFileWriter} object. + * @param p_identifier_type a {@link datastructures.IdentifierType} object. + * @throws java.io.IOException if any. + */ public static void write_net_id( rules.Net p_net, IndentFileWriter p_file, IdentifierType p_identifier_type) throws java.io.IOException { p_file.write("net "); @@ -72,6 +93,13 @@ public static void write_net_id( rules.Net p_net, IndentFileWriter p_file, Ident p_file.write(subnet_number.toString()); } + /** + *

write_pin.

+ * + * @param p_par a {@link designformats.specctra.WriteScopeParameter} object. + * @param p_pin a {@link board.Pin} object. + * @throws java.io.IOException if any. + */ public static void write_pin(WriteScopeParameter p_par, board.Pin p_pin) throws java.io.IOException { board.Component curr_component = p_par.board.components.get(p_pin.get_component_no()); @@ -93,6 +121,11 @@ public static void write_pin(WriteScopeParameter p_par, board.Pin p_pin) throws } + /** + *

set_pins.

+ * + * @param p_pin_list a {@link java.util.Collection} object. + */ public void set_pins(Collection p_pin_list) { pin_list = new TreeSet(); @@ -102,6 +135,11 @@ public void set_pins(Collection p_pin_list) } } + /** + *

get_pins.

+ * + * @return a {@link java.util.Set} object. + */ public Set get_pins() { return pin_list; @@ -159,4 +197,4 @@ public int compareTo(Pin p_other) public final String component_name; public final String pin_name; } -} \ No newline at end of file +} diff --git a/designformats/specctra/NetClass.java b/src/main/java/designformats/specctra/NetClass.java similarity index 89% rename from designformats/specctra/NetClass.java rename to src/main/java/designformats/specctra/NetClass.java index 2f58819..c5c13d9 100644 --- a/designformats/specctra/NetClass.java +++ b/src/main/java/designformats/specctra/NetClass.java @@ -27,10 +27,17 @@ * Contains the information of a Specctra Class scope. * * @author alfons + * @version $Id: $Id */ public class NetClass { + /** + *

read_scope.

+ * + * @param p_scanner a {@link designformats.specctra.Scanner} object. + * @return a {@link designformats.specctra.NetClass} object. + */ public static NetClass read_scope(Scanner p_scanner) { @@ -153,6 +160,12 @@ else if (next_token == Keyword.PULL_TIGHT) } } + /** + *

read_class_class_scope.

+ * + * @param p_scanner a {@link designformats.specctra.Scanner} object. + * @return a {@link designformats.specctra.NetClass.ClassClass} object. + */ public static ClassClass read_class_class_scope(Scanner p_scanner) { try @@ -200,7 +213,22 @@ else if (next_token == Keyword.LAYER_RULE) } } - /** Creates a new instance of NetClass */ + /** + * Creates a new instance of NetClass + * + * @param p_name a {@link java.lang.String} object. + * @param p_trace_clearance_class a {@link java.lang.String} object. + * @param p_net_list a {@link java.util.Collection} object. + * @param p_rules a {@link java.util.Collection} object. + * @param p_layer_rules a {@link java.util.Collection} object. + * @param p_use_via a {@link java.util.Collection} object. + * @param p_use_layer a {@link java.util.Collection} object. + * @param p_via_rule a {@link java.lang.String} object. + * @param p_shove_fixed a boolean. + * @param p_pull_tight a boolean. + * @param p_min_trace_length a double. + * @param p_max_trace_length a double. + */ public NetClass(String p_name, String p_trace_clearance_class, Collection p_net_list, Collection p_rules, Collection p_layer_rules, Collection p_use_via, Collection p_use_layer, String p_via_rule, boolean p_shove_fixed, boolean p_pull_tight, diff --git a/designformats/specctra/NetList.java b/src/main/java/designformats/specctra/NetList.java similarity index 82% rename from designformats/specctra/NetList.java rename to src/main/java/designformats/specctra/NetList.java index 7da2471..86f6a2a 100644 --- a/designformats/specctra/NetList.java +++ b/src/main/java/designformats/specctra/NetList.java @@ -31,12 +31,16 @@ * The net number is generated internally. * * @author alfons + * @version $Id: $Id */ public class NetList { /** * Returns true, if the netlist contains a net with the input name. + * + * @param p_net_id a {@link designformats.specctra.Net.Id} object. + * @return a boolean. */ public boolean contains(Net.Id p_net_id) { @@ -47,6 +51,9 @@ public boolean contains(Net.Id p_net_id) * Adds a new net mit the input name to the net list. * Returns null, if a net with p_name already exists in the net list. * In this case no new net is added. + * + * @param p_net_id a {@link designformats.specctra.Net.Id} object. + * @return a {@link designformats.specctra.Net} object. */ public Net add_net(Net.Id p_net_id) { @@ -66,6 +73,9 @@ public Net add_net(Net.Id p_net_id) /** * Returns the net with the input name, or null, * if the netlist does not contain a net with the input name. + * + * @param p_net_id a {@link designformats.specctra.Net.Id} object. + * @return a {@link designformats.specctra.Net} object. */ public Net get_net(Net.Id p_net_id) { @@ -75,6 +85,10 @@ public Net get_net(Net.Id p_net_id) /** * Returns all nets in this net list containing the input pin. + * + * @param p_component_name a {@link java.lang.String} object. + * @param p_pin_name a {@link java.lang.String} object. + * @return a {@link java.util.Collection} object. */ public Collection get_nets(String p_component_name, String p_pin_name) { diff --git a/designformats/specctra/Network.java b/src/main/java/designformats/specctra/Network.java similarity index 97% rename from designformats/specctra/Network.java rename to src/main/java/designformats/specctra/Network.java index 042c6b1..cb655b9 100644 --- a/designformats/specctra/Network.java +++ b/src/main/java/designformats/specctra/Network.java @@ -39,16 +39,20 @@ * Class for reading and writing net network from dsn-files. * * @author Alfons Wirtz + * @version $Id: $Id */ public class Network extends ScopeKeyword { - /** Creates a new instance of Network */ + /** + * Creates a new instance of Network + */ public Network() { super("network"); } + /** {@inheritDoc} */ public boolean read_scope(ReadScopeParameter p_par) { Collection classes = new LinkedList(); @@ -136,6 +140,12 @@ else if (next_token == Keyword.CLASS_CLASS) return true; } + /** + *

write_scope.

+ * + * @param p_par a {@link designformats.specctra.WriteScopeParameter} object. + * @throws java.io.IOException if any. + */ public static void write_scope(WriteScopeParameter p_par) throws java.io.IOException { p_par.file.start_scope(); @@ -151,6 +161,14 @@ public static void write_scope(WriteScopeParameter p_par) throws java.io.IOExcep p_par.file.end_scope(); } + /** + *

write_via_infos.

+ * + * @param p_rules a rules$BoardRules object. + * @param p_file a {@link datastructures.IndentFileWriter} object. + * @param p_identifier_type a {@link datastructures.IdentifierType} object. + * @throws java.io.IOException if any. + */ public static void write_via_infos(rules.BoardRules p_rules, IndentFileWriter p_file, IdentifierType p_identifier_type) throws java.io.IOException { @@ -173,6 +191,14 @@ public static void write_via_infos(rules.BoardRules p_rules, IndentFileWriter p_ } } + /** + *

write_via_rules.

+ * + * @param p_rules a rules$BoardRules object. + * @param p_file a {@link datastructures.IndentFileWriter} object. + * @param p_identifier_type a {@link datastructures.IdentifierType} object. + * @throws java.io.IOException if any. + */ public static void write_via_rules(rules.BoardRules p_rules, IndentFileWriter p_file, IdentifierType p_identifier_type) throws java.io.IOException { @@ -191,6 +217,12 @@ public static void write_via_rules(rules.BoardRules p_rules, IndentFileWriter p_ } } + /** + *

write_net_classes.

+ * + * @param p_par a {@link designformats.specctra.WriteScopeParameter} object. + * @throws java.io.IOException if any. + */ public static void write_net_classes(WriteScopeParameter p_par) throws java.io.IOException { @@ -200,6 +232,13 @@ public static void write_net_classes(WriteScopeParameter p_par) } } + /** + *

write_net_class.

+ * + * @param p_net_class a {@link rules.NetClass} object. + * @param p_par a {@link designformats.specctra.WriteScopeParameter} object. + * @throws java.io.IOException if any. + */ public static void write_net_class(rules.NetClass p_net_class, WriteScopeParameter p_par) throws java.io.IOException { diff --git a/designformats/specctra/Package.java b/src/main/java/designformats/specctra/Package.java similarity index 94% rename from designformats/specctra/Package.java rename to src/main/java/designformats/specctra/Package.java index 6347cac..d6f9e03 100644 --- a/designformats/specctra/Package.java +++ b/src/main/java/designformats/specctra/Package.java @@ -30,11 +30,22 @@ * Class for reading and writing package scopes from dsn-files. * * @author alfons + * @version $Id: $Id */ public class Package { - /** Creates a new instance of Package */ + /** + * Creates a new instance of Package + * + * @param p_name a {@link java.lang.String} object. + * @param p_pin_info_arr an array of {@link designformats.specctra.Package.PinInfo} objects. + * @param p_outline a java$util$Collection object. + * @param p_keepouts a java$util$Collection object. + * @param p_via_keepouts a java$util$Collection object. + * @param p_place_keepouts a java$util$Collection object. + * @param p_is_front a boolean. + */ public Package(String p_name, PinInfo[] p_pin_info_arr, Collection p_outline, Collection p_keepouts, Collection p_via_keepouts, Collection p_place_keepouts, boolean p_is_front) { @@ -47,6 +58,13 @@ public Package(String p_name, PinInfo[] p_pin_info_arr, Collection p_outl is_front = p_is_front; } + /** + *

read_scope.

+ * + * @param p_scanner a {@link designformats.specctra.Scanner} object. + * @param p_layer_structure a {@link designformats.specctra.LayerStructure} object. + * @return a {@link designformats.specctra.Package} object. + */ public static Package read_scope(Scanner p_scanner, LayerStructure p_layer_structure) { try @@ -155,6 +173,13 @@ else if (next_token == Keyword.PLACE_KEEPOUT) } } + /** + *

write_scope.

+ * + * @param p_par a {@link designformats.specctra.WriteScopeParameter} object. + * @param p_package a {@link library.Package} object. + * @throws java.io.IOException if any. + */ public static void write_scope(WriteScopeParameter p_par, library.Package p_package) throws java.io.IOException { p_par.file.start_scope(); @@ -410,6 +435,10 @@ else if (next_token instanceof Double) /** * Writes the placements of p_package to a Specctra dsn-file. + * + * @param p_par a {@link designformats.specctra.WriteScopeParameter} object. + * @param p_package a {@link library.Package} object. + * @throws java.io.IOException if any. */ public static void write_placement_scope(WriteScopeParameter p_par, library.Package p_package) throws java.io.IOException diff --git a/designformats/specctra/Parser.java b/src/main/java/designformats/specctra/Parser.java similarity index 95% rename from designformats/specctra/Parser.java rename to src/main/java/designformats/specctra/Parser.java index dffc2dc..fe959eb 100644 --- a/designformats/specctra/Parser.java +++ b/src/main/java/designformats/specctra/Parser.java @@ -25,16 +25,20 @@ * Class for reading and writing parser scopes from dsn-files. * * @author Alfons Wirtz + * @version $Id: $Id */ public class Parser extends ScopeKeyword { - /** Creates a new instance of Parser */ + /** + * Creates a new instance of Parser + */ public Parser() { super("parser"); } + /** {@inheritDoc} */ public boolean read_scope(ReadScopeParameter p_par) { Object next_token = null; @@ -182,6 +186,12 @@ private static String[] read_constant(ReadScopeParameter p_par) /** * p_reduced is true if the scope is written to a session file. + * + * @param p_file a {@link datastructures.IndentFileWriter} object. + * @param p_parser_info a {@link board.Communication.SpecctraParserInfo} object. + * @param p_identifier_type a {@link datastructures.IdentifierType} object. + * @param p_reduced a boolean. + * @throws java.io.IOException if any. */ public static void write_scope(datastructures.IndentFileWriter p_file, SpecctraParserInfo p_parser_info, datastructures.IdentifierType p_identifier_type, boolean p_reduced) throws java.io.IOException diff --git a/designformats/specctra/PartLibrary.java b/src/main/java/designformats/specctra/PartLibrary.java similarity index 97% rename from designformats/specctra/PartLibrary.java rename to src/main/java/designformats/specctra/PartLibrary.java index c0ebb4f..d05ec5d 100644 --- a/designformats/specctra/PartLibrary.java +++ b/src/main/java/designformats/specctra/PartLibrary.java @@ -21,18 +21,23 @@ package designformats.specctra; /** + *

PartLibrary class.

* * @author Alfons Wirtz + * @version $Id: $Id */ public class PartLibrary extends ScopeKeyword { - /** Creates a new instance of PartLibrary */ + /** + * Creates a new instance of PartLibrary + */ public PartLibrary() { super("part_library"); } + /** {@inheritDoc} */ public boolean read_scope(ReadScopeParameter p_par) { Object next_token = null; @@ -88,6 +93,12 @@ else if (next_token == Keyword.LOGICAL_PART) return true; } + /** + *

write_scope.

+ * + * @param p_par a {@link designformats.specctra.WriteScopeParameter} object. + * @throws java.io.IOException if any. + */ public static void write_scope(WriteScopeParameter p_par) throws java.io.IOException { library.LogicalParts logical_parts = p_par.board.library.logical_parts; diff --git a/designformats/specctra/Path.java b/src/main/java/designformats/specctra/Path.java similarity index 96% rename from designformats/specctra/Path.java rename to src/main/java/designformats/specctra/Path.java index 2cad403..16a06c3 100644 --- a/designformats/specctra/Path.java +++ b/src/main/java/designformats/specctra/Path.java @@ -27,6 +27,7 @@ * Class for writing path scopes from dsn-files. * * @author alfons + * @version $Id: $Id */ public abstract class Path extends Shape { @@ -40,6 +41,8 @@ public abstract class Path extends Shape } /** + * {@inheritDoc} + * * Writes this path as a scope to an output dsn-file. */ public abstract void write_scope(IndentFileWriter p_file, IdentifierType p_identifier) throws java.io.IOException; diff --git a/designformats/specctra/PlaceControl.java b/src/main/java/designformats/specctra/PlaceControl.java similarity index 95% rename from designformats/specctra/PlaceControl.java rename to src/main/java/designformats/specctra/PlaceControl.java index e71ab91..a8aee7b 100644 --- a/designformats/specctra/PlaceControl.java +++ b/src/main/java/designformats/specctra/PlaceControl.java @@ -24,17 +24,24 @@ * Class for reading place_control scopes from dsn-files. * * @author Alfons Wirtz + * @version $Id: $Id */ public class PlaceControl extends ScopeKeyword { - /** Creates a new instance of PlaceControl */ + /** + * Creates a new instance of PlaceControl + */ public PlaceControl() { super("place_control"); } - /** Reads the flip_style */ + /** + * {@inheritDoc} + * + * Reads the flip_style + */ public boolean read_scope(ReadScopeParameter p_par) { boolean flip_style_rotate_first = false; diff --git a/designformats/specctra/Placement.java b/src/main/java/designformats/specctra/Placement.java similarity index 85% rename from designformats/specctra/Placement.java rename to src/main/java/designformats/specctra/Placement.java index d03f9cd..c965bfa 100644 --- a/designformats/specctra/Placement.java +++ b/src/main/java/designformats/specctra/Placement.java @@ -24,16 +24,25 @@ * Class for writing placement scopes from dsn-files. * * @author Alfons Wirtz + * @version $Id: $Id */ public class Placement extends ScopeKeyword { - /** Creates a new instance of Placemet */ + /** + * Creates a new instance of Placemet + */ public Placement() { super("placement"); } + /** + *

write_scope.

+ * + * @param p_par a {@link designformats.specctra.WriteScopeParameter} object. + * @throws java.io.IOException if any. + */ public static void write_scope(WriteScopeParameter p_par) throws java.io.IOException { p_par.file.start_scope(); diff --git a/designformats/specctra/Plane.java b/src/main/java/designformats/specctra/Plane.java similarity index 91% rename from designformats/specctra/Plane.java rename to src/main/java/designformats/specctra/Plane.java index f58fab0..2090f52 100644 --- a/designformats/specctra/Plane.java +++ b/src/main/java/designformats/specctra/Plane.java @@ -26,16 +26,20 @@ * Class for reading and writing plane scopes from dsn-files. * * @author alfons + * @version $Id: $Id */ public class Plane extends ScopeKeyword { - /** Creates a new instance of Plane */ + /** + * Creates a new instance of Plane + */ public Plane() { super("plane"); } + /** {@inheritDoc} */ public boolean read_scope(ReadScopeParameter p_par) { // read the net name @@ -66,6 +70,13 @@ public boolean read_scope(ReadScopeParameter p_par) return true; } + /** + *

write_scope.

+ * + * @param p_par a {@link designformats.specctra.WriteScopeParameter} object. + * @param p_conduction a {@link board.ConductionArea} object. + * @throws java.io.IOException if any. + */ public static void write_scope(WriteScopeParameter p_par, board.ConductionArea p_conduction) throws java.io.IOException { int net_count = p_conduction.net_count(); diff --git a/designformats/specctra/Polygon.java b/src/main/java/designformats/specctra/Polygon.java similarity index 92% rename from designformats/specctra/Polygon.java rename to src/main/java/designformats/specctra/Polygon.java index 3231e54..278f3d8 100644 --- a/designformats/specctra/Polygon.java +++ b/src/main/java/designformats/specctra/Polygon.java @@ -27,6 +27,7 @@ * Describes a polygon in a Specctra dsn file. * * @author alfons + * @version $Id: $Id */ public class Polygon extends Shape { @@ -34,6 +35,9 @@ public class Polygon extends Shape * Creates a new instance of Polygon * p_coor is an array of dimension of dimension 2 * point_count and contains x0, y0, x1, y1, ... * If the polygon is used as rectangle, + * + * @param p_layer a {@link designformats.specctra.Layer} object. + * @param p_coor an array of double. */ public Polygon(Layer p_layer, double[] p_coor) { @@ -41,6 +45,7 @@ public Polygon(Layer p_layer, double[] p_coor) coor = p_coor; } + /** {@inheritDoc} */ public geometry.planar.Shape transform_to_board(CoordinateTransform p_coordinate_transform) { IntPoint [] corner_arr = new IntPoint[coor.length / 2]; @@ -54,6 +59,7 @@ public geometry.planar.Shape transform_to_board(CoordinateTransform p_coordinate return new geometry.planar.PolygonShape(corner_arr); } + /** {@inheritDoc} */ public geometry.planar.Shape transform_to_board_rel(CoordinateTransform p_coordinate_transform) { if (coor.length < 2) @@ -70,6 +76,11 @@ public geometry.planar.Shape transform_to_board_rel(CoordinateTransform p_coordi return new geometry.planar.PolygonShape(corner_arr); } + /** + *

bounding_box.

+ * + * @return a {@link designformats.specctra.Rectangle} object. + */ public Rectangle bounding_box() { double[] bounds = new double[4]; @@ -96,6 +107,8 @@ public Rectangle bounding_box() } /** + * {@inheritDoc} + * * Writes this polygon as a scope to an output dsn-file. */ public void write_scope(IndentFileWriter p_file, IdentifierType p_identifier_type) throws java.io.IOException @@ -116,6 +129,7 @@ public void write_scope(IndentFileWriter p_file, IdentifierType p_identifier_typ p_file.end_scope(); } + /** {@inheritDoc} */ public void write_scope_int(IndentFileWriter p_file, IdentifierType p_identifier_type) throws java.io.IOException { p_file.start_scope(); diff --git a/designformats/specctra/PolygonPath.java b/src/main/java/designformats/specctra/PolygonPath.java similarity index 92% rename from designformats/specctra/PolygonPath.java rename to src/main/java/designformats/specctra/PolygonPath.java index 298b013..c5bce9a 100644 --- a/designformats/specctra/PolygonPath.java +++ b/src/main/java/designformats/specctra/PolygonPath.java @@ -31,11 +31,18 @@ * Class for reading and writing path scopes consisting of a polygon from dsn-files. * * @author Alfons Wirtz + * @version $Id: $Id */ public class PolygonPath extends Path { - /** Creates a new instance of PolygonPath */ + /** + * Creates a new instance of PolygonPath + * + * @param p_layer a {@link designformats.specctra.Layer} object. + * @param p_width a double. + * @param p_coordinate_arr an array of double. + */ public PolygonPath(Layer p_layer, double p_width, double[] p_coordinate_arr) { super(p_layer, p_width, p_coordinate_arr); @@ -43,6 +50,8 @@ public PolygonPath(Layer p_layer, double p_width, double[] p_coordinate_arr) /** + * {@inheritDoc} + * * Writes this path as a scope to an output dsn-file. */ public void write_scope(IndentFileWriter p_file, IdentifierType p_identifier_type) throws java.io.IOException @@ -63,6 +72,7 @@ public void write_scope(IndentFileWriter p_file, IdentifierType p_identifier_typ p_file.end_scope(); } + /** {@inheritDoc} */ public void write_scope_int(IndentFileWriter p_file, IdentifierType p_identifier_type) throws java.io.IOException { p_file.start_scope(); @@ -83,6 +93,7 @@ public void write_scope_int(IndentFileWriter p_file, IdentifierType p_identifier p_file.end_scope(); } + /** {@inheritDoc} */ public geometry.planar.Shape transform_to_board(CoordinateTransform p_coordinate_transform) { FloatPoint [] corner_arr = new FloatPoint[this.coordinate_arr.length / 2]; @@ -112,6 +123,7 @@ public geometry.planar.Shape transform_to_board(CoordinateTransform p_coordinate return result; } + /** {@inheritDoc} */ public geometry.planar.Shape transform_to_board_rel(CoordinateTransform p_coordinate_transform) { FloatPoint [] corner_arr = new FloatPoint[this.coordinate_arr.length / 2]; @@ -141,6 +153,11 @@ public geometry.planar.Shape transform_to_board_rel(CoordinateTransform p_coordi return result; } + /** + *

bounding_box.

+ * + * @return a {@link designformats.specctra.Rectangle} object. + */ public Rectangle bounding_box() { double offset = this.width/2; diff --git a/designformats/specctra/PolylinePath.java b/src/main/java/designformats/specctra/PolylinePath.java similarity index 87% rename from designformats/specctra/PolylinePath.java rename to src/main/java/designformats/specctra/PolylinePath.java index 2add800..bebd744 100644 --- a/designformats/specctra/PolylinePath.java +++ b/src/main/java/designformats/specctra/PolylinePath.java @@ -28,17 +28,26 @@ * Describes a path defined by a sequence of lines (instead of a sequence of corners. * * @author alfons + * @version $Id: $Id */ public class PolylinePath extends Path { - /** Creates a new instance of PolylinePath */ + /** + * Creates a new instance of PolylinePath + * + * @param p_layer a {@link designformats.specctra.Layer} object. + * @param p_width a double. + * @param p_corner_arr an array of double. + */ public PolylinePath(Layer p_layer, double p_width, double[] p_corner_arr) { super(p_layer, p_width, p_corner_arr); } /** + * {@inheritDoc} + * * Writes this path as a scope to an output dsn-file. */ public void write_scope(IndentFileWriter p_file, IdentifierType p_identifier) throws java.io.IOException @@ -61,6 +70,7 @@ public void write_scope(IndentFileWriter p_file, IdentifierType p_identifier) th p_file.end_scope(); } + /** {@inheritDoc} */ public void write_scope_int(IndentFileWriter p_file, IdentifierType p_identifier) throws java.io.IOException { p_file.start_scope(); @@ -82,12 +92,14 @@ public void write_scope_int(IndentFileWriter p_file, IdentifierType p_identifier p_file.end_scope(); } + /** {@inheritDoc} */ public geometry.planar.Shape transform_to_board_rel(CoordinateTransform p_coordinate_transform) { System.out.println("PolylinePath.transform_to_board_rel not implemented"); return null; } + /** {@inheritDoc} */ public geometry.planar.Shape transform_to_board(CoordinateTransform p_coordinate_transform) { System.out.println("PolylinePath.transform_to_board_rel not implemented"); @@ -95,6 +107,11 @@ public geometry.planar.Shape transform_to_board(CoordinateTransform p_coordinate } + /** + *

bounding_box.

+ * + * @return a {@link designformats.specctra.Rectangle} object. + */ public Rectangle bounding_box() { System.out.println("PolylinePath.boundingbox not implemented"); diff --git a/designformats/specctra/ReadScopeParameter.java b/src/main/java/designformats/specctra/ReadScopeParameter.java similarity index 99% rename from designformats/specctra/ReadScopeParameter.java rename to src/main/java/designformats/specctra/ReadScopeParameter.java index 02f4a68..a90b5a6 100644 --- a/designformats/specctra/ReadScopeParameter.java +++ b/src/main/java/designformats/specctra/ReadScopeParameter.java @@ -27,6 +27,7 @@ * Default parameter type used while reading a Specctra dsn-file. * * @author alfons + * @version $Id: $Id */ public class ReadScopeParameter { diff --git a/designformats/specctra/Rectangle.java b/src/main/java/designformats/specctra/Rectangle.java similarity index 89% rename from designformats/specctra/Rectangle.java rename to src/main/java/designformats/specctra/Rectangle.java index 474d4c5..a49646c 100644 --- a/designformats/specctra/Rectangle.java +++ b/src/main/java/designformats/specctra/Rectangle.java @@ -29,6 +29,7 @@ * Describes a rectangle in a Specctra dsn file. * * @author alfons + * @version $Id: $Id */ public class Rectangle extends Shape { @@ -36,6 +37,9 @@ public class Rectangle extends Shape * Creates a new instance of Rectangle * p_coor is an array of dimension 4 and contains the rectangle coordinates * in the following order: lower left x, lower left y, upper right x, uppper right y. + * + * @param p_layer a {@link designformats.specctra.Layer} object. + * @param p_coor an array of double. */ public Rectangle(Layer p_layer, double[] p_coor) { @@ -43,6 +47,11 @@ public Rectangle(Layer p_layer, double[] p_coor) coor = p_coor; } + /** + *

bounding_box.

+ * + * @return a {@link designformats.specctra.Rectangle} object. + */ public Rectangle bounding_box() { return this; @@ -50,6 +59,9 @@ public Rectangle bounding_box() /** * Creates the smallest rectangle containing this rectangle and p_other + * + * @param p_other a {@link designformats.specctra.Rectangle} object. + * @return a {@link designformats.specctra.Rectangle} object. */ public Rectangle union (Rectangle p_other) { @@ -61,6 +73,7 @@ public Rectangle union (Rectangle p_other) return new Rectangle(this.layer, result_coor); } + /** {@inheritDoc} */ public geometry.planar.Shape transform_to_board_rel(CoordinateTransform p_coordinate_transform) { int box_coor[] = new int[4]; @@ -83,6 +96,7 @@ public geometry.planar.Shape transform_to_board_rel(CoordinateTransform p_coordi return result; } + /** {@inheritDoc} */ public geometry.planar.Shape transform_to_board(CoordinateTransform p_coordinate_transform) { double [] curr_point = new double [2]; @@ -96,6 +110,8 @@ public geometry.planar.Shape transform_to_board(CoordinateTransform p_coordinate } /** + * {@inheritDoc} + * * Writes this rectangle as a scope to an output dsn-file. */ public void write_scope(IndentFileWriter p_file, IdentifierType p_identifier) throws java.io.IOException @@ -111,6 +127,7 @@ public void write_scope(IndentFileWriter p_file, IdentifierType p_identifier) th p_file.write(")"); } + /** {@inheritDoc} */ public void write_scope_int(IndentFileWriter p_file, IdentifierType p_identifier) throws java.io.IOException { p_file.new_line(); @@ -126,4 +143,4 @@ public void write_scope_int(IndentFileWriter p_file, IdentifierType p_identifier } public final double [] coor; -} \ No newline at end of file +} diff --git a/designformats/specctra/Resolution.java b/src/main/java/designformats/specctra/Resolution.java similarity index 89% rename from designformats/specctra/Resolution.java rename to src/main/java/designformats/specctra/Resolution.java index 833c84a..49741d0 100644 --- a/designformats/specctra/Resolution.java +++ b/src/main/java/designformats/specctra/Resolution.java @@ -24,16 +24,20 @@ * Class for reading resolution scopes from dsn-files. * * @author alfons + * @version $Id: $Id */ public class Resolution extends ScopeKeyword { - /** Creates a new instance of Resolution */ + /** + * Creates a new instance of Resolution + */ public Resolution() { super("resolution"); } + /** {@inheritDoc} */ public boolean read_scope(ReadScopeParameter p_par) { try @@ -75,6 +79,13 @@ public boolean read_scope(ReadScopeParameter p_par) } } + /** + *

write_scope.

+ * + * @param p_file a {@link datastructures.IndentFileWriter} object. + * @param p_board_communication a {@link board.Communication} object. + * @throws java.io.IOException if any. + */ public static void write_scope(datastructures.IndentFileWriter p_file, board.Communication p_board_communication) throws java.io.IOException { p_file.new_line(); diff --git a/designformats/specctra/Rule.java b/src/main/java/designformats/specctra/Rule.java similarity index 90% rename from designformats/specctra/Rule.java rename to src/main/java/designformats/specctra/Rule.java index 0b90f3f..930a20d 100644 --- a/designformats/specctra/Rule.java +++ b/src/main/java/designformats/specctra/Rule.java @@ -28,11 +28,15 @@ * Class for reading and writing rule scopes from dsn-files. * * @author Alfons Wirtz + * @version $Id: $Id */ public abstract class Rule { /** * Returns a collection of objects of class Rule. + * + * @param p_scanner a {@link designformats.specctra.Scanner} object. + * @return a {@link java.util.Collection} object. */ public static Collection read_scope( Scanner p_scanner) { @@ -88,6 +92,9 @@ else if (next_token == Keyword.CLEARANCE) /** * Reads a LayerRule from dsn-file. + * + * @param p_scanner a {@link designformats.specctra.Scanner} object. + * @return a {@link designformats.specctra.Rule.LayerRule} object. */ public static LayerRule read_layer_rule_scope( Scanner p_scanner) { @@ -135,6 +142,12 @@ public static LayerRule read_layer_rule_scope( Scanner p_scanner) } } + /** + *

read_width_rule.

+ * + * @param p_scanner a {@link designformats.specctra.Scanner} object. + * @return a {@link designformats.specctra.Rule.WidthRule} object. + */ public static WidthRule read_width_rule(Scanner p_scanner) { try @@ -169,6 +182,13 @@ else if (next_token instanceof Integer) } } + /** + *

write_scope.

+ * + * @param p_net_class a {@link rules.NetClass} object. + * @param p_par a {@link designformats.specctra.WriteScopeParameter} object. + * @throws java.io.IOException if any. + */ public static void write_scope(rules.NetClass p_net_class, WriteScopeParameter p_par) throws java.io.IOException { p_par.file.start_scope(); @@ -216,6 +236,10 @@ private static void write_layer_rule(rules.NetClass p_net_class, int p_layer_no, /** * Writes the default rule as a scope to an output dsn-file. + * + * @param p_par a {@link designformats.specctra.WriteScopeParameter} object. + * @param p_layer a int. + * @throws java.io.IOException if any. */ public static void write_default_rule(WriteScopeParameter p_par, int p_layer) throws java.io.IOException { @@ -275,6 +299,12 @@ private static void write_clearance_rules(WriteScopeParameter p_par, } } + /** + *

read_clearance_rule.

+ * + * @param p_scanner a {@link designformats.specctra.Scanner} object. + * @return a {@link designformats.specctra.Rule.ClearanceRule} object. + */ public static ClearanceRule read_clearance_rule(Scanner p_scanner) { try @@ -341,6 +371,14 @@ else if (next_token instanceof Integer) } + /** + *

write_item_clearance_class.

+ * + * @param p_name a {@link java.lang.String} object. + * @param p_file a {@link datastructures.IndentFileWriter} object. + * @param p_identifier_type a {@link datastructures.IdentifierType} object. + * @throws java.io.IOException if any. + */ static public void write_item_clearance_class( String p_name, datastructures.IndentFileWriter p_file, datastructures.IdentifierType p_identifier_type) throws java.io.IOException { diff --git a/designformats/specctra/RulesFile.java b/src/main/java/designformats/specctra/RulesFile.java similarity index 95% rename from designformats/specctra/RulesFile.java rename to src/main/java/designformats/specctra/RulesFile.java index 23dc7d6..17fa930 100644 --- a/designformats/specctra/RulesFile.java +++ b/src/main/java/designformats/specctra/RulesFile.java @@ -30,10 +30,18 @@ * is creates anew from the host system. * * @author Alfons Wirtz + * @version $Id: $Id */ public class RulesFile { + /** + *

write.

+ * + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_output_stream a {@link java.io.OutputStream} object. + * @param p_design_name a {@link java.lang.String} object. + */ public static void write(interactive.BoardHandling p_board_handling, java.io.OutputStream p_output_stream, String p_design_name) { IndentFileWriter output_file = new IndentFileWriter(p_output_stream); @@ -60,6 +68,14 @@ public static void write(interactive.BoardHandling p_board_handling, java.io.Out } } + /** + *

read.

+ * + * @param p_input_stream a {@link java.io.InputStream} object. + * @param p_design_name a {@link java.lang.String} object. + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @return a boolean. + */ public static boolean read(java.io.InputStream p_input_stream, String p_design_name, interactive.BoardHandling p_board_handling) { diff --git a/designformats/specctra/Scanner.java b/src/main/java/designformats/specctra/Scanner.java similarity index 86% rename from designformats/specctra/Scanner.java rename to src/main/java/designformats/specctra/Scanner.java index 70c924b..0a8f4c1 100644 --- a/designformats/specctra/Scanner.java +++ b/src/main/java/designformats/specctra/Scanner.java @@ -24,16 +24,22 @@ * Interface for scanner generated by jflex. * * @author alfons + * @version $Id: $Id */ public interface Scanner { /** * Reads the next token from the input file. + * + * @return a {@link java.lang.Object} object. + * @throws java.io.IOException if any. */ Object next_token() throws java.io.IOException; /** * Starts a new state. + * + * @param p_new_state a int. */ void yybegin(int p_new_state); } diff --git a/designformats/specctra/ScopeKeyword.java b/src/main/java/designformats/specctra/ScopeKeyword.java similarity index 89% rename from designformats/specctra/ScopeKeyword.java rename to src/main/java/designformats/specctra/ScopeKeyword.java index f64b2bf..1109338 100644 --- a/designformats/specctra/ScopeKeyword.java +++ b/src/main/java/designformats/specctra/ScopeKeyword.java @@ -25,9 +25,19 @@ * @author alfons */ -/** Keywords defining a scope object*/ +/** + * Keywords defining a scope object + * + * @author harry + * @version $Id: $Id + */ public class ScopeKeyword extends Keyword { + /** + *

Constructor for ScopeKeyword.

+ * + * @param p_name a {@link java.lang.String} object. + */ public ScopeKeyword(String p_name) { super(p_name); @@ -36,6 +46,9 @@ public ScopeKeyword(String p_name) /** * Scips the current scope while reading a dsn file. * Returns false, if no legal scope was found. + * + * @param p_scanner a {@link designformats.specctra.Scanner} object. + * @return a boolean. */ public static boolean skip_scope(Scanner p_scanner) { @@ -72,6 +85,9 @@ else if (curr_token == Keyword.CLOSED_BRACKET) /** * Reads the next scope of this keyword from dsn file. + * + * @param p_par a {@link designformats.specctra.ReadScopeParameter} object. + * @return a boolean. */ public boolean read_scope(ReadScopeParameter p_par) { diff --git a/designformats/specctra/SessionFile.java b/src/main/java/designformats/specctra/SessionFile.java similarity index 91% rename from designformats/specctra/SessionFile.java rename to src/main/java/designformats/specctra/SessionFile.java index cc739b2..91815c6 100644 --- a/designformats/specctra/SessionFile.java +++ b/src/main/java/designformats/specctra/SessionFile.java @@ -37,11 +37,17 @@ * Methods to handle a Specctra session file. * * @author alfons + * @version $Id: $Id */ public class SessionFile { /** * Creates a Specctra session file to update the host system from the RoutingBooard + * + * @param p_board a {@link board.BasicBoard} object. + * @param p_output_stream a {@link java.io.OutputStream} object. + * @param p_design_name a {@link java.lang.String} object. + * @return a boolean. */ public static boolean write( BasicBoard p_board, java.io.OutputStream p_output_stream, String p_design_name) { @@ -101,6 +107,15 @@ private static void write_session_scope(BasicBoard p_board, IdentifierType p_ide p_file.end_scope(); } + /** + *

write_placement.

+ * + * @param p_board a {@link board.BasicBoard} object. + * @param p_identifier_type a {@link datastructures.IdentifierType} object. + * @param p_coordinate_transform a {@link designformats.specctra.CoordinateTransform} object. + * @param p_file a {@link datastructures.IndentFileWriter} object. + * @throws java.io.IOException if any. + */ public static void write_placement(BasicBoard p_board, IdentifierType p_identifier_type, CoordinateTransform p_coordinate_transform, IndentFileWriter p_file) throws java.io.IOException { @@ -117,6 +132,13 @@ public static void write_placement(BasicBoard p_board, IdentifierType p_identifi /** * Writes all components with the package p_package to the session file. + * + * @param p_board a {@link board.BasicBoard} object. + * @param p_identifier_type a {@link datastructures.IdentifierType} object. + * @param p_coordinate_transform a {@link designformats.specctra.CoordinateTransform} object. + * @param p_file a {@link datastructures.IndentFileWriter} object. + * @param p_package a {@link library.Package} object. + * @throws java.io.IOException if any. */ public static void write_components(BasicBoard p_board, IdentifierType p_identifier_type, CoordinateTransform p_coordinate_transform, IndentFileWriter p_file, library.Package p_package) throws java.io.IOException @@ -160,6 +182,16 @@ public static void write_components(BasicBoard p_board, IdentifierType p_identif } } + /** + *

write_component.

+ * + * @param p_board a {@link board.BasicBoard} object. + * @param p_identifier_type a {@link datastructures.IdentifierType} object. + * @param p_coordinate_transform a {@link designformats.specctra.CoordinateTransform} object. + * @param p_file a {@link datastructures.IndentFileWriter} object. + * @param p_component a {@link board.Component} object. + * @throws java.io.IOException if any. + */ public static void write_component(BasicBoard p_board, IdentifierType p_identifier_type, CoordinateTransform p_coordinate_transform, IndentFileWriter p_file, board.Component p_component) throws java.io.IOException { @@ -191,6 +223,14 @@ public static void write_component(BasicBoard p_board, IdentifierType p_identifi p_file.write(")"); } + /** + *

write_was_is.

+ * + * @param p_board a {@link board.BasicBoard} object. + * @param p_identifier_type a {@link datastructures.IdentifierType} object. + * @param p_file a {@link datastructures.IndentFileWriter} object. + * @throws java.io.IOException if any. + */ public static void write_was_is(BasicBoard p_board, IdentifierType p_identifier_type, IndentFileWriter p_file) throws java.io.IOException { @@ -519,4 +559,4 @@ private static void write_conduction_area( ConductionArea p_conduction_area, Bas } p_file.end_scope(); } -} \ No newline at end of file +} diff --git a/designformats/specctra/SessionToEagle.java b/src/main/java/designformats/specctra/SessionToEagle.java similarity index 97% rename from designformats/specctra/SessionToEagle.java rename to src/main/java/designformats/specctra/SessionToEagle.java index e921262..717ae5e 100644 --- a/designformats/specctra/SessionToEagle.java +++ b/src/main/java/designformats/specctra/SessionToEagle.java @@ -1,738 +1,747 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * SessionToEagle.java - * - * Created on 8. Dezember 2004, 07:42 - */ - -package designformats.specctra; - - -/** - * Transformes a Specctra session file into an Eagle script file. - * - * @author Alfons Wirtz - */ -public class SessionToEagle extends javax.swing.JFrame -{ - - public static boolean get_instance(java.io.InputStream p_session, java.io.OutputStream p_output_stream, - board.BasicBoard p_board) - { - if (p_output_stream == null) - { - return false; - } - - // create a scanner for reading the session_file. - - Scanner scanner = new SpecctraFileScanner(p_session); - - // create a file_writer for the eagle script file. - java.io.OutputStreamWriter file_writer = new java.io.OutputStreamWriter(p_output_stream); - - boolean result = true; - - double board_scale_factor = p_board.communication.coordinate_transform.board_to_dsn(1); - SessionToEagle new_instance = new SessionToEagle(scanner, file_writer, p_board, - p_board.communication.unit, p_board.communication.resolution, board_scale_factor); - - try - { - result = new_instance.process_session_scope(); - } - catch (java.io.IOException e) - { - System.out.println("unable to process session scope"); - result = false; - } - - // close files - try - { - p_session.close(); - file_writer.close(); - } - catch (java.io.IOException e) - { - System.out.println("unable to close files"); - } - return result; - } - - SessionToEagle(Scanner p_scanner, java.io.OutputStreamWriter p_out_file, board.BasicBoard p_board, - board.Unit p_unit, double p_session_file_scale_dominator, double p_board_scale_factor) - { - scanner = p_scanner; - out_file = p_out_file; - board = p_board; - this.specctra_layer_structure = new LayerStructure(p_board.layer_structure); - unit = p_unit; - session_file_scale_denominator = p_session_file_scale_dominator; - board_scale_factor = p_board_scale_factor; - } - - /** - * Processes the outmost scope of the session file. - * Returns false, if an error occured. - */ - private boolean process_session_scope() throws java.io.IOException - { - - // read the first line of the session file - Object next_token = null; - for (int i = 0; i < 3; ++i) - { - next_token = this.scanner.next_token(); - boolean keyword_ok = true; - if (i == 0) - { - keyword_ok = (next_token == Keyword.OPEN_BRACKET); - } - else if (i == 1) - { - keyword_ok = (next_token == Keyword.SESSION); - this.scanner.yybegin(SpecctraFileScanner.NAME); // to overread the name of the pcb for i = 2 - } - if (!keyword_ok) - { - System.out.println("SessionToEagle.process_session_scope specctra session file format expected"); - return false; - } - } - - // Write the header of the eagle script file. - - this.out_file.write("GRID "); - this.out_file.write(this.unit.toString()); - this.out_file.write("\n"); - this.out_file.write("SET WIRE_BEND 2\n"); - this.out_file.write("SET OPTIMIZING OFF\n"); - - // Activate all layers in Eagle. - - for (int i = 0; i < this.board.layer_structure.arr.length; ++i) - { - this.out_file.write("LAYER " + this.get_eagle_layer_string(i) + ";\n"); - } - - this.out_file.write("LAYER 17;\n"); - this.out_file.write("LAYER 18;\n"); - this.out_file.write("LAYER 19;\n"); - this.out_file.write("LAYER 20;\n"); - this.out_file.write("LAYER 23;\n"); - this.out_file.write("LAYER 24;\n"); - - // Generate Code to remove the complete route. - // Write a bounding rectangle with GROUP (Min_X-1 Min_Y-1) (Max_X+1 Max_Y+1); - - geometry.planar.IntBox board_bounding_box = this.board.get_bounding_box(); - - Float min_x = (float) this.board_scale_factor * (board_bounding_box.ll.x - 1); - Float min_y = (float) this.board_scale_factor * (board_bounding_box.ll.y - 1); - Float max_x = (float) this.board_scale_factor * (board_bounding_box.ur.x + 1); - Float max_y = (float) this.board_scale_factor * (board_bounding_box.ur.y + 1); - - this.out_file.write("GROUP ("); - this.out_file.write(min_x.toString()); - this.out_file.write(" "); - this.out_file.write(min_y.toString()); - this.out_file.write(") ("); - this.out_file.write(max_x.toString()); - this.out_file.write(" "); - this.out_file.write(max_y.toString()); - this.out_file.write(");\n"); - this.out_file.write("RIPUP;\n"); - - // read the direct subscopes of the session scope - for (;;) - { - Object prev_token = next_token; - next_token = this.scanner.next_token(); - if (next_token == null) - { - // end of file - return true; - } - if (next_token == Keyword.CLOSED_BRACKET) - { - // end of scope - break; - } - - if (prev_token == Keyword.OPEN_BRACKET) - { - if (next_token == Keyword.ROUTES) - { - if (!process_routes_scope()) - { - return false; - } - } - else if (next_token == Keyword.PLACEMENT_SCOPE) - { - if (!process_placement_scope()) - { - return false; - } - } - else - { - // overread all scopes except the routes scope for the time being - ScopeKeyword.skip_scope(this.scanner); - } - } - } - // Wird nur einmal am Ende benoetigt! - this.out_file.write("RATSNEST\n"); - return true; - } - - private boolean process_placement_scope() throws java.io.IOException - { - // read the component scopes - Object next_token = null; - for (;;) - { - Object prev_token = next_token; - next_token = this.scanner.next_token(); - if (next_token == null) - { - // unexpected end of file - return false; - } - if (next_token == Keyword.CLOSED_BRACKET) - { - // end of scope - break; - } - - if (prev_token == Keyword.OPEN_BRACKET) - { - - if (next_token == Keyword.COMPONENT_SCOPE) - { - if (!process_component_placement()) - { - return false; - } - } - else - { - // skip unknown scope - ScopeKeyword.skip_scope(this.scanner); - } - - } - } - process_swapped_pins(); - return true; - } - - private boolean process_component_placement() throws java.io.IOException - { - ComponentPlacement component_placement = Component.read_scope(this.scanner); - if (component_placement == null) - { - return false; - } - for (ComponentPlacement.ComponentLocation curr_location : component_placement.locations) - { - this.out_file.write("ROTATE ="); - Integer rotation = (int) Math.round(curr_location.rotation); - String rotation_string; - if (curr_location.is_front) - { - rotation_string = "R" + rotation.toString(); - } - else - { - rotation_string = "MR" + rotation.toString(); - } - this.out_file.write(rotation_string); - this.out_file.write(" '"); - this.out_file.write(curr_location.name); - this.out_file.write("';\n"); - this.out_file.write("move '"); - this.out_file.write(curr_location.name); - this.out_file.write("' ("); - Double x_coor = curr_location.coor[0] / this.session_file_scale_denominator; - this.out_file.write(x_coor.toString()); - this.out_file.write(" "); - Double y_coor = curr_location.coor[1] / this.session_file_scale_denominator; - this.out_file.write(y_coor.toString()); - this.out_file.write(");\n"); - } - return true; - } - - private boolean process_routes_scope() throws java.io.IOException - { - // read the direct subscopes of the routes scope - boolean result = true; - Object next_token = null; - for (;;) - { - Object prev_token = next_token; - next_token = this.scanner.next_token(); - if (next_token == null) - { - // unexpected end of file - return false; - } - if (next_token == Keyword.CLOSED_BRACKET) - { - // end of scope - break; - } - - if (prev_token == Keyword.OPEN_BRACKET) - { - - if (next_token == Keyword.NETWORK_OUT) - { - result = process_network_scope(); - } - else - { - // skip unknown scope - ScopeKeyword.skip_scope(this.scanner); - } - - } - } - return result; - } - - private boolean process_network_scope() throws java.io.IOException - { - boolean result = true; - Object next_token = null; - // read the net scopes - for (;;) - { - Object prev_token = next_token; - next_token = this.scanner.next_token(); - if (next_token == null) - { - // unexpected end of file - return false; - } - if (next_token == Keyword.CLOSED_BRACKET) - { - // end of scope - break; - } - - if (prev_token == Keyword.OPEN_BRACKET) - { - - if (next_token == Keyword.NET) - { - result = process_net_scope(); - } - else - { - // skip unknown scope - ScopeKeyword.skip_scope(this.scanner); - } - - } - } - return result; - } - - private boolean process_net_scope() throws java.io.IOException - { - // read the net name - Object next_token = this.scanner.next_token(); - if (!(next_token instanceof String)) - { - System.out.println("SessionToEagle.processnet_scope: String expected"); - return false; - } - String net_name = (String) next_token; - - // Hier alle nicht gefixten Traces und Vias des Netz mit Namen net_name - // in der Eagle Datenhaltung loeschen. - - // read the wires and vias of this net - for (;;) - { - Object prev_token = next_token; - next_token = this.scanner.next_token(); - if (next_token == null) - { - // end of file - return true; - } - if (next_token == Keyword.CLOSED_BRACKET) - { - // end of scope - break; - } - - if (prev_token == Keyword.OPEN_BRACKET) - { - if (next_token == Keyword.WIRE) - { - if (!process_wire_scope(net_name)) - { - return false; - } - } - else if (next_token == Keyword.VIA) - { - if (!process_via_scope(net_name)) - { - return false; - } - } - else - { - ScopeKeyword.skip_scope(this.scanner); - } - } - } - return true; - } - - private boolean process_wire_scope(String p_net_name) throws java.io.IOException - { - PolygonPath wire_path = null; - Object next_token = null; - for (;;) - { - Object prev_token = next_token; - next_token = this.scanner.next_token(); - if (next_token == null) - { - System.out.println("SessionToEagle.process_wire_scope: unexpected end of file"); - return false; - } - if (next_token == Keyword.CLOSED_BRACKET) - { - // end of scope - break; - } - if (prev_token == Keyword.OPEN_BRACKET) - { - if (next_token == Keyword.POLYGON_PATH) - { - wire_path = Shape.read_polygon_path_scope(this.scanner, this.specctra_layer_structure); - } - else - { - ScopeKeyword.skip_scope(this.scanner); - } - } - } - if (wire_path == null) - { - // conduction areas are skipped - return true; - } - - this.out_file.write("CHANGE LAYER "); - - this.out_file.write(wire_path.layer.name); - this.out_file.write(";\n"); - - //WIRE ['signal_name'] [width] [ROUND | FLAT] [curve | @radius] - - this.out_file.write("WIRE '"); - - this.out_file.write(p_net_name); - this.out_file.write("' "); - Double wire_width = wire_path.width / this.session_file_scale_denominator; - this.out_file.write(wire_width.toString()); - this.out_file.write(" ("); - for (int i = 0; i < wire_path.coordinate_arr.length; ++i) - { - Double wire_coor = wire_path.coordinate_arr[i] / this.session_file_scale_denominator; - this.out_file.write(wire_coor.toString()); - if (i % 2 == 0) - { - this.out_file.write(" "); - } - else - { - if (i == wire_path.coordinate_arr.length - 1) - { - this.out_file.write(")"); - } - else - { - this.out_file.write(") ("); - } - } - } - this.out_file.write(";\n"); - - return true; - } - - private boolean process_via_scope(String p_net_name) throws java.io.IOException - { - // read the padstack name - Object next_token = this.scanner.next_token(); - if (!(next_token instanceof String)) - { - System.out.println("SessionToEagle.process_via_scope: padstack name expected"); - return false; - } - String padstack_name = (String) next_token; - // read the location - double []location = new double [2]; - for (int i = 0; i < 2; ++i) - { - next_token = this.scanner.next_token(); - if (next_token instanceof Double) - { - location[i] = ((Double) next_token).doubleValue(); - } - else if (next_token instanceof Integer) - { - location[i] = ((Integer) next_token).intValue(); - } - else - { - System.out.println("SessionToEagle.process_via_scope: number expected"); - return false; - } - } - next_token = this.scanner.next_token(); - while (next_token == Keyword.OPEN_BRACKET) - { - // skip unknown scopes - ScopeKeyword.skip_scope(this.scanner); - next_token = this.scanner.next_token(); - } - if (next_token != Keyword.CLOSED_BRACKET) - { - System.out.println("SessionToEagle.process_via_scope: closing bracket expected"); - return false; - } - - if (padstack_name == null) - { - System.out.println("SessionToEagle.process_via_scope: padstack_name missing"); - return false; - } - - library.Padstack via_padstack = this.board.library.padstacks.get(padstack_name); - - if (via_padstack == null) - { - System.out.println("SessionToEagle.process_via_scope: via padstack not found"); - return false; - } - - geometry.planar.ConvexShape via_shape = via_padstack.get_shape(via_padstack.from_layer()); - - Double via_diameter = via_shape.max_width() * this.board_scale_factor; - - // The Padstack name is of the form Name$drill_diameter$from_layer-to_layer - - String [] name_parts = via_padstack.name.split("\\$", 3); - - // example CHANGE DRILL 0.2 - - this.out_file.write("CHANGE DRILL "); - if (name_parts.length > 1) - { - this.out_file.write(name_parts[1]); - } - else - { - // create a default drill, because it is needed in Eagle - this.out_file.write("0.1"); - } - this.out_file.write(";\n"); - - - //VIA ['signal_name'] [diameter] [shape] [layers] [flags] - // Via Net2 0.6 round 1-4 (20.0, 222.0); - this.out_file.write("VIA '"); - - this.out_file.write(p_net_name); - this.out_file.write("' "); - - //Durchmesser aus Padstack - this.out_file.write(via_diameter.toString()); - - //Shape lesen und einsetzen Square / Round / Octagon - if (via_shape instanceof geometry.planar.Circle) - { - this.out_file.write(" round "); - } - else if (via_shape instanceof geometry.planar.IntOctagon) - { - this.out_file.write(" octagon "); - } - else - { - this.out_file.write(" square "); - } - this.out_file.write(get_eagle_layer_string(via_padstack.from_layer())); - this.out_file.write("-"); - this.out_file.write(get_eagle_layer_string(via_padstack.to_layer())); - this.out_file.write(" ("); - Double x_coor = location[0] / this.session_file_scale_denominator; - this.out_file.write(x_coor.toString()); - this.out_file.write(" "); - Double y_coor = location[1] / this.session_file_scale_denominator; - this.out_file.write(y_coor.toString()); - this.out_file.write(");\n"); - - return true; - } - - private String get_eagle_layer_string(int p_layer_no) - { - if (p_layer_no < 0 || p_layer_no >= specctra_layer_structure.arr.length) - { - return "0"; - } - String [] name_pieces = this.specctra_layer_structure.arr[p_layer_no].name.split("#", 2); - return name_pieces[0]; - } - - private boolean process_swapped_pins() throws java.io.IOException - { - for (int i = 1; i <= this.board.components.count(); ++i) - { - if (!process_swapped_pins(i)) - { - return false; - } - } - return true; - } - - private boolean process_swapped_pins(int p_component_no) throws java.io.IOException - { - java.util.Collection component_pins = this.board.get_component_pins(p_component_no); - boolean component_has_swapped_pins = false; - for (board.Pin curr_pin : component_pins) - { - if (curr_pin.get_changed_to() != curr_pin) - { - component_has_swapped_pins = true; - break; - } - } - if (!component_has_swapped_pins) - { - return true; - } - PinInfo[] pin_info_arr = new PinInfo[component_pins.size()]; - int i = 0; - for (board.Pin curr_pin : component_pins) - { - pin_info_arr[i] = new PinInfo(curr_pin); - ++i; - } - for (i = 0; i < pin_info_arr.length; ++i) - { - PinInfo curr_pin_info = pin_info_arr[i]; - if (curr_pin_info.curr_changed_to != curr_pin_info.pin.get_changed_to()) - { - PinInfo other_pin_info = null; - for (int j = i + 1; j < pin_info_arr.length; ++j) - { - if (pin_info_arr[j].pin.get_changed_to() == curr_pin_info.pin) - { - other_pin_info = pin_info_arr[j]; - } - } - if (other_pin_info == null) - { - System.out.println("SessuinToEagle.process_swapped_pins: other_pin_info not found"); - return false; - } - write_pin_swap(curr_pin_info.pin, other_pin_info.pin); - curr_pin_info.curr_changed_to = other_pin_info.pin; - other_pin_info.curr_changed_to = curr_pin_info.pin; - } - } - return true; - } - - private void write_pin_swap( board.Pin p_pin_1, board.Pin p_pin_2) throws java.io.IOException - { - int layer_no = Math.max(p_pin_1.first_layer(), p_pin_2.first_layer()); - String layer_name = board.layer_structure.arr[layer_no].name; - - this.out_file.write("CHANGE LAYER "); - this.out_file.write(layer_name); - this.out_file.write(";\n"); - - double [] location_1 = - this.board.communication.coordinate_transform.board_to_dsn(p_pin_1.get_center().to_float()); - double [] location_2 = - this.board.communication.coordinate_transform.board_to_dsn(p_pin_2.get_center().to_float()); - - this.out_file.write("PINSWAP "); - this.out_file.write(" ("); - Double curr_coor = location_1[0]; - this.out_file.write(curr_coor.toString()); - this.out_file.write(" "); - curr_coor = location_1[1]; - this.out_file.write(curr_coor.toString()); - this.out_file.write(") ("); - curr_coor = location_2[0]; - this.out_file.write(curr_coor.toString()); - this.out_file.write(" "); - curr_coor = location_2[1]; - this.out_file.write(curr_coor.toString()); - this.out_file.write(");\n"); - } - - - - /** The function for scanning the session file */ - private final Scanner scanner; - - /** The generated Eagle script file. */ - private final java.io.OutputStreamWriter out_file; - - /** Some information is read from the board, because it is not contained in the speccctra session file. */ - private final board.BasicBoard board; - - /** The layer structure in specctra format */ - private final LayerStructure specctra_layer_structure; - - private final board.Unit unit; - - /** The scale factor for transforming coordinates from the session file to Eagle */ - private final double session_file_scale_denominator; - - /** The scale factor for transforming coordinates from the board to Eagle */ - private final double board_scale_factor; - - private static class PinInfo - { - PinInfo(board.Pin p_pin) - { - pin = p_pin; - curr_changed_to = p_pin; - } - final board.Pin pin; - board.Pin curr_changed_to; - } -} - +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * SessionToEagle.java + * + * Created on 8. Dezember 2004, 07:42 + */ + +package designformats.specctra; + + +/** + * Transformes a Specctra session file into an Eagle script file. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class SessionToEagle extends javax.swing.JFrame +{ + + /** + *

get_instance.

+ * + * @param p_session a {@link java.io.InputStream} object. + * @param p_output_stream a {@link java.io.OutputStream} object. + * @param p_board a {@link board.BasicBoard} object. + * @return a boolean. + */ + public static boolean get_instance(java.io.InputStream p_session, java.io.OutputStream p_output_stream, + board.BasicBoard p_board) + { + if (p_output_stream == null) + { + return false; + } + + // create a scanner for reading the session_file. + + Scanner scanner = new SpecctraFileScanner(p_session); + + // create a file_writer for the eagle script file. + java.io.OutputStreamWriter file_writer = new java.io.OutputStreamWriter(p_output_stream); + + boolean result = true; + + double board_scale_factor = p_board.communication.coordinate_transform.board_to_dsn(1); + SessionToEagle new_instance = new SessionToEagle(scanner, file_writer, p_board, + p_board.communication.unit, p_board.communication.resolution, board_scale_factor); + + try + { + result = new_instance.process_session_scope(); + } + catch (java.io.IOException e) + { + System.out.println("unable to process session scope"); + result = false; + } + + // close files + try + { + p_session.close(); + file_writer.close(); + } + catch (java.io.IOException e) + { + System.out.println("unable to close files"); + } + return result; + } + + SessionToEagle(Scanner p_scanner, java.io.OutputStreamWriter p_out_file, board.BasicBoard p_board, + board.Unit p_unit, double p_session_file_scale_dominator, double p_board_scale_factor) + { + scanner = p_scanner; + out_file = p_out_file; + board = p_board; + this.specctra_layer_structure = new LayerStructure(p_board.layer_structure); + unit = p_unit; + session_file_scale_denominator = p_session_file_scale_dominator; + board_scale_factor = p_board_scale_factor; + } + + /** + * Processes the outmost scope of the session file. + * Returns false, if an error occured. + */ + private boolean process_session_scope() throws java.io.IOException + { + + // read the first line of the session file + Object next_token = null; + for (int i = 0; i < 3; ++i) + { + next_token = this.scanner.next_token(); + boolean keyword_ok = true; + if (i == 0) + { + keyword_ok = (next_token == Keyword.OPEN_BRACKET); + } + else if (i == 1) + { + keyword_ok = (next_token == Keyword.SESSION); + this.scanner.yybegin(SpecctraFileScanner.NAME); // to overread the name of the pcb for i = 2 + } + if (!keyword_ok) + { + System.out.println("SessionToEagle.process_session_scope specctra session file format expected"); + return false; + } + } + + // Write the header of the eagle script file. + + this.out_file.write("GRID "); + this.out_file.write(this.unit.toString()); + this.out_file.write("\n"); + this.out_file.write("SET WIRE_BEND 2\n"); + this.out_file.write("SET OPTIMIZING OFF\n"); + + // Activate all layers in Eagle. + + for (int i = 0; i < this.board.layer_structure.arr.length; ++i) + { + this.out_file.write("LAYER " + this.get_eagle_layer_string(i) + ";\n"); + } + + this.out_file.write("LAYER 17;\n"); + this.out_file.write("LAYER 18;\n"); + this.out_file.write("LAYER 19;\n"); + this.out_file.write("LAYER 20;\n"); + this.out_file.write("LAYER 23;\n"); + this.out_file.write("LAYER 24;\n"); + + // Generate Code to remove the complete route. + // Write a bounding rectangle with GROUP (Min_X-1 Min_Y-1) (Max_X+1 Max_Y+1); + + geometry.planar.IntBox board_bounding_box = this.board.get_bounding_box(); + + Float min_x = (float) this.board_scale_factor * (board_bounding_box.ll.x - 1); + Float min_y = (float) this.board_scale_factor * (board_bounding_box.ll.y - 1); + Float max_x = (float) this.board_scale_factor * (board_bounding_box.ur.x + 1); + Float max_y = (float) this.board_scale_factor * (board_bounding_box.ur.y + 1); + + this.out_file.write("GROUP ("); + this.out_file.write(min_x.toString()); + this.out_file.write(" "); + this.out_file.write(min_y.toString()); + this.out_file.write(") ("); + this.out_file.write(max_x.toString()); + this.out_file.write(" "); + this.out_file.write(max_y.toString()); + this.out_file.write(");\n"); + this.out_file.write("RIPUP;\n"); + + // read the direct subscopes of the session scope + for (;;) + { + Object prev_token = next_token; + next_token = this.scanner.next_token(); + if (next_token == null) + { + // end of file + return true; + } + if (next_token == Keyword.CLOSED_BRACKET) + { + // end of scope + break; + } + + if (prev_token == Keyword.OPEN_BRACKET) + { + if (next_token == Keyword.ROUTES) + { + if (!process_routes_scope()) + { + return false; + } + } + else if (next_token == Keyword.PLACEMENT_SCOPE) + { + if (!process_placement_scope()) + { + return false; + } + } + else + { + // overread all scopes except the routes scope for the time being + ScopeKeyword.skip_scope(this.scanner); + } + } + } + // Wird nur einmal am Ende benoetigt! + this.out_file.write("RATSNEST\n"); + return true; + } + + private boolean process_placement_scope() throws java.io.IOException + { + // read the component scopes + Object next_token = null; + for (;;) + { + Object prev_token = next_token; + next_token = this.scanner.next_token(); + if (next_token == null) + { + // unexpected end of file + return false; + } + if (next_token == Keyword.CLOSED_BRACKET) + { + // end of scope + break; + } + + if (prev_token == Keyword.OPEN_BRACKET) + { + + if (next_token == Keyword.COMPONENT_SCOPE) + { + if (!process_component_placement()) + { + return false; + } + } + else + { + // skip unknown scope + ScopeKeyword.skip_scope(this.scanner); + } + + } + } + process_swapped_pins(); + return true; + } + + private boolean process_component_placement() throws java.io.IOException + { + ComponentPlacement component_placement = Component.read_scope(this.scanner); + if (component_placement == null) + { + return false; + } + for (ComponentPlacement.ComponentLocation curr_location : component_placement.locations) + { + this.out_file.write("ROTATE ="); + Integer rotation = (int) Math.round(curr_location.rotation); + String rotation_string; + if (curr_location.is_front) + { + rotation_string = "R" + rotation.toString(); + } + else + { + rotation_string = "MR" + rotation.toString(); + } + this.out_file.write(rotation_string); + this.out_file.write(" '"); + this.out_file.write(curr_location.name); + this.out_file.write("';\n"); + this.out_file.write("move '"); + this.out_file.write(curr_location.name); + this.out_file.write("' ("); + Double x_coor = curr_location.coor[0] / this.session_file_scale_denominator; + this.out_file.write(x_coor.toString()); + this.out_file.write(" "); + Double y_coor = curr_location.coor[1] / this.session_file_scale_denominator; + this.out_file.write(y_coor.toString()); + this.out_file.write(");\n"); + } + return true; + } + + private boolean process_routes_scope() throws java.io.IOException + { + // read the direct subscopes of the routes scope + boolean result = true; + Object next_token = null; + for (;;) + { + Object prev_token = next_token; + next_token = this.scanner.next_token(); + if (next_token == null) + { + // unexpected end of file + return false; + } + if (next_token == Keyword.CLOSED_BRACKET) + { + // end of scope + break; + } + + if (prev_token == Keyword.OPEN_BRACKET) + { + + if (next_token == Keyword.NETWORK_OUT) + { + result = process_network_scope(); + } + else + { + // skip unknown scope + ScopeKeyword.skip_scope(this.scanner); + } + + } + } + return result; + } + + private boolean process_network_scope() throws java.io.IOException + { + boolean result = true; + Object next_token = null; + // read the net scopes + for (;;) + { + Object prev_token = next_token; + next_token = this.scanner.next_token(); + if (next_token == null) + { + // unexpected end of file + return false; + } + if (next_token == Keyword.CLOSED_BRACKET) + { + // end of scope + break; + } + + if (prev_token == Keyword.OPEN_BRACKET) + { + + if (next_token == Keyword.NET) + { + result = process_net_scope(); + } + else + { + // skip unknown scope + ScopeKeyword.skip_scope(this.scanner); + } + + } + } + return result; + } + + private boolean process_net_scope() throws java.io.IOException + { + // read the net name + Object next_token = this.scanner.next_token(); + if (!(next_token instanceof String)) + { + System.out.println("SessionToEagle.processnet_scope: String expected"); + return false; + } + String net_name = (String) next_token; + + // Hier alle nicht gefixten Traces und Vias des Netz mit Namen net_name + // in der Eagle Datenhaltung loeschen. + + // read the wires and vias of this net + for (;;) + { + Object prev_token = next_token; + next_token = this.scanner.next_token(); + if (next_token == null) + { + // end of file + return true; + } + if (next_token == Keyword.CLOSED_BRACKET) + { + // end of scope + break; + } + + if (prev_token == Keyword.OPEN_BRACKET) + { + if (next_token == Keyword.WIRE) + { + if (!process_wire_scope(net_name)) + { + return false; + } + } + else if (next_token == Keyword.VIA) + { + if (!process_via_scope(net_name)) + { + return false; + } + } + else + { + ScopeKeyword.skip_scope(this.scanner); + } + } + } + return true; + } + + private boolean process_wire_scope(String p_net_name) throws java.io.IOException + { + PolygonPath wire_path = null; + Object next_token = null; + for (;;) + { + Object prev_token = next_token; + next_token = this.scanner.next_token(); + if (next_token == null) + { + System.out.println("SessionToEagle.process_wire_scope: unexpected end of file"); + return false; + } + if (next_token == Keyword.CLOSED_BRACKET) + { + // end of scope + break; + } + if (prev_token == Keyword.OPEN_BRACKET) + { + if (next_token == Keyword.POLYGON_PATH) + { + wire_path = Shape.read_polygon_path_scope(this.scanner, this.specctra_layer_structure); + } + else + { + ScopeKeyword.skip_scope(this.scanner); + } + } + } + if (wire_path == null) + { + // conduction areas are skipped + return true; + } + + this.out_file.write("CHANGE LAYER "); + + this.out_file.write(wire_path.layer.name); + this.out_file.write(";\n"); + + //WIRE ['signal_name'] [width] [ROUND | FLAT] [curve | @radius] + + this.out_file.write("WIRE '"); + + this.out_file.write(p_net_name); + this.out_file.write("' "); + Double wire_width = wire_path.width / this.session_file_scale_denominator; + this.out_file.write(wire_width.toString()); + this.out_file.write(" ("); + for (int i = 0; i < wire_path.coordinate_arr.length; ++i) + { + Double wire_coor = wire_path.coordinate_arr[i] / this.session_file_scale_denominator; + this.out_file.write(wire_coor.toString()); + if (i % 2 == 0) + { + this.out_file.write(" "); + } + else + { + if (i == wire_path.coordinate_arr.length - 1) + { + this.out_file.write(")"); + } + else + { + this.out_file.write(") ("); + } + } + } + this.out_file.write(";\n"); + + return true; + } + + private boolean process_via_scope(String p_net_name) throws java.io.IOException + { + // read the padstack name + Object next_token = this.scanner.next_token(); + if (!(next_token instanceof String)) + { + System.out.println("SessionToEagle.process_via_scope: padstack name expected"); + return false; + } + String padstack_name = (String) next_token; + // read the location + double []location = new double [2]; + for (int i = 0; i < 2; ++i) + { + next_token = this.scanner.next_token(); + if (next_token instanceof Double) + { + location[i] = ((Double) next_token).doubleValue(); + } + else if (next_token instanceof Integer) + { + location[i] = ((Integer) next_token).intValue(); + } + else + { + System.out.println("SessionToEagle.process_via_scope: number expected"); + return false; + } + } + next_token = this.scanner.next_token(); + while (next_token == Keyword.OPEN_BRACKET) + { + // skip unknown scopes + ScopeKeyword.skip_scope(this.scanner); + next_token = this.scanner.next_token(); + } + if (next_token != Keyword.CLOSED_BRACKET) + { + System.out.println("SessionToEagle.process_via_scope: closing bracket expected"); + return false; + } + + if (padstack_name == null) + { + System.out.println("SessionToEagle.process_via_scope: padstack_name missing"); + return false; + } + + library.Padstack via_padstack = this.board.library.padstacks.get(padstack_name); + + if (via_padstack == null) + { + System.out.println("SessionToEagle.process_via_scope: via padstack not found"); + return false; + } + + geometry.planar.ConvexShape via_shape = via_padstack.get_shape(via_padstack.from_layer()); + + Double via_diameter = via_shape.max_width() * this.board_scale_factor; + + // The Padstack name is of the form Name$drill_diameter$from_layer-to_layer + + String [] name_parts = via_padstack.name.split("\\$", 3); + + // example CHANGE DRILL 0.2 + + this.out_file.write("CHANGE DRILL "); + if (name_parts.length > 1) + { + this.out_file.write(name_parts[1]); + } + else + { + // create a default drill, because it is needed in Eagle + this.out_file.write("0.1"); + } + this.out_file.write(";\n"); + + + //VIA ['signal_name'] [diameter] [shape] [layers] [flags] + // Via Net2 0.6 round 1-4 (20.0, 222.0); + this.out_file.write("VIA '"); + + this.out_file.write(p_net_name); + this.out_file.write("' "); + + //Durchmesser aus Padstack + this.out_file.write(via_diameter.toString()); + + //Shape lesen und einsetzen Square / Round / Octagon + if (via_shape instanceof geometry.planar.Circle) + { + this.out_file.write(" round "); + } + else if (via_shape instanceof geometry.planar.IntOctagon) + { + this.out_file.write(" octagon "); + } + else + { + this.out_file.write(" square "); + } + this.out_file.write(get_eagle_layer_string(via_padstack.from_layer())); + this.out_file.write("-"); + this.out_file.write(get_eagle_layer_string(via_padstack.to_layer())); + this.out_file.write(" ("); + Double x_coor = location[0] / this.session_file_scale_denominator; + this.out_file.write(x_coor.toString()); + this.out_file.write(" "); + Double y_coor = location[1] / this.session_file_scale_denominator; + this.out_file.write(y_coor.toString()); + this.out_file.write(");\n"); + + return true; + } + + private String get_eagle_layer_string(int p_layer_no) + { + if (p_layer_no < 0 || p_layer_no >= specctra_layer_structure.arr.length) + { + return "0"; + } + String [] name_pieces = this.specctra_layer_structure.arr[p_layer_no].name.split("#", 2); + return name_pieces[0]; + } + + private boolean process_swapped_pins() throws java.io.IOException + { + for (int i = 1; i <= this.board.components.count(); ++i) + { + if (!process_swapped_pins(i)) + { + return false; + } + } + return true; + } + + private boolean process_swapped_pins(int p_component_no) throws java.io.IOException + { + java.util.Collection component_pins = this.board.get_component_pins(p_component_no); + boolean component_has_swapped_pins = false; + for (board.Pin curr_pin : component_pins) + { + if (curr_pin.get_changed_to() != curr_pin) + { + component_has_swapped_pins = true; + break; + } + } + if (!component_has_swapped_pins) + { + return true; + } + PinInfo[] pin_info_arr = new PinInfo[component_pins.size()]; + int i = 0; + for (board.Pin curr_pin : component_pins) + { + pin_info_arr[i] = new PinInfo(curr_pin); + ++i; + } + for (i = 0; i < pin_info_arr.length; ++i) + { + PinInfo curr_pin_info = pin_info_arr[i]; + if (curr_pin_info.curr_changed_to != curr_pin_info.pin.get_changed_to()) + { + PinInfo other_pin_info = null; + for (int j = i + 1; j < pin_info_arr.length; ++j) + { + if (pin_info_arr[j].pin.get_changed_to() == curr_pin_info.pin) + { + other_pin_info = pin_info_arr[j]; + } + } + if (other_pin_info == null) + { + System.out.println("SessuinToEagle.process_swapped_pins: other_pin_info not found"); + return false; + } + write_pin_swap(curr_pin_info.pin, other_pin_info.pin); + curr_pin_info.curr_changed_to = other_pin_info.pin; + other_pin_info.curr_changed_to = curr_pin_info.pin; + } + } + return true; + } + + private void write_pin_swap( board.Pin p_pin_1, board.Pin p_pin_2) throws java.io.IOException + { + int layer_no = Math.max(p_pin_1.first_layer(), p_pin_2.first_layer()); + String layer_name = board.layer_structure.arr[layer_no].name; + + this.out_file.write("CHANGE LAYER "); + this.out_file.write(layer_name); + this.out_file.write(";\n"); + + double [] location_1 = + this.board.communication.coordinate_transform.board_to_dsn(p_pin_1.get_center().to_float()); + double [] location_2 = + this.board.communication.coordinate_transform.board_to_dsn(p_pin_2.get_center().to_float()); + + this.out_file.write("PINSWAP "); + this.out_file.write(" ("); + Double curr_coor = location_1[0]; + this.out_file.write(curr_coor.toString()); + this.out_file.write(" "); + curr_coor = location_1[1]; + this.out_file.write(curr_coor.toString()); + this.out_file.write(") ("); + curr_coor = location_2[0]; + this.out_file.write(curr_coor.toString()); + this.out_file.write(" "); + curr_coor = location_2[1]; + this.out_file.write(curr_coor.toString()); + this.out_file.write(");\n"); + } + + + + /** The function for scanning the session file */ + private final Scanner scanner; + + /** The generated Eagle script file. */ + private final java.io.OutputStreamWriter out_file; + + /** Some information is read from the board, because it is not contained in the speccctra session file. */ + private final board.BasicBoard board; + + /** The layer structure in specctra format */ + private final LayerStructure specctra_layer_structure; + + private final board.Unit unit; + + /** The scale factor for transforming coordinates from the session file to Eagle */ + private final double session_file_scale_denominator; + + /** The scale factor for transforming coordinates from the board to Eagle */ + private final double board_scale_factor; + + private static class PinInfo + { + PinInfo(board.Pin p_pin) + { + pin = p_pin; + curr_changed_to = p_pin; + } + final board.Pin pin; + board.Pin curr_changed_to; + } +} + diff --git a/designformats/specctra/Shape.java b/src/main/java/designformats/specctra/Shape.java similarity index 89% rename from designformats/specctra/Shape.java rename to src/main/java/designformats/specctra/Shape.java index e1da944..78adf61 100644 --- a/designformats/specctra/Shape.java +++ b/src/main/java/designformats/specctra/Shape.java @@ -31,24 +31,37 @@ * Describes a shape in a Specctra dsn file. * * @author alfons + * @version $Id: $Id */ public abstract class Shape { /** * Writes a shape scope to a Specctra dsn file. + * + * @param p_file a {@link datastructures.IndentFileWriter} object. + * @param p_identifier a {@link datastructures.IdentifierType} object. + * @throws java.io.IOException if any. */ public abstract void write_scope(IndentFileWriter p_file, IdentifierType p_identifier) throws java.io.IOException; /** * Writes a shape scope to a Specctra session file. * In a session file all coordinates must be integer. + * + * @param p_file a {@link datastructures.IndentFileWriter} object. + * @param p_identifier a {@link datastructures.IdentifierType} object. + * @throws java.io.IOException if any. */ public abstract void write_scope_int(IndentFileWriter p_file, IdentifierType p_identifier) throws java.io.IOException; /** * Reads shape scope from a Specctra dsn file. * If p_layer_structure == null, only Layer.PCB and Layer.Signal are expected, no induvidual layers. + * + * @param p_scanner a {@link designformats.specctra.Scanner} object. + * @param p_layer_structure a {@link designformats.specctra.LayerStructure} object. + * @return a {@link designformats.specctra.Shape} object. */ public static final Shape read_scope(Scanner p_scanner, LayerStructure p_layer_structure) { @@ -98,6 +111,10 @@ else if (next_token == Keyword.POLYGON_PATH) /** * Reads an object of type PolylinePath from the dsn-file. + * + * @param p_scanner a {@link designformats.specctra.Scanner} object. + * @param p_layer_structure a {@link designformats.specctra.LayerStructure} object. + * @return a {@link designformats.specctra.PolylinePath} object. */ public static PolylinePath read_polyline_path_scope(Scanner p_scanner, LayerStructure p_layer_structure) { @@ -201,6 +218,11 @@ else if (next_object instanceof Integer) * Reads a shape , which may contain holes from a specctra dsn-file. * The first shape in the shape_list of the result is the border of the area. * The other shapes in the shape_list are holes (windows). + * + * @param p_scanner a {@link designformats.specctra.Scanner} object. + * @param p_layer_structure a {@link designformats.specctra.LayerStructure} object. + * @param p_skip_window_scopes a boolean. + * @return a {@link designformats.specctra.Shape.ReadAreaScopeResult} object. */ public static final ReadAreaScopeResult read_area_scope(Scanner p_scanner, LayerStructure p_layer_structure, boolean p_skip_window_scopes) @@ -302,6 +324,10 @@ else if (next_token == Keyword.CLEARANCE_CLASS) /** * Reads a rectangle scope from a Specctra dsn file. * If p_layer_structure == null, only Layer.PCB and Layer.Signal are expected, no induvidual layers. + * + * @param p_scanner a {@link designformats.specctra.Scanner} object. + * @param p_layer_structure a {@link designformats.specctra.LayerStructure} object. + * @return a {@link designformats.specctra.Rectangle} object. */ public static Rectangle read_rectangle_scope(Scanner p_scanner, LayerStructure p_layer_structure) { @@ -385,6 +411,10 @@ else if (next_token instanceof Integer) /** * Reads a closed polygon scope from a Specctra dsn file. * If p_layer_structure == null, only Layer.PCB and Layer.Signal are expected, no induvidual layers. + * + * @param p_scanner a {@link designformats.specctra.Scanner} object. + * @param p_layer_structure a {@link designformats.specctra.LayerStructure} object. + * @return a {@link designformats.specctra.Polygon} object. */ public static Polygon read_polygon_scope(Scanner p_scanner, LayerStructure p_layer_structure) { @@ -489,6 +519,10 @@ else if (next_object instanceof Integer) /** * Reads a circle scope from a Specctra dsn file. + * + * @param p_scanner a {@link designformats.specctra.Scanner} object. + * @param p_layer_structure a {@link designformats.specctra.LayerStructure} object. + * @return a {@link designformats.specctra.Circle} object. */ public static Circle read_circle_scope(Scanner p_scanner, LayerStructure p_layer_structure) { @@ -577,6 +611,10 @@ else if (next_token instanceof Integer) /** * Reads an object of type Path from the dsn-file. + * + * @param p_scanner a {@link designformats.specctra.Scanner} object. + * @param p_layer_structure a {@link designformats.specctra.LayerStructure} object. + * @return a {@link designformats.specctra.PolygonPath} object. */ public static PolygonPath read_polygon_path_scope(Scanner p_scanner, LayerStructure p_layer_structure) { @@ -694,6 +732,10 @@ else if (next_object instanceof Integer) * Transforms a shape with holes to the board coordinate system. * The first shape in the Collection p_area is the border, * the other shapes are holes of the area. + * + * @param p_area a java$util$Collection object. + * @param p_coordinate_transform a {@link designformats.specctra.CoordinateTransform} object. + * @return a {@link geometry.planar.Area} object. */ public static geometry.planar.Area transform_area_to_board(Collection p_area, CoordinateTransform p_coordinate_transform) { @@ -740,6 +782,10 @@ public static geometry.planar.Area transform_area_to_board(Collection p_a * Transforms the relative coordinates of a shape with holes to the board coordinate system. * The first shape in the Collection p_area is the border, * the other shapes are holes of the area. + * + * @param p_area a java$util$Collection object. + * @param p_coordinate_transform a {@link designformats.specctra.CoordinateTransform} object. + * @return a {@link geometry.planar.Area} object. */ public static geometry.planar.Area transform_area_to_board_rel(Collection p_area, CoordinateTransform p_coordinate_transform) { @@ -782,6 +828,13 @@ public static geometry.planar.Area transform_area_to_board_rel(Collection return result; } + /** + *

write_hole_scope.

+ * + * @param p_file a {@link datastructures.IndentFileWriter} object. + * @param p_identifier_type a {@link datastructures.IdentifierType} object. + * @throws java.io.IOException if any. + */ public void write_hole_scope(IndentFileWriter p_file, IdentifierType p_identifier_type) throws java.io.IOException { p_file.start_scope(); @@ -792,19 +845,32 @@ public void write_hole_scope(IndentFileWriter p_file, IdentifierType p_identifie /** * Transforms a specctra dsn shape to a geometry.planar.Shape. + * + * @param p_coordinate_transform a {@link designformats.specctra.CoordinateTransform} object. + * @return a {@link geometry.planar.Shape} object. */ public abstract geometry.planar.Shape transform_to_board(CoordinateTransform p_coordinate_transform); /** * Returns the smallest axis parallel rectangle containing this shape. + * + * @return a {@link designformats.specctra.Rectangle} object. */ public abstract Rectangle bounding_box(); /** * Transforms the relative (vector) coordinates of a specctra dsn shape to a geometry.planar.Shape. + * + * @param p_coordinate_transform a {@link designformats.specctra.CoordinateTransform} object. + * @return a {@link geometry.planar.Shape} object. */ public abstract geometry.planar.Shape transform_to_board_rel(CoordinateTransform p_coordinate_transform); + /** + *

Constructor for Shape.

+ * + * @param p_layer a {@link designformats.specctra.Layer} object. + */ protected Shape(Layer p_layer) { layer = p_layer; diff --git a/designformats/specctra/SpecctraFileDescription.flex b/src/main/java/designformats/specctra/SpecctraFileDescription.flex similarity index 100% rename from designformats/specctra/SpecctraFileDescription.flex rename to src/main/java/designformats/specctra/SpecctraFileDescription.flex diff --git a/designformats/specctra/SpecctraFileScanner.java b/src/main/java/designformats/specctra/SpecctraFileScanner.java similarity index 95% rename from designformats/specctra/SpecctraFileScanner.java rename to src/main/java/designformats/specctra/SpecctraFileScanner.java index b58c837..0945722 100644 --- a/designformats/specctra/SpecctraFileScanner.java +++ b/src/main/java/designformats/specctra/SpecctraFileScanner.java @@ -1,1459 +1,1473 @@ -/* The following code was generated by JFlex 1.4.1 on 16.10.08 09:27 */ - -package designformats.specctra; -@SuppressWarnings("all") - -/** - * This class is a scanner generated by - * JFlex 1.4.1 - * on 16.10.08 09:27 from the specification file - * C:/Users/Public/Documents/router/sources/designformats/specctra/SpecctraFileDescription.flex - */ -class SpecctraFileScanner implements Scanner { - - /** This character denotes the end of file */ - public static final int YYEOF = -1; - - /** initial size of the lookahead buffer */ - private static final int ZZ_BUFFERSIZE = 16384; - - /** lexical states */ - public static final int COMPONENT_NAME = 5; - public static final int IGNORE_QUOTE = 7; - public static final int YYINITIAL = 0; - public static final int SPEC_CHAR = 6; - public static final int LAYER_NAME = 4; - public static final int STRING2 = 2; - public static final int STRING1 = 1; - public static final int NAME = 3; - - /** - * Translates characters to character classes - */ - private static final String ZZ_CMAP_PACKED = - "\11\0\1\3\1\2\1\0\1\3\1\1\21\0\1\16\1\3\1\16"+ - "\1\11\1\6\1\16\1\16\1\16\1\12\1\53\1\54\1\5\1\20"+ - "\1\16\1\17\1\14\1\4\1\21\11\10\1\16\1\16\1\16\1\16"+ - "\1\16\1\16\1\16\1\23\1\24\1\32\1\42\1\22\1\41\1\35"+ - "\1\43\1\33\1\7\1\44\1\27\1\46\1\36\1\26\1\37\1\52"+ - "\1\40\1\25\1\31\1\30\1\34\1\51\1\47\1\45\1\50\1\16"+ - "\1\15\1\16\1\16\1\13\1\0\1\23\1\24\1\32\1\42\1\22"+ - "\1\41\1\35\1\43\1\33\1\7\1\44\1\27\1\46\1\36\1\26"+ - "\1\37\1\52\1\40\1\25\1\31\1\30\1\34\1\51\1\47\1\45"+ - "\1\50\3\0\1\16\42\0\136\16\1\16\122\0\2\16\14\0\2\16"+ - "\26\0\1\16\4\0\2\16\22\0\2\16\u0133\0\1\16\25\0\1\16"+ - "\u1d36\0\1\16\1\16\3\0\1\16\1\16\1\16\1\0\1\16\1\16"+ - "\1\16\1\0\1\16\1\16\1\16\3\0\1\16\11\0\1\16\10\0"+ - "\1\16\1\16\161\0\1\16\165\0\1\16\udedd\0"; - - /** - * Translates characters to character classes - */ - private static final char [] ZZ_CMAP = zzUnpackCMap(ZZ_CMAP_PACKED); - - /** - * Translates DFA states to action switch labels. - */ - private static final int [] ZZ_ACTION = zzUnpackAction(); - - private static final String ZZ_ACTION_PACKED_0 = - "\7\0\1\1\1\2\2\3\3\4\1\5\1\6\1\7"+ - "\1\2\1\5\22\4\1\10\1\11\1\12\1\13\1\14"+ - "\1\12\1\1\1\15\1\16\3\1\2\4\3\0\1\17"+ - "\16\4\1\20\45\4\2\1\1\0\1\4\2\17\1\0"+ - "\1\17\22\4\1\21\16\4\1\22\1\4\1\23\13\4"+ - "\1\24\1\25\11\4\1\26\10\4\1\1\1\27\1\0"+ - "\6\4\1\30\6\4\1\31\14\4\1\32\2\4\1\33"+ - "\2\4\1\34\3\4\1\35\2\4\1\36\2\4\1\37"+ - "\5\4\1\40\4\4\1\41\2\4\1\42\2\4\1\43"+ - "\11\4\1\44\3\4\1\1\14\4\1\45\1\46\2\4"+ - "\1\47\1\4\1\50\11\4\1\51\1\52\2\4\1\53"+ - "\20\4\1\54\1\55\1\56\6\4\1\57\3\4\1\60"+ - "\7\4\1\61\1\4\1\1\2\4\1\62\1\63\6\4"+ - "\1\64\3\4\1\65\15\4\1\34\10\4\1\66\1\4"+ - "\1\67\15\4\1\70\1\71\1\72\2\4\1\73\4\4"+ - "\1\74\1\4\1\75\1\4\1\76\4\4\1\77\6\4"+ - "\1\100\3\4\1\101\1\4\1\102\1\103\1\4\1\104"+ - "\3\4\1\105\1\106\6\4\1\107\6\4\1\40\17\4"+ - "\1\110\2\4\1\111\2\4\1\112\12\4\1\113\3\4"+ - "\1\114\2\4\1\115\5\4\1\116\1\4\1\117\14\4"+ - "\1\120\4\4\1\121\3\4\1\122\4\4\1\123\1\4"+ - "\1\124\1\33\1\51\2\4\1\125\5\4\1\126\3\4"+ - "\1\127\4\4\1\42\14\4\1\130\1\4\1\131\3\4"+ - "\1\132\11\4\1\133\1\4\1\134\2\4\1\135\1\4"+ - "\1\136\7\4\1\137\2\4\1\140\1\141\1\4\1\142"+ - "\20\4\1\143\1\144\3\4\1\145\5\4\1\146\1\4"+ - "\1\147\1\150\3\4\1\151\4\4\1\152\1\153\1\154"+ - "\1\155\23\4\1\156\1\4\1\157\11\4\1\160\1\161"+ - "\2\4\1\162\3\4\1\163\3\4\1\164\5\4\1\165"+ - "\6\4\1\166\20\4\1\167\7\4\1\170"; - - private static int [] zzUnpackAction() { - int [] result = new int[712]; - int offset = 0; - offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result); - return result; - } - - private static int zzUnpackAction(String packed, int offset, int [] result) { - int i = 0; /* index in packed string */ - int j = offset; /* index in unpacked array */ - int l = packed.length(); - while (i < l) { - int count = packed.charAt(i++); - int value = packed.charAt(i++); - do result[j++] = value; while (--count > 0); - } - return j; - } - - - /** - * Translates a state to a row index in the transition table - */ - private static final int [] ZZ_ROWMAP = zzUnpackRowMap(); - - private static final String ZZ_ROWMAP_PACKED_0 = - "\0\0\0\55\0\132\0\207\0\264\0\341\0\u010e\0\u013b"+ - "\0\u0168\0\u0195\0\u0168\0\u01c2\0\u01ef\0\u021c\0\u0249\0\u0168"+ - "\0\u0168\0\u0276\0\u02a3\0\u02d0\0\u02fd\0\u032a\0\u0357\0\u0384"+ - "\0\u03b1\0\u03de\0\u040b\0\u0438\0\u0465\0\u0492\0\u04bf\0\u04ec"+ - "\0\u0519\0\u0546\0\u0573\0\u05a0\0\u05cd\0\u0168\0\u0168\0\u05fa"+ - "\0\u0168\0\u0168\0\u0627\0\u0654\0\u0168\0\u0168\0\u0681\0\u06ae"+ - "\0\u06db\0\u0168\0\u0708\0\u0735\0\u0762\0\u078f\0\u02a3\0\u07bc"+ - "\0\u07e9\0\u0816\0\u0843\0\u0870\0\u089d\0\u08ca\0\u08f7\0\u0924"+ - "\0\u0951\0\u097e\0\u09ab\0\u09d8\0\u0a05\0\u01ef\0\u0a32\0\u0a5f"+ - "\0\u0a8c\0\u0ab9\0\u0ae6\0\u0b13\0\u0b40\0\u0b6d\0\u0b9a\0\u0bc7"+ - "\0\u0bf4\0\u0c21\0\u0c4e\0\u0c7b\0\u0ca8\0\u0cd5\0\u0d02\0\u0d2f"+ - "\0\u0d5c\0\u0d89\0\u0db6\0\u0de3\0\u0e10\0\u0e3d\0\u0e6a\0\u0e97"+ - "\0\u0ec4\0\u0ef1\0\u0f1e\0\u0f4b\0\u0f78\0\u0fa5\0\u0fd2\0\u0fff"+ - "\0\u102c\0\u1059\0\u1086\0\u10b3\0\u10e0\0\u110d\0\u113a\0\u1167"+ - "\0\u1194\0\u11c1\0\u0168\0\u11ee\0\u121b\0\u1248\0\u1275\0\u12a2"+ - "\0\u12cf\0\u12fc\0\u1329\0\u1356\0\u1383\0\u13b0\0\u13dd\0\u140a"+ - "\0\u1437\0\u1464\0\u1491\0\u14be\0\u14eb\0\u01ef\0\u1518\0\u1545"+ - "\0\u1572\0\u159f\0\u15cc\0\u15f9\0\u1626\0\u1653\0\u1680\0\u16ad"+ - "\0\u16da\0\u1707\0\u1734\0\u1761\0\u178e\0\u17bb\0\u17e8\0\u1815"+ - "\0\u1842\0\u186f\0\u189c\0\u18c9\0\u18f6\0\u1923\0\u1950\0\u197d"+ - "\0\u19aa\0\u19d7\0\u01ef\0\u1a04\0\u1a31\0\u1a5e\0\u1a8b\0\u1ab8"+ - "\0\u1ae5\0\u1b12\0\u1b3f\0\u1b6c\0\u1b99\0\u01ef\0\u1bc6\0\u1bf3"+ - "\0\u1c20\0\u1c4d\0\u1c7a\0\u1ca7\0\u1cd4\0\u1d01\0\u1d2e\0\u0654"+ - "\0\u1d5b\0\u1d88\0\u1db5\0\u1de2\0\u1e0f\0\u1e3c\0\u1e69\0\u01ef"+ - "\0\u1e96\0\u1ec3\0\u1ef0\0\u1f1d\0\u1f4a\0\u1f77\0\u01ef\0\u1fa4"+ - "\0\u1fd1\0\u1ffe\0\u202b\0\u2058\0\u2085\0\u20b2\0\u20df\0\u210c"+ - "\0\u2139\0\u2166\0\u2193\0\u01ef\0\u21c0\0\u21ed\0\u221a\0\u2247"+ - "\0\u2274\0\u22a1\0\u22ce\0\u22fb\0\u2328\0\u01ef\0\u2355\0\u2382"+ - "\0\u01ef\0\u23af\0\u23dc\0\u01ef\0\u2409\0\u2436\0\u2463\0\u2490"+ - "\0\u24bd\0\u24ea\0\u2517\0\u2544\0\u2571\0\u259e\0\u01ef\0\u25cb"+ - "\0\u25f8\0\u2625\0\u2652\0\u267f\0\u26ac\0\u26d9\0\u2706\0\u2733"+ - "\0\u2760\0\u278d\0\u27ba\0\u27e7\0\u2814\0\u2841\0\u286e\0\u289b"+ - "\0\u28c8\0\u28f5\0\u2922\0\u294f\0\u297c\0\u29a9\0\u29d6\0\u2a03"+ - "\0\u2a30\0\u2a5d\0\u2a8a\0\u2ab7\0\u2ae4\0\u2b11\0\u2b3e\0\u01ef"+ - "\0\u01ef\0\u2b6b\0\u2b98\0\u01ef\0\u2bc5\0\u2bf2\0\u2c1f\0\u2c4c"+ - "\0\u2c79\0\u2ca6\0\u2cd3\0\u2d00\0\u2d2d\0\u2d5a\0\u2d87\0\u2db4"+ - "\0\u2de1\0\u2e0e\0\u2e3b\0\u01ef\0\u2e68\0\u2e95\0\u2ec2\0\u2eef"+ - "\0\u2f1c\0\u2f49\0\u2f76\0\u2fa3\0\u2fd0\0\u2ffd\0\u302a\0\u3057"+ - "\0\u3084\0\u30b1\0\u30de\0\u310b\0\u01ef\0\u3138\0\u3165\0\u3192"+ - "\0\u31bf\0\u31ec\0\u3219\0\u3246\0\u3273\0\u01ef\0\u32a0\0\u32cd"+ - "\0\u32fa\0\u01ef\0\u3327\0\u3354\0\u3381\0\u33ae\0\u33db\0\u3408"+ - "\0\u3435\0\u01ef\0\u3462\0\u348f\0\u34bc\0\u34e9\0\u01ef\0\u01ef"+ - "\0\u3516\0\u3543\0\u3570\0\u359d\0\u35ca\0\u35f7\0\u01ef\0\u3624"+ - "\0\u3651\0\u367e\0\u01ef\0\u36ab\0\u36d8\0\u3705\0\u3732\0\u375f"+ - "\0\u378c\0\u37b9\0\u37e6\0\u3813\0\u3840\0\u386d\0\u389a\0\u38c7"+ - "\0\u01ef\0\u38f4\0\u3921\0\u394e\0\u397b\0\u39a8\0\u39d5\0\u3a02"+ - "\0\u3a2f\0\u01ef\0\u3a5c\0\u01ef\0\u3a89\0\u3ab6\0\u3ae3\0\u3b10"+ - "\0\u3b3d\0\u3b6a\0\u3b97\0\u3bc4\0\u3bf1\0\u3c1e\0\u3c4b\0\u3c78"+ - "\0\u3ca5\0\u01ef\0\u3cd2\0\u01ef\0\u3cff\0\u3d2c\0\u01ef\0\u3d59"+ - "\0\u3d86\0\u3db3\0\u3de0\0\u01ef\0\u3e0d\0\u01ef\0\u3e3a\0\u0654"+ - "\0\u3e67\0\u3e94\0\u3ec1\0\u3eee\0\u01ef\0\u3f1b\0\u3f48\0\u3f75"+ - "\0\u3fa2\0\u3fcf\0\u3ffc\0\u01ef\0\u4029\0\u4056\0\u4083\0\u01ef"+ - "\0\u40b0\0\u01ef\0\u01ef\0\u40dd\0\u01ef\0\u410a\0\u4137\0\u4164"+ - "\0\u01ef\0\u01ef\0\u4191\0\u41be\0\u41eb\0\u4218\0\u4245\0\u4272"+ - "\0\u429f\0\u42cc\0\u42f9\0\u4326\0\u4353\0\u4380\0\u43ad\0\u01ef"+ - "\0\u43da\0\u4407\0\u4434\0\u4461\0\u448e\0\u44bb\0\u44e8\0\u4515"+ - "\0\u4542\0\u456f\0\u459c\0\u45c9\0\u45f6\0\u4623\0\u4650\0\u01ef"+ - "\0\u467d\0\u46aa\0\u01ef\0\u46d7\0\u4704\0\u01ef\0\u4731\0\u475e"+ - "\0\u478b\0\u47b8\0\u47e5\0\u4812\0\u483f\0\u486c\0\u4899\0\u48c6"+ - "\0\u01ef\0\u48f3\0\u4920\0\u494d\0\u01ef\0\u497a\0\u49a7\0\u01ef"+ - "\0\u49d4\0\u4a01\0\u4a2e\0\u4a5b\0\u4a88\0\u01ef\0\u4ab5\0\u01ef"+ - "\0\u4ae2\0\u4b0f\0\u4b3c\0\u4b69\0\u4b96\0\u4bc3\0\u4bf0\0\u4c1d"+ - "\0\u4c4a\0\u4c77\0\u4ca4\0\u4cd1\0\u01ef\0\u4cfe\0\u4d2b\0\u4d58"+ - "\0\u4d85\0\u4db2\0\u4ddf\0\u4e0c\0\u4e39\0\u01ef\0\u4e66\0\u4e93"+ - "\0\u4ec0\0\u4eed\0\u01ef\0\u4f1a\0\u01ef\0\u01ef\0\u4f47\0\u4f74"+ - "\0\u4fa1\0\u01ef\0\u4fce\0\u4ffb\0\u5028\0\u5055\0\u5082\0\u01ef"+ - "\0\u50af\0\u50dc\0\u5109\0\u01ef\0\u5136\0\u5163\0\u5190\0\u51bd"+ - "\0\u01ef\0\u51ea\0\u5217\0\u5244\0\u5271\0\u529e\0\u52cb\0\u52f8"+ - "\0\u5325\0\u5352\0\u537f\0\u53ac\0\u53d9\0\u01ef\0\u5406\0\u01ef"+ - "\0\u5433\0\u5460\0\u548d\0\u01ef\0\u54ba\0\u54e7\0\u5514\0\u5541"+ - "\0\u556e\0\u559b\0\u55c8\0\u55f5\0\u5622\0\u01ef\0\u564f\0\u01ef"+ - "\0\u567c\0\u56a9\0\u01ef\0\u56d6\0\u01ef\0\u5703\0\u5730\0\u575d"+ - "\0\u578a\0\u57b7\0\u57e4\0\u5811\0\u01ef\0\u583e\0\u586b\0\u01ef"+ - "\0\u01ef\0\u5898\0\u01ef\0\u58c5\0\u58f2\0\u591f\0\u594c\0\u5979"+ - "\0\u59a6\0\u59d3\0\u5a00\0\u5a2d\0\u5a5a\0\u5a87\0\u5ab4\0\u5ae1"+ - "\0\u5b0e\0\u5b3b\0\u5b68\0\u01ef\0\u5b95\0\u5bc2\0\u5bef\0\u5c1c"+ - "\0\u01ef\0\u5c49\0\u5c76\0\u5ca3\0\u5cd0\0\u5cfd\0\u01ef\0\u5d2a"+ - "\0\u01ef\0\u01ef\0\u5d57\0\u5d84\0\u5db1\0\u01ef\0\u5dde\0\u5e0b"+ - "\0\u5e38\0\u5e65\0\u01ef\0\u01ef\0\u01ef\0\u01ef\0\u5e92\0\u5ebf"+ - "\0\u5eec\0\u5f19\0\u5f46\0\u5f73\0\u5fa0\0\u5fcd\0\u5ffa\0\u6027"+ - "\0\u6054\0\u6081\0\u60ae\0\u60db\0\u6108\0\u6135\0\u6162\0\u618f"+ - "\0\u61bc\0\u01ef\0\u61e9\0\u01ef\0\u6216\0\u6243\0\u6270\0\u629d"+ - "\0\u62ca\0\u62f7\0\u6324\0\u6351\0\u637e\0\u01ef\0\u01ef\0\u63ab"+ - "\0\u63d8\0\u01ef\0\u6405\0\u6432\0\u645f\0\u01ef\0\u648c\0\u64b9"+ - "\0\u64e6\0\u6513\0\u6540\0\u656d\0\u659a\0\u65c7\0\u65f4\0\u01ef"+ - "\0\u6621\0\u664e\0\u667b\0\u66a8\0\u66d5\0\u6702\0\u01ef\0\u672f"+ - "\0\u675c\0\u6789\0\u67b6\0\u67e3\0\u6810\0\u683d\0\u686a\0\u6897"+ - "\0\u68c4\0\u68f1\0\u691e\0\u694b\0\u6978\0\u69a5\0\u69d2\0\u01ef"+ - "\0\u69ff\0\u6a2c\0\u6a59\0\u6a86\0\u6ab3\0\u6ae0\0\u6b0d\0\u01ef"; - - private static int [] zzUnpackRowMap() { - int [] result = new int[712]; - int offset = 0; - offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result); - return result; - } - - private static int zzUnpackRowMap(String packed, int offset, int [] result) { - int i = 0; /* index in packed string */ - int j = offset; /* index in unpacked array */ - int l = packed.length(); - while (i < l) { - int high = packed.charAt(i++) << 16; - result[j++] = high | packed.charAt(i++); - } - return j; - } - - /** - * The transition table of the DFA - */ - private static final int [] ZZ_TRANS = zzUnpackTrans(); - - private static final String ZZ_TRANS_PACKED_0 = - "\1\11\1\12\2\13\1\14\1\15\1\16\1\15\1\17"+ - "\1\20\1\21\4\15\2\22\1\23\1\15\1\24\1\25"+ - "\1\26\1\27\1\30\1\31\1\32\1\33\1\34\1\35"+ - "\1\36\1\37\1\40\1\41\1\42\1\15\1\43\1\44"+ - "\4\15\1\45\1\15\1\46\1\47\11\50\1\51\3\50"+ - "\1\52\37\50\12\53\1\51\2\53\1\52\37\53\1\11"+ - "\1\12\2\13\5\54\1\20\1\21\40\54\1\55\1\56"+ - "\1\11\1\12\2\13\5\54\1\20\1\21\12\54\1\57"+ - "\11\54\1\60\13\54\1\55\1\56\1\11\1\12\2\13"+ - "\5\61\1\20\1\21\4\61\1\11\33\61\1\55\1\56"+ - "\4\11\3\62\4\11\6\62\35\11\1\12\2\13\47\54"+ - "\1\55\1\56\57\0\1\13\56\0\1\15\1\63\45\15"+ - "\6\0\47\15\2\0\1\64\1\12\1\13\1\64\47\16"+ - "\2\64\10\0\1\17\3\0\1\65\4\0\1\17\1\66"+ - "\42\0\1\17\10\0\1\23\43\0\1\67\3\0\1\65"+ - "\4\0\1\67\1\66\36\0\20\15\1\70\3\15\1\71"+ - "\1\72\1\73\2\15\1\74\15\15\6\0\17\15\1\75"+ - "\2\15\1\76\24\15\6\0\16\15\1\77\6\15\1\100"+ - "\1\15\1\101\2\15\1\102\1\103\3\15\1\104\7\15"+ - "\6\0\24\15\1\105\5\15\1\106\1\15\1\107\1\110"+ - "\11\15\6\0\16\15\1\111\1\112\2\15\1\113\4\15"+ - "\1\114\17\15\6\0\21\15\1\115\25\15\6\0\41\15"+ - "\1\116\5\15\6\0\22\15\1\117\1\120\3\15\1\121"+ - "\17\15\6\0\42\15\1\122\4\15\6\0\16\15\1\123"+ - "\10\15\1\124\17\15\6\0\16\15\1\125\30\15\6\0"+ - "\16\15\1\126\3\15\1\127\4\15\1\130\17\15\6\0"+ - "\17\15\1\131\2\15\1\132\1\133\1\134\1\15\1\135"+ - "\1\136\4\15\1\137\12\15\6\0\16\15\1\140\3\15"+ - "\1\141\1\15\1\142\22\15\6\0\17\15\1\143\2\15"+ - "\1\144\1\145\3\15\1\146\4\15\1\147\12\15\6\0"+ - "\22\15\1\150\24\15\6\0\16\15\1\151\30\15\6\0"+ - "\27\15\1\152\4\15\1\153\12\15\2\0\11\50\1\0"+ - "\3\50\1\0\37\50\12\53\1\0\2\53\1\0\37\53"+ - "\4\0\47\54\6\0\27\54\1\154\17\54\6\0\26\54"+ - "\1\155\20\54\6\0\13\61\1\0\33\61\2\0\4\156"+ - "\1\157\1\15\45\157\2\156\1\64\1\12\1\13\52\64"+ - "\10\0\1\160\10\0\1\160\43\0\1\161\6\0\2\162"+ - "\1\163\37\0\21\15\1\164\25\15\6\0\25\15\1\165"+ - "\21\15\6\0\25\15\1\166\21\15\6\0\25\15\1\167"+ - "\21\15\6\0\17\15\1\170\27\15\6\0\26\15\1\171"+ - "\20\15\6\0\24\15\1\172\22\15\6\0\21\15\1\173"+ - "\25\15\6\0\17\15\1\174\14\15\1\175\12\15\6\0"+ - "\31\15\1\176\4\15\1\177\10\15\6\0\17\15\1\200"+ - "\27\15\6\0\17\15\1\201\27\15\6\0\17\15\1\202"+ - "\2\15\1\203\24\15\6\0\25\15\1\204\21\15\6\0"+ - "\36\15\1\205\10\15\6\0\35\15\1\206\11\15\6\0"+ - "\32\15\1\207\14\15\6\0\41\15\1\210\5\15\6\0"+ - "\26\15\1\211\2\15\1\212\15\15\6\0\20\15\1\213"+ - "\26\15\6\0\16\15\1\214\30\15\6\0\33\15\1\215"+ - "\13\15\6\0\32\15\1\216\7\15\1\217\4\15\6\0"+ - "\16\15\1\220\1\221\27\15\6\0\34\15\1\222\12\15"+ - "\6\0\17\15\1\223\27\15\6\0\34\15\1\224\12\15"+ - "\6\0\17\15\1\225\27\15\6\0\32\15\1\226\14\15"+ - "\6\0\25\15\1\227\21\15\6\0\32\15\1\230\1\15"+ - "\1\231\12\15\6\0\32\15\1\232\14\15\6\0\25\15"+ - "\1\233\6\15\1\234\1\15\1\235\10\15\6\0\21\15"+ - "\1\236\1\15\1\237\21\15\1\240\1\15\6\0\17\15"+ - "\1\241\27\15\6\0\23\15\1\242\23\15\6\0\20\15"+ - "\1\243\26\15\6\0\32\15\1\244\14\15\6\0\16\15"+ - "\1\245\30\15\6\0\21\15\1\246\4\15\1\247\20\15"+ - "\6\0\24\15\1\250\1\251\21\15\6\0\23\15\1\252"+ - "\23\15\6\0\32\15\1\253\14\15\6\0\34\15\1\254"+ - "\12\15\6\0\27\15\1\255\17\15\6\0\43\15\1\256"+ - "\3\15\6\0\22\15\1\257\24\15\6\0\21\15\1\260"+ - "\12\15\1\261\12\15\6\0\16\15\1\262\30\15\6\0"+ - "\32\15\1\263\1\15\1\264\1\15\1\265\10\15\6\0"+ - "\27\15\1\266\17\15\6\0\31\54\1\267\15\54\6\0"+ - "\20\54\1\270\26\54\2\0\5\156\1\271\53\156\1\157"+ - "\1\272\45\157\2\156\10\0\1\160\10\0\1\160\1\66"+ - "\42\0\1\161\10\0\1\161\43\0\1\161\10\0\1\163"+ - "\37\0\22\15\1\273\24\15\6\0\22\15\1\274\24\15"+ - "\6\0\17\15\1\275\27\15\6\0\27\15\1\276\17\15"+ - "\6\0\27\15\1\277\17\15\6\0\40\15\1\300\6\15"+ - "\6\0\32\15\1\301\14\15\6\0\21\15\1\302\25\15"+ - "\6\0\34\15\1\303\12\15\6\0\24\15\1\304\2\15"+ - "\1\305\17\15\6\0\32\15\1\306\14\15\6\0\16\15"+ - "\1\307\30\15\6\0\33\15\1\310\13\15\6\0\34\15"+ - "\1\311\12\15\6\0\33\15\1\312\13\15\6\0\30\15"+ - "\1\313\16\15\6\0\23\15\1\314\23\15\6\0\16\15"+ - "\1\315\30\15\6\0\31\15\1\316\15\15\6\0\16\15"+ - "\1\317\30\15\6\0\40\15\1\320\6\15\6\0\27\15"+ - "\1\321\17\15\6\0\34\15\1\322\12\15\6\0\7\15"+ - "\1\323\37\15\6\0\16\15\1\324\30\15\6\0\21\15"+ - "\1\325\3\15\1\326\21\15\6\0\33\15\1\327\13\15"+ - "\6\0\17\15\1\330\27\15\6\0\21\15\1\331\25\15"+ - "\6\0\26\15\1\332\20\15\6\0\31\15\1\333\15\15"+ - "\6\0\25\15\1\334\21\15\6\0\7\15\1\335\11\15"+ - "\1\336\25\15\6\0\16\15\1\337\30\15\6\0\45\15"+ - "\1\340\1\15\6\0\16\15\1\341\30\15\6\0\42\15"+ - "\1\342\4\15\6\0\16\15\1\343\30\15\6\0\37\15"+ - "\1\344\7\15\6\0\21\15\1\345\3\15\1\346\21\15"+ - "\6\0\21\15\1\347\25\15\6\0\25\15\1\350\1\15"+ - "\1\351\17\15\6\0\41\15\1\352\5\15\6\0\16\15"+ - "\1\353\30\15\6\0\26\15\1\354\3\15\1\355\14\15"+ - "\6\0\23\15\1\356\23\15\6\0\21\15\1\357\25\15"+ - "\6\0\35\15\1\360\11\15\6\0\22\15\1\361\24\15"+ - "\6\0\25\15\1\362\21\15\6\0\25\15\1\363\21\15"+ - "\6\0\17\15\1\364\27\15\6\0\16\15\1\365\30\15"+ - "\6\0\22\15\1\366\24\15\6\0\25\15\1\367\21\15"+ - "\6\0\33\15\1\370\13\15\6\0\32\15\1\371\7\15"+ - "\1\372\4\15\6\0\25\15\1\373\21\15\6\0\27\15"+ - "\1\374\17\15\6\0\33\15\1\375\13\15\6\0\36\15"+ - "\1\376\10\15\6\0\16\15\1\377\10\15\1\u0100\17\15"+ - "\6\0\25\15\1\u0101\21\15\6\0\25\15\1\u0102\21\15"+ - "\6\0\32\54\1\u0103\14\54\2\0\4\156\1\13\1\271"+ - "\53\156\1\15\1\272\45\157\2\156\4\0\23\15\1\u0104"+ - "\23\15\6\0\34\15\1\u0105\12\15\6\0\26\15\1\u0106"+ - "\20\15\6\0\30\15\1\u0107\16\15\6\0\32\15\1\u0108"+ - "\14\15\6\0\36\15\1\u0109\10\15\6\0\27\15\1\u010a"+ - "\17\15\6\0\25\15\1\u010b\21\15\6\0\26\15\1\u010c"+ - "\20\15\6\0\32\15\1\u010d\14\15\6\0\17\15\1\u010e"+ - "\27\15\6\0\7\15\1\u010f\37\15\6\0\16\15\1\u0110"+ - "\30\15\6\0\16\15\1\u0111\30\15\6\0\16\15\1\u0112"+ - "\30\15\6\0\27\15\1\u0113\17\15\6\0\34\15\1\u0114"+ - "\12\15\6\0\25\15\1\u0115\21\15\6\0\34\15\1\u0116"+ - "\12\15\6\0\7\15\1\u0117\37\15\6\0\26\15\1\u0118"+ - "\20\15\6\0\17\15\1\u0119\27\15\6\0\23\15\1\u011a"+ - "\4\15\1\u011b\1\15\1\u011c\14\15\6\0\25\15\1\u011d"+ - "\21\15\6\0\34\15\1\u011e\12\15\6\0\22\15\1\u011f"+ - "\24\15\6\0\34\15\1\u0120\12\15\6\0\21\15\1\u0121"+ - "\25\15\6\0\23\15\1\u0122\1\u0123\22\15\6\0\16\15"+ - "\1\u0124\30\15\6\0\27\15\1\u0125\17\15\6\0\17\15"+ - "\1\u0126\6\15\1\u0127\5\15\1\u0128\3\15\1\u0129\6\15"+ - "\6\0\34\15\1\u012a\12\15\6\0\22\15\1\u012b\24\15"+ - "\6\0\17\15\1\u012c\27\15\6\0\25\15\1\u012d\21\15"+ - "\6\0\16\15\1\u012e\30\15\6\0\7\15\1\u012f\37\15"+ - "\6\0\25\15\1\u0130\21\15\6\0\34\15\1\u0131\12\15"+ - "\6\0\25\15\1\u0132\21\15\6\0\23\15\1\u0133\5\15"+ - "\1\u0134\15\15\6\0\34\15\1\u0135\12\15\6\0\16\15"+ - "\1\u0136\30\15\6\0\16\15\1\u0137\30\15\6\0\7\15"+ - "\1\u0138\37\15\6\0\16\15\1\u0139\30\15\6\0\23\15"+ - "\1\u013a\23\15\6\0\17\15\1\u013b\27\15\6\0\16\15"+ - "\1\u013c\30\15\6\0\25\15\1\u013d\21\15\6\0\21\15"+ - "\1\u013e\25\15\6\0\24\15\1\u013f\22\15\6\0\41\15"+ - "\1\u0140\5\15\6\0\7\15\1\u0141\37\15\6\0\25\15"+ - "\1\u0142\21\15\6\0\25\15\1\u0143\21\15\6\0\7\15"+ - "\1\u0144\37\15\6\0\44\15\1\u0145\2\15\6\0\22\15"+ - "\1\u0146\24\15\6\0\22\15\1\u0147\24\15\6\0\7\15"+ - "\1\u0148\37\15\6\0\32\15\1\u0149\14\15\6\0\37\15"+ - "\1\u014a\7\15\6\0\16\15\1\u014b\30\15\6\0\17\54"+ - "\1\u014c\27\54\6\0\24\15\1\u014d\22\15\6\0\22\15"+ - "\1\u014e\24\15\6\0\37\15\1\u014f\7\15\6\0\16\15"+ - "\1\u0150\30\15\6\0\21\15\1\u0151\25\15\6\0\17\15"+ - "\1\u0152\27\15\6\0\22\15\1\u0153\24\15\6\0\7\15"+ - "\1\u0154\37\15\6\0\25\15\1\u0155\21\15\6\0\31\15"+ - "\1\u0156\15\15\6\0\23\15\1\u0157\23\15\6\0\17\15"+ - "\1\u0158\27\15\6\0\7\15\1\u0159\37\15\6\0\32\15"+ - "\1\u015a\14\15\6\0\37\15\1\u015b\7\15\6\0\7\15"+ - "\1\u015c\37\15\6\0\25\15\1\u015d\21\15\6\0\17\15"+ - "\1\u015e\27\15\6\0\34\15\1\u015f\12\15\6\0\17\15"+ - "\1\u0160\27\15\6\0\27\15\1\u0161\17\15\6\0\16\15"+ - "\1\u0162\30\15\6\0\17\15\1\u0163\27\15\6\0\22\15"+ - "\1\u0164\24\15\6\0\32\15\1\u0165\14\15\6\0\17\15"+ - "\1\u0166\27\15\6\0\7\15\1\u0167\6\15\1\u0168\30\15"+ - "\6\0\16\15\1\u0169\30\15\6\0\27\15\1\u016a\17\15"+ - "\6\0\26\15\1\u016b\20\15\6\0\25\15\1\u016c\21\15"+ - "\6\0\22\15\1\u016d\24\15\6\0\24\15\1\u016e\22\15"+ - "\6\0\16\15\1\u016f\30\15\6\0\17\15\1\u0170\27\15"+ - "\6\0\34\15\1\u0171\12\15\6\0\23\15\1\u0172\23\15"+ - "\6\0\41\15\1\u0173\5\15\6\0\34\15\1\u0174\12\15"+ - "\6\0\23\15\1\u0175\23\15\6\0\17\15\1\u0176\27\15"+ - "\6\0\22\15\1\u0177\24\15\6\0\27\15\1\u0178\17\15"+ - "\6\0\27\15\1\u0179\17\15\6\0\22\15\1\u017a\24\15"+ - "\6\0\7\15\1\u017b\32\15\1\u017c\4\15\6\0\7\15"+ - "\1\u017d\37\15\6\0\25\15\1\u017e\21\15\6\0\34\15"+ - "\1\u017f\12\15\6\0\24\15\1\u0180\22\15\6\0\32\15"+ - "\1\u0181\14\15\6\0\21\15\1\u0182\25\15\6\0\16\15"+ - "\1\u0183\30\15\6\0\25\15\1\u0184\21\15\6\0\35\15"+ - "\1\u0185\11\15\6\0\21\15\1\u0186\25\15\6\0\22\15"+ - "\1\u0187\24\15\6\0\26\15\1\u0188\1\15\1\u0189\16\15"+ - "\6\0\22\15\1\u018a\24\15\6\0\24\15\1\u018b\22\15"+ - "\6\0\45\15\1\u018c\1\15\6\0\40\15\1\u018d\6\15"+ - "\6\0\31\15\1\u018e\15\15\6\0\7\15\1\u018f\37\15"+ - "\6\0\23\54\1\u0190\23\54\6\0\25\15\1\u0191\21\15"+ - "\6\0\24\15\1\u0192\22\15\6\0\25\15\1\u0193\21\15"+ - "\6\0\34\15\1\u0194\12\15\6\0\32\15\1\u0195\14\15"+ - "\6\0\33\15\1\u0196\1\u0197\12\15\6\0\24\15\1\u0198"+ - "\22\15\6\0\7\15\1\u0199\37\15\6\0\32\15\1\u019a"+ - "\14\15\6\0\35\15\1\u019b\11\15\6\0\16\15\1\u019c"+ - "\30\15\6\0\34\15\1\u019d\12\15\6\0\41\15\1\u019e"+ - "\5\15\6\0\23\15\1\u019f\23\15\6\0\41\15\1\u01a0"+ - "\5\15\6\0\41\15\1\u01a1\5\15\6\0\17\15\1\u01a2"+ - "\27\15\6\0\25\15\1\u01a3\21\15\6\0\32\15\1\u01a4"+ - "\14\15\6\0\23\15\1\u01a5\23\15\6\0\16\15\1\u01a6"+ - "\30\15\6\0\32\15\1\u01a7\14\15\6\0\26\15\1\u01a8"+ - "\20\15\6\0\21\15\1\u01a9\25\15\6\0\25\15\1\u01aa"+ - "\21\15\6\0\17\15\1\u01ab\27\15\6\0\7\15\1\u01ac"+ - "\37\15\6\0\21\15\1\u01ad\25\15\6\0\23\15\1\u01ae"+ - "\23\15\6\0\16\15\1\u01af\30\15\6\0\25\15\1\u01b0"+ - "\21\15\6\0\40\15\1\u01b1\6\15\6\0\7\15\1\u01b2"+ - "\37\15\6\0\27\15\1\u01b3\17\15\6\0\26\15\1\u01b4"+ - "\20\15\6\0\24\15\1\u01b5\22\15\6\0\22\15\1\u01b6"+ - "\24\15\6\0\32\15\1\u01b7\14\15\6\0\32\15\1\u01b8"+ - "\14\15\6\0\26\15\1\u01b9\11\15\1\u01ba\6\15\6\0"+ - "\16\15\1\u01bb\30\15\6\0\30\15\1\u01bc\16\15\6\0"+ - "\27\15\1\u01bd\17\15\6\0\16\15\1\u01be\15\15\1\u01bf"+ - "\12\15\6\0\25\15\1\u01c0\21\15\6\0\31\15\1\u01c1"+ - "\15\15\6\0\7\15\1\u01c2\37\15\6\0\27\15\1\u01c3"+ - "\17\15\6\0\25\15\1\u01c4\21\15\6\0\17\15\1\u01c5"+ - "\27\15\6\0\16\15\1\u01c6\30\15\6\0\32\15\1\u01c7"+ - "\14\15\6\0\25\15\1\u01c8\21\15\6\0\16\15\1\u01c9"+ - "\30\15\6\0\34\15\1\u01ca\12\15\6\0\16\15\1\u01cb"+ - "\30\15\6\0\25\15\1\u01cc\21\15\6\0\7\15\1\u01cd"+ - "\37\15\6\0\41\15\1\u01ce\5\15\6\0\17\15\1\u01cf"+ - "\27\15\6\0\27\15\1\u01d0\17\15\6\0\34\15\1\u01d1"+ - "\12\15\6\0\46\15\1\u01d2\6\0\31\15\1\u01d3\15\15"+ - "\6\0\27\15\1\u01d4\17\15\6\0\24\15\1\u01d5\22\15"+ - "\6\0\33\15\1\u01d6\13\15\6\0\7\15\1\u01d7\37\15"+ - "\6\0\16\15\1\u01d8\30\15\6\0\25\15\1\u01d9\21\15"+ - "\6\0\32\15\1\u01da\14\15\6\0\26\15\1\u01db\20\15"+ - "\6\0\23\15\1\u01dc\23\15\6\0\23\15\1\u01dd\23\15"+ - "\6\0\21\15\1\u01de\25\15\6\0\25\15\1\u01df\21\15"+ - "\6\0\16\15\1\u01e0\30\15\6\0\33\15\1\u01e1\13\15"+ - "\6\0\16\15\1\u01e2\30\15\6\0\7\15\1\u01e3\37\15"+ - "\6\0\36\15\1\u01e4\10\15\6\0\20\15\1\u01e5\26\15"+ - "\6\0\40\15\1\u01e6\6\15\6\0\25\15\1\u01e7\21\15"+ - "\6\0\32\15\1\u01e8\14\15\6\0\16\15\1\u01e9\30\15"+ - "\6\0\22\15\1\u01ea\24\15\6\0\16\15\1\u01eb\30\15"+ - "\6\0\32\15\1\u01ec\14\15\6\0\27\15\1\u01ed\17\15"+ - "\6\0\31\15\1\u01ee\15\15\6\0\36\15\1\u01ef\10\15"+ - "\6\0\16\15\1\u01be\30\15\6\0\27\15\1\u01f0\17\15"+ - "\6\0\23\15\1\u01f1\23\15\6\0\35\15\1\u01f2\11\15"+ - "\6\0\30\15\1\u01f3\16\15\6\0\41\15\1\u01f4\5\15"+ - "\6\0\36\15\1\u01f5\10\15\6\0\34\15\1\u01f6\12\15"+ - "\6\0\25\15\1\u01f7\21\15\6\0\16\15\1\u01f8\30\15"+ - "\6\0\16\15\1\u01f9\30\15\6\0\16\15\1\u01fa\30\15"+ - "\6\0\33\15\1\u01fb\13\15\6\0\21\15\1\u01fc\25\15"+ - "\6\0\33\15\1\u01fd\13\15\6\0\16\15\1\u01fe\30\15"+ - "\6\0\24\15\1\u01ff\22\15\6\0\23\15\1\u0200\23\15"+ - "\6\0\43\15\1\u0201\3\15\6\0\23\15\1\u0202\23\15"+ - "\6\0\16\15\1\u0203\30\15\6\0\33\15\1\u0204\13\15"+ - "\6\0\34\15\1\u0205\12\15\6\0\25\15\1\u0206\21\15"+ - "\6\0\16\15\1\u0207\30\15\6\0\17\15\1\u0208\27\15"+ - "\6\0\42\15\1\u0209\4\15\6\0\21\15\1\u020a\25\15"+ - "\6\0\22\15\1\u020b\24\15\6\0\36\15\1\u020c\10\15"+ - "\6\0\22\15\1\u020d\24\15\6\0\16\15\1\u020e\30\15"+ - "\6\0\34\15\1\u020f\12\15\6\0\16\15\1\u0210\30\15"+ - "\6\0\7\15\1\u0211\37\15\6\0\32\15\1\u0212\14\15"+ - "\6\0\16\15\1\u0213\30\15\6\0\25\15\1\u0214\21\15"+ - "\6\0\17\15\1\u0215\27\15\6\0\37\15\1\u0216\7\15"+ - "\6\0\7\15\1\u0217\37\15\6\0\22\15\1\u0218\24\15"+ - "\6\0\16\15\1\u0219\30\15\6\0\27\15\1\u021a\17\15"+ - "\6\0\16\15\1\u021b\30\15\6\0\23\15\1\u021c\23\15"+ - "\6\0\21\15\1\u021d\25\15\6\0\17\15\1\u021e\27\15"+ - "\6\0\33\15\1\u021f\13\15\6\0\21\15\1\u0220\25\15"+ - "\6\0\7\15\1\u0221\37\15\6\0\34\15\1\u0222\12\15"+ - "\6\0\21\15\1\u0223\25\15\6\0\24\15\1\u0224\22\15"+ - "\6\0\22\15\1\u0225\24\15\6\0\16\15\1\u0226\30\15"+ - "\6\0\16\15\1\u0227\30\15\6\0\16\15\1\u0228\30\15"+ - "\6\0\17\15\1\u0229\27\15\6\0\7\15\1\u022a\37\15"+ - "\6\0\21\15\1\u022b\25\15\6\0\36\15\1\u022c\10\15"+ - "\6\0\24\15\1\u022d\22\15\6\0\7\15\1\u022e\37\15"+ - "\6\0\24\15\1\u022f\22\15\6\0\31\15\1\u0230\15\15"+ - "\6\0\17\15\1\u0231\27\15\6\0\33\15\1\u0232\13\15"+ - "\6\0\25\15\1\u0233\21\15\6\0\33\15\1\u0234\13\15"+ - "\6\0\7\15\1\u0235\37\15\6\0\25\15\1\u0236\21\15"+ - "\6\0\36\15\1\u0237\10\15\6\0\32\15\1\u0238\14\15"+ - "\6\0\34\15\1\u0239\12\15\6\0\7\15\1\u023a\37\15"+ - "\6\0\16\15\1\u023b\30\15\6\0\27\15\1\u023c\17\15"+ - "\6\0\23\15\1\u023d\23\15\6\0\22\15\1\u023e\24\15"+ - "\6\0\22\15\1\u023f\24\15\6\0\21\15\1\u0240\25\15"+ - "\6\0\16\15\1\u0241\30\15\6\0\7\15\1\u0242\37\15"+ - "\6\0\33\15\1\u0243\13\15\6\0\25\15\1\u0244\21\15"+ - "\6\0\36\15\1\u0245\10\15\6\0\34\15\1\u0246\12\15"+ - "\6\0\26\15\1\u0247\20\15\6\0\21\15\1\u0248\25\15"+ - "\6\0\25\15\1\u0249\21\15\6\0\20\15\1\u024a\26\15"+ - "\6\0\25\15\1\u024b\21\15\6\0\34\15\1\u024c\12\15"+ - "\6\0\34\15\1\u024d\12\15\6\0\17\15\1\u024e\27\15"+ - "\6\0\34\15\1\u024f\12\15\6\0\22\15\1\u0250\24\15"+ - "\6\0\26\15\1\u0251\20\15\6\0\27\15\1\u0252\17\15"+ - "\6\0\21\15\1\u0253\25\15\6\0\36\15\1\u0254\10\15"+ - "\6\0\22\15\1\u0255\24\15\6\0\24\15\1\u0256\22\15"+ - "\6\0\23\15\1\u0257\23\15\6\0\16\15\1\u0258\30\15"+ - "\6\0\35\15\1\u0259\11\15\6\0\32\15\1\u025a\14\15"+ - "\6\0\7\15\1\u025b\37\15\6\0\16\15\1\u025c\30\15"+ - "\6\0\25\15\1\u025d\21\15\6\0\23\15\1\u025e\23\15"+ - "\6\0\41\15\1\u025f\5\15\6\0\16\15\1\u0260\30\15"+ - "\6\0\41\15\1\u0261\5\15\6\0\25\15\1\u0262\21\15"+ - "\6\0\22\15\1\u0263\24\15\6\0\24\15\1\u0264\22\15"+ - "\6\0\22\15\1\u0265\24\15\6\0\34\15\1\u0266\12\15"+ - "\6\0\25\15\1\u0267\21\15\6\0\16\15\1\u0268\30\15"+ - "\6\0\32\15\1\u0269\14\15\6\0\25\15\1\u026a\21\15"+ - "\6\0\24\15\1\u026b\22\15\6\0\25\15\1\u026c\21\15"+ - "\6\0\16\15\1\u026d\30\15\6\0\22\15\1\u026e\24\15"+ - "\6\0\26\15\1\u026f\20\15\6\0\7\15\1\u0270\37\15"+ - "\6\0\17\15\1\u0271\27\15\6\0\7\15\1\u0272\37\15"+ - "\6\0\16\15\1\u0273\30\15\6\0\37\15\1\u0274\7\15"+ - "\6\0\23\15\1\u0275\23\15\6\0\25\15\1\u0276\21\15"+ - "\6\0\21\15\1\u0277\25\15\6\0\16\15\1\u0278\30\15"+ - "\6\0\31\15\1\u0279\15\15\6\0\25\15\1\u027a\21\15"+ - "\6\0\25\15\1\u027b\21\15\6\0\34\15\1\u027c\12\15"+ - "\6\0\22\15\1\u027d\24\15\6\0\42\15\1\u027e\4\15"+ - "\6\0\21\15\1\u027f\25\15\6\0\35\15\1\u0280\11\15"+ - "\6\0\25\15\1\u0281\21\15\6\0\26\15\1\u0282\20\15"+ - "\6\0\34\15\1\u0283\12\15\6\0\27\15\1\u0284\17\15"+ - "\6\0\27\15\1\u0285\17\15\6\0\16\15\1\u0286\15\15"+ - "\1\u0287\12\15\6\0\21\15\1\u0288\25\15\6\0\17\15"+ - "\1\u0289\27\15\6\0\21\15\1\u028a\25\15\6\0\34\15"+ - "\1\u028b\12\15\6\0\21\15\1\u028c\25\15\6\0\25\15"+ - "\1\u028d\21\15\6\0\16\15\1\u028e\30\15\6\0\22\15"+ - "\1\u028f\24\15\6\0\32\15\1\u0290\14\15\6\0\36\15"+ - "\1\u0291\10\15\6\0\16\15\1\u0286\30\15\6\0\25\15"+ - "\1\u0292\21\15\6\0\33\15\1\u0293\13\15\6\0\16\15"+ - "\1\u0294\30\15\6\0\27\15\1\u0295\17\15\6\0\16\15"+ - "\1\u0296\30\15\6\0\32\15\1\u0297\14\15\6\0\31\15"+ - "\1\u0298\15\15\6\0\7\15\1\u0299\37\15\6\0\21\15"+ - "\1\u029a\25\15\6\0\33\15\1\u029b\13\15\6\0\16\15"+ - "\1\u029c\30\15\6\0\22\15\1\u029d\24\15\6\0\21\15"+ - "\1\u029e\25\15\6\0\36\15\1\u029f\10\15\6\0\27\15"+ - "\1\u02a0\17\15\6\0\34\15\1\u02a1\12\15\6\0\32\15"+ - "\1\u02a2\14\15\6\0\27\15\1\u02a3\17\15\6\0\32\15"+ - "\1\u02a4\14\15\6\0\22\15\1\u02a5\24\15\6\0\7\15"+ - "\1\u02a6\37\15\6\0\34\15\1\u02a7\12\15\6\0\31\15"+ - "\1\u02a8\15\15\6\0\24\15\1\u02a9\22\15\6\0\25\15"+ - "\1\u02aa\21\15\6\0\16\15\1\u02ab\30\15\6\0\25\15"+ - "\1\u02ac\21\15\6\0\34\15\1\u02ad\12\15\6\0\26\15"+ - "\1\u02ae\20\15\6\0\16\15\1\u02af\30\15\6\0\17\15"+ - "\1\u02b0\27\15\6\0\25\15\1\u02b1\21\15\6\0\26\15"+ - "\1\u02b2\20\15\6\0\27\15\1\u02b3\17\15\6\0\16\15"+ - "\1\u02b4\30\15\6\0\22\15\1\u02b5\24\15\6\0\7\15"+ - "\1\u02b6\37\15\6\0\32\15\1\u02b7\14\15\6\0\26\15"+ - "\1\u02b8\20\15\6\0\7\15\1\u02b9\37\15\6\0\22\15"+ - "\1\u02ba\24\15\6\0\25\15\1\u02bb\21\15\6\0\21\15"+ - "\1\u02bc\25\15\6\0\34\15\1\u02bd\12\15\6\0\25\15"+ - "\1\u02be\21\15\6\0\17\15\1\u02bf\27\15\6\0\21\15"+ - "\1\u02c0\25\15\6\0\26\15\1\u02c1\20\15\6\0\16\15"+ - "\1\u02c2\30\15\6\0\7\15\1\u02c3\37\15\6\0\26\15"+ - "\1\u02c4\20\15\6\0\22\15\1\u02c5\24\15\6\0\21\15"+ - "\1\u02c6\25\15\6\0\25\15\1\u02c7\21\15\6\0\21\15"+ - "\1\u02c8\25\15\2\0"; - - private static int [] zzUnpackTrans() { - int [] result = new int[27450]; - int offset = 0; - offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result); - return result; - } - - private static int zzUnpackTrans(String packed, int offset, int [] result) { - int i = 0; /* index in packed string */ - int j = offset; /* index in unpacked array */ - int l = packed.length(); - while (i < l) { - int count = packed.charAt(i++); - int value = packed.charAt(i++); - value--; - do result[j++] = value; while (--count > 0); - } - return j; - } - - - /* error codes */ - private static final int ZZ_UNKNOWN_ERROR = 0; - private static final int ZZ_NO_MATCH = 1; - private static final int ZZ_PUSHBACK_2BIG = 2; - - /* error messages for the codes above */ - private static final String ZZ_ERROR_MSG[] = { - "Unkown internal scanner error", - "Error: could not match input", - "Error: pushback value was too large" - }; - - /** - * ZZ_ATTRIBUTE[aState] contains the attributes of state aState - */ - private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute(); - - private static final String ZZ_ATTRIBUTE_PACKED_0 = - "\7\0\1\1\1\11\1\1\1\11\4\1\2\11\24\1"+ - "\2\11\1\1\2\11\2\1\2\11\3\1\1\11\1\1"+ - "\3\0\67\1\1\0\3\1\1\0\1\11\105\1\1\0"+ - "\u020f\1"; - - private static int [] zzUnpackAttribute() { - int [] result = new int[712]; - int offset = 0; - offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result); - return result; - } - - private static int zzUnpackAttribute(String packed, int offset, int [] result) { - int i = 0; /* index in packed string */ - int j = offset; /* index in unpacked array */ - int l = packed.length(); - while (i < l) { - int count = packed.charAt(i++); - int value = packed.charAt(i++); - do result[j++] = value; while (--count > 0); - } - return j; - } - - /** the input device */ - private java.io.Reader zzReader; - - /** the current state of the DFA */ - private int zzState; - - /** the current lexical state */ - private int zzLexicalState = YYINITIAL; - - /** this buffer contains the current text to be matched and is - the source of the yytext() string */ - private char zzBuffer[] = new char[ZZ_BUFFERSIZE]; - - /** the textposition at the last accepting state */ - private int zzMarkedPos; - - /** the textposition at the last state to be included in yytext */ - private int zzPushbackPos; - - /** the current text position in the buffer */ - private int zzCurrentPos; - - /** startRead marks the beginning of the yytext() string in the buffer */ - private int zzStartRead; - - /** endRead marks the last character in the buffer, that has been read - from input */ - private int zzEndRead; - - /** number of newlines encountered up to the start of the matched text */ - private int yyline; - - /** the number of characters up to the start of the matched text */ - private int yychar; - - /** - * the number of characters from the last newline up to the start of the - * matched text - */ - private int yycolumn; - - /** - * zzAtBOL == true <=> the scanner is currently at the beginning of a line - */ - private boolean zzAtBOL = true; - - /** zzAtEOF == true <=> the scanner is at the EOF */ - private boolean zzAtEOF; - - /* user code: */ - StringBuffer string = new StringBuffer(); - - - /** - * Creates a new scanner - * There is also a java.io.InputStream version of this constructor. - * - * @param in the java.io.Reader to read input from. - */ - SpecctraFileScanner(java.io.Reader in) { - this.zzReader = in; - } - - /** - * Creates a new scanner. - * There is also java.io.Reader version of this constructor. - * - * @param in the java.io.Inputstream to read input from. - */ - SpecctraFileScanner(java.io.InputStream in) { - this(new java.io.InputStreamReader(in)); - } - - /** - * Unpacks the compressed character translation table. - * - * @param packed the packed character translation table - * @return the unpacked character translation table - */ - private static char [] zzUnpackCMap(String packed) { - char [] map = new char[0x10000]; - int i = 0; /* index in packed string */ - int j = 0; /* index in unpacked array */ - while (i < 274) { - int count = packed.charAt(i++); - char value = packed.charAt(i++); - do map[j++] = value; while (--count > 0); - } - return map; - } - - - /** - * Refills the input buffer. - * - * @return false, iff there was new input. - * - * @exception java.io.IOException if any I/O-Error occurs - */ - private boolean zzRefill() throws java.io.IOException { - - /* first: make room (if you can) */ - if (zzStartRead > 0) { - System.arraycopy(zzBuffer, zzStartRead, - zzBuffer, 0, - zzEndRead-zzStartRead); - - /* translate stored positions */ - zzEndRead-= zzStartRead; - zzCurrentPos-= zzStartRead; - zzMarkedPos-= zzStartRead; - zzPushbackPos-= zzStartRead; - zzStartRead = 0; - } - - /* is the buffer big enough? */ - if (zzCurrentPos >= zzBuffer.length) { - /* if not: blow it up */ - char newBuffer[] = new char[zzCurrentPos*2]; - System.arraycopy(zzBuffer, 0, newBuffer, 0, zzBuffer.length); - zzBuffer = newBuffer; - } - - /* finally: fill the buffer with new input */ - int numRead = zzReader.read(zzBuffer, zzEndRead, - zzBuffer.length-zzEndRead); - - if (numRead < 0) { - return true; - } - else { - zzEndRead+= numRead; - return false; - } - } - - - /** - * Closes the input stream. - */ - public final void yyclose() throws java.io.IOException { - zzAtEOF = true; /* indicate end of file */ - zzEndRead = zzStartRead; /* invalidate buffer */ - - if (zzReader != null) - zzReader.close(); - } - - - /** - * Resets the scanner to read from a new input stream. - * Does not close the old reader. - * - * All internal variables are reset, the old input stream - * cannot be reused (internal buffer is discarded and lost). - * Lexical state is set to ZZ_INITIAL. - * - * @param reader the new input stream - */ - public final void yyreset(java.io.Reader reader) { - zzReader = reader; - zzAtBOL = true; - zzAtEOF = false; - zzEndRead = zzStartRead = 0; - zzCurrentPos = zzMarkedPos = zzPushbackPos = 0; - yyline = yychar = yycolumn = 0; - zzLexicalState = YYINITIAL; - } - - - /** - * Returns the current lexical state. - */ - public final int yystate() { - return zzLexicalState; - } - - - /** - * Enters a new lexical state - * - * @param newState the new lexical state - */ - public final void yybegin(int newState) { - zzLexicalState = newState; - } - - - /** - * Returns the text matched by the current regular expression. - */ - public final String yytext() { - return new String( zzBuffer, zzStartRead, zzMarkedPos-zzStartRead ); - } - - - /** - * Returns the character at position pos from the - * matched text. - * - * It is equivalent to yytext().charAt(pos), but faster - * - * @param pos the position of the character to fetch. - * A value from 0 to yylength()-1. - * - * @return the character at position pos - */ - public final char yycharat(int pos) { - return zzBuffer[zzStartRead+pos]; - } - - - /** - * Returns the length of the matched text region. - */ - public final int yylength() { - return zzMarkedPos-zzStartRead; - } - - - /** - * Reports an error that occured while scanning. - * - * In a wellformed scanner (no or only correct usage of - * yypushback(int) and a match-all fallback rule) this method - * will only be called with things that "Can't Possibly Happen". - * If this method is called, something is seriously wrong - * (e.g. a JFlex bug producing a faulty scanner etc.). - * - * Usual syntax/scanner level error handling should be done - * in error fallback rules. - * - * @param errorCode the code of the errormessage to display - */ - private void zzScanError(int errorCode) { - String message; - try { - message = ZZ_ERROR_MSG[errorCode]; - } - catch (ArrayIndexOutOfBoundsException e) { - message = ZZ_ERROR_MSG[ZZ_UNKNOWN_ERROR]; - } - - throw new Error(message); - } - - - /** - * Pushes the specified amount of characters back into the input stream. - * - * They will be read again by then next call of the scanning method - * - * @param number the number of characters to be read again. - * This number must not be greater than yylength()! - */ - public void yypushback(int number) { - if ( number > yylength() ) - zzScanError(ZZ_PUSHBACK_2BIG); - - zzMarkedPos -= number; - } - - - /** - * Resumes scanning until the next regular expression is matched, - * the end of input is encountered or an I/O-Error occurs. - * - * @return the next token - * @exception java.io.IOException if any I/O-Error occurs - */ - public Object next_token() throws java.io.IOException { - int zzInput; - int zzAction; - - // cached fields: - int zzCurrentPosL; - int zzMarkedPosL; - int zzEndReadL = zzEndRead; - char [] zzBufferL = zzBuffer; - char [] zzCMapL = ZZ_CMAP; - - int [] zzTransL = ZZ_TRANS; - int [] zzRowMapL = ZZ_ROWMAP; - int [] zzAttrL = ZZ_ATTRIBUTE; - - while (true) { - zzMarkedPosL = zzMarkedPos; - - zzAction = -1; - - zzCurrentPosL = zzCurrentPos = zzStartRead = zzMarkedPosL; - - zzState = zzLexicalState; - - - zzForAction: { - while (true) { - - if (zzCurrentPosL < zzEndReadL) - zzInput = zzBufferL[zzCurrentPosL++]; - else if (zzAtEOF) { - zzInput = YYEOF; - break zzForAction; - } - else { - // store back cached positions - zzCurrentPos = zzCurrentPosL; - zzMarkedPos = zzMarkedPosL; - boolean eof = zzRefill(); - // get translated positions and possibly new buffer - zzCurrentPosL = zzCurrentPos; - zzMarkedPosL = zzMarkedPos; - zzBufferL = zzBuffer; - zzEndReadL = zzEndRead; - if (eof) { - zzInput = YYEOF; - break zzForAction; - } - else { - zzInput = zzBufferL[zzCurrentPosL++]; - } - } - int zzNext = zzTransL[ zzRowMapL[zzState] + zzCMapL[zzInput] ]; - if (zzNext == -1) break zzForAction; - zzState = zzNext; - - int zzAttributes = zzAttrL[zzState]; - if ( (zzAttributes & 1) == 1 ) { - zzAction = zzState; - zzMarkedPosL = zzCurrentPosL; - if ( (zzAttributes & 8) == 8 ) break zzForAction; - } - - } - } - - // store back cached position - zzMarkedPos = zzMarkedPosL; - - switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) { - case 18: - { yybegin(NAME); return Keyword.VIA; - } - case 121: break; - case 24: - { return Keyword.BACK; - } - case 122: break; - case 31: - { yybegin(LAYER_NAME); return Keyword.POLYGON_PATH; - } - case 123: break; - case 71: - { return Keyword.NETWORK_SCOPE; - } - case 124: break; - case 56: - { return Keyword.ROUTES; - } - case 125: break; - case 93: - { return Keyword.FLIP_STYLE; - } - case 126: break; - case 108: - { return Keyword.PLACE_CONTROL; - } - case 127: break; - case 32: - { yybegin(LAYER_NAME); return Keyword.POLYGON; - } - case 128: break; - case 78: - { yybegin(NAME); return Keyword.PADSTACK; - } - case 129: break; - case 110: - { yybegin(NAME); return Keyword.CLEARANCE_CLASS; - } - case 130: break; - case 115: - { return Keyword.AUTOROUTE_SETTINGS; - } - case 131: break; - case 13: - { yybegin(YYINITIAL); return Keyword.OPEN_BRACKET; - } - case 132: break; - case 105: - { return Keyword.START_PASS_NO; - } - case 133: break; - case 23: - { yybegin(YYINITIAL); return Keyword.PCB_SCOPE; - } - case 134: break; - case 34: - { yybegin(LAYER_NAME); return Keyword.RECTANGLE; - } - case 135: break; - case 82: - { return Keyword.STRUCTURE_SCOPE; - } - case 136: break; - case 27: - { yybegin(NAME); return Keyword.COMPONENT_SCOPE; - } - case 137: break; - case 43: - { yybegin(NAME); return Keyword.IMAGE; - } - case 138: break; - case 112: - { return Keyword.FORTYFIVE_DEGREE; - } - case 139: break; - case 60: - { return Keyword.WINDOW; - } - case 140: break; - case 76: - { return Keyword.VERTICAL; - } - case 141: break; - case 20: - { return Keyword.PCB_SCOPE; - } - case 142: break; - case 37: - { return Keyword.SPARE; - } - case 143: break; - case 21: - { return Keyword.PIN; - } - case 144: break; - case 35: - { return Keyword.RULE; - } - case 145: break; - case 29: - { return Keyword.VIAS; - } - case 146: break; - case 16: - { return Keyword.ON; - } - case 147: break; - case 63: - { return Keyword.SESSION; - } - case 148: break; - case 74: - { return Keyword.BOUNDARY; - } - case 149: break; - case 88: - { return Keyword.SNAP_ANGLE; - } - case 150: break; - case 113: - { return Keyword.WRITE_RESOLUTION; - } - case 151: break; - case 54: - { return Keyword.NORMAL; - } - case 152: break; - case 8: - { return Keyword.OPEN_BRACKET; - } - case 153: break; - case 22: - { return Keyword.FIX; - } - case 154: break; - case 89: - { yybegin(NAME); return Keyword.LAYER_RULE; - } - case 155: break; - case 86: - { return Keyword.POSTROUTE; - } - case 156: break; - case 14: - { yybegin(YYINITIAL); return Keyword.CLOSED_BRACKET; - } - case 157: break; - case 9: - { return Keyword.CLOSED_BRACKET; - } - case 158: break; - case 90: - { return Keyword.VIA_AT_SMD; - } - case 159: break; - case 28: - { yybegin(LAYER_NAME); return Keyword.CIRCLE; - } - case 160: break; - case 50: - { return Keyword.ATTACH; - } - case 161: break; - case 92: - { return Keyword.RESOLUTION_SCOPE; - } - case 162: break; - case 77: - { return Keyword.VIA_RULE; - } - case 163: break; - case 70: - { return Keyword.CIRCUIT; - } - case 164: break; - case 87: - { return Keyword.PLACEMENT_SCOPE; - } - case 165: break; - case 36: - { yybegin(NAME); return Keyword.WIRE; - } - case 166: break; - case 116: - { return Keyword.PREFERRED_DIRECTION; - } - case 167: break; - case 40: - { yybegin(NAME); return Keyword.LAYER; - } - case 168: break; - case 69: - { return Keyword.CLASSES; - } - case 169: break; - case 61: - { return Keyword.WIRING_SCOPE; - } - case 170: break; - case 103: - { yybegin(NAME); return Keyword.HOST_VERSION; - } - case 171: break; - case 4: - { return yytext(); - } - case 172: break; - case 73: - { return Keyword.ABSOLUTE; - } - case 173: break; - case 58: - { return Keyword.FANOUT; - } - case 174: break; - case 79: - { return Keyword.POSITION; - } - case 175: break; - case 47: - { return Keyword.RULES; - } - case 176: break; - case 57: - { return Keyword.ROTATE; - } - case 177: break; - case 7: - { string.setLength(0); yybegin(STRING2); - } - case 178: break; - case 84: - { yybegin(NAME); return Keyword.USE_LAYER; - } - case 179: break; - case 80: - { yybegin(NAME); return Keyword.HOST_CAD; - } - case 180: break; - case 64: - { return Keyword.OUTLINE; - } - case 181: break; - case 45: - { yybegin(NAME); return Keyword.PLACE; - } - case 182: break; - case 6: - { string.setLength(0); yybegin(STRING1); - } - case 183: break; - case 99: - { yybegin(IGNORE_QUOTE); return Keyword.STRING_QUOTE; - } - case 184: break; - case 39: - { return Keyword.ORDER; - } - case 185: break; - case 17: - { return Keyword.OFF; - } - case 186: break; - case 81: - { return Keyword.AUTOROUTE; - } - case 187: break; - case 52: - { return Keyword.SIGNAL; - } - case 188: break; - case 107: - { yybegin(LAYER_NAME); return Keyword.POLYLINE_PATH; - } - case 189: break; - case 68: - { return Keyword.CONTROL; - } - case 190: break; - case 46: - { yybegin(NAME); return Keyword.PLANE_SCOPE; - } - case 191: break; - case 1: - { yybegin(YYINITIAL); return yytext(); - } - case 192: break; - case 100: - { yybegin(NAME); return Keyword.LOGICAL_PART; - } - case 193: break; - case 83: - { return Keyword.LOCK_TYPE; - } - case 194: break; - case 109: - { yybegin(NAME); return Keyword.PLACE_KEEPOUT; - } - case 195: break; - case 49: - { return Keyword.WIDTH; - } - case 196: break; - case 106: - { return Keyword.NINETY_DEGREE; - } - case 197: break; - case 67: - { yybegin(NAME); return Keyword.USE_NET; - } - case 198: break; - case 118: - { return Keyword.GENERATED_BY_FREEROUTE; - } - case 199: break; - case 101: - { return Keyword.PART_LIBRARY_SCOPE; - } - case 200: break; - case 85: - { return Keyword.VIA_COSTS; - } - case 201: break; - case 102: - { return Keyword.ROTATE_FIRST; - } - case 202: break; - case 75: - { return Keyword.CONSTANT; - } - case 203: break; - case 12: - { string.append('\\'); - } - case 204: break; - case 15: - { return new Double(yytext()); - } - case 205: break; - case 42: - { yybegin(NAME); return Keyword.CLASS; - } - case 206: break; - case 91: - { return Keyword.PULL_TIGHT; - } - case 207: break; - case 30: - { return Keyword.NONE; - } - case 208: break; - case 120: - { return Keyword.AGAINST_PREFERRED_DIRECTION_TRACE_COSTS; - } - case 209: break; - case 114: - { return Keyword.START_RIPUP_COSTS; - } - case 210: break; - case 53: - { return Keyword.LENGTH; - } - case 211: break; - case 38: - { return Keyword.SHAPE; - } - case 212: break; - case 59: - { return Keyword.FROMTO; - } - case 213: break; - case 44: - { return Keyword.POWER; - } - case 214: break; - case 94: - { return Keyword.HORIZONTAL; - } - case 215: break; - case 26: - { return Keyword.TYPE; - } - case 216: break; - case 51: - { return Keyword.ACTIVE; - } - case 217: break; - case 48: - { return Keyword.FRONT; - } - case 218: break; - case 11: - { yybegin(YYINITIAL); return string.toString(); - } - case 219: break; - case 19: - { yybegin(NAME); return Keyword.NET; - } - case 220: break; - case 96: - { return Keyword.CLASS_CLASS; - } - case 221: break; - case 66: - { yybegin(NAME); return Keyword.USE_VIA; - } - case 222: break; - case 65: - { return Keyword.LIBRARY_SCOPE; - } - case 223: break; - case 3: - { /* ignore */ - } - case 224: break; - case 117: - { yybegin(NAME); return Keyword.LOGICAL_PART_MAPPING; - } - case 225: break; - case 111: - { return Keyword.PLANE_VIA_COSTS; - } - case 226: break; - case 72: - { yybegin(NAME); return Keyword.KEEPOUT; - } - case 227: break; - case 98: - { return Keyword.NETWORK_OUT; - } - case 228: break; - case 55: - { return Keyword.PARSER_SCOPE; - } - case 229: break; - case 10: - { string.append( yytext() ); - } - case 230: break; - case 2: - { throw new Error("Illegal character <"+ - yytext()+">"); - } - case 231: break; - case 95: - { return Keyword.SHOVE_FIXED; - } - case 232: break; - case 104: - { return Keyword.KEEPOUT; - } - case 233: break; - case 33: - { return Keyword.PINS; - } - case 234: break; - case 119: - { return Keyword.PREFERRED_DIRECTION_TRACE_COSTS; - } - case 235: break; - case 5: - { return new Integer(yytext()); - } - case 236: break; - case 25: - { return Keyword.SIDE; - } - case 237: break; - case 41: - { return Keyword.CLEARANCE; - } - case 238: break; - case 97: - { yybegin(NAME); return Keyword.VIA_KEEPOUT; - } - case 239: break; - case 62: - { yybegin(YYINITIAL); return Keyword.SIGNAL; - } - case 240: break; - default: - if (zzInput == YYEOF && zzStartRead == zzCurrentPos) { - zzAtEOF = true; - return null; - } - else { - zzScanError(ZZ_NO_MATCH); - } - } - } - } - - -} +/* The following code was generated by JFlex 1.4.1 on 16.10.08 09:27 */ + +package designformats.specctra; +@SuppressWarnings("all") + +/** + * This class is a scanner generated by + * JFlex 1.4.1 + * on 16.10.08 09:27 from the specification file + * C:/Users/Public/Documents/router/sources/designformats/specctra/SpecctraFileDescription.flex + */ +class SpecctraFileScanner implements Scanner { + + /** This character denotes the end of file */ + public static final int YYEOF = -1; + + /** initial size of the lookahead buffer */ + private static final int ZZ_BUFFERSIZE = 16384; + + /** lexical states */ + public static final int COMPONENT_NAME = 5; + /** Constant IGNORE_QUOTE=7 */ + public static final int IGNORE_QUOTE = 7; + /** Constant YYINITIAL=0 */ + public static final int YYINITIAL = 0; + /** Constant SPEC_CHAR=6 */ + public static final int SPEC_CHAR = 6; + /** Constant LAYER_NAME=4 */ + public static final int LAYER_NAME = 4; + /** Constant STRING2=2 */ + public static final int STRING2 = 2; + /** Constant STRING1=1 */ + public static final int STRING1 = 1; + /** Constant NAME=3 */ + public static final int NAME = 3; + + /** + * Translates characters to character classes + */ + private static final String ZZ_CMAP_PACKED = + "\11\0\1\3\1\2\1\0\1\3\1\1\21\0\1\16\1\3\1\16"+ + "\1\11\1\6\1\16\1\16\1\16\1\12\1\53\1\54\1\5\1\20"+ + "\1\16\1\17\1\14\1\4\1\21\11\10\1\16\1\16\1\16\1\16"+ + "\1\16\1\16\1\16\1\23\1\24\1\32\1\42\1\22\1\41\1\35"+ + "\1\43\1\33\1\7\1\44\1\27\1\46\1\36\1\26\1\37\1\52"+ + "\1\40\1\25\1\31\1\30\1\34\1\51\1\47\1\45\1\50\1\16"+ + "\1\15\1\16\1\16\1\13\1\0\1\23\1\24\1\32\1\42\1\22"+ + "\1\41\1\35\1\43\1\33\1\7\1\44\1\27\1\46\1\36\1\26"+ + "\1\37\1\52\1\40\1\25\1\31\1\30\1\34\1\51\1\47\1\45"+ + "\1\50\3\0\1\16\42\0\136\16\1\16\122\0\2\16\14\0\2\16"+ + "\26\0\1\16\4\0\2\16\22\0\2\16\u0133\0\1\16\25\0\1\16"+ + "\u1d36\0\1\16\1\16\3\0\1\16\1\16\1\16\1\0\1\16\1\16"+ + "\1\16\1\0\1\16\1\16\1\16\3\0\1\16\11\0\1\16\10\0"+ + "\1\16\1\16\161\0\1\16\165\0\1\16\udedd\0"; + + /** + * Translates characters to character classes + */ + private static final char [] ZZ_CMAP = zzUnpackCMap(ZZ_CMAP_PACKED); + + /** + * Translates DFA states to action switch labels. + */ + private static final int [] ZZ_ACTION = zzUnpackAction(); + + private static final String ZZ_ACTION_PACKED_0 = + "\7\0\1\1\1\2\2\3\3\4\1\5\1\6\1\7"+ + "\1\2\1\5\22\4\1\10\1\11\1\12\1\13\1\14"+ + "\1\12\1\1\1\15\1\16\3\1\2\4\3\0\1\17"+ + "\16\4\1\20\45\4\2\1\1\0\1\4\2\17\1\0"+ + "\1\17\22\4\1\21\16\4\1\22\1\4\1\23\13\4"+ + "\1\24\1\25\11\4\1\26\10\4\1\1\1\27\1\0"+ + "\6\4\1\30\6\4\1\31\14\4\1\32\2\4\1\33"+ + "\2\4\1\34\3\4\1\35\2\4\1\36\2\4\1\37"+ + "\5\4\1\40\4\4\1\41\2\4\1\42\2\4\1\43"+ + "\11\4\1\44\3\4\1\1\14\4\1\45\1\46\2\4"+ + "\1\47\1\4\1\50\11\4\1\51\1\52\2\4\1\53"+ + "\20\4\1\54\1\55\1\56\6\4\1\57\3\4\1\60"+ + "\7\4\1\61\1\4\1\1\2\4\1\62\1\63\6\4"+ + "\1\64\3\4\1\65\15\4\1\34\10\4\1\66\1\4"+ + "\1\67\15\4\1\70\1\71\1\72\2\4\1\73\4\4"+ + "\1\74\1\4\1\75\1\4\1\76\4\4\1\77\6\4"+ + "\1\100\3\4\1\101\1\4\1\102\1\103\1\4\1\104"+ + "\3\4\1\105\1\106\6\4\1\107\6\4\1\40\17\4"+ + "\1\110\2\4\1\111\2\4\1\112\12\4\1\113\3\4"+ + "\1\114\2\4\1\115\5\4\1\116\1\4\1\117\14\4"+ + "\1\120\4\4\1\121\3\4\1\122\4\4\1\123\1\4"+ + "\1\124\1\33\1\51\2\4\1\125\5\4\1\126\3\4"+ + "\1\127\4\4\1\42\14\4\1\130\1\4\1\131\3\4"+ + "\1\132\11\4\1\133\1\4\1\134\2\4\1\135\1\4"+ + "\1\136\7\4\1\137\2\4\1\140\1\141\1\4\1\142"+ + "\20\4\1\143\1\144\3\4\1\145\5\4\1\146\1\4"+ + "\1\147\1\150\3\4\1\151\4\4\1\152\1\153\1\154"+ + "\1\155\23\4\1\156\1\4\1\157\11\4\1\160\1\161"+ + "\2\4\1\162\3\4\1\163\3\4\1\164\5\4\1\165"+ + "\6\4\1\166\20\4\1\167\7\4\1\170"; + + private static int [] zzUnpackAction() { + int [] result = new int[712]; + int offset = 0; + offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackAction(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int count = packed.charAt(i++); + int value = packed.charAt(i++); + do result[j++] = value; while (--count > 0); + } + return j; + } + + + /** + * Translates a state to a row index in the transition table + */ + private static final int [] ZZ_ROWMAP = zzUnpackRowMap(); + + private static final String ZZ_ROWMAP_PACKED_0 = + "\0\0\0\55\0\132\0\207\0\264\0\341\0\u010e\0\u013b"+ + "\0\u0168\0\u0195\0\u0168\0\u01c2\0\u01ef\0\u021c\0\u0249\0\u0168"+ + "\0\u0168\0\u0276\0\u02a3\0\u02d0\0\u02fd\0\u032a\0\u0357\0\u0384"+ + "\0\u03b1\0\u03de\0\u040b\0\u0438\0\u0465\0\u0492\0\u04bf\0\u04ec"+ + "\0\u0519\0\u0546\0\u0573\0\u05a0\0\u05cd\0\u0168\0\u0168\0\u05fa"+ + "\0\u0168\0\u0168\0\u0627\0\u0654\0\u0168\0\u0168\0\u0681\0\u06ae"+ + "\0\u06db\0\u0168\0\u0708\0\u0735\0\u0762\0\u078f\0\u02a3\0\u07bc"+ + "\0\u07e9\0\u0816\0\u0843\0\u0870\0\u089d\0\u08ca\0\u08f7\0\u0924"+ + "\0\u0951\0\u097e\0\u09ab\0\u09d8\0\u0a05\0\u01ef\0\u0a32\0\u0a5f"+ + "\0\u0a8c\0\u0ab9\0\u0ae6\0\u0b13\0\u0b40\0\u0b6d\0\u0b9a\0\u0bc7"+ + "\0\u0bf4\0\u0c21\0\u0c4e\0\u0c7b\0\u0ca8\0\u0cd5\0\u0d02\0\u0d2f"+ + "\0\u0d5c\0\u0d89\0\u0db6\0\u0de3\0\u0e10\0\u0e3d\0\u0e6a\0\u0e97"+ + "\0\u0ec4\0\u0ef1\0\u0f1e\0\u0f4b\0\u0f78\0\u0fa5\0\u0fd2\0\u0fff"+ + "\0\u102c\0\u1059\0\u1086\0\u10b3\0\u10e0\0\u110d\0\u113a\0\u1167"+ + "\0\u1194\0\u11c1\0\u0168\0\u11ee\0\u121b\0\u1248\0\u1275\0\u12a2"+ + "\0\u12cf\0\u12fc\0\u1329\0\u1356\0\u1383\0\u13b0\0\u13dd\0\u140a"+ + "\0\u1437\0\u1464\0\u1491\0\u14be\0\u14eb\0\u01ef\0\u1518\0\u1545"+ + "\0\u1572\0\u159f\0\u15cc\0\u15f9\0\u1626\0\u1653\0\u1680\0\u16ad"+ + "\0\u16da\0\u1707\0\u1734\0\u1761\0\u178e\0\u17bb\0\u17e8\0\u1815"+ + "\0\u1842\0\u186f\0\u189c\0\u18c9\0\u18f6\0\u1923\0\u1950\0\u197d"+ + "\0\u19aa\0\u19d7\0\u01ef\0\u1a04\0\u1a31\0\u1a5e\0\u1a8b\0\u1ab8"+ + "\0\u1ae5\0\u1b12\0\u1b3f\0\u1b6c\0\u1b99\0\u01ef\0\u1bc6\0\u1bf3"+ + "\0\u1c20\0\u1c4d\0\u1c7a\0\u1ca7\0\u1cd4\0\u1d01\0\u1d2e\0\u0654"+ + "\0\u1d5b\0\u1d88\0\u1db5\0\u1de2\0\u1e0f\0\u1e3c\0\u1e69\0\u01ef"+ + "\0\u1e96\0\u1ec3\0\u1ef0\0\u1f1d\0\u1f4a\0\u1f77\0\u01ef\0\u1fa4"+ + "\0\u1fd1\0\u1ffe\0\u202b\0\u2058\0\u2085\0\u20b2\0\u20df\0\u210c"+ + "\0\u2139\0\u2166\0\u2193\0\u01ef\0\u21c0\0\u21ed\0\u221a\0\u2247"+ + "\0\u2274\0\u22a1\0\u22ce\0\u22fb\0\u2328\0\u01ef\0\u2355\0\u2382"+ + "\0\u01ef\0\u23af\0\u23dc\0\u01ef\0\u2409\0\u2436\0\u2463\0\u2490"+ + "\0\u24bd\0\u24ea\0\u2517\0\u2544\0\u2571\0\u259e\0\u01ef\0\u25cb"+ + "\0\u25f8\0\u2625\0\u2652\0\u267f\0\u26ac\0\u26d9\0\u2706\0\u2733"+ + "\0\u2760\0\u278d\0\u27ba\0\u27e7\0\u2814\0\u2841\0\u286e\0\u289b"+ + "\0\u28c8\0\u28f5\0\u2922\0\u294f\0\u297c\0\u29a9\0\u29d6\0\u2a03"+ + "\0\u2a30\0\u2a5d\0\u2a8a\0\u2ab7\0\u2ae4\0\u2b11\0\u2b3e\0\u01ef"+ + "\0\u01ef\0\u2b6b\0\u2b98\0\u01ef\0\u2bc5\0\u2bf2\0\u2c1f\0\u2c4c"+ + "\0\u2c79\0\u2ca6\0\u2cd3\0\u2d00\0\u2d2d\0\u2d5a\0\u2d87\0\u2db4"+ + "\0\u2de1\0\u2e0e\0\u2e3b\0\u01ef\0\u2e68\0\u2e95\0\u2ec2\0\u2eef"+ + "\0\u2f1c\0\u2f49\0\u2f76\0\u2fa3\0\u2fd0\0\u2ffd\0\u302a\0\u3057"+ + "\0\u3084\0\u30b1\0\u30de\0\u310b\0\u01ef\0\u3138\0\u3165\0\u3192"+ + "\0\u31bf\0\u31ec\0\u3219\0\u3246\0\u3273\0\u01ef\0\u32a0\0\u32cd"+ + "\0\u32fa\0\u01ef\0\u3327\0\u3354\0\u3381\0\u33ae\0\u33db\0\u3408"+ + "\0\u3435\0\u01ef\0\u3462\0\u348f\0\u34bc\0\u34e9\0\u01ef\0\u01ef"+ + "\0\u3516\0\u3543\0\u3570\0\u359d\0\u35ca\0\u35f7\0\u01ef\0\u3624"+ + "\0\u3651\0\u367e\0\u01ef\0\u36ab\0\u36d8\0\u3705\0\u3732\0\u375f"+ + "\0\u378c\0\u37b9\0\u37e6\0\u3813\0\u3840\0\u386d\0\u389a\0\u38c7"+ + "\0\u01ef\0\u38f4\0\u3921\0\u394e\0\u397b\0\u39a8\0\u39d5\0\u3a02"+ + "\0\u3a2f\0\u01ef\0\u3a5c\0\u01ef\0\u3a89\0\u3ab6\0\u3ae3\0\u3b10"+ + "\0\u3b3d\0\u3b6a\0\u3b97\0\u3bc4\0\u3bf1\0\u3c1e\0\u3c4b\0\u3c78"+ + "\0\u3ca5\0\u01ef\0\u3cd2\0\u01ef\0\u3cff\0\u3d2c\0\u01ef\0\u3d59"+ + "\0\u3d86\0\u3db3\0\u3de0\0\u01ef\0\u3e0d\0\u01ef\0\u3e3a\0\u0654"+ + "\0\u3e67\0\u3e94\0\u3ec1\0\u3eee\0\u01ef\0\u3f1b\0\u3f48\0\u3f75"+ + "\0\u3fa2\0\u3fcf\0\u3ffc\0\u01ef\0\u4029\0\u4056\0\u4083\0\u01ef"+ + "\0\u40b0\0\u01ef\0\u01ef\0\u40dd\0\u01ef\0\u410a\0\u4137\0\u4164"+ + "\0\u01ef\0\u01ef\0\u4191\0\u41be\0\u41eb\0\u4218\0\u4245\0\u4272"+ + "\0\u429f\0\u42cc\0\u42f9\0\u4326\0\u4353\0\u4380\0\u43ad\0\u01ef"+ + "\0\u43da\0\u4407\0\u4434\0\u4461\0\u448e\0\u44bb\0\u44e8\0\u4515"+ + "\0\u4542\0\u456f\0\u459c\0\u45c9\0\u45f6\0\u4623\0\u4650\0\u01ef"+ + "\0\u467d\0\u46aa\0\u01ef\0\u46d7\0\u4704\0\u01ef\0\u4731\0\u475e"+ + "\0\u478b\0\u47b8\0\u47e5\0\u4812\0\u483f\0\u486c\0\u4899\0\u48c6"+ + "\0\u01ef\0\u48f3\0\u4920\0\u494d\0\u01ef\0\u497a\0\u49a7\0\u01ef"+ + "\0\u49d4\0\u4a01\0\u4a2e\0\u4a5b\0\u4a88\0\u01ef\0\u4ab5\0\u01ef"+ + "\0\u4ae2\0\u4b0f\0\u4b3c\0\u4b69\0\u4b96\0\u4bc3\0\u4bf0\0\u4c1d"+ + "\0\u4c4a\0\u4c77\0\u4ca4\0\u4cd1\0\u01ef\0\u4cfe\0\u4d2b\0\u4d58"+ + "\0\u4d85\0\u4db2\0\u4ddf\0\u4e0c\0\u4e39\0\u01ef\0\u4e66\0\u4e93"+ + "\0\u4ec0\0\u4eed\0\u01ef\0\u4f1a\0\u01ef\0\u01ef\0\u4f47\0\u4f74"+ + "\0\u4fa1\0\u01ef\0\u4fce\0\u4ffb\0\u5028\0\u5055\0\u5082\0\u01ef"+ + "\0\u50af\0\u50dc\0\u5109\0\u01ef\0\u5136\0\u5163\0\u5190\0\u51bd"+ + "\0\u01ef\0\u51ea\0\u5217\0\u5244\0\u5271\0\u529e\0\u52cb\0\u52f8"+ + "\0\u5325\0\u5352\0\u537f\0\u53ac\0\u53d9\0\u01ef\0\u5406\0\u01ef"+ + "\0\u5433\0\u5460\0\u548d\0\u01ef\0\u54ba\0\u54e7\0\u5514\0\u5541"+ + "\0\u556e\0\u559b\0\u55c8\0\u55f5\0\u5622\0\u01ef\0\u564f\0\u01ef"+ + "\0\u567c\0\u56a9\0\u01ef\0\u56d6\0\u01ef\0\u5703\0\u5730\0\u575d"+ + "\0\u578a\0\u57b7\0\u57e4\0\u5811\0\u01ef\0\u583e\0\u586b\0\u01ef"+ + "\0\u01ef\0\u5898\0\u01ef\0\u58c5\0\u58f2\0\u591f\0\u594c\0\u5979"+ + "\0\u59a6\0\u59d3\0\u5a00\0\u5a2d\0\u5a5a\0\u5a87\0\u5ab4\0\u5ae1"+ + "\0\u5b0e\0\u5b3b\0\u5b68\0\u01ef\0\u5b95\0\u5bc2\0\u5bef\0\u5c1c"+ + "\0\u01ef\0\u5c49\0\u5c76\0\u5ca3\0\u5cd0\0\u5cfd\0\u01ef\0\u5d2a"+ + "\0\u01ef\0\u01ef\0\u5d57\0\u5d84\0\u5db1\0\u01ef\0\u5dde\0\u5e0b"+ + "\0\u5e38\0\u5e65\0\u01ef\0\u01ef\0\u01ef\0\u01ef\0\u5e92\0\u5ebf"+ + "\0\u5eec\0\u5f19\0\u5f46\0\u5f73\0\u5fa0\0\u5fcd\0\u5ffa\0\u6027"+ + "\0\u6054\0\u6081\0\u60ae\0\u60db\0\u6108\0\u6135\0\u6162\0\u618f"+ + "\0\u61bc\0\u01ef\0\u61e9\0\u01ef\0\u6216\0\u6243\0\u6270\0\u629d"+ + "\0\u62ca\0\u62f7\0\u6324\0\u6351\0\u637e\0\u01ef\0\u01ef\0\u63ab"+ + "\0\u63d8\0\u01ef\0\u6405\0\u6432\0\u645f\0\u01ef\0\u648c\0\u64b9"+ + "\0\u64e6\0\u6513\0\u6540\0\u656d\0\u659a\0\u65c7\0\u65f4\0\u01ef"+ + "\0\u6621\0\u664e\0\u667b\0\u66a8\0\u66d5\0\u6702\0\u01ef\0\u672f"+ + "\0\u675c\0\u6789\0\u67b6\0\u67e3\0\u6810\0\u683d\0\u686a\0\u6897"+ + "\0\u68c4\0\u68f1\0\u691e\0\u694b\0\u6978\0\u69a5\0\u69d2\0\u01ef"+ + "\0\u69ff\0\u6a2c\0\u6a59\0\u6a86\0\u6ab3\0\u6ae0\0\u6b0d\0\u01ef"; + + private static int [] zzUnpackRowMap() { + int [] result = new int[712]; + int offset = 0; + offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackRowMap(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int high = packed.charAt(i++) << 16; + result[j++] = high | packed.charAt(i++); + } + return j; + } + + /** + * The transition table of the DFA + */ + private static final int [] ZZ_TRANS = zzUnpackTrans(); + + private static final String ZZ_TRANS_PACKED_0 = + "\1\11\1\12\2\13\1\14\1\15\1\16\1\15\1\17"+ + "\1\20\1\21\4\15\2\22\1\23\1\15\1\24\1\25"+ + "\1\26\1\27\1\30\1\31\1\32\1\33\1\34\1\35"+ + "\1\36\1\37\1\40\1\41\1\42\1\15\1\43\1\44"+ + "\4\15\1\45\1\15\1\46\1\47\11\50\1\51\3\50"+ + "\1\52\37\50\12\53\1\51\2\53\1\52\37\53\1\11"+ + "\1\12\2\13\5\54\1\20\1\21\40\54\1\55\1\56"+ + "\1\11\1\12\2\13\5\54\1\20\1\21\12\54\1\57"+ + "\11\54\1\60\13\54\1\55\1\56\1\11\1\12\2\13"+ + "\5\61\1\20\1\21\4\61\1\11\33\61\1\55\1\56"+ + "\4\11\3\62\4\11\6\62\35\11\1\12\2\13\47\54"+ + "\1\55\1\56\57\0\1\13\56\0\1\15\1\63\45\15"+ + "\6\0\47\15\2\0\1\64\1\12\1\13\1\64\47\16"+ + "\2\64\10\0\1\17\3\0\1\65\4\0\1\17\1\66"+ + "\42\0\1\17\10\0\1\23\43\0\1\67\3\0\1\65"+ + "\4\0\1\67\1\66\36\0\20\15\1\70\3\15\1\71"+ + "\1\72\1\73\2\15\1\74\15\15\6\0\17\15\1\75"+ + "\2\15\1\76\24\15\6\0\16\15\1\77\6\15\1\100"+ + "\1\15\1\101\2\15\1\102\1\103\3\15\1\104\7\15"+ + "\6\0\24\15\1\105\5\15\1\106\1\15\1\107\1\110"+ + "\11\15\6\0\16\15\1\111\1\112\2\15\1\113\4\15"+ + "\1\114\17\15\6\0\21\15\1\115\25\15\6\0\41\15"+ + "\1\116\5\15\6\0\22\15\1\117\1\120\3\15\1\121"+ + "\17\15\6\0\42\15\1\122\4\15\6\0\16\15\1\123"+ + "\10\15\1\124\17\15\6\0\16\15\1\125\30\15\6\0"+ + "\16\15\1\126\3\15\1\127\4\15\1\130\17\15\6\0"+ + "\17\15\1\131\2\15\1\132\1\133\1\134\1\15\1\135"+ + "\1\136\4\15\1\137\12\15\6\0\16\15\1\140\3\15"+ + "\1\141\1\15\1\142\22\15\6\0\17\15\1\143\2\15"+ + "\1\144\1\145\3\15\1\146\4\15\1\147\12\15\6\0"+ + "\22\15\1\150\24\15\6\0\16\15\1\151\30\15\6\0"+ + "\27\15\1\152\4\15\1\153\12\15\2\0\11\50\1\0"+ + "\3\50\1\0\37\50\12\53\1\0\2\53\1\0\37\53"+ + "\4\0\47\54\6\0\27\54\1\154\17\54\6\0\26\54"+ + "\1\155\20\54\6\0\13\61\1\0\33\61\2\0\4\156"+ + "\1\157\1\15\45\157\2\156\1\64\1\12\1\13\52\64"+ + "\10\0\1\160\10\0\1\160\43\0\1\161\6\0\2\162"+ + "\1\163\37\0\21\15\1\164\25\15\6\0\25\15\1\165"+ + "\21\15\6\0\25\15\1\166\21\15\6\0\25\15\1\167"+ + "\21\15\6\0\17\15\1\170\27\15\6\0\26\15\1\171"+ + "\20\15\6\0\24\15\1\172\22\15\6\0\21\15\1\173"+ + "\25\15\6\0\17\15\1\174\14\15\1\175\12\15\6\0"+ + "\31\15\1\176\4\15\1\177\10\15\6\0\17\15\1\200"+ + "\27\15\6\0\17\15\1\201\27\15\6\0\17\15\1\202"+ + "\2\15\1\203\24\15\6\0\25\15\1\204\21\15\6\0"+ + "\36\15\1\205\10\15\6\0\35\15\1\206\11\15\6\0"+ + "\32\15\1\207\14\15\6\0\41\15\1\210\5\15\6\0"+ + "\26\15\1\211\2\15\1\212\15\15\6\0\20\15\1\213"+ + "\26\15\6\0\16\15\1\214\30\15\6\0\33\15\1\215"+ + "\13\15\6\0\32\15\1\216\7\15\1\217\4\15\6\0"+ + "\16\15\1\220\1\221\27\15\6\0\34\15\1\222\12\15"+ + "\6\0\17\15\1\223\27\15\6\0\34\15\1\224\12\15"+ + "\6\0\17\15\1\225\27\15\6\0\32\15\1\226\14\15"+ + "\6\0\25\15\1\227\21\15\6\0\32\15\1\230\1\15"+ + "\1\231\12\15\6\0\32\15\1\232\14\15\6\0\25\15"+ + "\1\233\6\15\1\234\1\15\1\235\10\15\6\0\21\15"+ + "\1\236\1\15\1\237\21\15\1\240\1\15\6\0\17\15"+ + "\1\241\27\15\6\0\23\15\1\242\23\15\6\0\20\15"+ + "\1\243\26\15\6\0\32\15\1\244\14\15\6\0\16\15"+ + "\1\245\30\15\6\0\21\15\1\246\4\15\1\247\20\15"+ + "\6\0\24\15\1\250\1\251\21\15\6\0\23\15\1\252"+ + "\23\15\6\0\32\15\1\253\14\15\6\0\34\15\1\254"+ + "\12\15\6\0\27\15\1\255\17\15\6\0\43\15\1\256"+ + "\3\15\6\0\22\15\1\257\24\15\6\0\21\15\1\260"+ + "\12\15\1\261\12\15\6\0\16\15\1\262\30\15\6\0"+ + "\32\15\1\263\1\15\1\264\1\15\1\265\10\15\6\0"+ + "\27\15\1\266\17\15\6\0\31\54\1\267\15\54\6\0"+ + "\20\54\1\270\26\54\2\0\5\156\1\271\53\156\1\157"+ + "\1\272\45\157\2\156\10\0\1\160\10\0\1\160\1\66"+ + "\42\0\1\161\10\0\1\161\43\0\1\161\10\0\1\163"+ + "\37\0\22\15\1\273\24\15\6\0\22\15\1\274\24\15"+ + "\6\0\17\15\1\275\27\15\6\0\27\15\1\276\17\15"+ + "\6\0\27\15\1\277\17\15\6\0\40\15\1\300\6\15"+ + "\6\0\32\15\1\301\14\15\6\0\21\15\1\302\25\15"+ + "\6\0\34\15\1\303\12\15\6\0\24\15\1\304\2\15"+ + "\1\305\17\15\6\0\32\15\1\306\14\15\6\0\16\15"+ + "\1\307\30\15\6\0\33\15\1\310\13\15\6\0\34\15"+ + "\1\311\12\15\6\0\33\15\1\312\13\15\6\0\30\15"+ + "\1\313\16\15\6\0\23\15\1\314\23\15\6\0\16\15"+ + "\1\315\30\15\6\0\31\15\1\316\15\15\6\0\16\15"+ + "\1\317\30\15\6\0\40\15\1\320\6\15\6\0\27\15"+ + "\1\321\17\15\6\0\34\15\1\322\12\15\6\0\7\15"+ + "\1\323\37\15\6\0\16\15\1\324\30\15\6\0\21\15"+ + "\1\325\3\15\1\326\21\15\6\0\33\15\1\327\13\15"+ + "\6\0\17\15\1\330\27\15\6\0\21\15\1\331\25\15"+ + "\6\0\26\15\1\332\20\15\6\0\31\15\1\333\15\15"+ + "\6\0\25\15\1\334\21\15\6\0\7\15\1\335\11\15"+ + "\1\336\25\15\6\0\16\15\1\337\30\15\6\0\45\15"+ + "\1\340\1\15\6\0\16\15\1\341\30\15\6\0\42\15"+ + "\1\342\4\15\6\0\16\15\1\343\30\15\6\0\37\15"+ + "\1\344\7\15\6\0\21\15\1\345\3\15\1\346\21\15"+ + "\6\0\21\15\1\347\25\15\6\0\25\15\1\350\1\15"+ + "\1\351\17\15\6\0\41\15\1\352\5\15\6\0\16\15"+ + "\1\353\30\15\6\0\26\15\1\354\3\15\1\355\14\15"+ + "\6\0\23\15\1\356\23\15\6\0\21\15\1\357\25\15"+ + "\6\0\35\15\1\360\11\15\6\0\22\15\1\361\24\15"+ + "\6\0\25\15\1\362\21\15\6\0\25\15\1\363\21\15"+ + "\6\0\17\15\1\364\27\15\6\0\16\15\1\365\30\15"+ + "\6\0\22\15\1\366\24\15\6\0\25\15\1\367\21\15"+ + "\6\0\33\15\1\370\13\15\6\0\32\15\1\371\7\15"+ + "\1\372\4\15\6\0\25\15\1\373\21\15\6\0\27\15"+ + "\1\374\17\15\6\0\33\15\1\375\13\15\6\0\36\15"+ + "\1\376\10\15\6\0\16\15\1\377\10\15\1\u0100\17\15"+ + "\6\0\25\15\1\u0101\21\15\6\0\25\15\1\u0102\21\15"+ + "\6\0\32\54\1\u0103\14\54\2\0\4\156\1\13\1\271"+ + "\53\156\1\15\1\272\45\157\2\156\4\0\23\15\1\u0104"+ + "\23\15\6\0\34\15\1\u0105\12\15\6\0\26\15\1\u0106"+ + "\20\15\6\0\30\15\1\u0107\16\15\6\0\32\15\1\u0108"+ + "\14\15\6\0\36\15\1\u0109\10\15\6\0\27\15\1\u010a"+ + "\17\15\6\0\25\15\1\u010b\21\15\6\0\26\15\1\u010c"+ + "\20\15\6\0\32\15\1\u010d\14\15\6\0\17\15\1\u010e"+ + "\27\15\6\0\7\15\1\u010f\37\15\6\0\16\15\1\u0110"+ + "\30\15\6\0\16\15\1\u0111\30\15\6\0\16\15\1\u0112"+ + "\30\15\6\0\27\15\1\u0113\17\15\6\0\34\15\1\u0114"+ + "\12\15\6\0\25\15\1\u0115\21\15\6\0\34\15\1\u0116"+ + "\12\15\6\0\7\15\1\u0117\37\15\6\0\26\15\1\u0118"+ + "\20\15\6\0\17\15\1\u0119\27\15\6\0\23\15\1\u011a"+ + "\4\15\1\u011b\1\15\1\u011c\14\15\6\0\25\15\1\u011d"+ + "\21\15\6\0\34\15\1\u011e\12\15\6\0\22\15\1\u011f"+ + "\24\15\6\0\34\15\1\u0120\12\15\6\0\21\15\1\u0121"+ + "\25\15\6\0\23\15\1\u0122\1\u0123\22\15\6\0\16\15"+ + "\1\u0124\30\15\6\0\27\15\1\u0125\17\15\6\0\17\15"+ + "\1\u0126\6\15\1\u0127\5\15\1\u0128\3\15\1\u0129\6\15"+ + "\6\0\34\15\1\u012a\12\15\6\0\22\15\1\u012b\24\15"+ + "\6\0\17\15\1\u012c\27\15\6\0\25\15\1\u012d\21\15"+ + "\6\0\16\15\1\u012e\30\15\6\0\7\15\1\u012f\37\15"+ + "\6\0\25\15\1\u0130\21\15\6\0\34\15\1\u0131\12\15"+ + "\6\0\25\15\1\u0132\21\15\6\0\23\15\1\u0133\5\15"+ + "\1\u0134\15\15\6\0\34\15\1\u0135\12\15\6\0\16\15"+ + "\1\u0136\30\15\6\0\16\15\1\u0137\30\15\6\0\7\15"+ + "\1\u0138\37\15\6\0\16\15\1\u0139\30\15\6\0\23\15"+ + "\1\u013a\23\15\6\0\17\15\1\u013b\27\15\6\0\16\15"+ + "\1\u013c\30\15\6\0\25\15\1\u013d\21\15\6\0\21\15"+ + "\1\u013e\25\15\6\0\24\15\1\u013f\22\15\6\0\41\15"+ + "\1\u0140\5\15\6\0\7\15\1\u0141\37\15\6\0\25\15"+ + "\1\u0142\21\15\6\0\25\15\1\u0143\21\15\6\0\7\15"+ + "\1\u0144\37\15\6\0\44\15\1\u0145\2\15\6\0\22\15"+ + "\1\u0146\24\15\6\0\22\15\1\u0147\24\15\6\0\7\15"+ + "\1\u0148\37\15\6\0\32\15\1\u0149\14\15\6\0\37\15"+ + "\1\u014a\7\15\6\0\16\15\1\u014b\30\15\6\0\17\54"+ + "\1\u014c\27\54\6\0\24\15\1\u014d\22\15\6\0\22\15"+ + "\1\u014e\24\15\6\0\37\15\1\u014f\7\15\6\0\16\15"+ + "\1\u0150\30\15\6\0\21\15\1\u0151\25\15\6\0\17\15"+ + "\1\u0152\27\15\6\0\22\15\1\u0153\24\15\6\0\7\15"+ + "\1\u0154\37\15\6\0\25\15\1\u0155\21\15\6\0\31\15"+ + "\1\u0156\15\15\6\0\23\15\1\u0157\23\15\6\0\17\15"+ + "\1\u0158\27\15\6\0\7\15\1\u0159\37\15\6\0\32\15"+ + "\1\u015a\14\15\6\0\37\15\1\u015b\7\15\6\0\7\15"+ + "\1\u015c\37\15\6\0\25\15\1\u015d\21\15\6\0\17\15"+ + "\1\u015e\27\15\6\0\34\15\1\u015f\12\15\6\0\17\15"+ + "\1\u0160\27\15\6\0\27\15\1\u0161\17\15\6\0\16\15"+ + "\1\u0162\30\15\6\0\17\15\1\u0163\27\15\6\0\22\15"+ + "\1\u0164\24\15\6\0\32\15\1\u0165\14\15\6\0\17\15"+ + "\1\u0166\27\15\6\0\7\15\1\u0167\6\15\1\u0168\30\15"+ + "\6\0\16\15\1\u0169\30\15\6\0\27\15\1\u016a\17\15"+ + "\6\0\26\15\1\u016b\20\15\6\0\25\15\1\u016c\21\15"+ + "\6\0\22\15\1\u016d\24\15\6\0\24\15\1\u016e\22\15"+ + "\6\0\16\15\1\u016f\30\15\6\0\17\15\1\u0170\27\15"+ + "\6\0\34\15\1\u0171\12\15\6\0\23\15\1\u0172\23\15"+ + "\6\0\41\15\1\u0173\5\15\6\0\34\15\1\u0174\12\15"+ + "\6\0\23\15\1\u0175\23\15\6\0\17\15\1\u0176\27\15"+ + "\6\0\22\15\1\u0177\24\15\6\0\27\15\1\u0178\17\15"+ + "\6\0\27\15\1\u0179\17\15\6\0\22\15\1\u017a\24\15"+ + "\6\0\7\15\1\u017b\32\15\1\u017c\4\15\6\0\7\15"+ + "\1\u017d\37\15\6\0\25\15\1\u017e\21\15\6\0\34\15"+ + "\1\u017f\12\15\6\0\24\15\1\u0180\22\15\6\0\32\15"+ + "\1\u0181\14\15\6\0\21\15\1\u0182\25\15\6\0\16\15"+ + "\1\u0183\30\15\6\0\25\15\1\u0184\21\15\6\0\35\15"+ + "\1\u0185\11\15\6\0\21\15\1\u0186\25\15\6\0\22\15"+ + "\1\u0187\24\15\6\0\26\15\1\u0188\1\15\1\u0189\16\15"+ + "\6\0\22\15\1\u018a\24\15\6\0\24\15\1\u018b\22\15"+ + "\6\0\45\15\1\u018c\1\15\6\0\40\15\1\u018d\6\15"+ + "\6\0\31\15\1\u018e\15\15\6\0\7\15\1\u018f\37\15"+ + "\6\0\23\54\1\u0190\23\54\6\0\25\15\1\u0191\21\15"+ + "\6\0\24\15\1\u0192\22\15\6\0\25\15\1\u0193\21\15"+ + "\6\0\34\15\1\u0194\12\15\6\0\32\15\1\u0195\14\15"+ + "\6\0\33\15\1\u0196\1\u0197\12\15\6\0\24\15\1\u0198"+ + "\22\15\6\0\7\15\1\u0199\37\15\6\0\32\15\1\u019a"+ + "\14\15\6\0\35\15\1\u019b\11\15\6\0\16\15\1\u019c"+ + "\30\15\6\0\34\15\1\u019d\12\15\6\0\41\15\1\u019e"+ + "\5\15\6\0\23\15\1\u019f\23\15\6\0\41\15\1\u01a0"+ + "\5\15\6\0\41\15\1\u01a1\5\15\6\0\17\15\1\u01a2"+ + "\27\15\6\0\25\15\1\u01a3\21\15\6\0\32\15\1\u01a4"+ + "\14\15\6\0\23\15\1\u01a5\23\15\6\0\16\15\1\u01a6"+ + "\30\15\6\0\32\15\1\u01a7\14\15\6\0\26\15\1\u01a8"+ + "\20\15\6\0\21\15\1\u01a9\25\15\6\0\25\15\1\u01aa"+ + "\21\15\6\0\17\15\1\u01ab\27\15\6\0\7\15\1\u01ac"+ + "\37\15\6\0\21\15\1\u01ad\25\15\6\0\23\15\1\u01ae"+ + "\23\15\6\0\16\15\1\u01af\30\15\6\0\25\15\1\u01b0"+ + "\21\15\6\0\40\15\1\u01b1\6\15\6\0\7\15\1\u01b2"+ + "\37\15\6\0\27\15\1\u01b3\17\15\6\0\26\15\1\u01b4"+ + "\20\15\6\0\24\15\1\u01b5\22\15\6\0\22\15\1\u01b6"+ + "\24\15\6\0\32\15\1\u01b7\14\15\6\0\32\15\1\u01b8"+ + "\14\15\6\0\26\15\1\u01b9\11\15\1\u01ba\6\15\6\0"+ + "\16\15\1\u01bb\30\15\6\0\30\15\1\u01bc\16\15\6\0"+ + "\27\15\1\u01bd\17\15\6\0\16\15\1\u01be\15\15\1\u01bf"+ + "\12\15\6\0\25\15\1\u01c0\21\15\6\0\31\15\1\u01c1"+ + "\15\15\6\0\7\15\1\u01c2\37\15\6\0\27\15\1\u01c3"+ + "\17\15\6\0\25\15\1\u01c4\21\15\6\0\17\15\1\u01c5"+ + "\27\15\6\0\16\15\1\u01c6\30\15\6\0\32\15\1\u01c7"+ + "\14\15\6\0\25\15\1\u01c8\21\15\6\0\16\15\1\u01c9"+ + "\30\15\6\0\34\15\1\u01ca\12\15\6\0\16\15\1\u01cb"+ + "\30\15\6\0\25\15\1\u01cc\21\15\6\0\7\15\1\u01cd"+ + "\37\15\6\0\41\15\1\u01ce\5\15\6\0\17\15\1\u01cf"+ + "\27\15\6\0\27\15\1\u01d0\17\15\6\0\34\15\1\u01d1"+ + "\12\15\6\0\46\15\1\u01d2\6\0\31\15\1\u01d3\15\15"+ + "\6\0\27\15\1\u01d4\17\15\6\0\24\15\1\u01d5\22\15"+ + "\6\0\33\15\1\u01d6\13\15\6\0\7\15\1\u01d7\37\15"+ + "\6\0\16\15\1\u01d8\30\15\6\0\25\15\1\u01d9\21\15"+ + "\6\0\32\15\1\u01da\14\15\6\0\26\15\1\u01db\20\15"+ + "\6\0\23\15\1\u01dc\23\15\6\0\23\15\1\u01dd\23\15"+ + "\6\0\21\15\1\u01de\25\15\6\0\25\15\1\u01df\21\15"+ + "\6\0\16\15\1\u01e0\30\15\6\0\33\15\1\u01e1\13\15"+ + "\6\0\16\15\1\u01e2\30\15\6\0\7\15\1\u01e3\37\15"+ + "\6\0\36\15\1\u01e4\10\15\6\0\20\15\1\u01e5\26\15"+ + "\6\0\40\15\1\u01e6\6\15\6\0\25\15\1\u01e7\21\15"+ + "\6\0\32\15\1\u01e8\14\15\6\0\16\15\1\u01e9\30\15"+ + "\6\0\22\15\1\u01ea\24\15\6\0\16\15\1\u01eb\30\15"+ + "\6\0\32\15\1\u01ec\14\15\6\0\27\15\1\u01ed\17\15"+ + "\6\0\31\15\1\u01ee\15\15\6\0\36\15\1\u01ef\10\15"+ + "\6\0\16\15\1\u01be\30\15\6\0\27\15\1\u01f0\17\15"+ + "\6\0\23\15\1\u01f1\23\15\6\0\35\15\1\u01f2\11\15"+ + "\6\0\30\15\1\u01f3\16\15\6\0\41\15\1\u01f4\5\15"+ + "\6\0\36\15\1\u01f5\10\15\6\0\34\15\1\u01f6\12\15"+ + "\6\0\25\15\1\u01f7\21\15\6\0\16\15\1\u01f8\30\15"+ + "\6\0\16\15\1\u01f9\30\15\6\0\16\15\1\u01fa\30\15"+ + "\6\0\33\15\1\u01fb\13\15\6\0\21\15\1\u01fc\25\15"+ + "\6\0\33\15\1\u01fd\13\15\6\0\16\15\1\u01fe\30\15"+ + "\6\0\24\15\1\u01ff\22\15\6\0\23\15\1\u0200\23\15"+ + "\6\0\43\15\1\u0201\3\15\6\0\23\15\1\u0202\23\15"+ + "\6\0\16\15\1\u0203\30\15\6\0\33\15\1\u0204\13\15"+ + "\6\0\34\15\1\u0205\12\15\6\0\25\15\1\u0206\21\15"+ + "\6\0\16\15\1\u0207\30\15\6\0\17\15\1\u0208\27\15"+ + "\6\0\42\15\1\u0209\4\15\6\0\21\15\1\u020a\25\15"+ + "\6\0\22\15\1\u020b\24\15\6\0\36\15\1\u020c\10\15"+ + "\6\0\22\15\1\u020d\24\15\6\0\16\15\1\u020e\30\15"+ + "\6\0\34\15\1\u020f\12\15\6\0\16\15\1\u0210\30\15"+ + "\6\0\7\15\1\u0211\37\15\6\0\32\15\1\u0212\14\15"+ + "\6\0\16\15\1\u0213\30\15\6\0\25\15\1\u0214\21\15"+ + "\6\0\17\15\1\u0215\27\15\6\0\37\15\1\u0216\7\15"+ + "\6\0\7\15\1\u0217\37\15\6\0\22\15\1\u0218\24\15"+ + "\6\0\16\15\1\u0219\30\15\6\0\27\15\1\u021a\17\15"+ + "\6\0\16\15\1\u021b\30\15\6\0\23\15\1\u021c\23\15"+ + "\6\0\21\15\1\u021d\25\15\6\0\17\15\1\u021e\27\15"+ + "\6\0\33\15\1\u021f\13\15\6\0\21\15\1\u0220\25\15"+ + "\6\0\7\15\1\u0221\37\15\6\0\34\15\1\u0222\12\15"+ + "\6\0\21\15\1\u0223\25\15\6\0\24\15\1\u0224\22\15"+ + "\6\0\22\15\1\u0225\24\15\6\0\16\15\1\u0226\30\15"+ + "\6\0\16\15\1\u0227\30\15\6\0\16\15\1\u0228\30\15"+ + "\6\0\17\15\1\u0229\27\15\6\0\7\15\1\u022a\37\15"+ + "\6\0\21\15\1\u022b\25\15\6\0\36\15\1\u022c\10\15"+ + "\6\0\24\15\1\u022d\22\15\6\0\7\15\1\u022e\37\15"+ + "\6\0\24\15\1\u022f\22\15\6\0\31\15\1\u0230\15\15"+ + "\6\0\17\15\1\u0231\27\15\6\0\33\15\1\u0232\13\15"+ + "\6\0\25\15\1\u0233\21\15\6\0\33\15\1\u0234\13\15"+ + "\6\0\7\15\1\u0235\37\15\6\0\25\15\1\u0236\21\15"+ + "\6\0\36\15\1\u0237\10\15\6\0\32\15\1\u0238\14\15"+ + "\6\0\34\15\1\u0239\12\15\6\0\7\15\1\u023a\37\15"+ + "\6\0\16\15\1\u023b\30\15\6\0\27\15\1\u023c\17\15"+ + "\6\0\23\15\1\u023d\23\15\6\0\22\15\1\u023e\24\15"+ + "\6\0\22\15\1\u023f\24\15\6\0\21\15\1\u0240\25\15"+ + "\6\0\16\15\1\u0241\30\15\6\0\7\15\1\u0242\37\15"+ + "\6\0\33\15\1\u0243\13\15\6\0\25\15\1\u0244\21\15"+ + "\6\0\36\15\1\u0245\10\15\6\0\34\15\1\u0246\12\15"+ + "\6\0\26\15\1\u0247\20\15\6\0\21\15\1\u0248\25\15"+ + "\6\0\25\15\1\u0249\21\15\6\0\20\15\1\u024a\26\15"+ + "\6\0\25\15\1\u024b\21\15\6\0\34\15\1\u024c\12\15"+ + "\6\0\34\15\1\u024d\12\15\6\0\17\15\1\u024e\27\15"+ + "\6\0\34\15\1\u024f\12\15\6\0\22\15\1\u0250\24\15"+ + "\6\0\26\15\1\u0251\20\15\6\0\27\15\1\u0252\17\15"+ + "\6\0\21\15\1\u0253\25\15\6\0\36\15\1\u0254\10\15"+ + "\6\0\22\15\1\u0255\24\15\6\0\24\15\1\u0256\22\15"+ + "\6\0\23\15\1\u0257\23\15\6\0\16\15\1\u0258\30\15"+ + "\6\0\35\15\1\u0259\11\15\6\0\32\15\1\u025a\14\15"+ + "\6\0\7\15\1\u025b\37\15\6\0\16\15\1\u025c\30\15"+ + "\6\0\25\15\1\u025d\21\15\6\0\23\15\1\u025e\23\15"+ + "\6\0\41\15\1\u025f\5\15\6\0\16\15\1\u0260\30\15"+ + "\6\0\41\15\1\u0261\5\15\6\0\25\15\1\u0262\21\15"+ + "\6\0\22\15\1\u0263\24\15\6\0\24\15\1\u0264\22\15"+ + "\6\0\22\15\1\u0265\24\15\6\0\34\15\1\u0266\12\15"+ + "\6\0\25\15\1\u0267\21\15\6\0\16\15\1\u0268\30\15"+ + "\6\0\32\15\1\u0269\14\15\6\0\25\15\1\u026a\21\15"+ + "\6\0\24\15\1\u026b\22\15\6\0\25\15\1\u026c\21\15"+ + "\6\0\16\15\1\u026d\30\15\6\0\22\15\1\u026e\24\15"+ + "\6\0\26\15\1\u026f\20\15\6\0\7\15\1\u0270\37\15"+ + "\6\0\17\15\1\u0271\27\15\6\0\7\15\1\u0272\37\15"+ + "\6\0\16\15\1\u0273\30\15\6\0\37\15\1\u0274\7\15"+ + "\6\0\23\15\1\u0275\23\15\6\0\25\15\1\u0276\21\15"+ + "\6\0\21\15\1\u0277\25\15\6\0\16\15\1\u0278\30\15"+ + "\6\0\31\15\1\u0279\15\15\6\0\25\15\1\u027a\21\15"+ + "\6\0\25\15\1\u027b\21\15\6\0\34\15\1\u027c\12\15"+ + "\6\0\22\15\1\u027d\24\15\6\0\42\15\1\u027e\4\15"+ + "\6\0\21\15\1\u027f\25\15\6\0\35\15\1\u0280\11\15"+ + "\6\0\25\15\1\u0281\21\15\6\0\26\15\1\u0282\20\15"+ + "\6\0\34\15\1\u0283\12\15\6\0\27\15\1\u0284\17\15"+ + "\6\0\27\15\1\u0285\17\15\6\0\16\15\1\u0286\15\15"+ + "\1\u0287\12\15\6\0\21\15\1\u0288\25\15\6\0\17\15"+ + "\1\u0289\27\15\6\0\21\15\1\u028a\25\15\6\0\34\15"+ + "\1\u028b\12\15\6\0\21\15\1\u028c\25\15\6\0\25\15"+ + "\1\u028d\21\15\6\0\16\15\1\u028e\30\15\6\0\22\15"+ + "\1\u028f\24\15\6\0\32\15\1\u0290\14\15\6\0\36\15"+ + "\1\u0291\10\15\6\0\16\15\1\u0286\30\15\6\0\25\15"+ + "\1\u0292\21\15\6\0\33\15\1\u0293\13\15\6\0\16\15"+ + "\1\u0294\30\15\6\0\27\15\1\u0295\17\15\6\0\16\15"+ + "\1\u0296\30\15\6\0\32\15\1\u0297\14\15\6\0\31\15"+ + "\1\u0298\15\15\6\0\7\15\1\u0299\37\15\6\0\21\15"+ + "\1\u029a\25\15\6\0\33\15\1\u029b\13\15\6\0\16\15"+ + "\1\u029c\30\15\6\0\22\15\1\u029d\24\15\6\0\21\15"+ + "\1\u029e\25\15\6\0\36\15\1\u029f\10\15\6\0\27\15"+ + "\1\u02a0\17\15\6\0\34\15\1\u02a1\12\15\6\0\32\15"+ + "\1\u02a2\14\15\6\0\27\15\1\u02a3\17\15\6\0\32\15"+ + "\1\u02a4\14\15\6\0\22\15\1\u02a5\24\15\6\0\7\15"+ + "\1\u02a6\37\15\6\0\34\15\1\u02a7\12\15\6\0\31\15"+ + "\1\u02a8\15\15\6\0\24\15\1\u02a9\22\15\6\0\25\15"+ + "\1\u02aa\21\15\6\0\16\15\1\u02ab\30\15\6\0\25\15"+ + "\1\u02ac\21\15\6\0\34\15\1\u02ad\12\15\6\0\26\15"+ + "\1\u02ae\20\15\6\0\16\15\1\u02af\30\15\6\0\17\15"+ + "\1\u02b0\27\15\6\0\25\15\1\u02b1\21\15\6\0\26\15"+ + "\1\u02b2\20\15\6\0\27\15\1\u02b3\17\15\6\0\16\15"+ + "\1\u02b4\30\15\6\0\22\15\1\u02b5\24\15\6\0\7\15"+ + "\1\u02b6\37\15\6\0\32\15\1\u02b7\14\15\6\0\26\15"+ + "\1\u02b8\20\15\6\0\7\15\1\u02b9\37\15\6\0\22\15"+ + "\1\u02ba\24\15\6\0\25\15\1\u02bb\21\15\6\0\21\15"+ + "\1\u02bc\25\15\6\0\34\15\1\u02bd\12\15\6\0\25\15"+ + "\1\u02be\21\15\6\0\17\15\1\u02bf\27\15\6\0\21\15"+ + "\1\u02c0\25\15\6\0\26\15\1\u02c1\20\15\6\0\16\15"+ + "\1\u02c2\30\15\6\0\7\15\1\u02c3\37\15\6\0\26\15"+ + "\1\u02c4\20\15\6\0\22\15\1\u02c5\24\15\6\0\21\15"+ + "\1\u02c6\25\15\6\0\25\15\1\u02c7\21\15\6\0\21\15"+ + "\1\u02c8\25\15\2\0"; + + private static int [] zzUnpackTrans() { + int [] result = new int[27450]; + int offset = 0; + offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackTrans(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int count = packed.charAt(i++); + int value = packed.charAt(i++); + value--; + do result[j++] = value; while (--count > 0); + } + return j; + } + + + /* error codes */ + private static final int ZZ_UNKNOWN_ERROR = 0; + private static final int ZZ_NO_MATCH = 1; + private static final int ZZ_PUSHBACK_2BIG = 2; + + /* error messages for the codes above */ + private static final String ZZ_ERROR_MSG[] = { + "Unkown internal scanner error", + "Error: could not match input", + "Error: pushback value was too large" + }; + + /** + * ZZ_ATTRIBUTE[aState] contains the attributes of state aState + */ + private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute(); + + private static final String ZZ_ATTRIBUTE_PACKED_0 = + "\7\0\1\1\1\11\1\1\1\11\4\1\2\11\24\1"+ + "\2\11\1\1\2\11\2\1\2\11\3\1\1\11\1\1"+ + "\3\0\67\1\1\0\3\1\1\0\1\11\105\1\1\0"+ + "\u020f\1"; + + private static int [] zzUnpackAttribute() { + int [] result = new int[712]; + int offset = 0; + offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackAttribute(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int count = packed.charAt(i++); + int value = packed.charAt(i++); + do result[j++] = value; while (--count > 0); + } + return j; + } + + /** the input device */ + private java.io.Reader zzReader; + + /** the current state of the DFA */ + private int zzState; + + /** the current lexical state */ + private int zzLexicalState = YYINITIAL; + + /** this buffer contains the current text to be matched and is + the source of the yytext() string */ + private char zzBuffer[] = new char[ZZ_BUFFERSIZE]; + + /** the textposition at the last accepting state */ + private int zzMarkedPos; + + /** the textposition at the last state to be included in yytext */ + private int zzPushbackPos; + + /** the current text position in the buffer */ + private int zzCurrentPos; + + /** startRead marks the beginning of the yytext() string in the buffer */ + private int zzStartRead; + + /** endRead marks the last character in the buffer, that has been read + from input */ + private int zzEndRead; + + /** number of newlines encountered up to the start of the matched text */ + private int yyline; + + /** the number of characters up to the start of the matched text */ + private int yychar; + + /** + * the number of characters from the last newline up to the start of the + * matched text + */ + private int yycolumn; + + /** + * zzAtBOL == true <=> the scanner is currently at the beginning of a line + */ + private boolean zzAtBOL = true; + + /** zzAtEOF == true <=> the scanner is at the EOF */ + private boolean zzAtEOF; + + /* user code: */ + StringBuffer string = new StringBuffer(); + + + /** + * Creates a new scanner + * There is also a java.io.InputStream version of this constructor. + * + * @param in the java.io.Reader to read input from. + */ + SpecctraFileScanner(java.io.Reader in) { + this.zzReader = in; + } + + /** + * Creates a new scanner. + * There is also java.io.Reader version of this constructor. + * + * @param in the java.io.Inputstream to read input from. + */ + SpecctraFileScanner(java.io.InputStream in) { + this(new java.io.InputStreamReader(in)); + } + + /** + * Unpacks the compressed character translation table. + * + * @param packed the packed character translation table + * @return the unpacked character translation table + */ + private static char [] zzUnpackCMap(String packed) { + char [] map = new char[0x10000]; + int i = 0; /* index in packed string */ + int j = 0; /* index in unpacked array */ + while (i < 274) { + int count = packed.charAt(i++); + char value = packed.charAt(i++); + do map[j++] = value; while (--count > 0); + } + return map; + } + + + /** + * Refills the input buffer. + * + * @return false, iff there was new input. + * + * @exception java.io.IOException if any I/O-Error occurs + */ + private boolean zzRefill() throws java.io.IOException { + /* first: make room (if you can) */ + if (zzStartRead > 0) { + System.arraycopy(zzBuffer, zzStartRead, + zzBuffer, 0, + zzEndRead-zzStartRead); + + /* translate stored positions */ + zzEndRead-= zzStartRead; + zzCurrentPos-= zzStartRead; + zzMarkedPos-= zzStartRead; + zzPushbackPos-= zzStartRead; + zzStartRead = 0; + } + + /* is the buffer big enough? */ + if (zzCurrentPos >= zzBuffer.length) { + /* if not: blow it up */ + char newBuffer[] = new char[zzCurrentPos*2]; + System.arraycopy(zzBuffer, 0, newBuffer, 0, zzBuffer.length); + zzBuffer = newBuffer; + } + + /* finally: fill the buffer with new input */ + int numRead = zzReader.read(zzBuffer, zzEndRead, + zzBuffer.length-zzEndRead); + + if (numRead < 0) { + return true; + } + else { + zzEndRead+= numRead; + return false; + } + } + + + /** + * Closes the input stream. + * + * @throws java.io.IOException if any. + */ + public final void yyclose() throws java.io.IOException { + zzAtEOF = true; /* indicate end of file */ + zzEndRead = zzStartRead; /* invalidate buffer */ + + if (zzReader != null) + zzReader.close(); + } + + + /** + * Resets the scanner to read from a new input stream. + * Does not close the old reader. + * + * All internal variables are reset, the old input stream + * cannot be reused (internal buffer is discarded and lost). + * Lexical state is set to ZZ_INITIAL. + * + * @param reader the new input stream + */ + public final void yyreset(java.io.Reader reader) { + zzReader = reader; + zzAtBOL = true; + zzAtEOF = false; + zzEndRead = zzStartRead = 0; + zzCurrentPos = zzMarkedPos = zzPushbackPos = 0; + yyline = yychar = yycolumn = 0; + zzLexicalState = YYINITIAL; + } + + + /** + * Returns the current lexical state. + * + * @return a int. + */ + public final int yystate() { + return zzLexicalState; + } + + + /** + * {@inheritDoc} + * + * Enters a new lexical state + */ + public final void yybegin(int newState) { + zzLexicalState = newState; + } + + + /** + * Returns the text matched by the current regular expression. + * + * @return a {@link java.lang.String} object. + */ + public final String yytext() { + return new String( zzBuffer, zzStartRead, zzMarkedPos-zzStartRead ); + } + + + /** + * Returns the character at position pos from the + * matched text. + * + * It is equivalent to yytext().charAt(pos), but faster + * + * @param pos the position of the character to fetch. + * A value from 0 to yylength()-1. + * @return the character at position pos + */ + public final char yycharat(int pos) { + return zzBuffer[zzStartRead+pos]; + } + + + /** + * Returns the length of the matched text region. + * + * @return a int. + */ + public final int yylength() { + return zzMarkedPos-zzStartRead; + } + + + /** + * Reports an error that occured while scanning. + * + * In a wellformed scanner (no or only correct usage of + * yypushback(int) and a match-all fallback rule) this method + * will only be called with things that "Can't Possibly Happen". + * If this method is called, something is seriously wrong + * (e.g. a JFlex bug producing a faulty scanner etc.). + * + * Usual syntax/scanner level error handling should be done + * in error fallback rules. + * + * @param errorCode the code of the errormessage to display + */ + private void zzScanError(int errorCode) { + String message; + try { + message = ZZ_ERROR_MSG[errorCode]; + } + catch (ArrayIndexOutOfBoundsException e) { + message = ZZ_ERROR_MSG[ZZ_UNKNOWN_ERROR]; + } + + throw new Error(message); + } + + + /** + * Pushes the specified amount of characters back into the input stream. + * + * They will be read again by then next call of the scanning method + * + * @param number the number of characters to be read again. + * This number must not be greater than yylength()! + */ + public void yypushback(int number) { + if ( number > yylength() ) + zzScanError(ZZ_PUSHBACK_2BIG); + + zzMarkedPos -= number; + } + + + /** + * Resumes scanning until the next regular expression is matched, + * the end of input is encountered or an I/O-Error occurs. + * + * @return the next token + * @exception java.io.IOException if any I/O-Error occurs + * @throws java.io.IOException if any. + */ + public Object next_token() throws java.io.IOException { + int zzInput; + int zzAction; + + // cached fields: + int zzCurrentPosL; + int zzMarkedPosL; + int zzEndReadL = zzEndRead; + char [] zzBufferL = zzBuffer; + char [] zzCMapL = ZZ_CMAP; + + int [] zzTransL = ZZ_TRANS; + int [] zzRowMapL = ZZ_ROWMAP; + int [] zzAttrL = ZZ_ATTRIBUTE; + + while (true) { + zzMarkedPosL = zzMarkedPos; + + zzAction = -1; + + zzCurrentPosL = zzCurrentPos = zzStartRead = zzMarkedPosL; + + zzState = zzLexicalState; + + + zzForAction: { + while (true) { + + if (zzCurrentPosL < zzEndReadL) + zzInput = zzBufferL[zzCurrentPosL++]; + else if (zzAtEOF) { + zzInput = YYEOF; + break zzForAction; + } + else { + // store back cached positions + zzCurrentPos = zzCurrentPosL; + zzMarkedPos = zzMarkedPosL; + boolean eof = zzRefill(); + // get translated positions and possibly new buffer + zzCurrentPosL = zzCurrentPos; + zzMarkedPosL = zzMarkedPos; + zzBufferL = zzBuffer; + zzEndReadL = zzEndRead; + if (eof) { + zzInput = YYEOF; + break zzForAction; + } + else { + zzInput = zzBufferL[zzCurrentPosL++]; + } + } + int zzNext = zzTransL[ zzRowMapL[zzState] + zzCMapL[zzInput] ]; + if (zzNext == -1) break zzForAction; + zzState = zzNext; + + int zzAttributes = zzAttrL[zzState]; + if ( (zzAttributes & 1) == 1 ) { + zzAction = zzState; + zzMarkedPosL = zzCurrentPosL; + if ( (zzAttributes & 8) == 8 ) break zzForAction; + } + + } + } + + // store back cached position + zzMarkedPos = zzMarkedPosL; + + switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) { + case 18: + { yybegin(NAME); return Keyword.VIA; + } + case 121: break; + case 24: + { return Keyword.BACK; + } + case 122: break; + case 31: + { yybegin(LAYER_NAME); return Keyword.POLYGON_PATH; + } + case 123: break; + case 71: + { return Keyword.NETWORK_SCOPE; + } + case 124: break; + case 56: + { return Keyword.ROUTES; + } + case 125: break; + case 93: + { return Keyword.FLIP_STYLE; + } + case 126: break; + case 108: + { return Keyword.PLACE_CONTROL; + } + case 127: break; + case 32: + { yybegin(LAYER_NAME); return Keyword.POLYGON; + } + case 128: break; + case 78: + { yybegin(NAME); return Keyword.PADSTACK; + } + case 129: break; + case 110: + { yybegin(NAME); return Keyword.CLEARANCE_CLASS; + } + case 130: break; + case 115: + { return Keyword.AUTOROUTE_SETTINGS; + } + case 131: break; + case 13: + { yybegin(YYINITIAL); return Keyword.OPEN_BRACKET; + } + case 132: break; + case 105: + { return Keyword.START_PASS_NO; + } + case 133: break; + case 23: + { yybegin(YYINITIAL); return Keyword.PCB_SCOPE; + } + case 134: break; + case 34: + { yybegin(LAYER_NAME); return Keyword.RECTANGLE; + } + case 135: break; + case 82: + { return Keyword.STRUCTURE_SCOPE; + } + case 136: break; + case 27: + { yybegin(NAME); return Keyword.COMPONENT_SCOPE; + } + case 137: break; + case 43: + { yybegin(NAME); return Keyword.IMAGE; + } + case 138: break; + case 112: + { return Keyword.FORTYFIVE_DEGREE; + } + case 139: break; + case 60: + { return Keyword.WINDOW; + } + case 140: break; + case 76: + { return Keyword.VERTICAL; + } + case 141: break; + case 20: + { return Keyword.PCB_SCOPE; + } + case 142: break; + case 37: + { return Keyword.SPARE; + } + case 143: break; + case 21: + { return Keyword.PIN; + } + case 144: break; + case 35: + { return Keyword.RULE; + } + case 145: break; + case 29: + { return Keyword.VIAS; + } + case 146: break; + case 16: + { return Keyword.ON; + } + case 147: break; + case 63: + { return Keyword.SESSION; + } + case 148: break; + case 74: + { return Keyword.BOUNDARY; + } + case 149: break; + case 88: + { return Keyword.SNAP_ANGLE; + } + case 150: break; + case 113: + { return Keyword.WRITE_RESOLUTION; + } + case 151: break; + case 54: + { return Keyword.NORMAL; + } + case 152: break; + case 8: + { return Keyword.OPEN_BRACKET; + } + case 153: break; + case 22: + { return Keyword.FIX; + } + case 154: break; + case 89: + { yybegin(NAME); return Keyword.LAYER_RULE; + } + case 155: break; + case 86: + { return Keyword.POSTROUTE; + } + case 156: break; + case 14: + { yybegin(YYINITIAL); return Keyword.CLOSED_BRACKET; + } + case 157: break; + case 9: + { return Keyword.CLOSED_BRACKET; + } + case 158: break; + case 90: + { return Keyword.VIA_AT_SMD; + } + case 159: break; + case 28: + { yybegin(LAYER_NAME); return Keyword.CIRCLE; + } + case 160: break; + case 50: + { return Keyword.ATTACH; + } + case 161: break; + case 92: + { return Keyword.RESOLUTION_SCOPE; + } + case 162: break; + case 77: + { return Keyword.VIA_RULE; + } + case 163: break; + case 70: + { return Keyword.CIRCUIT; + } + case 164: break; + case 87: + { return Keyword.PLACEMENT_SCOPE; + } + case 165: break; + case 36: + { yybegin(NAME); return Keyword.WIRE; + } + case 166: break; + case 116: + { return Keyword.PREFERRED_DIRECTION; + } + case 167: break; + case 40: + { yybegin(NAME); return Keyword.LAYER; + } + case 168: break; + case 69: + { return Keyword.CLASSES; + } + case 169: break; + case 61: + { return Keyword.WIRING_SCOPE; + } + case 170: break; + case 103: + { yybegin(NAME); return Keyword.HOST_VERSION; + } + case 171: break; + case 4: + { return yytext(); + } + case 172: break; + case 73: + { return Keyword.ABSOLUTE; + } + case 173: break; + case 58: + { return Keyword.FANOUT; + } + case 174: break; + case 79: + { return Keyword.POSITION; + } + case 175: break; + case 47: + { return Keyword.RULES; + } + case 176: break; + case 57: + { return Keyword.ROTATE; + } + case 177: break; + case 7: + { string.setLength(0); yybegin(STRING2); + } + case 178: break; + case 84: + { yybegin(NAME); return Keyword.USE_LAYER; + } + case 179: break; + case 80: + { yybegin(NAME); return Keyword.HOST_CAD; + } + case 180: break; + case 64: + { return Keyword.OUTLINE; + } + case 181: break; + case 45: + { yybegin(NAME); return Keyword.PLACE; + } + case 182: break; + case 6: + { string.setLength(0); yybegin(STRING1); + } + case 183: break; + case 99: + { yybegin(IGNORE_QUOTE); return Keyword.STRING_QUOTE; + } + case 184: break; + case 39: + { return Keyword.ORDER; + } + case 185: break; + case 17: + { return Keyword.OFF; + } + case 186: break; + case 81: + { return Keyword.AUTOROUTE; + } + case 187: break; + case 52: + { return Keyword.SIGNAL; + } + case 188: break; + case 107: + { yybegin(LAYER_NAME); return Keyword.POLYLINE_PATH; + } + case 189: break; + case 68: + { return Keyword.CONTROL; + } + case 190: break; + case 46: + { yybegin(NAME); return Keyword.PLANE_SCOPE; + } + case 191: break; + case 1: + { yybegin(YYINITIAL); return yytext(); + } + case 192: break; + case 100: + { yybegin(NAME); return Keyword.LOGICAL_PART; + } + case 193: break; + case 83: + { return Keyword.LOCK_TYPE; + } + case 194: break; + case 109: + { yybegin(NAME); return Keyword.PLACE_KEEPOUT; + } + case 195: break; + case 49: + { return Keyword.WIDTH; + } + case 196: break; + case 106: + { return Keyword.NINETY_DEGREE; + } + case 197: break; + case 67: + { yybegin(NAME); return Keyword.USE_NET; + } + case 198: break; + case 118: + { return Keyword.GENERATED_BY_FREEROUTE; + } + case 199: break; + case 101: + { return Keyword.PART_LIBRARY_SCOPE; + } + case 200: break; + case 85: + { return Keyword.VIA_COSTS; + } + case 201: break; + case 102: + { return Keyword.ROTATE_FIRST; + } + case 202: break; + case 75: + { return Keyword.CONSTANT; + } + case 203: break; + case 12: + { string.append('\\'); + } + case 204: break; + case 15: + { return new Double(yytext()); + } + case 205: break; + case 42: + { yybegin(NAME); return Keyword.CLASS; + } + case 206: break; + case 91: + { return Keyword.PULL_TIGHT; + } + case 207: break; + case 30: + { return Keyword.NONE; + } + case 208: break; + case 120: + { return Keyword.AGAINST_PREFERRED_DIRECTION_TRACE_COSTS; + } + case 209: break; + case 114: + { return Keyword.START_RIPUP_COSTS; + } + case 210: break; + case 53: + { return Keyword.LENGTH; + } + case 211: break; + case 38: + { return Keyword.SHAPE; + } + case 212: break; + case 59: + { return Keyword.FROMTO; + } + case 213: break; + case 44: + { return Keyword.POWER; + } + case 214: break; + case 94: + { return Keyword.HORIZONTAL; + } + case 215: break; + case 26: + { return Keyword.TYPE; + } + case 216: break; + case 51: + { return Keyword.ACTIVE; + } + case 217: break; + case 48: + { return Keyword.FRONT; + } + case 218: break; + case 11: + { yybegin(YYINITIAL); return string.toString(); + } + case 219: break; + case 19: + { yybegin(NAME); return Keyword.NET; + } + case 220: break; + case 96: + { return Keyword.CLASS_CLASS; + } + case 221: break; + case 66: + { yybegin(NAME); return Keyword.USE_VIA; + } + case 222: break; + case 65: + { return Keyword.LIBRARY_SCOPE; + } + case 223: break; + case 3: + { /* ignore */ + } + case 224: break; + case 117: + { yybegin(NAME); return Keyword.LOGICAL_PART_MAPPING; + } + case 225: break; + case 111: + { return Keyword.PLANE_VIA_COSTS; + } + case 226: break; + case 72: + { yybegin(NAME); return Keyword.KEEPOUT; + } + case 227: break; + case 98: + { return Keyword.NETWORK_OUT; + } + case 228: break; + case 55: + { return Keyword.PARSER_SCOPE; + } + case 229: break; + case 10: + { string.append( yytext() ); + } + case 230: break; + case 2: + { throw new Error("Illegal character <"+ + yytext()+">"); + } + case 231: break; + case 95: + { return Keyword.SHOVE_FIXED; + } + case 232: break; + case 104: + { return Keyword.KEEPOUT; + } + case 233: break; + case 33: + { return Keyword.PINS; + } + case 234: break; + case 119: + { return Keyword.PREFERRED_DIRECTION_TRACE_COSTS; + } + case 235: break; + case 5: + { return new Integer(yytext()); + } + case 236: break; + case 25: + { return Keyword.SIDE; + } + case 237: break; + case 41: + { return Keyword.CLEARANCE; + } + case 238: break; + case 97: + { yybegin(NAME); return Keyword.VIA_KEEPOUT; + } + case 239: break; + case 62: + { yybegin(YYINITIAL); return Keyword.SIGNAL; + } + case 240: break; + default: + if (zzInput == YYEOF && zzStartRead == zzCurrentPos) { + zzAtEOF = true; + return null; + } + else { + zzScanError(ZZ_NO_MATCH); + } + } + } + } + + +} diff --git a/designformats/specctra/SpecctraFileScanner.java~ b/src/main/java/designformats/specctra/SpecctraFileScanner.java~ similarity index 100% rename from designformats/specctra/SpecctraFileScanner.java~ rename to src/main/java/designformats/specctra/SpecctraFileScanner.java~ diff --git a/designformats/specctra/Structure.java b/src/main/java/designformats/specctra/Structure.java similarity index 99% rename from designformats/specctra/Structure.java rename to src/main/java/designformats/specctra/Structure.java index 24d2382..81d064a 100644 --- a/designformats/specctra/Structure.java +++ b/src/main/java/designformats/specctra/Structure.java @@ -48,12 +48,15 @@ class Structure extends ScopeKeyword { - /** Creates a new instance of Structure */ + /** + * Creates a new instance of Structure + */ public Structure() { super("structure"); } + /** {@inheritDoc} */ public boolean read_scope(ReadScopeParameter p_par) { BoardConstructionInfo board_construction_info = new BoardConstructionInfo(); @@ -291,6 +294,12 @@ else if (next_token == Keyword.SNAP_ANGLE) return result; } + /** + *

write_scope.

+ * + * @param p_par a {@link designformats.specctra.WriteScopeParameter} object. + * @throws java.io.IOException if any. + */ public static void write_scope(WriteScopeParameter p_par) throws java.io.IOException { p_par.file.start_scope(); diff --git a/designformats/specctra/Wiring.java b/src/main/java/designformats/specctra/Wiring.java similarity index 99% rename from designformats/specctra/Wiring.java rename to src/main/java/designformats/specctra/Wiring.java index a4c6519..5d323ec 100644 --- a/designformats/specctra/Wiring.java +++ b/src/main/java/designformats/specctra/Wiring.java @@ -52,12 +52,15 @@ class Wiring extends ScopeKeyword { - /** Creates a new instance of Wiring */ + /** + * Creates a new instance of Wiring + */ public Wiring() { super("wiring"); } + /** {@inheritDoc} */ public boolean read_scope(ReadScopeParameter p_par) { Object next_token = null; @@ -112,6 +115,12 @@ else if (next_token == Keyword.VIA) return true; } + /** + *

write_scope.

+ * + * @param p_par a {@link designformats.specctra.WriteScopeParameter} object. + * @throws java.io.IOException if any. + */ public static void write_scope(WriteScopeParameter p_par) throws java.io.IOException { p_par.file.start_scope(); diff --git a/designformats/specctra/WriteScopeParameter.java b/src/main/java/designformats/specctra/WriteScopeParameter.java similarity index 98% rename from designformats/specctra/WriteScopeParameter.java rename to src/main/java/designformats/specctra/WriteScopeParameter.java index 2810d08..ad61e4e 100644 --- a/designformats/specctra/WriteScopeParameter.java +++ b/src/main/java/designformats/specctra/WriteScopeParameter.java @@ -28,6 +28,7 @@ * Default parameter type used while writing a Specctra dsn-file. * * @author alfons + * @version $Id: $Id */ public class WriteScopeParameter { diff --git a/designformats/specctra/package.html b/src/main/java/designformats/specctra/package.html similarity index 100% rename from designformats/specctra/package.html rename to src/main/java/designformats/specctra/package.html diff --git a/geometry/planar/Area.java b/src/main/java/geometry/planar/Area.java similarity index 68% rename from geometry/planar/Area.java rename to src/main/java/geometry/planar/Area.java index 1f93618..545b6d5 100644 --- a/geometry/planar/Area.java +++ b/src/main/java/geometry/planar/Area.java @@ -26,17 +26,22 @@ * The border and the holes of an Area are of class Shape. * * @author Alfons Wirtz + * @version $Id: $Id */ public interface Area { /** * returns true, if the area is empty + * + * @return a boolean. */ boolean is_empty(); /** * returns true, if the area is contained in a sufficiently large box + * + * @return a boolean. */ boolean is_bounded(); @@ -45,22 +50,31 @@ public interface Area * 1, if it contains curves, * 0, if it is reduced to a points and * -1, if it is empty. + * + * @return a int. */ int dimension(); /** * Checks, if this area is completely contained in p_box. + * + * @param p_box a {@link geometry.planar.IntBox} object. + * @return a boolean. */ boolean is_contained_in(IntBox p_box); /** * returns the border shape of this area + * + * @return a {@link geometry.planar.Shape} object. */ Shape get_border(); /** * Returns the array of holes, of this area. + * + * @return an array of {@link geometry.planar.Shape} objects. */ Shape[] get_holes(); @@ -68,6 +82,8 @@ public interface Area * Returns the smallest surrounding box of the area. * If the area is not bounded, some coordinates of the resulting * box may be equal Integer.MAX_VALUE + * + * @return a {@link geometry.planar.IntBox} object. */ IntBox bounding_box(); @@ -75,6 +91,8 @@ public interface Area * Returns the smallest surrounding octagon of the area. * If the area is not bounded, some coordinates of the resulting * octagon may be equal Integer.MAX_VALUE + * + * @return a {@link geometry.planar.IntOctagon} object. */ IntOctagon bounding_octagon(); @@ -83,55 +101,85 @@ public interface Area * but not inside a hole. * Being on the border is not defined for FloatPoints * because of numerical inacurracy. + * + * @param p_point a {@link geometry.planar.FloatPoint} object. + * @return a boolean. */ boolean contains(FloatPoint p_point); /** * Returns true, if p_point is inside or on the border * of this area, but not inside a hole. + * + * @param p_point a {@link geometry.planar.Point} object. + * @return a boolean. */ boolean contains(Point p_point); /** * Calculates an approximation of the nearest point of the shape * to p_from_point + * + * @param p_ftom_point a {@link geometry.planar.FloatPoint} object. + * @return a {@link geometry.planar.FloatPoint} object. */ FloatPoint nearest_point_approx(FloatPoint p_ftom_point); /** * Turns this area by p_factor times 90 degree around p_pole. + * + * @param p_factor a int. + * @param p_pole a {@link geometry.planar.IntPoint} object. + * @return a {@link geometry.planar.Area} object. */ Area turn_90_degree(int p_factor, IntPoint p_pole); /** * Rotates the area around p_pole by p_angle. * The result may be not exact. - */ + * + * @param p_angle a double. + * @param p_pole a {@link geometry.planar.FloatPoint} object. + * @return a {@link geometry.planar.Area} object. + */ Area rotate_approx(double p_angle, FloatPoint p_pole); /** * Returns the affine translation of the area by p_vector + * + * @param p_vector a {@link geometry.planar.Vector} object. + * @return a {@link geometry.planar.Area} object. */ Area translate_by(Vector p_vector); /** * Mirrors this area at the horizontal line through p_pole. + * + * @param p_pole a {@link geometry.planar.IntPoint} object. + * @return a {@link geometry.planar.Area} object. */ Area mirror_horizontal(IntPoint p_pole); /** * Mirrors this area at the vertical line through p_pole. + * + * @param p_pole a {@link geometry.planar.IntPoint} object. + * @return a {@link geometry.planar.Area} object. */ Area mirror_vertical (IntPoint p_pole); /** * Returns an approximation of the corners of this area. + * + * @return an array of {@link geometry.planar.FloatPoint} objects. */ FloatPoint[] corner_approx_arr(); /** * Returns a division of this area into convex pieces. + * + * @return an array of {@link geometry.planar.TileShape} objects. */ TileShape[] split_to_convex(); diff --git a/geometry/planar/BigIntDirection.java b/src/main/java/geometry/planar/BigIntDirection.java similarity index 88% rename from geometry/planar/BigIntDirection.java rename to src/main/java/geometry/planar/BigIntDirection.java index 5f4dc35..9ecb1ad 100644 --- a/geometry/planar/BigIntDirection.java +++ b/src/main/java/geometry/planar/BigIntDirection.java @@ -1,156 +1,179 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * BigIntDirection.java - * - * Created on 4. Februar 2003, 14:10 - */ - -package geometry.planar; -import java.math.BigInteger; - -/** - * - * Implements the abstract class Direction as a tuple - * of infinite precision integers. - * - * - * @author Alfons Wirtz - */ - -public class BigIntDirection extends Direction implements java.io.Serializable -{ - public boolean is_orthogonal() - { - return (x.signum() == 0 || y.signum() == 0); - } - - public boolean is_diagonal() - { - return x.abs().equals(y.abs()); - } - - public Vector get_vector() - { - return new RationalVector(x, y, BigInteger.ONE); - } - - public Direction turn_45_degree(int p_factor) - { - System.out.println("BigIntDirection: turn_45_degree not yet implemented"); - return this; - } - - public Direction opposite() - { - return new BigIntDirection(x.negate(), y.negate()); - } - - final BigInteger x; - final BigInteger y; - - BigIntDirection(BigInteger p_x, BigInteger p_y) - { - x = p_x; - y = p_y; - } - - /** - * creates a BigIntDirection from an IntDirection - */ - BigIntDirection(IntDirection p_dir) - { - x = BigInteger.valueOf(p_dir.x); - y = BigInteger.valueOf(p_dir.y); - } - - /** - * Implements the Comparable interface. - * Returns 1, if this direction has a strict bigger angle with - * the positive x-axis than p_other_direction, - * 0, if this direction is equal to p_other_direction, - * and -1 otherwise. - * Throws an exception, if p_other_direction is not a Direction. - */ - public int compareTo(Direction p_other_direction) - { - return -p_other_direction.compareTo(this); - } - - int compareTo(IntDirection p_other) - { - BigIntDirection other = new BigIntDirection(p_other); - return compareTo(other); - } - - int compareTo(BigIntDirection p_other) - { - int x1 = x.signum(); - int y1 = y.signum(); - int x2 = p_other.x.signum(); - int y2 = p_other.y.signum(); - if (y1 > 0) - { - if (y2 < 0) - { - return -1 ; - } - if (y2 == 0) - { - if (x2 > 0) - { - return 1 ; - } - return -1 ; - } - } - else if (y1 < 0) - { - if (y2 >= 0) - { - return 1 ; - } - } - else // y1 == 0 - { - if (x1 > 0) - { - if (y2 != 0 || x2 < 0) - { - return -1 ; - } - return 0 ; - } - // x1 < 0 - if (y2 > 0 || y2 == 0 && x2 > 0) - { - return 1 ; - } - if (y2 < 0) - { - return -1 ; - } - return 0; - } - - // now this direction and p_other are located in the same - // open horizontal half plane - - BigInteger tmp_1 = y.multiply(p_other.x); - BigInteger tmp_2 = x.multiply(p_other.y); - BigInteger determinant = tmp_1.subtract(tmp_2); - return determinant.signum(); - } -} \ No newline at end of file +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * BigIntDirection.java + * + * Created on 4. Februar 2003, 14:10 + */ + +package geometry.planar; +import java.math.BigInteger; + +/** + * + * Implements the abstract class Direction as a tuple + * of infinite precision integers. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class BigIntDirection extends Direction implements java.io.Serializable +{ + /** + *

is_orthogonal.

+ * + * @return a boolean. + */ + public boolean is_orthogonal() + { + return (x.signum() == 0 || y.signum() == 0); + } + + /** + *

is_diagonal.

+ * + * @return a boolean. + */ + public boolean is_diagonal() + { + return x.abs().equals(y.abs()); + } + + /** + *

get_vector.

+ * + * @return a {@link geometry.planar.Vector} object. + */ + public Vector get_vector() + { + return new RationalVector(x, y, BigInteger.ONE); + } + + /** {@inheritDoc} */ + public Direction turn_45_degree(int p_factor) + { + System.out.println("BigIntDirection: turn_45_degree not yet implemented"); + return this; + } + + /** + *

opposite.

+ * + * @return a {@link geometry.planar.Direction} object. + */ + public Direction opposite() + { + return new BigIntDirection(x.negate(), y.negate()); + } + + final BigInteger x; + final BigInteger y; + + BigIntDirection(BigInteger p_x, BigInteger p_y) + { + x = p_x; + y = p_y; + } + + /** + * creates a BigIntDirection from an IntDirection + */ + BigIntDirection(IntDirection p_dir) + { + x = BigInteger.valueOf(p_dir.x); + y = BigInteger.valueOf(p_dir.y); + } + + /** + * Implements the Comparable interface. + * Returns 1, if this direction has a strict bigger angle with + * the positive x-axis than p_other_direction, + * 0, if this direction is equal to p_other_direction, + * and -1 otherwise. + * Throws an exception, if p_other_direction is not a Direction. + * + * @param p_other_direction a {@link geometry.planar.Direction} object. + * @return a int. + */ + public int compareTo(Direction p_other_direction) + { + return -p_other_direction.compareTo(this); + } + + int compareTo(IntDirection p_other) + { + BigIntDirection other = new BigIntDirection(p_other); + return compareTo(other); + } + + int compareTo(BigIntDirection p_other) + { + int x1 = x.signum(); + int y1 = y.signum(); + int x2 = p_other.x.signum(); + int y2 = p_other.y.signum(); + if (y1 > 0) + { + if (y2 < 0) + { + return -1 ; + } + if (y2 == 0) + { + if (x2 > 0) + { + return 1 ; + } + return -1 ; + } + } + else if (y1 < 0) + { + if (y2 >= 0) + { + return 1 ; + } + } + else // y1 == 0 + { + if (x1 > 0) + { + if (y2 != 0 || x2 < 0) + { + return -1 ; + } + return 0 ; + } + // x1 < 0 + if (y2 > 0 || y2 == 0 && x2 > 0) + { + return 1 ; + } + if (y2 < 0) + { + return -1 ; + } + return 0; + } + + // now this direction and p_other are located in the same + // open horizontal half plane + + BigInteger tmp_1 = y.multiply(p_other.x); + BigInteger tmp_2 = x.multiply(p_other.y); + BigInteger determinant = tmp_1.subtract(tmp_2); + return determinant.signum(); + } +} diff --git a/geometry/planar/Circle.java b/src/main/java/geometry/planar/Circle.java similarity index 77% rename from geometry/planar/Circle.java rename to src/main/java/geometry/planar/Circle.java index ac2d115..4c59b81 100644 --- a/geometry/planar/Circle.java +++ b/src/main/java/geometry/planar/Circle.java @@ -24,11 +24,17 @@ * Discribes functionality of a circle shape in the plane. * * @author Alfons Wirtz + * @version $Id: $Id */ public class Circle implements ConvexShape, java.io.Serializable { - /** Creates a new instance of Circle */ + /** + * Creates a new instance of Circle + * + * @param p_center a {@link geometry.planar.IntPoint} object. + * @param p_radius a int. + */ public Circle(IntPoint p_center, int p_radius) { center = p_center; @@ -43,16 +49,31 @@ public Circle(IntPoint p_center, int p_radius) } } + /** + *

is_empty.

+ * + * @return a boolean. + */ public boolean is_empty() { return false; } + /** + *

is_bounded.

+ * + * @return a boolean. + */ public boolean is_bounded() { return true; } + /** + *

dimension.

+ * + * @return a int. + */ public int dimension() { if (radius == 0) @@ -63,60 +84,96 @@ public int dimension() return 2; } + /** + *

circumference.

+ * + * @return a double. + */ public double circumference() { return 2.0 * Math.PI * radius; } + /** + *

area.

+ * + * @return a double. + */ public double area() { return ( Math.PI * radius) * radius; } + /** + *

centre_of_gravity.

+ * + * @return a {@link geometry.planar.FloatPoint} object. + */ public FloatPoint centre_of_gravity() { return center.to_float(); } + /** {@inheritDoc} */ public boolean is_outside(Point p_point) { FloatPoint fp = p_point.to_float(); return fp.distance_square(center.to_float()) > (double) radius * radius; } + /** {@inheritDoc} */ public boolean contains(Point p_point) { return !is_outside(p_point); } + /** {@inheritDoc} */ public boolean contains_inside(Point p_point) { FloatPoint fp = p_point.to_float(); return fp.distance_square(center.to_float()) < (double) radius * radius; } + /** {@inheritDoc} */ public boolean contains_on_border(Point p_point) { FloatPoint fp = p_point.to_float(); return fp.distance_square(center.to_float()) == (double) radius * radius; } + /** + *

contains.

+ * + * @param p_point a {@link geometry.planar.FloatPoint} object. + * @return a boolean. + */ public boolean contains(FloatPoint p_point) { return p_point.distance_square(center.to_float()) <= (double) radius * radius; } + /** {@inheritDoc} */ public double distance(FloatPoint p_point) { double d = p_point.distance(center.to_float()) - radius; return Math.max(d, 0.0); } + /** + *

smallest_radius.

+ * + * @return a double. + */ public double smallest_radius() { return radius; } + /** + *

bounding_box.

+ * + * @return a {@link geometry.planar.IntBox} object. + */ public IntBox bounding_box() { int llx = center.x - radius; @@ -127,6 +184,11 @@ public IntBox bounding_box() } + /** + *

bounding_octagon.

+ * + * @return a {@link geometry.planar.IntOctagon} object. + */ public IntOctagon bounding_octagon() { int lx = center.x - radius; @@ -145,6 +207,11 @@ public IntOctagon bounding_octagon() return new IntOctagon(lx, ly, rx, uy, ulx, lrx, llx, urx); } + /** + *

bounding_tile.

+ * + * @return a {@link geometry.planar.TileShape} object. + */ public TileShape bounding_tile() { return bounding_octagon(); @@ -159,6 +226,9 @@ public TileShape bounding_tile() /** * Creates a bounding tile shape around this circle, so that the length of the * line segments of the tile is at most p_max_segment_length. + * + * @param p_max_segment_length a int. + * @return a {@link geometry.planar.TileShape} object. */ public TileShape bounding_tile(int p_max_segment_length) { @@ -195,6 +265,7 @@ public TileShape bounding_tile(int p_max_segment_length) return TileShape.get_instance(tangent_line_arr); } + /** {@inheritDoc} */ public boolean is_contained_in(IntBox p_box) { if (p_box.ll.x > center.x - radius) @@ -216,12 +287,14 @@ public boolean is_contained_in(IntBox p_box) return true; } + /** {@inheritDoc} */ public Circle turn_90_degree(int p_factor, IntPoint p_pole) { IntPoint new_center = (IntPoint) center.turn_90_degree(p_factor, p_pole); return new Circle(new_center, radius); } + /** {@inheritDoc} */ public Circle rotate_approx(double p_angle, FloatPoint p_pole) { IntPoint new_center = center.to_float().rotate(p_angle, p_pole).round(); @@ -229,33 +302,47 @@ public Circle rotate_approx(double p_angle, FloatPoint p_pole) } + /** {@inheritDoc} */ public Circle mirror_vertical(IntPoint p_pole) { IntPoint new_center = (IntPoint) center.mirror_vertical(p_pole); return new Circle(new_center, radius); } + /** {@inheritDoc} */ public Circle mirror_horizontal(IntPoint p_pole) { IntPoint new_center = (IntPoint) center.mirror_horizontal(p_pole); return new Circle(new_center, radius); } + /** + *

max_width.

+ * + * @return a double. + */ public double max_width() { return 2 * this.radius; } + /** + *

min_width.

+ * + * @return a double. + */ public double min_width() { return 2 * this.radius; } + /** {@inheritDoc} */ public RegularTileShape bounding_shape(ShapeBoundingDirections p_dirs) { return p_dirs.bounds(this); } + /** {@inheritDoc} */ public Circle offset(double p_offset) { double new_radius = this.radius + p_offset; @@ -263,6 +350,7 @@ public Circle offset(double p_offset) return new Circle(this.center, r); } + /** {@inheritDoc} */ public Circle shrink(double p_offset) { double new_radius = this.radius - p_offset; @@ -270,6 +358,7 @@ public Circle shrink(double p_offset) return new Circle(this.center, r); } + /** {@inheritDoc} */ public Circle translate_by(Vector p_vector) { if (p_vector.equals(Vector.ZERO)) @@ -286,18 +375,21 @@ public Circle translate_by(Vector p_vector) } + /** {@inheritDoc} */ public FloatPoint nearest_point_approx(FloatPoint p_point) { System.out.println("Circle.nearest_point_approx not yet implemented"); return null; } + /** {@inheritDoc} */ public double border_distance(FloatPoint p_point) { double d = p_point.distance(center.to_float()) - radius; return Math.abs(d); } + /** {@inheritDoc} */ public Circle enlarge(double p_offset) { if (p_offset == 0) @@ -308,38 +400,69 @@ public Circle enlarge(double p_offset) return new Circle(center, new_radius); } + /** + *

intersects.

+ * + * @param p_other a {@link geometry.planar.Shape} object. + * @return a boolean. + */ public boolean intersects(Shape p_other) { return p_other.intersects(this); } + /** {@inheritDoc} */ public Polyline[] cutout(Polyline p_polyline) { System.out.println("Circle.cutout not yet implemented"); return null; } + /** + *

intersects.

+ * + * @param p_other a {@link geometry.planar.Circle} object. + * @return a boolean. + */ public boolean intersects(Circle p_other) { double d_square = radius + p_other.radius; d_square *= d_square; return center.distance_square(p_other.center) <= d_square; } + /** + *

intersects.

+ * + * @param p_box a {@link geometry.planar.IntBox} object. + * @return a boolean. + */ public boolean intersects(IntBox p_box) { return p_box.distance(center.to_float()) <= radius; } + /** {@inheritDoc} */ public boolean intersects(IntOctagon p_oct) { return p_oct.distance(center.to_float()) <= radius; } + /** + *

intersects.

+ * + * @param p_simplex a {@link geometry.planar.Simplex} object. + * @return a boolean. + */ public boolean intersects(Simplex p_simplex) { return p_simplex.distance(center.to_float()) <= radius; } + /** + *

split_to_convex.

+ * + * @return an array of {@link geometry.planar.TileShape} objects. + */ public TileShape[] split_to_convex() { TileShape[] result = new TileShape[1]; @@ -347,26 +470,52 @@ public TileShape[] split_to_convex() return result; } + /** + *

get_border.

+ * + * @return a {@link geometry.planar.Circle} object. + */ public Circle get_border() { return this; } + /** + *

get_holes.

+ * + * @return an array of {@link geometry.planar.Shape} objects. + */ public Shape[] get_holes() { return new Shape[0]; } + /** + *

corner_approx_arr.

+ * + * @return an array of {@link geometry.planar.FloatPoint} objects. + */ public FloatPoint[] corner_approx_arr() { return new FloatPoint[0]; } + /** + *

toString.

+ * + * @return a {@link java.lang.String} object. + */ public String toString() { return to_string(java.util.Locale.ENGLISH); } + /** + *

to_string.

+ * + * @param p_locale a {@link java.util.Locale} object. + * @return a {@link java.lang.String} object. + */ public String to_string(java.util.Locale p_locale) { String result = "Circle: "; diff --git a/geometry/planar/ConvexShape.java b/src/main/java/geometry/planar/ConvexShape.java similarity index 79% rename from geometry/planar/ConvexShape.java rename to src/main/java/geometry/planar/ConvexShape.java index 5038438..84519a7 100644 --- a/geometry/planar/ConvexShape.java +++ b/src/main/java/geometry/planar/ConvexShape.java @@ -25,30 +25,41 @@ * contained in the shape the whole segment is contained completely in the shape. * * @author Alfons Wirtz + * @version $Id: $Id */ public interface ConvexShape extends Shape { /** * Calculates the offset shape by p_distance. - * If p_distance > 0, the shape will be enlarged, else the result + * If {@code p_distance > 0}, the shape will be enlarged, else the result * shape will be smaller. + * + * @param p_distance a double. + * @return a {@link geometry.planar.ConvexShape} object. */ ConvexShape offset(double p_distance); /** * Shrinks the shape by p_offset. * The result shape will not be empty. + * + * @param p_offset a double. + * @return a {@link geometry.planar.ConvexShape} object. */ ConvexShape shrink(double p_offset); /** * Returns the maximum diameter of the shape. + * + * @return a double. */ double max_width(); /** * Returns the minimum diameter of the shape. + * + * @return a double. */ double min_width(); } diff --git a/geometry/planar/Direction.java b/src/main/java/geometry/planar/Direction.java similarity index 82% rename from geometry/planar/Direction.java rename to src/main/java/geometry/planar/Direction.java index 6d2cbac..5d15d04 100644 --- a/geometry/planar/Direction.java +++ b/src/main/java/geometry/planar/Direction.java @@ -1,254 +1,296 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * Direction.java - * - * Created on 3. Februar 2003, 15:36 - */ - -package geometry.planar; -import datastructures.Signum; - -/** - * - * Abstract class defining functionality of directions - * in the plane. A Direction is an equivalence class of - * vectors. Two vectors define the same object of class - * Direction, if they point into the same direction. - * We prefer using directions instead of angles, because - * with angles the arithmetic calculations are in - * general not exact. - * - * @author Alfons Wirtz - */ - -public abstract class Direction implements Comparable, java.io.Serializable -{ - public static final IntDirection NULL = new IntDirection(0,0); - - /** - * the direction to the east - */ - public static final IntDirection RIGHT = new IntDirection(1, 0); - /** - * the direction to the northeast - */ - public static final IntDirection RIGHT45 = new IntDirection(1, 1); - /** - * the direction to the north - */ - public static final IntDirection UP = new IntDirection(0, 1); - /** - * the direction to the northwest - */ - public static final IntDirection UP45 = new IntDirection(-1, 1); - /** - * the direction to the west - */ - public static final IntDirection LEFT = new IntDirection(-1, 0); - /** - * the direction to the southwest - */ - public static final IntDirection LEFT45 = new IntDirection(-1, -1); - /** - * the direction to the south - */ - public static final IntDirection DOWN = new IntDirection(0, -1); - /** - * the direction to the southeast - */ - public static final IntDirection DOWN45 = new IntDirection(1, -1); - - /** - * creates a Direction from the input Vector - */ - public static Direction get_instance( Vector p_vector ) - { - return p_vector.to_normalized_direction(); - } - - /** - * Calculates the direction from p_from to p_to. - * If p_from and p_to are equal, null is returned. - */ - public static Direction get_instance( Point p_from, Point p_to ) - { - if ( p_from.equals(p_to) ) - { - return null; - } - return get_instance(p_to.difference_by( p_from )); - } - - /** - * Creates a Direction whose angle with the x-axis is nearly equal to p_angle - */ - public static Direction get_instance_approx( double p_angle ) - { - final double scale_factor = 10000; - int x = (int)Math.round(Math.cos(p_angle) * scale_factor); - int y = (int)Math.round(Math.sin(p_angle) * scale_factor); - return get_instance(new IntVector(x, y)); - } - - /** - * return any Vector pointing into this direction - */ - public abstract Vector get_vector(); - - /** - * returns true, if the direction is horizontal or vertical - */ - public abstract boolean is_orthogonal(); - - /** - * returns true, if the direction is diagonal - */ - public abstract boolean is_diagonal(); - - /** - * returns true, if the direction is orthogonal or diagonal - */ - public boolean is_multiple_of_45_degree() - { - return ( is_orthogonal() || is_diagonal() ) ; - } - - /** - * turns the direction by p_factor times 45 degree - */ - public abstract Direction turn_45_degree(int p_factor); - - /** - * returns the opposite direction of this direction - */ - public abstract Direction opposite(); - - /** - * Returns true, if p_ob is a Direction and - * this Direction and p_ob point into the same direction - */ - public final boolean equals( Direction p_other ) - { - if ( this == p_other ) - { - return true; - } - if ( p_other == null ) - { - return false; - } - - if (this.side_of(p_other) != Side.COLLINEAR) - { - return false; - } - // check, that dir and other_dir do not point into opposite directions - Vector this_vector = get_vector(); - Vector other_vector = p_other.get_vector() ; - return this_vector.projection(other_vector) == Signum.POSITIVE; - } - - /** - * Let L be the line from the Zero Vector to p_other.get_vector(). - * The function returns - * Side.ON_THE_LEFT, if this.get_vector() is on the left of L - * Side.ON_THE_RIGHT, if this.get_vector() is on the right of L - * and Side.COLLINEAR, if this.get_vector() is collinear with L. - */ - public Side side_of(Direction p_other) - { - return this.get_vector().side_of(p_other.get_vector()); - } - - /** - * The function returns - * Signum.POSITIVE, if the scalar product of of a vector representing - * this direction and a vector representing p_other is > 0, - * Signum.NEGATIVE, if the scalar product is < 0, - * and Signum.ZERO, if the scalar product is equal 0. - */ - public Signum projection(Direction p_other) - { - return this.get_vector().projection(p_other.get_vector()); - } - - /** - * calculates an approximation of the direction in the middle of - * this direction and p_other - */ - public Direction middle_approx(Direction p_other) - { - FloatPoint v1 = get_vector().to_float(); - FloatPoint v2 = p_other.get_vector().to_float(); - double length1 = v1.size(); - double length2 = v2.size(); - double x = v1.x / length1 + v2.x /length2; - double y = v1.y / length1 + v2.y /length2; - final double scale_factor = 1000; - Vector vm = new IntVector((int)Math.round(x * scale_factor), - (int)Math.round(y * scale_factor)); - return Direction.get_instance(vm); - } - - - /** - * Returns 1, if the angle between p_1 and this direction is bigger - * the angle between p_2 and this direction, - * 0, if p_1 is equal to p_2, * and -1 otherwise. - */ - public int compare_from(Direction p_1, Direction p_2) - { - int result; - if (p_1.compareTo(this) >= 0) - { - if (p_2.compareTo(this) >= 0) - { - result = p_1.compareTo(p_2); - } - else - { - result = -1; - } - } - else - { - if (p_2.compareTo(this) >= 0) - { - result = 1; - } - else - { - result = p_1.compareTo(p_2); - } - } - return result; - } - - /** - * Returns an approximation of the signed angle corresponding to this dierection. - */ - public double angle_approx() - { - return this.get_vector().angle_approx(); - } - - // auxiliary functions needed because the virtual function mechanism - // does not work in parameter position - - abstract int compareTo(IntDirection p_other); - abstract int compareTo(BigIntDirection p_other); - -} \ No newline at end of file +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * Direction.java + * + * Created on 3. Februar 2003, 15:36 + */ + +package geometry.planar; +import datastructures.Signum; + +/** + * + * Abstract class defining functionality of directions + * in the plane. A Direction is an equivalence class of + * vectors. Two vectors define the same object of class + * Direction, if they point into the same direction. + * We prefer using directions instead of angles, because + * with angles the arithmetic calculations are in + * general not exact. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public abstract class Direction implements Comparable, java.io.Serializable +{ + /** Constant NULL */ + public static final IntDirection NULL = new IntDirection(0,0); + + /** + * the direction to the east + */ + public static final IntDirection RIGHT = new IntDirection(1, 0); + /** + * the direction to the northeast + */ + public static final IntDirection RIGHT45 = new IntDirection(1, 1); + /** + * the direction to the north + */ + public static final IntDirection UP = new IntDirection(0, 1); + /** + * the direction to the northwest + */ + public static final IntDirection UP45 = new IntDirection(-1, 1); + /** + * the direction to the west + */ + public static final IntDirection LEFT = new IntDirection(-1, 0); + /** + * the direction to the southwest + */ + public static final IntDirection LEFT45 = new IntDirection(-1, -1); + /** + * the direction to the south + */ + public static final IntDirection DOWN = new IntDirection(0, -1); + /** + * the direction to the southeast + */ + public static final IntDirection DOWN45 = new IntDirection(1, -1); + + /** + * creates a Direction from the input Vector + * + * @param p_vector a {@link geometry.planar.Vector} object. + * @return a {@link geometry.planar.Direction} object. + */ + public static Direction get_instance( Vector p_vector ) + { + return p_vector.to_normalized_direction(); + } + + /** + * Calculates the direction from p_from to p_to. + * If p_from and p_to are equal, null is returned. + * + * @param p_from a {@link geometry.planar.Point} object. + * @param p_to a {@link geometry.planar.Point} object. + * @return a {@link geometry.planar.Direction} object. + */ + public static Direction get_instance( Point p_from, Point p_to ) + { + if ( p_from.equals(p_to) ) + { + return null; + } + return get_instance(p_to.difference_by( p_from )); + } + + /** + * Creates a Direction whose angle with the x-axis is nearly equal to p_angle + * + * @param p_angle a double. + * @return a {@link geometry.planar.Direction} object. + */ + public static Direction get_instance_approx( double p_angle ) + { + final double scale_factor = 10000; + int x = (int)Math.round(Math.cos(p_angle) * scale_factor); + int y = (int)Math.round(Math.sin(p_angle) * scale_factor); + return get_instance(new IntVector(x, y)); + } + + /** + * return any Vector pointing into this direction + * + * @return a {@link geometry.planar.Vector} object. + */ + public abstract Vector get_vector(); + + /** + * returns true, if the direction is horizontal or vertical + * + * @return a boolean. + */ + public abstract boolean is_orthogonal(); + + /** + * returns true, if the direction is diagonal + * + * @return a boolean. + */ + public abstract boolean is_diagonal(); + + /** + * returns true, if the direction is orthogonal or diagonal + * + * @return a boolean. + */ + public boolean is_multiple_of_45_degree() + { + return ( is_orthogonal() || is_diagonal() ) ; + } + + /** + * turns the direction by p_factor times 45 degree + * + * @param p_factor a int. + * @return a {@link geometry.planar.Direction} object. + */ + public abstract Direction turn_45_degree(int p_factor); + + /** + * returns the opposite direction of this direction + * + * @return a {@link geometry.planar.Direction} object. + */ + public abstract Direction opposite(); + + /** + * Returns true, if p_ob is a Direction and + * this Direction and p_ob point into the same direction + * + * @param p_other a {@link geometry.planar.Direction} object. + * @return a boolean. + */ + public final boolean equals( Direction p_other ) + { + if ( this == p_other ) + { + return true; + } + if ( p_other == null ) + { + return false; + } + + if (this.side_of(p_other) != Side.COLLINEAR) + { + return false; + } + // check, that dir and other_dir do not point into opposite directions + Vector this_vector = get_vector(); + Vector other_vector = p_other.get_vector() ; + return this_vector.projection(other_vector) == Signum.POSITIVE; + } + + /** + * Let L be the line from the Zero Vector to p_other.get_vector(). + * The function returns + * Side.ON_THE_LEFT, if this.get_vector() is on the left of L + * Side.ON_THE_RIGHT, if this.get_vector() is on the right of L + * and Side.COLLINEAR, if this.get_vector() is collinear with L. + * + * @param p_other a {@link geometry.planar.Direction} object. + * @return a {@link geometry.planar.Side} object. + */ + public Side side_of(Direction p_other) + { + return this.get_vector().side_of(p_other.get_vector()); + } + + /** + * The function returns + * Signum.POSITIVE, if the scalar product of of a vector representing + * this direction and a vector representing p_other is {@code > 0}, + * Signum.NEGATIVE, if the scalar product is {@code < 0}, + * and Signum.ZERO, if the scalar product is equal 0. + * + * @param p_other a {@link geometry.planar.Direction} object. + * @return a {@link datastructures.Signum} object. + */ + public Signum projection(Direction p_other) + { + return this.get_vector().projection(p_other.get_vector()); + } + + /** + * calculates an approximation of the direction in the middle of + * this direction and p_other + * + * @param p_other a {@link geometry.planar.Direction} object. + * @return a {@link geometry.planar.Direction} object. + */ + public Direction middle_approx(Direction p_other) + { + FloatPoint v1 = get_vector().to_float(); + FloatPoint v2 = p_other.get_vector().to_float(); + double length1 = v1.size(); + double length2 = v2.size(); + double x = v1.x / length1 + v2.x /length2; + double y = v1.y / length1 + v2.y /length2; + final double scale_factor = 1000; + Vector vm = new IntVector((int)Math.round(x * scale_factor), + (int)Math.round(y * scale_factor)); + return Direction.get_instance(vm); + } + + + /** + * Returns 1, if the angle between p_1 and this direction is bigger + * the angle between p_2 and this direction, + * 0, if p_1 is equal to p_2, * and -1 otherwise. + * + * @param p_1 a {@link geometry.planar.Direction} object. + * @param p_2 a {@link geometry.planar.Direction} object. + * @return a int. + */ + public int compare_from(Direction p_1, Direction p_2) + { + int result; + if (p_1.compareTo(this) >= 0) + { + if (p_2.compareTo(this) >= 0) + { + result = p_1.compareTo(p_2); + } + else + { + result = -1; + } + } + else + { + if (p_2.compareTo(this) >= 0) + { + result = 1; + } + else + { + result = p_1.compareTo(p_2); + } + } + return result; + } + + /** + * Returns an approximation of the signed angle corresponding to this dierection. + * + * @return a double. + */ + public double angle_approx() + { + return this.get_vector().angle_approx(); + } + + // auxiliary functions needed because the virtual function mechanism + // does not work in parameter position + + abstract int compareTo(IntDirection p_other); + abstract int compareTo(BigIntDirection p_other); + +} diff --git a/geometry/planar/Ellipse.java b/src/main/java/geometry/planar/Ellipse.java similarity index 84% rename from geometry/planar/Ellipse.java rename to src/main/java/geometry/planar/Ellipse.java index c82f2a4..fe89a88 100644 --- a/geometry/planar/Ellipse.java +++ b/src/main/java/geometry/planar/Ellipse.java @@ -26,11 +26,19 @@ * Does not implement the ConvexShape interface, because coordinates are float. * * @author Alfons Wirtz + * @version $Id: $Id */ public class Ellipse implements java.io.Serializable { - /** Creates a new instance of Ellipse */ + /** + * Creates a new instance of Ellipse + * + * @param p_center a {@link geometry.planar.FloatPoint} object. + * @param p_rotation a double. + * @param p_radius_1 a double. + * @param p_radius_2 a double. + */ public Ellipse(FloatPoint p_center, double p_rotation, double p_radius_1, double p_radius_2) { this.center = p_center; @@ -60,7 +68,7 @@ public Ellipse(FloatPoint p_center, double p_rotation, double p_radius_1, double public final FloatPoint center; - /** Rotation of the ellipse in radian normed to 0 <= rotation < pi */ + /** Rotation of the ellipse in radian normed to {@code 0 <= rotation < pi }*/ public final double rotation; public final double bigger_radius; public final double smaller_radius; diff --git a/geometry/planar/FloatLine.java b/src/main/java/geometry/planar/FloatLine.java similarity index 87% rename from geometry/planar/FloatLine.java rename to src/main/java/geometry/planar/FloatLine.java index 5e4e249..ea1002c 100644 --- a/geometry/planar/FloatLine.java +++ b/src/main/java/geometry/planar/FloatLine.java @@ -27,12 +27,16 @@ * If exactnesss is needed, use the class Line instead. * * @author Alfons Wirtz + * @version $Id: $Id */ public class FloatLine { /** * Creates a line from two FloatPoints. + * + * @param p_a a {@link geometry.planar.FloatPoint} object. + * @param p_b a {@link geometry.planar.FloatPoint} object. */ public FloatLine(FloatPoint p_a, FloatPoint p_b) { @@ -46,12 +50,20 @@ public FloatLine(FloatPoint p_a, FloatPoint p_b) /** * Returns the FloatLine with swapped end points. + * + * @return a {@link geometry.planar.FloatLine} object. */ public FloatLine opposite() { return new FloatLine(this.b, this.a); } + /** + *

adjust_direction.

+ * + * @param p_other a {@link geometry.planar.FloatLine} object. + * @return a {@link geometry.planar.FloatLine} object. + */ public FloatLine adjust_direction(FloatLine p_other) { if (this.b.side_of(this.a, p_other.a )== p_other.b.side_of(this.a, p_other.a )) @@ -64,6 +76,9 @@ public FloatLine adjust_direction(FloatLine p_other) /** * Calculates the intersection of this line with p_other. * Returns null, if the lines are parallel. + * + * @param p_other a {@link geometry.planar.FloatLine} object. + * @return a {@link geometry.planar.FloatPoint} object. */ public FloatPoint intersection(FloatLine p_other) { @@ -87,7 +102,10 @@ public FloatPoint intersection(FloatLine p_other) /** * translates the line perpendicular at about p_dist. - * If p_dist > 0, the line will be translated to the left, else to the right + * If {@code p_dist > 0}, the line will be translated to the left, else to the right + * + * @param p_dist a double. + * @return a {@link geometry.planar.FloatLine} object. */ public FloatLine translate(double p_dist) { @@ -117,6 +135,9 @@ public FloatLine translate(double p_dist) * Returns the signed distance of this line from p_point. * The result will be positive, if the line is on the left of p_point, * else negative. + * + * @param p_point a {@link geometry.planar.FloatPoint} object. + * @return a double. */ public double signed_distance(FloatPoint p_point) { @@ -133,6 +154,9 @@ public double signed_distance(FloatPoint p_point) /** * Returns an approximation of the perpensicular projection * of p_point onto this line. + * + * @param p_point a {@link geometry.planar.FloatPoint} object. + * @return a {@link geometry.planar.FloatPoint} object. */ public FloatPoint perpendicular_projection(FloatPoint p_point) { @@ -159,6 +183,9 @@ public FloatPoint perpendicular_projection(FloatPoint p_point) /** * Returns the distance of p_point to the nearest point of this line * betweem this.a and this.b. + * + * @param p_point a {@link geometry.planar.FloatPoint} object. + * @return a double. */ public double segment_distance(FloatPoint p_point) { @@ -178,6 +205,9 @@ public double segment_distance(FloatPoint p_point) /** * Returns the perpendicular projection of p_line_segment onto this oriented line segment, * Returns null, if the projection is empty. + * + * @param p_line_segment a {@link geometry.planar.FloatLine} object. + * @return a {@link geometry.planar.FloatLine} object. */ public FloatLine segment_projection(FloatLine p_line_segment) { @@ -222,6 +252,9 @@ public FloatLine segment_projection(FloatLine p_line_segment) * Returns the projection of p_line_segment onto this oriented line segment * by moving p_line_segment perpendicular into the direction of this line segmant * Returns null, if the projection is empty or p_line_segment.a == p_line_segment.b + * + * @param p_line_segment a {@link geometry.planar.FloatLine} object. + * @return a {@link geometry.planar.FloatLine} object. */ public FloatLine segment_projection_2(FloatLine p_line_segment) { @@ -271,6 +304,9 @@ public FloatLine segment_projection_2(FloatLine p_line_segment) /** * Shrinks this line on both sides by p_value. * The result will contain at least the gravity point of the line. + * + * @param p_offset a double. + * @return a {@link geometry.planar.FloatLine} object. */ public FloatLine shrink_segment(double p_offset) { @@ -291,6 +327,9 @@ public FloatLine shrink_segment(double p_offset) /** * Calculates the nearest point on this line to p_from_point between * this.a and this.b. + * + * @param p_from_point a {@link geometry.planar.FloatPoint} object. + * @return a {@link geometry.planar.FloatPoint} object. */ public FloatPoint nearest_segment_point(FloatPoint p_from_point) { @@ -315,6 +354,9 @@ public FloatPoint nearest_segment_point(FloatPoint p_from_point) /** * Divides this line segment into p_count line segments of nearly equal length. * and at most p_max_section_length. + * + * @param p_count a int. + * @return an array of {@link geometry.planar.FloatLine} objects. */ public FloatLine[] divide_segment_into_sections(int p_count) { diff --git a/geometry/planar/FloatPoint.java b/src/main/java/geometry/planar/FloatPoint.java similarity index 82% rename from geometry/planar/FloatPoint.java rename to src/main/java/geometry/planar/FloatPoint.java index cbc0d52..473ece8 100644 --- a/geometry/planar/FloatPoint.java +++ b/src/main/java/geometry/planar/FloatPoint.java @@ -1,653 +1,767 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * FloatPoint.java - * - * Created on 2. Februar 2003, 09:14 - */ - -package geometry.planar; - -/** - * - * Implements a point in the plane as a touple of double's. - * Because arithmetic calculations with double's are in general not - * exact, FloatPoint is not derived from the abstract class Point. - * - * - * @author Alfons Wirtz - */ - - -public class FloatPoint implements java.io.Serializable -{ - - public static final FloatPoint ZERO = new FloatPoint(0,0); - - /** - * creates an instance of class FloatPoint from two double's, - */ - public FloatPoint(double p_x, double p_y) - { - x = p_x; - y = p_y; - } - - public FloatPoint(IntPoint p_pt) - { - x = p_pt.x ; - y = p_pt.y ; - } - - /** - * returns the square of the distance from this point to the zero point - */ - public final double size_square() - { - return x * x + y * y; - } - - /** - * returns the distance from this point to the zero point - */ - public final double size() - { - return Math.sqrt(size_square()); - } - - /** - * returns the square of the distance from this Point to the Point p_other - */ - public final double distance_square(FloatPoint p_other) - { - double dx = p_other.x - x; - double dy = p_other.y - y; - return dx * dx + dy * dy; - } - - /** - * returns the distance from this point to the point p_other - */ - public final double distance(FloatPoint p_other) - { - return Math.sqrt(distance_square(p_other)); - } - - /** - * Computes the weighted distance to p_other. - */ - public double weighted_distance(FloatPoint p_other, double p_horizontal_weight, double p_vertical_weight) - { - double delta_x = this.x - p_other.x; - double delta_y = this.y - p_other.y; - delta_x *= p_horizontal_weight; - delta_y *= p_vertical_weight; - double result = Math.sqrt(delta_x * delta_x + delta_y * delta_y); - return result; - } - - /** - * rounds the coordinates from an object of class Point_double to - * an object of class IntPoint - */ - public IntPoint round() - { - return new IntPoint((int)Math.round(x), (int)Math.round(y)); - } - - /** - * Rounds this point, so that if this point is on the right side - * of any directed line with direction p_dir, the result - * point will also be on the right side. - */ - public IntPoint round_to_the_right(Direction p_dir) - { - FloatPoint dir = p_dir.get_vector().to_float(); - int rounded_x; - - if (dir.y > 0) - { - rounded_x = (int) Math.ceil(x); - } - else if (dir.y < 0) - { - rounded_x = (int) Math.floor(x); - } - else - { - rounded_x = (int) Math.round(x); - } - - int rounded_y; - - if (dir.x > 0) - { - rounded_y = (int) Math.floor(y); - } - else if (dir.x < 0) - { - rounded_y = (int) Math.ceil(y); - } - else - { - rounded_y = (int) Math.round(y); - } - return new IntPoint(rounded_x, rounded_y); - } - - /** - * Round this Point so the x coordinate of the result will be a multiple of p_horizontal_grid - * and the y coordinate a multiple of p_vertical_grid. - */ - public IntPoint round_to_grid(int p_horizontal_grid, int p_vertical_grid) - { - double rounded_x; - if (p_horizontal_grid > 0) - { - rounded_x = Math.rint(this.x / p_horizontal_grid) * p_horizontal_grid; - } - else - { - rounded_x = this.x; - } - double rounded_y; - if (p_vertical_grid > 0) - { - rounded_y = Math.rint(this.y / p_vertical_grid) * p_vertical_grid; - } - else - { - rounded_y = this.y; - } - return new IntPoint((int) rounded_x, (int) rounded_y ); - } - - /** - * Rounds this point, so that if this point is on the left side - * of any directed line with direction p_dir, the result - * point will also be on the left side. - */ - public IntPoint round_to_the_left(Direction p_dir) - { - FloatPoint dir = p_dir.get_vector().to_float(); - int rounded_x; - - if (dir.y > 0) - { - rounded_x = (int) Math.floor(x); - } - else if (dir.y < 0) - { - rounded_x = (int) Math.ceil(x); - } - else - { - rounded_x = (int) Math.round(x); - } - - int rounded_y; - - if (dir.x > 0) - { - rounded_y = (int) Math.ceil(y); - } - else if (dir.x < 0) - { - rounded_y = (int) Math.floor(y); - } - else - { - rounded_y = (int) Math.round(y); - } - return new IntPoint(rounded_x, rounded_y); - } - - /** - * Adds the coordinates of this FloatPoint and p_other. - */ - public FloatPoint add(FloatPoint p_other) - { - return new FloatPoint(this.x + p_other.x, this.y + p_other.y); - } - - /** - * Substracts the coordinates of p_other from this FloatPoint. - */ - public FloatPoint substract(FloatPoint p_other) - { - return new FloatPoint(this.x - p_other.x, this.y - p_other.y); - } - - /** - * Returns an approximation of the perpendicular projection - * of this point onto p_line - */ - public FloatPoint projection_approx(Line p_line) - { - FloatLine line = new FloatLine(p_line.a.to_float(), p_line.b.to_float()); - return line.perpendicular_projection(this); - } - - /** - * Calculates the scalar prodct of (p_1 - this). with (p_2 - this). - */ - public double scalar_product(FloatPoint p_1, FloatPoint p_2) - { - if (p_1 == null || p_2 == null) - { - System.out.println("FloatPoint.scalar_product: parameter point is null"); - return 0; - } - double dx_1 = p_1.x - this.x; - double dx_2 = p_2.x - this.x; - double dy_1 = p_1.y - this.y; - double dy_2 = p_2.y - this.y; - return (dx_1 * dx_2 + dy_1 * dy_2); - } - - /** - * Approximates a FloatPoint on the line from zero to this point - * with distance p_new_length from zero. - */ - public FloatPoint change_size(double p_new_size) - { - if (x == 0 && y == 0) - { - // the size of the zero point cannot be changed - return this; - } - double length = Math.sqrt(x * x + y * y); - double new_x = (x * p_new_size) / length; - double new_y = (y * p_new_size) / length; - return new FloatPoint(new_x, new_y); - } - - /** - * Approximates a FloatPoint on the line from this point to p_to_point - * with distance p_new_length from this point. - */ - public FloatPoint change_length(FloatPoint p_to_point, double p_new_length) - { - double dx = p_to_point.x - this.x; - double dy = p_to_point.y - this.y; - if (dx == 0 && dy == 0) - { - System.out.println("IntPoint.change_length: Points are equal"); - return p_to_point; - } - double length = Math.sqrt(dx * dx + dy * dy); - double new_x = this.x + (dx * p_new_length) / length; - double new_y = this.y + (dy * p_new_length) / length; - return new FloatPoint(new_x, new_y); - } - - /** - * Returns the middle point between this point and p_to_point. - */ - public FloatPoint middle_point(FloatPoint p_to_point) - { - if (p_to_point == this) - { - return this; - } - double middle_x = 0.5 * (this.x + p_to_point.x); - double middle_y = 0.5 * (this.y + p_to_point.y); - return new FloatPoint(middle_x, middle_y); - } - - /** - * The function returns - * Side.ON_THE_LEFT, if this Point is on the left of the line from p_1 to p_2; - * and Side.ON_THE_RIGHT, if this Point is on the right of the line from p_1 to p_2. - * Collinearity is not defined, becouse numerical calculations ar not exact for FloatPoints. - */ - public Side side_of(FloatPoint p_1, FloatPoint p_2) - { - double d21_x = p_2.x - p_1.x; - double d21_y = p_2.y - p_1.y; - double d01_x = this.x - p_1.x; - double d01_y = this.y - p_1.y; - double determinant = d21_x * d01_y - d21_y * d01_x; - return Side.of(determinant); - } - - /** - * Rotates this FloatPoints by p_angle ( in radian ) around the p_pole. - */ - public FloatPoint rotate(double p_angle, FloatPoint p_pole) - { - if (p_angle == 0) - { - return this; - } - double dx = x - p_pole.x; - double dy = y - p_pole.y; - double sin_angle = Math.sin(p_angle); - double cos_angle = Math.cos(p_angle); - double new_dx = dx * cos_angle - dy * sin_angle; - double new_dy = dx * sin_angle + dy * cos_angle; - return new FloatPoint(p_pole.x + new_dx, p_pole.y + new_dy); - } - - /** - * Turns this FloatPoint by p_factor times 90 degree around ZERO. - */ - public FloatPoint turn_90_degree(int p_factor) - { - int n = p_factor; - while (n < 0) - { - n += 4; - } - while (n >= 4) - { - n -= 4; - } - double new_x ; - double new_y ; - switch (n) - { - case 0: // 0 degree - new_x = x; - new_y = y; - break; - case 1: // 90 degree - new_x = -y ; - new_y = x ; - break; - case 2: // 180 degree - new_x = -x ; - new_y = -y ; - break; - case 3: // 270 degree - new_x = y ; - new_y = -x ; - break; - default: - new_x = 0 ; - new_y = 0 ; - } - return new FloatPoint(new_x, new_y); - } - - /** - * Turns this FloatPoint by p_factor times 90 degree around p_pole. - */ - public FloatPoint turn_90_degree(int p_factor, FloatPoint p_pole) - { - FloatPoint v = this.substract(p_pole); - v = v.turn_90_degree(p_factor); - return p_pole.add(v); - } - /** - * Checks, if this point is contained in the box spanned by p_1 and p_2 with the input tolerance. - */ - public boolean is_contained_in_box(FloatPoint p_1, FloatPoint p_2, double p_tolerance) - { - double min_x; - double max_x; - if (p_1.x < p_2.x) - { - min_x = p_1.x; - max_x = p_2.x; - } - else - { - min_x = p_2.x; - max_x = p_1.x; - } - if (this.x < min_x - p_tolerance || this.x > max_x + p_tolerance) - { - return false; - } - double min_y; - double max_y; - if (p_1.y < p_2.y) - { - min_y = p_1.y; - max_y = p_2.y; - } - else - { - min_y = p_2.y; - max_y = p_1.y; - } - return (this.y >= min_y - p_tolerance && this.y <= max_y + p_tolerance); - } - - /** - * Creates the smallest IntBox containing this point. - */ - public IntBox bounding_box() - { - IntPoint lower_left = new IntPoint((int)Math.floor(this.x),(int)Math.floor(this.y)); - IntPoint upper_right = new IntPoint((int)Math.ceil(this.x),(int)Math.ceil(this.y)); - return new IntBox(lower_left, upper_right); - } - - /** - * Calculates the touching points of the tangents from this point to a circle - * around p_to_point with radius p_distance. - * Solves the quadratic equation, which results by substituting x by the - * term in y from the equation of the polar line of a circle with center - * p_to_point and radius p_distance and putting it into the circle - * equation. The polar line is the line through the 2 tangential points - * of the circle looked at from from this point and - * has the equation - * (this.x - p_to_point.x) * (x - p_to_point.x) - * + (this.y - p_to_point.y) * (y - p_to_point.y) = p_distance **2 - */ - public FloatPoint[] tangential_points(FloatPoint p_to_point, double p_distance) - { - // turn the situation 90 degree if the x difference is smaller - // than the y difference for better numerical stability - - double dx = Math.abs(this.x - p_to_point.x); - double dy = Math.abs(this.y - p_to_point.y); - boolean situation_turned = (dy > dx); - FloatPoint pole; - FloatPoint circle_center; - - if (situation_turned) - { - // turn the situation by 90 degree - pole = new FloatPoint(-this.y, this.x); - circle_center = new FloatPoint(-p_to_point.y, p_to_point.x); - } - else - { - pole = this; - circle_center = p_to_point; - } - - dx = pole.x - circle_center.x; - dy = pole.y - circle_center.y; - double dx_square = dx * dx; - double dy_square = dy * dy; - double dist_square = dx_square + dy_square; - double radius_square = p_distance * p_distance; - double discriminant = radius_square * dy_square - (radius_square - dx_square) * dist_square; - - if (discriminant <= 0) - { - // pole is inside the circle. - return new FloatPoint[0]; - } - double square_root = Math.sqrt(discriminant); - - FloatPoint[] result = new FloatPoint[2]; - - double a1 = radius_square * dy; - double dy1 = (a1 + p_distance * square_root) / dist_square; - double dy2 = (a1 - p_distance * square_root) / dist_square; - - double first_point_y = dy1 + circle_center.y; - double first_point_x = (radius_square - dy * dy1) / dx + circle_center.x; - double second_point_y = dy2 + circle_center.y; - double second_point_x = (radius_square - dy * dy2) / dx + circle_center.x; - - if (situation_turned) - { - // turn the result by 270 degree - result[0] = new FloatPoint(first_point_y, -first_point_x); - result[1] = new FloatPoint(second_point_y, -second_point_x); - } - else - { - result[0] = new FloatPoint(first_point_x, first_point_y); - result[1] = new FloatPoint(second_point_x, second_point_y); - } - return result; - } - - /** - * Calculates the left tangential point of the line from this point - * to a circle around p_to_point with radius p_distance. - * Returns null, if this point is inside this circle. - */ - public FloatPoint left_tangential_point(FloatPoint p_to_point, double p_distance) - { - if (p_to_point == null) - { - return null; - } - FloatPoint[] tangent_points = tangential_points(p_to_point, p_distance); - if (tangent_points.length < 2) - { - return null; - } - FloatPoint result; - if (p_to_point.side_of(this, tangent_points[0]) == Side.ON_THE_RIGHT) - { - result = tangent_points[0]; - } - else - { - result = tangent_points[1]; - } - return result; - } - - /** - * Calculates the right tangential point of the line from this point - * to a circle around p_to_point with radius p_distance. - * Returns null, if this point is inside this circle. - */ - public FloatPoint right_tangential_point(FloatPoint p_to_point, double p_distance) - { - if (p_to_point == null) - { - return null; - } - FloatPoint[] tangent_points = tangential_points(p_to_point, p_distance); - if (tangent_points.length < 2) - { - return null; - } - FloatPoint result; - if (p_to_point.side_of(this, tangent_points[0]) == Side.ON_THE_LEFT) - { - result = tangent_points[0]; - } - else - { - result = tangent_points[1]; - } - return result; - } - - /** - * Calculates the center of the circle through this point, p_1 and p_2 - * by calculating the intersection of the two lines perpendicular to and passing through - * the midpoints of the lines (this, p_1) and (p_1, p_2). - */ - public FloatPoint circle_center(FloatPoint p_1, FloatPoint p_2) - { - double slope_1 = (p_1.y - this.y)/(p_1.x - this.x); - double slope_2 = (p_2.y - p_1.y)/(p_2.x - p_1.x); - double x_center = - (slope_1 * slope_2 * (this.y -p_2.y) + slope_2 * (this.x + p_1.x) - slope_1 *(p_1.x + p_2.x)) - /(2 * (slope_2 - slope_1)); - double y_center = (0.5 * (this.x + p_1.x) - x_center)/slope_1 + 0.5 * (this.y + p_1.y); - return new FloatPoint(x_center, y_center); - } - - /** - * Returns true, if this point is contained in the circle through p_1, p_2 and p_3. - */ - public boolean inside_circle(FloatPoint p_1, FloatPoint p_2, FloatPoint p_3) - { - FloatPoint center = p_1.circle_center(p_2, p_3); - double radius_square = center.distance_square(p_1); - return (this.distance_square(center) < radius_square - 1); // - 1 is a tolerance for numerical stability. - } - - public String to_string(java.util.Locale p_locale) - { - java.text.NumberFormat nf = java.text.NumberFormat.getInstance(p_locale); - nf.setMaximumFractionDigits(4); - return (" (" + nf.format(x) + " , " + nf.format(y) + ") "); - } - - public String toString() - { - return to_string(java.util.Locale.ENGLISH); - } - - /** - * Calculates the smallest IntOctagon containing all the input points - */ - public static IntOctagon bounding_octagon(FloatPoint [] p_point_arr) - { - double lx = Integer.MAX_VALUE; - double ly = Integer.MAX_VALUE; - double rx = Integer.MIN_VALUE; - double uy = Integer.MIN_VALUE; - double ulx = Integer.MAX_VALUE; - double lrx = Integer.MIN_VALUE; - double llx = Integer.MAX_VALUE; - double urx = Integer.MIN_VALUE; - for (int i = 0; i < p_point_arr.length; ++i) - { - FloatPoint curr = p_point_arr[i]; - lx = Math.min(lx, curr.x); - ly = Math.min(ly, curr.y); - rx = Math.max(rx, curr.x); - uy = Math.max(uy, curr.y); - double tmp = curr.x - curr.y; - ulx = Math.min(ulx, tmp); - lrx = Math.max(lrx, tmp); - tmp = curr.x + curr.y; - llx = Math.min(llx, tmp); - urx = Math.max(urx, tmp); - } - IntOctagon surrounding_octagon = new - IntOctagon((int)Math.floor(lx), (int)Math.floor(ly), - (int)Math.ceil(rx), (int)Math.ceil(uy), - (int)Math.floor(ulx), (int)Math.ceil(lrx), - (int)Math.floor(llx), (int)Math.ceil(urx)); - return surrounding_octagon; - } - - /** - * the x coordinate of this point - */ - public final double x; - - /** - * the y coordinate of this point - */ - public final double y; -} \ No newline at end of file +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * FloatPoint.java + * + * Created on 2. Februar 2003, 09:14 + */ + +package geometry.planar; + +/** + * + * Implements a point in the plane as a touple of double's. + * Because arithmetic calculations with double's are in general not + * exact, FloatPoint is not derived from the abstract class Point. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class FloatPoint implements java.io.Serializable +{ + + /** Constant ZERO */ + public static final FloatPoint ZERO = new FloatPoint(0,0); + + /** + * creates an instance of class FloatPoint from two double's, + * + * @param p_x a double. + * @param p_y a double. + */ + public FloatPoint(double p_x, double p_y) + { + x = p_x; + y = p_y; + } + + /** + *

Constructor for FloatPoint.

+ * + * @param p_pt a {@link geometry.planar.IntPoint} object. + */ + public FloatPoint(IntPoint p_pt) + { + x = p_pt.x ; + y = p_pt.y ; + } + + /** + * returns the square of the distance from this point to the zero point + * + * @return a double. + */ + public final double size_square() + { + return x * x + y * y; + } + + /** + * returns the distance from this point to the zero point + * + * @return a double. + */ + public final double size() + { + return Math.sqrt(size_square()); + } + + /** + * returns the square of the distance from this Point to the Point p_other + * + * @param p_other a {@link geometry.planar.FloatPoint} object. + * @return a double. + */ + public final double distance_square(FloatPoint p_other) + { + double dx = p_other.x - x; + double dy = p_other.y - y; + return dx * dx + dy * dy; + } + + /** + * returns the distance from this point to the point p_other + * + * @param p_other a {@link geometry.planar.FloatPoint} object. + * @return a double. + */ + public final double distance(FloatPoint p_other) + { + return Math.sqrt(distance_square(p_other)); + } + + /** + * Computes the weighted distance to p_other. + * + * @param p_other a {@link geometry.planar.FloatPoint} object. + * @param p_horizontal_weight a double. + * @param p_vertical_weight a double. + * @return a double. + */ + public double weighted_distance(FloatPoint p_other, double p_horizontal_weight, double p_vertical_weight) + { + double delta_x = this.x - p_other.x; + double delta_y = this.y - p_other.y; + delta_x *= p_horizontal_weight; + delta_y *= p_vertical_weight; + double result = Math.sqrt(delta_x * delta_x + delta_y * delta_y); + return result; + } + + /** + * rounds the coordinates from an object of class Point_double to + * an object of class IntPoint + * + * @return a {@link geometry.planar.IntPoint} object. + */ + public IntPoint round() + { + return new IntPoint((int)Math.round(x), (int)Math.round(y)); + } + + /** + * Rounds this point, so that if this point is on the right side + * of any directed line with direction p_dir, the result + * point will also be on the right side. + * + * @param p_dir a {@link geometry.planar.Direction} object. + * @return a {@link geometry.planar.IntPoint} object. + */ + public IntPoint round_to_the_right(Direction p_dir) + { + FloatPoint dir = p_dir.get_vector().to_float(); + int rounded_x; + + if (dir.y > 0) + { + rounded_x = (int) Math.ceil(x); + } + else if (dir.y < 0) + { + rounded_x = (int) Math.floor(x); + } + else + { + rounded_x = (int) Math.round(x); + } + + int rounded_y; + + if (dir.x > 0) + { + rounded_y = (int) Math.floor(y); + } + else if (dir.x < 0) + { + rounded_y = (int) Math.ceil(y); + } + else + { + rounded_y = (int) Math.round(y); + } + return new IntPoint(rounded_x, rounded_y); + } + + /** + * Round this Point so the x coordinate of the result will be a multiple of p_horizontal_grid + * and the y coordinate a multiple of p_vertical_grid. + * + * @param p_horizontal_grid a int. + * @param p_vertical_grid a int. + * @return a {@link geometry.planar.IntPoint} object. + */ + public IntPoint round_to_grid(int p_horizontal_grid, int p_vertical_grid) + { + double rounded_x; + if (p_horizontal_grid > 0) + { + rounded_x = Math.rint(this.x / p_horizontal_grid) * p_horizontal_grid; + } + else + { + rounded_x = this.x; + } + double rounded_y; + if (p_vertical_grid > 0) + { + rounded_y = Math.rint(this.y / p_vertical_grid) * p_vertical_grid; + } + else + { + rounded_y = this.y; + } + return new IntPoint((int) rounded_x, (int) rounded_y ); + } + + /** + * Rounds this point, so that if this point is on the left side + * of any directed line with direction p_dir, the result + * point will also be on the left side. + * + * @param p_dir a {@link geometry.planar.Direction} object. + * @return a {@link geometry.planar.IntPoint} object. + */ + public IntPoint round_to_the_left(Direction p_dir) + { + FloatPoint dir = p_dir.get_vector().to_float(); + int rounded_x; + + if (dir.y > 0) + { + rounded_x = (int) Math.floor(x); + } + else if (dir.y < 0) + { + rounded_x = (int) Math.ceil(x); + } + else + { + rounded_x = (int) Math.round(x); + } + + int rounded_y; + + if (dir.x > 0) + { + rounded_y = (int) Math.ceil(y); + } + else if (dir.x < 0) + { + rounded_y = (int) Math.floor(y); + } + else + { + rounded_y = (int) Math.round(y); + } + return new IntPoint(rounded_x, rounded_y); + } + + /** + * Adds the coordinates of this FloatPoint and p_other. + * + * @param p_other a {@link geometry.planar.FloatPoint} object. + * @return a {@link geometry.planar.FloatPoint} object. + */ + public FloatPoint add(FloatPoint p_other) + { + return new FloatPoint(this.x + p_other.x, this.y + p_other.y); + } + + /** + * Substracts the coordinates of p_other from this FloatPoint. + * + * @param p_other a {@link geometry.planar.FloatPoint} object. + * @return a {@link geometry.planar.FloatPoint} object. + */ + public FloatPoint substract(FloatPoint p_other) + { + return new FloatPoint(this.x - p_other.x, this.y - p_other.y); + } + + /** + * Returns an approximation of the perpendicular projection + * of this point onto p_line + * + * @param p_line a {@link geometry.planar.Line} object. + * @return a {@link geometry.planar.FloatPoint} object. + */ + public FloatPoint projection_approx(Line p_line) + { + FloatLine line = new FloatLine(p_line.a.to_float(), p_line.b.to_float()); + return line.perpendicular_projection(this); + } + + /** + * Calculates the scalar prodct of (p_1 - this). with (p_2 - this). + * + * @param p_1 a {@link geometry.planar.FloatPoint} object. + * @param p_2 a {@link geometry.planar.FloatPoint} object. + * @return a double. + */ + public double scalar_product(FloatPoint p_1, FloatPoint p_2) + { + if (p_1 == null || p_2 == null) + { + System.out.println("FloatPoint.scalar_product: parameter point is null"); + return 0; + } + double dx_1 = p_1.x - this.x; + double dx_2 = p_2.x - this.x; + double dy_1 = p_1.y - this.y; + double dy_2 = p_2.y - this.y; + return (dx_1 * dx_2 + dy_1 * dy_2); + } + + /** + * Approximates a FloatPoint on the line from zero to this point + * with distance p_new_length from zero. + * + * @param p_new_size a double. + * @return a {@link geometry.planar.FloatPoint} object. + */ + public FloatPoint change_size(double p_new_size) + { + if (x == 0 && y == 0) + { + // the size of the zero point cannot be changed + return this; + } + double length = Math.sqrt(x * x + y * y); + double new_x = (x * p_new_size) / length; + double new_y = (y * p_new_size) / length; + return new FloatPoint(new_x, new_y); + } + + /** + * Approximates a FloatPoint on the line from this point to p_to_point + * with distance p_new_length from this point. + * + * @param p_to_point a {@link geometry.planar.FloatPoint} object. + * @param p_new_length a double. + * @return a {@link geometry.planar.FloatPoint} object. + */ + public FloatPoint change_length(FloatPoint p_to_point, double p_new_length) + { + double dx = p_to_point.x - this.x; + double dy = p_to_point.y - this.y; + if (dx == 0 && dy == 0) + { + System.out.println("IntPoint.change_length: Points are equal"); + return p_to_point; + } + double length = Math.sqrt(dx * dx + dy * dy); + double new_x = this.x + (dx * p_new_length) / length; + double new_y = this.y + (dy * p_new_length) / length; + return new FloatPoint(new_x, new_y); + } + + /** + * Returns the middle point between this point and p_to_point. + * + * @param p_to_point a {@link geometry.planar.FloatPoint} object. + * @return a {@link geometry.planar.FloatPoint} object. + */ + public FloatPoint middle_point(FloatPoint p_to_point) + { + if (p_to_point == this) + { + return this; + } + double middle_x = 0.5 * (this.x + p_to_point.x); + double middle_y = 0.5 * (this.y + p_to_point.y); + return new FloatPoint(middle_x, middle_y); + } + + /** + * The function returns + * Side.ON_THE_LEFT, if this Point is on the left of the line from p_1 to p_2; + * and Side.ON_THE_RIGHT, if this Point is on the right of the line from p_1 to p_2. + * Collinearity is not defined, becouse numerical calculations ar not exact for FloatPoints. + * + * @param p_1 a {@link geometry.planar.FloatPoint} object. + * @param p_2 a {@link geometry.planar.FloatPoint} object. + * @return a {@link geometry.planar.Side} object. + */ + public Side side_of(FloatPoint p_1, FloatPoint p_2) + { + double d21_x = p_2.x - p_1.x; + double d21_y = p_2.y - p_1.y; + double d01_x = this.x - p_1.x; + double d01_y = this.y - p_1.y; + double determinant = d21_x * d01_y - d21_y * d01_x; + return Side.of(determinant); + } + + /** + * Rotates this FloatPoints by p_angle ( in radian ) around the p_pole. + * + * @param p_angle a double. + * @param p_pole a {@link geometry.planar.FloatPoint} object. + * @return a {@link geometry.planar.FloatPoint} object. + */ + public FloatPoint rotate(double p_angle, FloatPoint p_pole) + { + if (p_angle == 0) + { + return this; + } + double dx = x - p_pole.x; + double dy = y - p_pole.y; + double sin_angle = Math.sin(p_angle); + double cos_angle = Math.cos(p_angle); + double new_dx = dx * cos_angle - dy * sin_angle; + double new_dy = dx * sin_angle + dy * cos_angle; + return new FloatPoint(p_pole.x + new_dx, p_pole.y + new_dy); + } + + /** + * Turns this FloatPoint by p_factor times 90 degree around ZERO. + * + * @param p_factor a int. + * @return a {@link geometry.planar.FloatPoint} object. + */ + public FloatPoint turn_90_degree(int p_factor) + { + int n = p_factor; + while (n < 0) + { + n += 4; + } + while (n >= 4) + { + n -= 4; + } + double new_x ; + double new_y ; + switch (n) + { + case 0: // 0 degree + new_x = x; + new_y = y; + break; + case 1: // 90 degree + new_x = -y ; + new_y = x ; + break; + case 2: // 180 degree + new_x = -x ; + new_y = -y ; + break; + case 3: // 270 degree + new_x = y ; + new_y = -x ; + break; + default: + new_x = 0 ; + new_y = 0 ; + } + return new FloatPoint(new_x, new_y); + } + + /** + * Turns this FloatPoint by p_factor times 90 degree around p_pole. + * + * @param p_factor a int. + * @param p_pole a {@link geometry.planar.FloatPoint} object. + * @return a {@link geometry.planar.FloatPoint} object. + */ + public FloatPoint turn_90_degree(int p_factor, FloatPoint p_pole) + { + FloatPoint v = this.substract(p_pole); + v = v.turn_90_degree(p_factor); + return p_pole.add(v); + } + /** + * Checks, if this point is contained in the box spanned by p_1 and p_2 with the input tolerance. + * + * @param p_1 a {@link geometry.planar.FloatPoint} object. + * @param p_2 a {@link geometry.planar.FloatPoint} object. + * @param p_tolerance a double. + * @return a boolean. + */ + public boolean is_contained_in_box(FloatPoint p_1, FloatPoint p_2, double p_tolerance) + { + double min_x; + double max_x; + if (p_1.x < p_2.x) + { + min_x = p_1.x; + max_x = p_2.x; + } + else + { + min_x = p_2.x; + max_x = p_1.x; + } + if (this.x < min_x - p_tolerance || this.x > max_x + p_tolerance) + { + return false; + } + double min_y; + double max_y; + if (p_1.y < p_2.y) + { + min_y = p_1.y; + max_y = p_2.y; + } + else + { + min_y = p_2.y; + max_y = p_1.y; + } + return (this.y >= min_y - p_tolerance && this.y <= max_y + p_tolerance); + } + + /** + * Creates the smallest IntBox containing this point. + * + * @return a {@link geometry.planar.IntBox} object. + */ + public IntBox bounding_box() + { + IntPoint lower_left = new IntPoint((int)Math.floor(this.x),(int)Math.floor(this.y)); + IntPoint upper_right = new IntPoint((int)Math.ceil(this.x),(int)Math.ceil(this.y)); + return new IntBox(lower_left, upper_right); + } + + /** + * Calculates the touching points of the tangents from this point to a circle + * around p_to_point with radius p_distance. + * Solves the quadratic equation, which results by substituting x by the + * term in y from the equation of the polar line of a circle with center + * p_to_point and radius p_distance and putting it into the circle + * equation. The polar line is the line through the 2 tangential points + * of the circle looked at from from this point and + * has the equation + * (this.x - p_to_point.x) * (x - p_to_point.x) + * + (this.y - p_to_point.y) * (y - p_to_point.y) = p_distance **2 + * + * @param p_to_point a {@link geometry.planar.FloatPoint} object. + * @param p_distance a double. + * @return an array of {@link geometry.planar.FloatPoint} objects. + */ + public FloatPoint[] tangential_points(FloatPoint p_to_point, double p_distance) + { + // turn the situation 90 degree if the x difference is smaller + // than the y difference for better numerical stability + + double dx = Math.abs(this.x - p_to_point.x); + double dy = Math.abs(this.y - p_to_point.y); + boolean situation_turned = (dy > dx); + FloatPoint pole; + FloatPoint circle_center; + + if (situation_turned) + { + // turn the situation by 90 degree + pole = new FloatPoint(-this.y, this.x); + circle_center = new FloatPoint(-p_to_point.y, p_to_point.x); + } + else + { + pole = this; + circle_center = p_to_point; + } + + dx = pole.x - circle_center.x; + dy = pole.y - circle_center.y; + double dx_square = dx * dx; + double dy_square = dy * dy; + double dist_square = dx_square + dy_square; + double radius_square = p_distance * p_distance; + double discriminant = radius_square * dy_square - (radius_square - dx_square) * dist_square; + + if (discriminant <= 0) + { + // pole is inside the circle. + return new FloatPoint[0]; + } + double square_root = Math.sqrt(discriminant); + + FloatPoint[] result = new FloatPoint[2]; + + double a1 = radius_square * dy; + double dy1 = (a1 + p_distance * square_root) / dist_square; + double dy2 = (a1 - p_distance * square_root) / dist_square; + + double first_point_y = dy1 + circle_center.y; + double first_point_x = (radius_square - dy * dy1) / dx + circle_center.x; + double second_point_y = dy2 + circle_center.y; + double second_point_x = (radius_square - dy * dy2) / dx + circle_center.x; + + if (situation_turned) + { + // turn the result by 270 degree + result[0] = new FloatPoint(first_point_y, -first_point_x); + result[1] = new FloatPoint(second_point_y, -second_point_x); + } + else + { + result[0] = new FloatPoint(first_point_x, first_point_y); + result[1] = new FloatPoint(second_point_x, second_point_y); + } + return result; + } + + /** + * Calculates the left tangential point of the line from this point + * to a circle around p_to_point with radius p_distance. + * Returns null, if this point is inside this circle. + * + * @param p_to_point a {@link geometry.planar.FloatPoint} object. + * @param p_distance a double. + * @return a {@link geometry.planar.FloatPoint} object. + */ + public FloatPoint left_tangential_point(FloatPoint p_to_point, double p_distance) + { + if (p_to_point == null) + { + return null; + } + FloatPoint[] tangent_points = tangential_points(p_to_point, p_distance); + if (tangent_points.length < 2) + { + return null; + } + FloatPoint result; + if (p_to_point.side_of(this, tangent_points[0]) == Side.ON_THE_RIGHT) + { + result = tangent_points[0]; + } + else + { + result = tangent_points[1]; + } + return result; + } + + /** + * Calculates the right tangential point of the line from this point + * to a circle around p_to_point with radius p_distance. + * Returns null, if this point is inside this circle. + * + * @param p_to_point a {@link geometry.planar.FloatPoint} object. + * @param p_distance a double. + * @return a {@link geometry.planar.FloatPoint} object. + */ + public FloatPoint right_tangential_point(FloatPoint p_to_point, double p_distance) + { + if (p_to_point == null) + { + return null; + } + FloatPoint[] tangent_points = tangential_points(p_to_point, p_distance); + if (tangent_points.length < 2) + { + return null; + } + FloatPoint result; + if (p_to_point.side_of(this, tangent_points[0]) == Side.ON_THE_LEFT) + { + result = tangent_points[0]; + } + else + { + result = tangent_points[1]; + } + return result; + } + + /** + * Calculates the center of the circle through this point, p_1 and p_2 + * by calculating the intersection of the two lines perpendicular to and passing through + * the midpoints of the lines (this, p_1) and (p_1, p_2). + * + * @param p_1 a {@link geometry.planar.FloatPoint} object. + * @param p_2 a {@link geometry.planar.FloatPoint} object. + * @return a {@link geometry.planar.FloatPoint} object. + */ + public FloatPoint circle_center(FloatPoint p_1, FloatPoint p_2) + { + double slope_1 = (p_1.y - this.y)/(p_1.x - this.x); + double slope_2 = (p_2.y - p_1.y)/(p_2.x - p_1.x); + double x_center = + (slope_1 * slope_2 * (this.y -p_2.y) + slope_2 * (this.x + p_1.x) - slope_1 *(p_1.x + p_2.x)) + /(2 * (slope_2 - slope_1)); + double y_center = (0.5 * (this.x + p_1.x) - x_center)/slope_1 + 0.5 * (this.y + p_1.y); + return new FloatPoint(x_center, y_center); + } + + /** + * Returns true, if this point is contained in the circle through p_1, p_2 and p_3. + * + * @param p_1 a {@link geometry.planar.FloatPoint} object. + * @param p_2 a {@link geometry.planar.FloatPoint} object. + * @param p_3 a {@link geometry.planar.FloatPoint} object. + * @return a boolean. + */ + public boolean inside_circle(FloatPoint p_1, FloatPoint p_2, FloatPoint p_3) + { + FloatPoint center = p_1.circle_center(p_2, p_3); + double radius_square = center.distance_square(p_1); + return (this.distance_square(center) < radius_square - 1); // - 1 is a tolerance for numerical stability. + } + + /** + *

to_string.

+ * + * @param p_locale a {@link java.util.Locale} object. + * @return a {@link java.lang.String} object. + */ + public String to_string(java.util.Locale p_locale) + { + java.text.NumberFormat nf = java.text.NumberFormat.getInstance(p_locale); + nf.setMaximumFractionDigits(4); + return (" (" + nf.format(x) + " , " + nf.format(y) + ") "); + } + + /** + *

toString.

+ * + * @return a {@link java.lang.String} object. + */ + public String toString() + { + return to_string(java.util.Locale.ENGLISH); + } + + /** + * Calculates the smallest IntOctagon containing all the input points + * + * @param p_point_arr an array of {@link geometry.planar.FloatPoint} objects. + * @return a {@link geometry.planar.IntOctagon} object. + */ + public static IntOctagon bounding_octagon(FloatPoint [] p_point_arr) + { + double lx = Integer.MAX_VALUE; + double ly = Integer.MAX_VALUE; + double rx = Integer.MIN_VALUE; + double uy = Integer.MIN_VALUE; + double ulx = Integer.MAX_VALUE; + double lrx = Integer.MIN_VALUE; + double llx = Integer.MAX_VALUE; + double urx = Integer.MIN_VALUE; + for (int i = 0; i < p_point_arr.length; ++i) + { + FloatPoint curr = p_point_arr[i]; + lx = Math.min(lx, curr.x); + ly = Math.min(ly, curr.y); + rx = Math.max(rx, curr.x); + uy = Math.max(uy, curr.y); + double tmp = curr.x - curr.y; + ulx = Math.min(ulx, tmp); + lrx = Math.max(lrx, tmp); + tmp = curr.x + curr.y; + llx = Math.min(llx, tmp); + urx = Math.max(urx, tmp); + } + IntOctagon surrounding_octagon = new + IntOctagon((int)Math.floor(lx), (int)Math.floor(ly), + (int)Math.ceil(rx), (int)Math.ceil(uy), + (int)Math.floor(ulx), (int)Math.ceil(lrx), + (int)Math.floor(llx), (int)Math.ceil(urx)); + return surrounding_octagon; + } + + /** + * the x coordinate of this point + */ + public final double x; + + /** + * the y coordinate of this point + */ + public final double y; +} diff --git a/geometry/planar/FortyfiveDegreeBoundingDirections.java b/src/main/java/geometry/planar/FortyfiveDegreeBoundingDirections.java similarity index 66% rename from geometry/planar/FortyfiveDegreeBoundingDirections.java rename to src/main/java/geometry/planar/FortyfiveDegreeBoundingDirections.java index 46938db..e5f8c74 100644 --- a/geometry/planar/FortyfiveDegreeBoundingDirections.java +++ b/src/main/java/geometry/planar/FortyfiveDegreeBoundingDirections.java @@ -1,76 +1,113 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - */ - -package geometry.planar; - -/** - * - * Implements the abstract class ShapeBoundingDirections as - * the 8 directions, which are multiples of 45 degree. - * The class is a singleton with the only instanciation INSTANCE. - * - * @author Alfons Wirtz - */ -public class FortyfiveDegreeBoundingDirections implements ShapeBoundingDirections -{ - /** - * the one and only instantiation - */ - public static final FortyfiveDegreeBoundingDirections - INSTANCE = new FortyfiveDegreeBoundingDirections(); - - public int count() - { - return 8; - } - - public RegularTileShape bounds (ConvexShape p_shape) - { - return p_shape.bounding_shape(this); - } - - public RegularTileShape bounds (IntBox p_box) - { - return p_box.to_IntOctagon(); - } - - public RegularTileShape bounds (IntOctagon p_oct) - { - return p_oct; - } - - public RegularTileShape bounds (Simplex p_simplex) - { - return p_simplex.bounding_octagon(); - } - - public RegularTileShape bounds (Circle p_circle) - { - return p_circle.bounding_octagon(); - } - - public RegularTileShape bounds (PolygonShape p_polygon) - { - return p_polygon.bounding_octagon(); - } - - /** - * prevent instantiation - */ - private FortyfiveDegreeBoundingDirections() - { - } -} \ No newline at end of file +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + */ + +package geometry.planar; + +/** + * + * Implements the abstract class ShapeBoundingDirections as + * the 8 directions, which are multiples of 45 degree. + * The class is a singleton with the only instanciation INSTANCE. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class FortyfiveDegreeBoundingDirections implements ShapeBoundingDirections +{ + /** + * the one and only instantiation + */ + public static final FortyfiveDegreeBoundingDirections + INSTANCE = new FortyfiveDegreeBoundingDirections(); + + /** + *

count.

+ * + * @return a int. + */ + public int count() + { + return 8; + } + + /** + *

bounds.

+ * + * @param p_shape a {@link geometry.planar.ConvexShape} object. + * @return a {@link geometry.planar.RegularTileShape} object. + */ + public RegularTileShape bounds (ConvexShape p_shape) + { + return p_shape.bounding_shape(this); + } + + /** + *

bounds.

+ * + * @param p_box a {@link geometry.planar.IntBox} object. + * @return a {@link geometry.planar.RegularTileShape} object. + */ + public RegularTileShape bounds (IntBox p_box) + { + return p_box.to_IntOctagon(); + } + + /** + *

bounds.

+ * + * @param p_oct a {@link geometry.planar.IntOctagon} object. + * @return a {@link geometry.planar.RegularTileShape} object. + */ + public RegularTileShape bounds (IntOctagon p_oct) + { + return p_oct; + } + + /** {@inheritDoc} */ + public RegularTileShape bounds (Simplex p_simplex) + { + return p_simplex.bounding_octagon(); + } + + /** + *

bounds.

+ * + * @param p_circle a {@link geometry.planar.Circle} object. + * @return a {@link geometry.planar.RegularTileShape} object. + */ + public RegularTileShape bounds (Circle p_circle) + { + return p_circle.bounding_octagon(); + } + + /** + *

bounds.

+ * + * @param p_polygon a {@link geometry.planar.PolygonShape} object. + * @return a {@link geometry.planar.RegularTileShape} object. + */ + public RegularTileShape bounds (PolygonShape p_polygon) + { + return p_polygon.bounding_octagon(); + } + + /** + * prevent instantiation + */ + private FortyfiveDegreeBoundingDirections() + { + } +} diff --git a/geometry/planar/FortyfiveDegreeDirection.java b/src/main/java/geometry/planar/FortyfiveDegreeDirection.java similarity index 98% rename from geometry/planar/FortyfiveDegreeDirection.java rename to src/main/java/geometry/planar/FortyfiveDegreeDirection.java index 16356ae..ff5f17e 100644 --- a/geometry/planar/FortyfiveDegreeDirection.java +++ b/src/main/java/geometry/planar/FortyfiveDegreeDirection.java @@ -26,6 +26,7 @@ * Enum for the eight 45-degree direction starting from right in counterclocksense to down45. * * @author alfons + * @version $Id: $Id */ public enum FortyfiveDegreeDirection { diff --git a/geometry/planar/IntBox.java b/src/main/java/geometry/planar/IntBox.java similarity index 84% rename from geometry/planar/IntBox.java rename to src/main/java/geometry/planar/IntBox.java index a2a8bcb..e2e7bc6 100644 --- a/geometry/planar/IntBox.java +++ b/src/main/java/geometry/planar/IntBox.java @@ -1,993 +1,1187 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * IntBox.java - * - * Created on 2. Februar 2003, 14:09 - */ - -package geometry.planar; - -/** - * - * Implements functionality of orthogonal rectangles in the plane - * with integer coordinates. - * - * - * @author Alfons Wirtz - */ - -public class IntBox extends RegularTileShape implements java.io.Serializable -{ - /** - * Standard implementataion of an empty box. - */ - public static final IntBox EMPTY = new IntBox(Limits.CRIT_INT, Limits.CRIT_INT, - -Limits.CRIT_INT, -Limits.CRIT_INT); - - /** - * Creates an IntBox from its lower left and upper right corners. - */ - public IntBox(IntPoint p_ll, IntPoint p_ur) - { - ll = p_ll; - ur = p_ur; - } - - /** - * creates an IntBox from the coordinates of its lower left and - * upper right corners. - */ - public IntBox(int p_ll_x, int p_ll_y, int p_ur_x, int p_ur_y) - { - ll = new IntPoint(p_ll_x, p_ll_y); - ur = new IntPoint(p_ur_x, p_ur_y); - } - - public boolean is_IntOctagon() - { - return true; - } - - - /** - * Returns true, if the box is empty - */ - public boolean is_empty() - { - return (ll.x > ur.x || ll.y > ur.y); - } - - public int border_line_count() - { - return 4; - } - - /** - * returns the horizontal extension of the box. - */ - public int width() - { - return (ur.x - ll.x); - } - - /** - * Returns the vertical extension of the box. - */ - public int height() - { - return (ur.y - ll.y) ; - } - - public double max_width() - { - return Math.max(ur.x - ll.x, ur.y - ll.y); - } - - public double min_width() - { - return Math.min(ur.x - ll.x, ur.y - ll.y); - } - - public double area() - { - return ((double)(ur.x - ll.x))* ((double) (ur.y - ll.y)); - } - - public double circumference() - { - return 2 * ((ur.x - ll.x) + (ur.y - ll.y)); - } - - public IntPoint corner(int p_no) - { - if (p_no == 0) - { - return ll; - } - if (p_no == 1) - { - return new IntPoint(ur.x, ll.y); - } - if (p_no == 2) - { - return ur; - } - if (p_no == 3) - { - return new IntPoint(ll.x, ur.y); - } - throw new IllegalArgumentException("IntBox.corner: p_no out of range"); - } - - public int dimension() - { - if (is_empty()) - { - return -1; - } - if (ll.equals(ur)) - { - return 0; - } - if (ur.x == ll.x || ll.y == ur.y) - { - return 1; - } - return 2; - } - - /** - * Chechs, if p_point is located in the interiour of this box. - */ - public boolean contains_inside(IntPoint p_point) - { - return p_point.x > this.ll.x && p_point.x < this.ur.x - && p_point.y > this.ll.y && p_point.y < this.ur.y; - } - - public boolean is_IntBox() - { - return true; - } - - public TileShape simplify() - { - return this; - } - - /** - * Calculates the nearest point of this box to p_from_point. - */ - public FloatPoint nearest_point(FloatPoint p_from_point) - { - double x; - if (p_from_point.x <= ll.x) - x = ll.x; - else if (p_from_point.x >= ur.x) - x = ur.x; - else - x = p_from_point.x; - - double y; - if (p_from_point.y <= ll.y) - y = ll.y; - else if (p_from_point.y >= ur.y) - y = ur.y; - else - y = p_from_point.y; - - return new FloatPoint(x,y); - } - - /** - * Calculates the sorted p_max_result_points nearest points on the border of this box. - * p_point is assumed to be located in the interiour of this nox. - * The funtion is only imoplemented for p_max_result_points <= 2; - */ - public IntPoint[] nearest_border_projections(IntPoint p_point, int p_max_result_points) - { - if (p_max_result_points <= 0) - { - return new IntPoint[0]; - } - p_max_result_points = Math.min(p_max_result_points, 2); - IntPoint [] result = new IntPoint[p_max_result_points]; - - int lower_x_diff = p_point.x - ll.x; - int upper_x_diff = ur.x - p_point.x; - int lower_y_diff = p_point.y - ll.y; - int upper_y_diff = ur.y - p_point.y; - - int min_diff; - int second_min_diff; - - int nearest_projection_x = p_point.x; - int nearest_projection_y = p_point.y; - int second_nearest_projection_x = p_point.x; - int second_nearest_projection_y = p_point.y; - if (lower_x_diff <= upper_x_diff) - { - min_diff = lower_x_diff; - second_min_diff = upper_x_diff; - nearest_projection_x = ll.x; - second_nearest_projection_x = ur.x; - } - else - { - min_diff = upper_x_diff; - second_min_diff = lower_x_diff; - nearest_projection_x = ur.x; - second_nearest_projection_x = ll.x; - } - if (lower_y_diff < min_diff) - { - second_min_diff = min_diff; - min_diff = lower_y_diff; - second_nearest_projection_x = nearest_projection_x; - second_nearest_projection_y = nearest_projection_y; - nearest_projection_x = p_point.x; - nearest_projection_y = ll.y; - } - else if (lower_y_diff < second_min_diff) - { - second_min_diff = lower_y_diff; - second_nearest_projection_x = p_point.x; - second_nearest_projection_y = ll.y; - } - if (upper_y_diff < min_diff) - { - second_min_diff = min_diff; - min_diff = upper_y_diff; - second_nearest_projection_x = nearest_projection_x; - second_nearest_projection_y = nearest_projection_y; - nearest_projection_x = p_point.x; - nearest_projection_y = ur.y; - } - else if (upper_y_diff < second_min_diff) - { - second_min_diff = upper_y_diff; - second_nearest_projection_x = p_point.x; - second_nearest_projection_y = ur.y; - } - result[0] = new IntPoint(nearest_projection_x, nearest_projection_y); - if (result.length > 1) - { - result[1] = new IntPoint(second_nearest_projection_x, second_nearest_projection_y); - } - - return result; - } - - /** - * Calculates distance of this box to p_from_point. - */ - public double distance(FloatPoint p_from_point) - { - return p_from_point.distance(nearest_point(p_from_point)); - } - - /** - * Computes the weighted distance to the box p_other. - */ - public double weighted_distance(IntBox p_other, double p_horizontal_weight, double p_vertical_weight) - { - double result; - - double max_ll_x = Math.max(this.ll.x, p_other.ll.x); - double max_ll_y = Math.max(this.ll.y, p_other.ll.y); - double min_ur_x = Math.min(this.ur.x, p_other.ur.x); - double min_ur_y = Math.min(this.ur.y, p_other.ur.y); - - if (min_ur_x >= max_ll_x) - { - result = Math.max(p_vertical_weight * (max_ll_y - min_ur_y), 0); - } - else if (min_ur_y >= max_ll_y) - { - result = Math.max(p_horizontal_weight * (max_ll_x - min_ur_x), 0); - } - else - { - double delta_x = max_ll_x - min_ur_x; - double delta_y = max_ll_y - min_ur_y; - delta_x *= p_horizontal_weight; - delta_y *= p_vertical_weight; - result = Math.sqrt(delta_x * delta_x + delta_y * delta_y); - } - return result; - } - - public IntBox bounding_box() - { - return this; - } - - public IntOctagon bounding_octagon() - { - return to_IntOctagon(); - } - - public boolean is_bounded() - { - return true; - } - - public IntBox bounding_tile() - { - return this; - } - - public boolean corner_is_bounded(int p_no) - { - return true; - } - - public RegularTileShape union(RegularTileShape p_other) - { - return p_other.union(this); - } - - public IntBox union(IntBox p_other) - { - int llx = Math.min(ll.x, p_other.ll.x); - int lly = Math.min(ll.y, p_other.ll.y); - int urx = Math.max(ur.x, p_other.ur.x); - int ury = Math.max(ur.y, p_other.ur.y); - return new IntBox(llx, lly, urx, ury); - } - - /** - * Returns the intersection of this box with an IntBox. - */ - public IntBox intersection(IntBox p_other) - { - if (p_other.ll.x > ur.x) - { - return EMPTY; - } - if (p_other.ll.y > ur.y) - { - return EMPTY; - } - if (ll.x > p_other.ur.x) - { - return EMPTY; - } - if (ll.y > p_other.ur.y) - { - return EMPTY; - } - int llx = Math.max(ll.x, p_other.ll.x); - int urx = Math.min(ur.x, p_other.ur.x); - int lly = Math.max(ll.y, p_other.ll.y); - int ury = Math.min(ur.y, p_other.ur.y); - return new IntBox(llx, lly, urx, ury); - } - - /** - * returns the intersection of this box with a ConvexShape - */ - public TileShape intersection(TileShape p_other) - { - return p_other.intersection(this); - } - - - IntOctagon intersection(IntOctagon p_other) - { - return p_other.intersection(this.to_IntOctagon()); - } - - Simplex intersection(Simplex p_other) - { - return p_other.intersection(this.to_Simplex()); - } - - public boolean intersects(Shape p_other) - { - return p_other.intersects(this); - } - - public boolean intersects(IntBox p_other) - { - if (p_other.ll.x > this.ur.x) - return false; - if (p_other.ll.y > this.ur.y) - return false; - if (this.ll.x > p_other.ur.x) - return false; - if (this.ll.y > p_other.ur.y) - return false; - return true; - } - - /** - * Returns true, if this box intersects with p_other and the intersection is 2-dimensional. - */ - public boolean overlaps(IntBox p_other) - { - if (p_other.ll.x >= this.ur.x) - return false; - if (p_other.ll.y >= this.ur.y) - return false; - if (this.ll.x >= p_other.ur.x) - return false; - if (this.ll.y >= p_other.ur.y) - return false; - return true; - } - - public boolean contains(RegularTileShape p_other) - { - return p_other.is_contained_in(this); - } - - public RegularTileShape bounding_shape(ShapeBoundingDirections p_dirs) - { - return p_dirs.bounds(this); - } - - /** - * Enlarges the box by p_offset. - * Contrary to the offset() method the result is an IntOctagon, not an IntBox. - */ - public IntOctagon enlarge(double p_offset) - { - return bounding_octagon().offset(p_offset); - } - - public IntBox translate_by(Vector p_rel_coor) - { - // This function is at the moment only implemented for Vectors - // with integer coordinates. - // The general implementation is still missing. - - if (p_rel_coor.equals(Vector.ZERO)) - { - return this; - } - IntPoint new_ll = (IntPoint)ll.translate_by(p_rel_coor); - IntPoint new_ur = (IntPoint)ur.translate_by(p_rel_coor); - return new IntBox(new_ll, new_ur); - } - - public IntBox turn_90_degree(int p_factor, IntPoint p_pole) - { - IntPoint p1 = (IntPoint) ll.turn_90_degree(p_factor, p_pole); - IntPoint p2 = (IntPoint) ur.turn_90_degree(p_factor, p_pole); - - int llx = Math.min(p1.x, p2.x); - int lly = Math.min(p1.y, p2.y); - int urx = Math.max(p1.x, p2.x); - int ury = Math.max(p1.y, p2.y); - return new IntBox(llx,lly,urx,ury); - } - - public Line border_line(int p_no) - { - int a_x; - int a_y; - int b_x; - int b_y; - switch (p_no) - { - case 0: - // lower boundary line - a_x = 0; - a_y = ll.y; - b_x = 1; - b_y = ll.y; - break; - case 1: - // right boundary line - a_x = ur.x; - a_y = 0; - b_x = ur.x; - b_y = 1; - break; - case 2: - // upper boundary line - a_x = 0; - a_y = ur.y; - b_x = -1; - b_y = ur.y; - break; - case 3: - // left boundary line - a_x = ll.x; - a_y = 0; - b_x = ll.x; - b_y = -1; - break; - default: - throw new IllegalArgumentException - ("IntBox.edge_line: p_no out of range"); - } - return new Line(a_x, a_y, b_x, b_y); - } - - public int border_line_index(Line p_line) - { - System.out.println("edge_index_of_line not yet implemented for IntBoxes"); - return -1; - } - - /** - * Returns the box offseted by p_dist. - * If p_dist > 0, the offset is to the outside, - * else to the inside. - */ - public IntBox offset(double p_dist) - { - if (p_dist == 0 || is_empty()) - { - return this; - } - int dist = (int)Math.round(p_dist); - IntPoint lower_left = new IntPoint(ll.x - dist, ll.y - dist); - IntPoint upper_right = new IntPoint(ur.x + dist, ur.y + dist); - return new IntBox(lower_left, upper_right); - } - - /** - * Returns the box, where the horizontal boundary is offseted by p_dist. - * If p_dist > 0, the offset is to the outside, - * else to the inside. - */ - public IntBox horizontal_offset(double p_dist) - { - if (p_dist == 0 || is_empty()) - { - return this; - } - int dist = (int)Math.round(p_dist); - IntPoint lower_left = new IntPoint(ll.x - dist, ll.y); - IntPoint upper_right = new IntPoint(ur.x + dist, ur.y); - return new IntBox(lower_left, upper_right); - } - - /** - * Returns the box, where the vertical boundary is offseted by p_dist. - * If p_dist > 0, the offset is to the outside, - * else to the inside. - */ - public IntBox vertical_offset(double p_dist) - { - if (p_dist == 0 || is_empty()) - { - return this; - } - int dist = (int)Math.round(p_dist); - IntPoint lower_left = new IntPoint(ll.x, ll.y - dist); - IntPoint upper_right = new IntPoint(ur.x, ur.y + dist); - return new IntBox(lower_left, upper_right); - } - - /** - * Shrinks the width and height of the box by the input width. - * The box will not vanish completely. - */ - public IntBox shrink(int p_width) - { - int ll_x; - int ur_x; - if (2 * p_width <= this.ur.x - this.ll.x) - { - ll_x = this.ll.x + p_width; - ur_x = this.ur.x - p_width; - } - else - { - ll_x = (this.ll.x + this.ur.x) / 2; - ur_x = ll_x; - } - int ll_y; - int ur_y; - if (2 * p_width <= this.ur.y - this.ll.y) - { - ll_y = this.ll.y + p_width; - ur_y = this.ur.y - p_width; - } - else - { - ll_y = (this.ll.y + this.ur.y) / 2; - ur_y = ll_y; - } - return new IntBox(ll_x, ll_y, ur_x, ur_y); - } - - public Side compare(RegularTileShape p_other, int p_edge_no) - { - Side result = p_other.compare(this, p_edge_no); - return result.negate(); - } - - public Side compare(IntBox p_other, int p_edge_no) - { - Side result; - switch (p_edge_no) - { - case 0: - // compare the lower edge line - if (ll.y > p_other.ll.y) - { - result = Side.ON_THE_LEFT; - } - else if (ll.y < p_other.ll.y) - { - result = Side.ON_THE_RIGHT; - } - else - { - result = Side.COLLINEAR; - } - break; - - case 1: - // compare the right edge line - if (ur.x < p_other.ur.x) - { - result = Side.ON_THE_LEFT; - } - else if (ur.x > p_other.ur.x) - { - result = Side.ON_THE_RIGHT; - } - else - { - result = Side.COLLINEAR; - } - break; - - case 2: - // compare the upper edge line - if (ur.y < p_other.ur.y) - { - result = Side.ON_THE_LEFT; - } - else if (ur.y > p_other.ur.y) - { - result = Side.ON_THE_RIGHT; - } - else - { - result = Side.COLLINEAR; - } - break; - - case 3: - // compare the left edge line - if (ll.x > p_other.ll.x) - { - result = Side.ON_THE_LEFT; - } - else if (ll.x < p_other.ll.x) - { - result = Side.ON_THE_RIGHT; - } - else - { - result = Side.COLLINEAR; - } - break; - default: - throw new IllegalArgumentException - ("IntBox.compare: p_edge_no out of range"); - - } - return result; - } - - /** - * Returns an object of class IntOctagon defining the same shape - */ - public IntOctagon to_IntOctagon() - { - return new IntOctagon(ll.x, ll.y, ur.x, ur.y, ll.x - ur.y, - ur.x - ll.y, ll.x + ll.y, ur.x + ur.y); - } - - /** - * Returns an object of class Simplex defining the same shape - */ - public Simplex to_Simplex() - { - Line[] line_arr; - if (is_empty()) - { - line_arr = new Line[0]; - } - else - { - line_arr = new Line[4]; - line_arr[0] = Line.get_instance(ll, IntDirection.RIGHT); - line_arr[1] = Line.get_instance(ur, IntDirection.UP); - line_arr[2] = Line.get_instance(ur, IntDirection.LEFT); - line_arr[3] = Line.get_instance(ll, IntDirection.DOWN); - } - return new Simplex(line_arr); - } - - public boolean is_contained_in( IntBox p_other) - { - if (is_empty() || this == p_other) - { - return true; - } - if (ll.x < p_other.ll.x || ll.y < p_other.ll.y - || ur.x > p_other.ur.x || ur.y > p_other.ur.y) - { - return false; - } - return true; - } - - /** - * Return true, if p_other is contained in the interiour of this box. - */ - public boolean contains_in_interiour(IntBox p_other) - { - if (p_other.is_empty()) - { - return true; - } - if (p_other.ll.x <= ll.x || p_other.ll.y <= ll.y - || p_other.ur.x >= ur.x || p_other.ur.y >= ur.y) - { - return false; - } - return true; - } - - /** - * Calculates the part of p_from_box, which has minimal distance - * to this box. - */ - public IntBox nearest_part(IntBox p_from_box) - { - int ll_x; - - if (p_from_box.ll.x >= this.ll.x) - { - ll_x = p_from_box.ll.x; - } - else if (p_from_box.ur.x >= this.ll.x) - { - ll_x = this.ll.x; - } - else - { - ll_x = p_from_box.ur.x; - } - - int ur_x; - - if (p_from_box.ur.x <= this.ur.x) - { - ur_x = p_from_box.ur.x; - } - else if (p_from_box.ll.x <= this.ur.x) - { - ur_x = this.ur.x; - } - else - { - ur_x = p_from_box.ll.x; - } - - int ll_y; - - if (p_from_box.ll.y >= this.ll.y) - { - ll_y = p_from_box.ll.y; - } - else if (p_from_box.ur.y >= this.ll.y) - { - ll_y = this.ll.y; - } - else - { - ll_y = p_from_box.ur.y; - } - - int ur_y; - - if (p_from_box.ur.y <= this.ur.y) - { - ur_y = p_from_box.ur.y; - } - else if (p_from_box.ll.y <= this.ur.y) - { - ur_y = this.ur.y; - } - else - { - ur_y = p_from_box.ll.y; - } - return new IntBox(ll_x, ll_y, ur_x, ur_y); - } - - public boolean is_contained_in( IntOctagon p_other) - { - return p_other.contains(to_IntOctagon()); - } - - public boolean intersects( IntOctagon p_other) - { - return p_other.intersects(to_IntOctagon()); - } - - public boolean intersects( Simplex p_other) - { - return p_other.intersects(to_Simplex()); - } - - public boolean intersects( Circle p_other) - { - return p_other.intersects(this); - } - - public IntOctagon union( IntOctagon p_other) - { - return p_other.union(to_IntOctagon()); - } - - public Side compare(IntOctagon p_other, int p_edge_no) - { - return to_IntOctagon().compare(p_other, p_edge_no); - } - - /** - * Divides this box into sections with width and height at most p_max_section_width - * of about equal size. - */ - public IntBox[] divide_into_sections(double p_max_section_width) - { - if (p_max_section_width <= 0) - { - return new IntBox[0]; - } - double length = this.ur.x - this.ll.x; - double height = this.ur.y - this.ll.y; - int x_count = (int) Math.ceil(length / p_max_section_width); - int y_count = (int) Math.ceil(height / p_max_section_width); - int section_length_x = (int) Math.ceil(length / x_count); - int section_length_y = (int) Math.ceil(height / y_count); - IntBox [] result = new IntBox[x_count * y_count]; - int curr_index = 0; - for (int j = 0; j < y_count; ++j) - { - int curr_lly = this.ll.y + j * section_length_y; - int curr_ury; - if (j == (y_count - 1)) - { - curr_ury = this.ur.y; - } - else - { - curr_ury = curr_lly + section_length_y; - } - for (int i = 0; i < x_count; ++i) - { - int curr_llx = this.ll.x + i * section_length_x; - int curr_urx; - if (i == (x_count - 1)) - { - curr_urx = this.ur.x; - } - else - { - curr_urx = curr_llx + section_length_x; - } - result[curr_index] = new IntBox(curr_llx, curr_lly, curr_urx, curr_ury); - ++curr_index; - } - } - return result; - } - - public TileShape[] cutout(TileShape p_shape) - { - TileShape[] tmp_result = p_shape.cutout_from(this); - TileShape[] result = new TileShape[tmp_result.length]; - for (int i = 0; i < result.length; ++i) - { - result[i] = tmp_result[i].simplify(); - } - return result; - } - - IntBox[] cutout_from(IntBox p_d) - { - IntBox c = this.intersection(p_d); - if (this.is_empty() || c.dimension() < this.dimension()) - { - // there is only an overlap at the border - IntBox[] result = new IntBox[1]; - result[0] = p_d; - return result; - } - - IntBox[] result = new IntBox[4]; - - result[0] = new IntBox(p_d.ll.x, p_d.ll.y, c.ur.x, c.ll.y); - - result[1] = new IntBox(p_d.ll.x, c.ll.y, c.ll.x, p_d.ur.y); - - result[2] = new IntBox(c.ur.x, p_d.ll.y, p_d.ur.x, c.ur.y); - - result[3] = new IntBox(c.ll.x, c.ur.y, p_d.ur.x, p_d.ur.y); - - // now the division will be optimised, so that the cumulative - // circumference will be minimal. - - IntBox b = null; - - if (c.ll.x - p_d.ll.x > c.ll.y - p_d.ll.y) - { - // switch left dividing line to lower - b = result[0]; - result[0] = new IntBox(c.ll.x, b.ll.y, b.ur.x, b.ur.y); - b = result[1]; - result[1] = new IntBox(b.ll.x, p_d.ll.y, b.ur.x, b.ur.y); - } - if (p_d.ur.y - c.ur.y > c.ll.x - p_d.ll.x) - { - // switch upper dividing line to the left - b = result[1]; - result[1]= new IntBox(b.ll.x, b.ll.y, b.ur.x, c.ur.y); - b = result[3]; - result[3] = new IntBox(p_d.ll.x, b.ll.y, b.ur.x, b.ur.y); - } - if (p_d.ur.x - c.ur.x > p_d.ur.y - c.ur.y) - { - // switch right dividing line to upper - b = result[2]; - result[2] = new IntBox(b.ll.x, b.ll.y, b.ur.x, p_d.ur.y); - b = result[3]; - result[3] = new IntBox(b.ll.x, b.ll.y, c.ur.x, b.ur.y); - } - if (c.ll.y - p_d.ll.y > p_d.ur.x - c.ur.x) - { - // switch lower dividing line to the left - b = result[0]; - result[0] = new IntBox(b.ll.x, b.ll.y, p_d.ur.x, b.ur.y); - b = result[2]; - result[2] = new IntBox(b.ll.x, c.ll.y, b.ur.x, b.ur.y); - } - return result; - } - - Simplex[] cutout_from(Simplex p_simplex) - { - return this.to_Simplex().cutout_from(p_simplex); - } - - IntOctagon[] cutout_from(IntOctagon p_oct) - { - return this.to_IntOctagon().cutout_from(p_oct); - } - - /** - * coordinates of the lower left corner - */ - public final IntPoint ll; - - /** - * coordinates of the upper right corner - */ - public final IntPoint ur; -} \ No newline at end of file +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * IntBox.java + * + * Created on 2. Februar 2003, 14:09 + */ + +package geometry.planar; + +/** + * + * Implements functionality of orthogonal rectangles in the plane + * with integer coordinates. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class IntBox extends RegularTileShape implements java.io.Serializable +{ + /** + * Standard implementataion of an empty box. + */ + public static final IntBox EMPTY = new IntBox(Limits.CRIT_INT, Limits.CRIT_INT, + -Limits.CRIT_INT, -Limits.CRIT_INT); + + /** + * Creates an IntBox from its lower left and upper right corners. + * + * @param p_ll a {@link geometry.planar.IntPoint} object. + * @param p_ur a {@link geometry.planar.IntPoint} object. + */ + public IntBox(IntPoint p_ll, IntPoint p_ur) + { + ll = p_ll; + ur = p_ur; + } + + /** + * creates an IntBox from the coordinates of its lower left and + * upper right corners. + * + * @param p_ll_x a int. + * @param p_ll_y a int. + * @param p_ur_x a int. + * @param p_ur_y a int. + */ + public IntBox(int p_ll_x, int p_ll_y, int p_ur_x, int p_ur_y) + { + ll = new IntPoint(p_ll_x, p_ll_y); + ur = new IntPoint(p_ur_x, p_ur_y); + } + + /** + *

is_IntOctagon.

+ * + * @return a boolean. + */ + public boolean is_IntOctagon() + { + return true; + } + + + /** + * Returns true, if the box is empty + * + * @return a boolean. + */ + public boolean is_empty() + { + return (ll.x > ur.x || ll.y > ur.y); + } + + /** + *

border_line_count.

+ * + * @return a int. + */ + public int border_line_count() + { + return 4; + } + + /** + * returns the horizontal extension of the box. + * + * @return a int. + */ + public int width() + { + return (ur.x - ll.x); + } + + /** + * Returns the vertical extension of the box. + * + * @return a int. + */ + public int height() + { + return (ur.y - ll.y) ; + } + + /** + *

max_width.

+ * + * @return a double. + */ + public double max_width() + { + return Math.max(ur.x - ll.x, ur.y - ll.y); + } + + /** + *

min_width.

+ * + * @return a double. + */ + public double min_width() + { + return Math.min(ur.x - ll.x, ur.y - ll.y); + } + + /** + *

area.

+ * + * @return a double. + */ + public double area() + { + return ((double)(ur.x - ll.x))* ((double) (ur.y - ll.y)); + } + + /** + *

circumference.

+ * + * @return a double. + */ + public double circumference() + { + return 2 * ((ur.x - ll.x) + (ur.y - ll.y)); + } + + /** {@inheritDoc} */ + public IntPoint corner(int p_no) + { + if (p_no == 0) + { + return ll; + } + if (p_no == 1) + { + return new IntPoint(ur.x, ll.y); + } + if (p_no == 2) + { + return ur; + } + if (p_no == 3) + { + return new IntPoint(ll.x, ur.y); + } + throw new IllegalArgumentException("IntBox.corner: p_no out of range"); + } + + /** + *

dimension.

+ * + * @return a int. + */ + public int dimension() + { + if (is_empty()) + { + return -1; + } + if (ll.equals(ur)) + { + return 0; + } + if (ur.x == ll.x || ll.y == ur.y) + { + return 1; + } + return 2; + } + + /** + * Chechs, if p_point is located in the interiour of this box. + * + * @param p_point a {@link geometry.planar.IntPoint} object. + * @return a boolean. + */ + public boolean contains_inside(IntPoint p_point) + { + return p_point.x > this.ll.x && p_point.x < this.ur.x + && p_point.y > this.ll.y && p_point.y < this.ur.y; + } + + /** + *

is_IntBox.

+ * + * @return a boolean. + */ + public boolean is_IntBox() + { + return true; + } + + /** + *

simplify.

+ * + * @return a {@link geometry.planar.TileShape} object. + */ + public TileShape simplify() + { + return this; + } + + /** + * Calculates the nearest point of this box to p_from_point. + * + * @param p_from_point a {@link geometry.planar.FloatPoint} object. + * @return a {@link geometry.planar.FloatPoint} object. + */ + public FloatPoint nearest_point(FloatPoint p_from_point) + { + double x; + if (p_from_point.x <= ll.x) + x = ll.x; + else if (p_from_point.x >= ur.x) + x = ur.x; + else + x = p_from_point.x; + + double y; + if (p_from_point.y <= ll.y) + y = ll.y; + else if (p_from_point.y >= ur.y) + y = ur.y; + else + y = p_from_point.y; + + return new FloatPoint(x,y); + } + + /** + * Calculates the sorted p_max_result_points nearest points on the border of this box. + * p_point is assumed to be located in the interiour of this nox. + * The funtion is only imoplemented for {@code p_max_result_points <= 2}; + * + * @param p_point a {@link geometry.planar.IntPoint} object. + * @param p_max_result_points a int. + * @return an array of {@link geometry.planar.IntPoint} objects. + */ + public IntPoint[] nearest_border_projections(IntPoint p_point, int p_max_result_points) + { + if (p_max_result_points <= 0) + { + return new IntPoint[0]; + } + p_max_result_points = Math.min(p_max_result_points, 2); + IntPoint [] result = new IntPoint[p_max_result_points]; + + int lower_x_diff = p_point.x - ll.x; + int upper_x_diff = ur.x - p_point.x; + int lower_y_diff = p_point.y - ll.y; + int upper_y_diff = ur.y - p_point.y; + + int min_diff; + int second_min_diff; + + int nearest_projection_x = p_point.x; + int nearest_projection_y = p_point.y; + int second_nearest_projection_x = p_point.x; + int second_nearest_projection_y = p_point.y; + if (lower_x_diff <= upper_x_diff) + { + min_diff = lower_x_diff; + second_min_diff = upper_x_diff; + nearest_projection_x = ll.x; + second_nearest_projection_x = ur.x; + } + else + { + min_diff = upper_x_diff; + second_min_diff = lower_x_diff; + nearest_projection_x = ur.x; + second_nearest_projection_x = ll.x; + } + if (lower_y_diff < min_diff) + { + second_min_diff = min_diff; + min_diff = lower_y_diff; + second_nearest_projection_x = nearest_projection_x; + second_nearest_projection_y = nearest_projection_y; + nearest_projection_x = p_point.x; + nearest_projection_y = ll.y; + } + else if (lower_y_diff < second_min_diff) + { + second_min_diff = lower_y_diff; + second_nearest_projection_x = p_point.x; + second_nearest_projection_y = ll.y; + } + if (upper_y_diff < min_diff) + { + second_min_diff = min_diff; + min_diff = upper_y_diff; + second_nearest_projection_x = nearest_projection_x; + second_nearest_projection_y = nearest_projection_y; + nearest_projection_x = p_point.x; + nearest_projection_y = ur.y; + } + else if (upper_y_diff < second_min_diff) + { + second_min_diff = upper_y_diff; + second_nearest_projection_x = p_point.x; + second_nearest_projection_y = ur.y; + } + result[0] = new IntPoint(nearest_projection_x, nearest_projection_y); + if (result.length > 1) + { + result[1] = new IntPoint(second_nearest_projection_x, second_nearest_projection_y); + } + + return result; + } + + /** + * {@inheritDoc} + * + * Calculates distance of this box to p_from_point. + */ + public double distance(FloatPoint p_from_point) + { + return p_from_point.distance(nearest_point(p_from_point)); + } + + /** + * Computes the weighted distance to the box p_other. + * + * @param p_other a {@link geometry.planar.IntBox} object. + * @param p_horizontal_weight a double. + * @param p_vertical_weight a double. + * @return a double. + */ + public double weighted_distance(IntBox p_other, double p_horizontal_weight, double p_vertical_weight) + { + double result; + + double max_ll_x = Math.max(this.ll.x, p_other.ll.x); + double max_ll_y = Math.max(this.ll.y, p_other.ll.y); + double min_ur_x = Math.min(this.ur.x, p_other.ur.x); + double min_ur_y = Math.min(this.ur.y, p_other.ur.y); + + if (min_ur_x >= max_ll_x) + { + result = Math.max(p_vertical_weight * (max_ll_y - min_ur_y), 0); + } + else if (min_ur_y >= max_ll_y) + { + result = Math.max(p_horizontal_weight * (max_ll_x - min_ur_x), 0); + } + else + { + double delta_x = max_ll_x - min_ur_x; + double delta_y = max_ll_y - min_ur_y; + delta_x *= p_horizontal_weight; + delta_y *= p_vertical_weight; + result = Math.sqrt(delta_x * delta_x + delta_y * delta_y); + } + return result; + } + + /** + *

bounding_box.

+ * + * @return a {@link geometry.planar.IntBox} object. + */ + public IntBox bounding_box() + { + return this; + } + + /** + *

bounding_octagon.

+ * + * @return a {@link geometry.planar.IntOctagon} object. + */ + public IntOctagon bounding_octagon() + { + return to_IntOctagon(); + } + + /** + *

is_bounded.

+ * + * @return a boolean. + */ + public boolean is_bounded() + { + return true; + } + + /** + *

bounding_tile.

+ * + * @return a {@link geometry.planar.IntBox} object. + */ + public IntBox bounding_tile() + { + return this; + } + + /** {@inheritDoc} */ + public boolean corner_is_bounded(int p_no) + { + return true; + } + + /** + * {@inheritDoc} + * + *

union.

+ */ + public RegularTileShape union(RegularTileShape p_other) + { + return p_other.union(this); + } + + /** + *

union.

+ * + * @param p_other a {@link geometry.planar.IntBox} object. + * @return a {@link geometry.planar.IntBox} object. + */ + public IntBox union(IntBox p_other) + { + int llx = Math.min(ll.x, p_other.ll.x); + int lly = Math.min(ll.y, p_other.ll.y); + int urx = Math.max(ur.x, p_other.ur.x); + int ury = Math.max(ur.y, p_other.ur.y); + return new IntBox(llx, lly, urx, ury); + } + + /** + * Returns the intersection of this box with an IntBox. + * + * @param p_other a {@link geometry.planar.IntBox} object. + * @return a {@link geometry.planar.IntBox} object. + */ + public IntBox intersection(IntBox p_other) + { + if (p_other.ll.x > ur.x) + { + return EMPTY; + } + if (p_other.ll.y > ur.y) + { + return EMPTY; + } + if (ll.x > p_other.ur.x) + { + return EMPTY; + } + if (ll.y > p_other.ur.y) + { + return EMPTY; + } + int llx = Math.max(ll.x, p_other.ll.x); + int urx = Math.min(ur.x, p_other.ur.x); + int lly = Math.max(ll.y, p_other.ll.y); + int ury = Math.min(ur.y, p_other.ur.y); + return new IntBox(llx, lly, urx, ury); + } + + /** + * {@inheritDoc} + * + * returns the intersection of this box with a ConvexShape + */ + public TileShape intersection(TileShape p_other) + { + return p_other.intersection(this); + } + + + IntOctagon intersection(IntOctagon p_other) + { + return p_other.intersection(this.to_IntOctagon()); + } + + Simplex intersection(Simplex p_other) + { + return p_other.intersection(this.to_Simplex()); + } + + /** + *

intersects.

+ * + * @param p_other a {@link geometry.planar.Shape} object. + * @return a boolean. + */ + public boolean intersects(Shape p_other) + { + return p_other.intersects(this); + } + + /** + *

intersects.

+ * + * @param p_other a {@link geometry.planar.IntBox} object. + * @return a boolean. + */ + public boolean intersects(IntBox p_other) + { + if (p_other.ll.x > this.ur.x) + return false; + if (p_other.ll.y > this.ur.y) + return false; + if (this.ll.x > p_other.ur.x) + return false; + if (this.ll.y > p_other.ur.y) + return false; + return true; + } + + /** + * Returns true, if this box intersects with p_other and the intersection is 2-dimensional. + * + * @param p_other a {@link geometry.planar.IntBox} object. + * @return a boolean. + */ + public boolean overlaps(IntBox p_other) + { + if (p_other.ll.x >= this.ur.x) + return false; + if (p_other.ll.y >= this.ur.y) + return false; + if (this.ll.x >= p_other.ur.x) + return false; + if (this.ll.y >= p_other.ur.y) + return false; + return true; + } + + /** {@inheritDoc} */ + public boolean contains(RegularTileShape p_other) + { + return p_other.is_contained_in(this); + } + + /** {@inheritDoc} */ + public RegularTileShape bounding_shape(ShapeBoundingDirections p_dirs) + { + return p_dirs.bounds(this); + } + + /** + * {@inheritDoc} + * + * Enlarges the box by p_offset. + * Contrary to the offset() method the result is an IntOctagon, not an IntBox. + */ + public IntOctagon enlarge(double p_offset) + { + return bounding_octagon().offset(p_offset); + } + + /** {@inheritDoc} */ + public IntBox translate_by(Vector p_rel_coor) + { + // This function is at the moment only implemented for Vectors + // with integer coordinates. + // The general implementation is still missing. + + if (p_rel_coor.equals(Vector.ZERO)) + { + return this; + } + IntPoint new_ll = (IntPoint)ll.translate_by(p_rel_coor); + IntPoint new_ur = (IntPoint)ur.translate_by(p_rel_coor); + return new IntBox(new_ll, new_ur); + } + + /** {@inheritDoc} */ + public IntBox turn_90_degree(int p_factor, IntPoint p_pole) + { + IntPoint p1 = (IntPoint) ll.turn_90_degree(p_factor, p_pole); + IntPoint p2 = (IntPoint) ur.turn_90_degree(p_factor, p_pole); + + int llx = Math.min(p1.x, p2.x); + int lly = Math.min(p1.y, p2.y); + int urx = Math.max(p1.x, p2.x); + int ury = Math.max(p1.y, p2.y); + return new IntBox(llx,lly,urx,ury); + } + + /** {@inheritDoc} */ + public Line border_line(int p_no) + { + int a_x; + int a_y; + int b_x; + int b_y; + switch (p_no) + { + case 0: + // lower boundary line + a_x = 0; + a_y = ll.y; + b_x = 1; + b_y = ll.y; + break; + case 1: + // right boundary line + a_x = ur.x; + a_y = 0; + b_x = ur.x; + b_y = 1; + break; + case 2: + // upper boundary line + a_x = 0; + a_y = ur.y; + b_x = -1; + b_y = ur.y; + break; + case 3: + // left boundary line + a_x = ll.x; + a_y = 0; + b_x = ll.x; + b_y = -1; + break; + default: + throw new IllegalArgumentException + ("IntBox.edge_line: p_no out of range"); + } + return new Line(a_x, a_y, b_x, b_y); + } + + /** {@inheritDoc} */ + public int border_line_index(Line p_line) + { + System.out.println("edge_index_of_line not yet implemented for IntBoxes"); + return -1; + } + + /** + * {@inheritDoc} + * + * Returns the box offseted by p_dist. + * If {@code p_dist > 0}, the offset is to the outside, + * else to the inside. + */ + public IntBox offset(double p_dist) + { + if (p_dist == 0 || is_empty()) + { + return this; + } + int dist = (int)Math.round(p_dist); + IntPoint lower_left = new IntPoint(ll.x - dist, ll.y - dist); + IntPoint upper_right = new IntPoint(ur.x + dist, ur.y + dist); + return new IntBox(lower_left, upper_right); + } + + /** + * Returns the box, where the horizontal boundary is offseted by p_dist. + * If {@code p_dist > 0}, the offset is to the outside, + * else to the inside. + * + * @param p_dist a double. + * @return a {@link geometry.planar.IntBox} object. + */ + public IntBox horizontal_offset(double p_dist) + { + if (p_dist == 0 || is_empty()) + { + return this; + } + int dist = (int)Math.round(p_dist); + IntPoint lower_left = new IntPoint(ll.x - dist, ll.y); + IntPoint upper_right = new IntPoint(ur.x + dist, ur.y); + return new IntBox(lower_left, upper_right); + } + + /** + * Returns the box, where the vertical boundary is offseted by p_dist. + * If {@code p_dist > 0}, the offset is to the outside, + * else to the inside. + * + * @param p_dist a double. + * @return a {@link geometry.planar.IntBox} object. + */ + public IntBox vertical_offset(double p_dist) + { + if (p_dist == 0 || is_empty()) + { + return this; + } + int dist = (int)Math.round(p_dist); + IntPoint lower_left = new IntPoint(ll.x, ll.y - dist); + IntPoint upper_right = new IntPoint(ur.x, ur.y + dist); + return new IntBox(lower_left, upper_right); + } + + /** + * Shrinks the width and height of the box by the input width. + * The box will not vanish completely. + * + * @param p_width a int. + * @return a {@link geometry.planar.IntBox} object. + */ + public IntBox shrink(int p_width) + { + int ll_x; + int ur_x; + if (2 * p_width <= this.ur.x - this.ll.x) + { + ll_x = this.ll.x + p_width; + ur_x = this.ur.x - p_width; + } + else + { + ll_x = (this.ll.x + this.ur.x) / 2; + ur_x = ll_x; + } + int ll_y; + int ur_y; + if (2 * p_width <= this.ur.y - this.ll.y) + { + ll_y = this.ll.y + p_width; + ur_y = this.ur.y - p_width; + } + else + { + ll_y = (this.ll.y + this.ur.y) / 2; + ur_y = ll_y; + } + return new IntBox(ll_x, ll_y, ur_x, ur_y); + } + + /** {@inheritDoc} */ + public Side compare(RegularTileShape p_other, int p_edge_no) + { + Side result = p_other.compare(this, p_edge_no); + return result.negate(); + } + + /** {@inheritDoc} */ + public Side compare(IntBox p_other, int p_edge_no) + { + Side result; + switch (p_edge_no) + { + case 0: + // compare the lower edge line + if (ll.y > p_other.ll.y) + { + result = Side.ON_THE_LEFT; + } + else if (ll.y < p_other.ll.y) + { + result = Side.ON_THE_RIGHT; + } + else + { + result = Side.COLLINEAR; + } + break; + + case 1: + // compare the right edge line + if (ur.x < p_other.ur.x) + { + result = Side.ON_THE_LEFT; + } + else if (ur.x > p_other.ur.x) + { + result = Side.ON_THE_RIGHT; + } + else + { + result = Side.COLLINEAR; + } + break; + + case 2: + // compare the upper edge line + if (ur.y < p_other.ur.y) + { + result = Side.ON_THE_LEFT; + } + else if (ur.y > p_other.ur.y) + { + result = Side.ON_THE_RIGHT; + } + else + { + result = Side.COLLINEAR; + } + break; + + case 3: + // compare the left edge line + if (ll.x > p_other.ll.x) + { + result = Side.ON_THE_LEFT; + } + else if (ll.x < p_other.ll.x) + { + result = Side.ON_THE_RIGHT; + } + else + { + result = Side.COLLINEAR; + } + break; + default: + throw new IllegalArgumentException + ("IntBox.compare: p_edge_no out of range"); + + } + return result; + } + + /** + * Returns an object of class IntOctagon defining the same shape + * + * @return a {@link geometry.planar.IntOctagon} object. + */ + public IntOctagon to_IntOctagon() + { + return new IntOctagon(ll.x, ll.y, ur.x, ur.y, ll.x - ur.y, + ur.x - ll.y, ll.x + ll.y, ur.x + ur.y); + } + + /** + * Returns an object of class Simplex defining the same shape + * + * @return a {@link geometry.planar.Simplex} object. + */ + public Simplex to_Simplex() + { + Line[] line_arr; + if (is_empty()) + { + line_arr = new Line[0]; + } + else + { + line_arr = new Line[4]; + line_arr[0] = Line.get_instance(ll, IntDirection.RIGHT); + line_arr[1] = Line.get_instance(ur, IntDirection.UP); + line_arr[2] = Line.get_instance(ur, IntDirection.LEFT); + line_arr[3] = Line.get_instance(ll, IntDirection.DOWN); + } + return new Simplex(line_arr); + } + + /** {@inheritDoc} */ + public boolean is_contained_in( IntBox p_other) + { + if (is_empty() || this == p_other) + { + return true; + } + if (ll.x < p_other.ll.x || ll.y < p_other.ll.y + || ur.x > p_other.ur.x || ur.y > p_other.ur.y) + { + return false; + } + return true; + } + + /** + * Return true, if p_other is contained in the interiour of this box. + * + * @param p_other a {@link geometry.planar.IntBox} object. + * @return a boolean. + */ + public boolean contains_in_interiour(IntBox p_other) + { + if (p_other.is_empty()) + { + return true; + } + if (p_other.ll.x <= ll.x || p_other.ll.y <= ll.y + || p_other.ur.x >= ur.x || p_other.ur.y >= ur.y) + { + return false; + } + return true; + } + + /** + * Calculates the part of p_from_box, which has minimal distance + * to this box. + * + * @param p_from_box a {@link geometry.planar.IntBox} object. + * @return a {@link geometry.planar.IntBox} object. + */ + public IntBox nearest_part(IntBox p_from_box) + { + int ll_x; + + if (p_from_box.ll.x >= this.ll.x) + { + ll_x = p_from_box.ll.x; + } + else if (p_from_box.ur.x >= this.ll.x) + { + ll_x = this.ll.x; + } + else + { + ll_x = p_from_box.ur.x; + } + + int ur_x; + + if (p_from_box.ur.x <= this.ur.x) + { + ur_x = p_from_box.ur.x; + } + else if (p_from_box.ll.x <= this.ur.x) + { + ur_x = this.ur.x; + } + else + { + ur_x = p_from_box.ll.x; + } + + int ll_y; + + if (p_from_box.ll.y >= this.ll.y) + { + ll_y = p_from_box.ll.y; + } + else if (p_from_box.ur.y >= this.ll.y) + { + ll_y = this.ll.y; + } + else + { + ll_y = p_from_box.ur.y; + } + + int ur_y; + + if (p_from_box.ur.y <= this.ur.y) + { + ur_y = p_from_box.ur.y; + } + else if (p_from_box.ll.y <= this.ur.y) + { + ur_y = this.ur.y; + } + else + { + ur_y = p_from_box.ll.y; + } + return new IntBox(ll_x, ll_y, ur_x, ur_y); + } + + /** + *

is_contained_in.

+ * + * @param p_other a {@link geometry.planar.IntOctagon} object. + * @return a boolean. + */ + public boolean is_contained_in( IntOctagon p_other) + { + return p_other.contains(to_IntOctagon()); + } + + /** {@inheritDoc} */ + public boolean intersects( IntOctagon p_other) + { + return p_other.intersects(to_IntOctagon()); + } + + /** + *

intersects.

+ * + * @param p_other a {@link geometry.planar.Simplex} object. + * @return a boolean. + */ + public boolean intersects( Simplex p_other) + { + return p_other.intersects(to_Simplex()); + } + + /** + *

intersects.

+ * + * @param p_other a {@link geometry.planar.Circle} object. + * @return a boolean. + */ + public boolean intersects( Circle p_other) + { + return p_other.intersects(this); + } + + /** + * {@inheritDoc} + * + * @param p_other a {@link geometry.planar.IntOctagon} object. + * @return a {@link geometry.planar.IntOctagon} object. + */ + public IntOctagon union( IntOctagon p_other) + { + return p_other.union(to_IntOctagon()); + } + + /** {@inheritDoc} */ + public Side compare(IntOctagon p_other, int p_edge_no) + { + return to_IntOctagon().compare(p_other, p_edge_no); + } + + /** + * {@inheritDoc} + * + * Divides this box into sections with width and height at most p_max_section_width + * of about equal size. + */ + public IntBox[] divide_into_sections(double p_max_section_width) + { + if (p_max_section_width <= 0) + { + return new IntBox[0]; + } + double length = this.ur.x - this.ll.x; + double height = this.ur.y - this.ll.y; + int x_count = (int) Math.ceil(length / p_max_section_width); + int y_count = (int) Math.ceil(height / p_max_section_width); + int section_length_x = (int) Math.ceil(length / x_count); + int section_length_y = (int) Math.ceil(height / y_count); + IntBox [] result = new IntBox[x_count * y_count]; + int curr_index = 0; + for (int j = 0; j < y_count; ++j) + { + int curr_lly = this.ll.y + j * section_length_y; + int curr_ury; + if (j == (y_count - 1)) + { + curr_ury = this.ur.y; + } + else + { + curr_ury = curr_lly + section_length_y; + } + for (int i = 0; i < x_count; ++i) + { + int curr_llx = this.ll.x + i * section_length_x; + int curr_urx; + if (i == (x_count - 1)) + { + curr_urx = this.ur.x; + } + else + { + curr_urx = curr_llx + section_length_x; + } + result[curr_index] = new IntBox(curr_llx, curr_lly, curr_urx, curr_ury); + ++curr_index; + } + } + return result; + } + + /** + *

cutout.

+ * + * @param p_shape a {@link geometry.planar.TileShape} object. + * @return an array of {@link geometry.planar.TileShape} objects. + */ + public TileShape[] cutout(TileShape p_shape) + { + TileShape[] tmp_result = p_shape.cutout_from(this); + TileShape[] result = new TileShape[tmp_result.length]; + for (int i = 0; i < result.length; ++i) + { + result[i] = tmp_result[i].simplify(); + } + return result; + } + + IntBox[] cutout_from(IntBox p_d) + { + IntBox c = this.intersection(p_d); + if (this.is_empty() || c.dimension() < this.dimension()) + { + // there is only an overlap at the border + IntBox[] result = new IntBox[1]; + result[0] = p_d; + return result; + } + + IntBox[] result = new IntBox[4]; + + result[0] = new IntBox(p_d.ll.x, p_d.ll.y, c.ur.x, c.ll.y); + + result[1] = new IntBox(p_d.ll.x, c.ll.y, c.ll.x, p_d.ur.y); + + result[2] = new IntBox(c.ur.x, p_d.ll.y, p_d.ur.x, c.ur.y); + + result[3] = new IntBox(c.ll.x, c.ur.y, p_d.ur.x, p_d.ur.y); + + // now the division will be optimised, so that the cumulative + // circumference will be minimal. + + IntBox b = null; + + if (c.ll.x - p_d.ll.x > c.ll.y - p_d.ll.y) + { + // switch left dividing line to lower + b = result[0]; + result[0] = new IntBox(c.ll.x, b.ll.y, b.ur.x, b.ur.y); + b = result[1]; + result[1] = new IntBox(b.ll.x, p_d.ll.y, b.ur.x, b.ur.y); + } + if (p_d.ur.y - c.ur.y > c.ll.x - p_d.ll.x) + { + // switch upper dividing line to the left + b = result[1]; + result[1]= new IntBox(b.ll.x, b.ll.y, b.ur.x, c.ur.y); + b = result[3]; + result[3] = new IntBox(p_d.ll.x, b.ll.y, b.ur.x, b.ur.y); + } + if (p_d.ur.x - c.ur.x > p_d.ur.y - c.ur.y) + { + // switch right dividing line to upper + b = result[2]; + result[2] = new IntBox(b.ll.x, b.ll.y, b.ur.x, p_d.ur.y); + b = result[3]; + result[3] = new IntBox(b.ll.x, b.ll.y, c.ur.x, b.ur.y); + } + if (c.ll.y - p_d.ll.y > p_d.ur.x - c.ur.x) + { + // switch lower dividing line to the left + b = result[0]; + result[0] = new IntBox(b.ll.x, b.ll.y, p_d.ur.x, b.ur.y); + b = result[2]; + result[2] = new IntBox(b.ll.x, c.ll.y, b.ur.x, b.ur.y); + } + return result; + } + + Simplex[] cutout_from(Simplex p_simplex) + { + return this.to_Simplex().cutout_from(p_simplex); + } + + IntOctagon[] cutout_from(IntOctagon p_oct) + { + return this.to_IntOctagon().cutout_from(p_oct); + } + + /** + * coordinates of the lower left corner + */ + public final IntPoint ll; + + /** + * coordinates of the upper right corner + */ + public final IntPoint ur; +} diff --git a/geometry/planar/IntDirection.java b/src/main/java/geometry/planar/IntDirection.java similarity index 90% rename from geometry/planar/IntDirection.java rename to src/main/java/geometry/planar/IntDirection.java index 5a34f4e..41c4ee1 100644 --- a/geometry/planar/IntDirection.java +++ b/src/main/java/geometry/planar/IntDirection.java @@ -1,195 +1,218 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * IntDirection.java - * - * Created on 3. Februar 2003, 08:17 - */ - -package geometry.planar; -import datastructures.Signum; - -/** - * - * Implements an abstract class Direction as an equivalence class of IntVector's. - * - * - * @author Alfons Wirtz - */ - -public class IntDirection extends Direction implements java.io.Serializable -{ - - - public boolean is_orthogonal() - { - return ( x == 0 || y == 0 ) ; - } - - public boolean is_diagonal() - { - return ( Math.abs(x) == Math.abs(y) ) ; - } - - public Vector get_vector() - { - return new IntVector(x,y); - } - - IntDirection(int p_x, int p_y) - { - x = p_x; - y = p_y; - } - - IntDirection(IntVector p_vector) - { - x = p_vector.x; - y = p_vector.y; - } - - - - int compareTo( IntDirection p_other ) - { - if (y > 0) - { - if (p_other.y < 0) - { - return -1 ; - } - if (p_other.y == 0) - { - if (p_other.x > 0) - { - return 1 ; - } - return -1 ; - } - } - else if (y < 0) - { - if (p_other.y >= 0) - { - return 1 ; - } - } - else // y == 0 - { - if (x > 0) - { - if (p_other.y != 0 || p_other.x < 0) - { - return -1 ; - } - return 0 ; - } - // x < 0 - if (p_other.y > 0 || p_other.y == 0 && p_other.x > 0) - { - return 1 ; - } - if (p_other.y < 0) - { - return -1 ; - } - return 0; - } - - // now this direction and p_other are located in the same - // open horizontal half plane - - double determinant = (double) p_other.x * y - (double) p_other.y * x; - return Signum.as_int(determinant); - } - - public Direction opposite() - { - return new IntDirection(-x, -y); - } - - public Direction turn_45_degree(int p_factor) - { - int n = p_factor % 8 ; - int new_x ; - int new_y ; - switch (n) - { - case 0: // 0 degree - new_x = x; - new_y = y; - break; - case 1: // 45 degree - new_x = x - y ; - new_y = x + y ; - break; - case 2: // 90 degree - new_x = -y ; - new_y = x ; - break; - case 3: // 135 degree - new_x = -x - y ; - new_y = x - y ; - break; - case 4: // 180 degree - new_x = -x ; - new_y = -y ; - break; - case 5: // 225 degree - new_x = y - x ; - new_y = -x - y ; - break; - case 6: // 270 degree - new_x = y ; - new_y = -x ; - break; - case 7: // 315 degree - new_x = x + y ; - new_y = y - x ; - break; - default: - new_x = 0 ; - new_y = 0 ; - } - return new IntDirection(new_x, new_y) ; - } - - - /** - * Implements the Comparable interface. - * Returns 1, if this direction has a strict bigger angle with - * the positive x-axis than p_other_direction, - * 0, if this direction is equal to p_other_direction, - * and -1 otherwise. - * Throws an exception, if p_other_direction is not a Direction. - */ - public int compareTo(Direction p_other_direction) - { - return -p_other_direction.compareTo(this); - } - - int compareTo(BigIntDirection p_other) - { - return -(p_other.compareTo(this)); - } - - final double determinant(IntDirection p_other) - { - return (double)x * p_other.y - (double)y * p_other.x; - } - - public final int x; - public final int y; -} \ No newline at end of file +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * IntDirection.java + * + * Created on 3. Februar 2003, 08:17 + */ + +package geometry.planar; +import datastructures.Signum; + +/** + * + * Implements an abstract class Direction as an equivalence class of IntVector's. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class IntDirection extends Direction implements java.io.Serializable +{ + + + /** + *

is_orthogonal.

+ * + * @return a boolean. + */ + public boolean is_orthogonal() + { + return ( x == 0 || y == 0 ) ; + } + + /** + *

is_diagonal.

+ * + * @return a boolean. + */ + public boolean is_diagonal() + { + return ( Math.abs(x) == Math.abs(y) ) ; + } + + /** + *

get_vector.

+ * + * @return a {@link geometry.planar.Vector} object. + */ + public Vector get_vector() + { + return new IntVector(x,y); + } + + IntDirection(int p_x, int p_y) + { + x = p_x; + y = p_y; + } + + IntDirection(IntVector p_vector) + { + x = p_vector.x; + y = p_vector.y; + } + + + + int compareTo( IntDirection p_other ) + { + if (y > 0) + { + if (p_other.y < 0) + { + return -1 ; + } + if (p_other.y == 0) + { + if (p_other.x > 0) + { + return 1 ; + } + return -1 ; + } + } + else if (y < 0) + { + if (p_other.y >= 0) + { + return 1 ; + } + } + else // y == 0 + { + if (x > 0) + { + if (p_other.y != 0 || p_other.x < 0) + { + return -1 ; + } + return 0 ; + } + // x < 0 + if (p_other.y > 0 || p_other.y == 0 && p_other.x > 0) + { + return 1 ; + } + if (p_other.y < 0) + { + return -1 ; + } + return 0; + } + + // now this direction and p_other are located in the same + // open horizontal half plane + + double determinant = (double) p_other.x * y - (double) p_other.y * x; + return Signum.as_int(determinant); + } + + /** + *

opposite.

+ * + * @return a {@link geometry.planar.Direction} object. + */ + public Direction opposite() + { + return new IntDirection(-x, -y); + } + + /** {@inheritDoc} */ + public Direction turn_45_degree(int p_factor) + { + int n = p_factor % 8 ; + int new_x ; + int new_y ; + switch (n) + { + case 0: // 0 degree + new_x = x; + new_y = y; + break; + case 1: // 45 degree + new_x = x - y ; + new_y = x + y ; + break; + case 2: // 90 degree + new_x = -y ; + new_y = x ; + break; + case 3: // 135 degree + new_x = -x - y ; + new_y = x - y ; + break; + case 4: // 180 degree + new_x = -x ; + new_y = -y ; + break; + case 5: // 225 degree + new_x = y - x ; + new_y = -x - y ; + break; + case 6: // 270 degree + new_x = y ; + new_y = -x ; + break; + case 7: // 315 degree + new_x = x + y ; + new_y = y - x ; + break; + default: + new_x = 0 ; + new_y = 0 ; + } + return new IntDirection(new_x, new_y) ; + } + + + /** + * Implements the Comparable interface. + * Returns 1, if this direction has a strict bigger angle with + * the positive x-axis than p_other_direction, + * 0, if this direction is equal to p_other_direction, + * and -1 otherwise. + * Throws an exception, if p_other_direction is not a Direction. + * + * @param p_other_direction a {@link geometry.planar.Direction} object. + * @return a int. + */ + public int compareTo(Direction p_other_direction) + { + return -p_other_direction.compareTo(this); + } + + int compareTo(BigIntDirection p_other) + { + return -(p_other.compareTo(this)); + } + + final double determinant(IntDirection p_other) + { + return (double)x * p_other.y - (double)y * p_other.x; + } + + public final int x; + public final int y; +} diff --git a/geometry/planar/IntOctagon.java b/src/main/java/geometry/planar/IntOctagon.java similarity index 92% rename from geometry/planar/IntOctagon.java rename to src/main/java/geometry/planar/IntOctagon.java index deb3e39..4a352ed 100644 --- a/geometry/planar/IntOctagon.java +++ b/src/main/java/geometry/planar/IntOctagon.java @@ -1,1850 +1,2050 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - */ - -package geometry.planar; - -/** - * - * Implements functionality for convex shapes, whose borderline directions are - * multiples of 45 degree and defined with integer coordinates. - * - * @author Alfons Wirtz - */ - -public class IntOctagon extends RegularTileShape implements java.io.Serializable -{ - /** - * Reusable instance of an empty octagon. - */ - public static final IntOctagon EMPTY = - new IntOctagon(Limits.CRIT_INT, Limits.CRIT_INT, -Limits.CRIT_INT, - -Limits.CRIT_INT, Limits.CRIT_INT, -Limits.CRIT_INT, - Limits.CRIT_INT, -Limits.CRIT_INT); - - /** - * Creates an IntOctagon from 8 integer values. - * p_lx is the smallest x value of the shape. - * p_ly is the smallest y value of the shape. - * p_rx is the biggest x valuje af the shape. - * p_uy is the biggest y value of the shape. - * p_ulx is the intersection of the upper left diagonal boundary line - * with the x axis. - * p_lrx is the intersection of the lower right diagonal boundary line - * with the x axis. - * p_llx is the intersection of the lower left diagonal boundary line - * with the x axis. - * p_urx is the intersection of the upper right diagonal boundary line - * with the x axis. - */ - public IntOctagon(int p_lx, int p_ly, int p_rx, int p_uy, - int p_ulx, int p_lrx, int p_llx, int p_urx) - { - lx = p_lx; - ly = p_ly; - rx = p_rx; - uy = p_uy; - ulx = p_ulx; - lrx = p_lrx; - llx = p_llx; - urx = p_urx; - } - - public boolean is_empty() - { - return this == EMPTY; - } - - public boolean is_IntOctagon() - { - return true; - } - - public boolean is_bounded() - { - return true; - } - - public boolean corner_is_bounded(int p_no) - { - return true; - } - - public IntBox bounding_box() - { - return new IntBox(lx, ly, rx, uy); - } - - public IntOctagon bounding_octagon() - { - return this; - } - - public IntOctagon bounding_tile() - { - return this; - } - - public int dimension() - { - if (this == EMPTY) - { - return -1; - } - int result; - - if (rx > lx && uy > ly && lrx > ulx && urx > llx) - { - result = 2; - } - else if (rx == lx && uy == ly) - { - result = 0; - } - else - { - result = 1; - } - return result; - } - - public IntPoint corner(int p_no) - { - - int x; - int y; - switch (p_no) - { - case 0: - x = llx - ly; - y = ly; - break; - case 1: - x = lrx + ly; - y = ly; - break; - case 2: - x = rx; - y = rx - lrx; - break; - case 3: - x = rx; - y = urx - rx; - break; - case 4: - x = urx - uy; - y = uy; - break; - case 5: - x = ulx + uy; - y = uy; - break; - case 6: - x = lx; - y = lx - ulx; - break; - case 7: - x = lx; - y = llx - lx; - break; - default: - throw new IllegalArgumentException - ("IntOctagon.corner: p_no out of range"); - } - return new IntPoint(x,y); - } - - /** - * Additional to the function corner() for performance reasons to avoid allocation of an IntPoint. - */ - public int corner_y(int p_no) - { - int y; - switch (p_no) - { - case 0: - y = ly; - break; - case 1: - y = ly; - break; - case 2: - y = rx - lrx; - break; - case 3: - y = urx - rx; - break; - case 4: - y = uy; - break; - case 5: - y = uy; - break; - case 6: - y = lx - ulx; - break; - case 7: - y = llx - lx; - break; - default: - throw new IllegalArgumentException - ("IntOctagon.corner: p_no out of range"); - } - return y; - } - - /** - * Additional to the function corner() for performance reasons to avoid allocation of an IntPoint. - */ - public int corner_x(int p_no) - { - - int x; - switch (p_no) - { - case 0: - x = llx - ly; - break; - case 1: - x = lrx + ly; - break; - case 2: - x = rx; - break; - case 3: - x = rx; - break; - case 4: - x = urx - uy; - break; - case 5: - x = ulx + uy; - break; - case 6: - x = lx; - break; - case 7: - x = lx; - break; - default: - throw new IllegalArgumentException - ("IntOctagon.corner: p_no out of range"); - } - return x; - } - - public double area() - { - - // calculate half of the absolute value of - // x0 (y1 - y7) + x1 (y2 - y0) + x2 (y3 - y1) + ...+ x7( y0 - y6) - // where xi, yi are the coordinates of the i-th corner of this Octagon. - - // Overwrites the same implementation in TileShape for performence - // reasons to avoid Point allocation. - - double result = (double) (llx - ly) * (double) (ly - llx + lx); - result += (double) (lrx + ly) * (double) (rx - lrx - ly); - result += (double) rx * (double) (urx - 2 * rx - ly + uy + lrx); - result += (double) (urx - uy) * (double) (uy - urx + rx); - result += (double) (ulx + uy) * (double) (lx - ulx - uy); - result += (double) lx * (double) (llx - 2 * lx - uy + ly + ulx); - - return 0.5 * Math.abs(result); - } - - public int border_line_count() - { - return 8; - } - - public Line border_line(int p_no) - { - int a_x; - int a_y; - int b_x; - int b_y; - switch (p_no) - { - case 0: - // lower boundary line - a_x = 0; - a_y = ly; - b_x = 1; - b_y = ly; - break; - case 1: - // lower right boundary line - a_x = lrx; - a_y = 0; - b_x = lrx + 1; - b_y = 1; - break; - case 2: - // right boundary line - a_x = rx; - a_y = 0; - b_x = rx; - b_y = 1; - break; - case 3: - // upper right boundary line - a_x = urx; - a_y = 0; - b_x = urx - 1; - b_y = 1; - break; - case 4: - // upper boundary line - a_x = 0; - a_y = uy; - b_x = -1; - b_y = uy; - break; - case 5: - // upper left boundary line - a_x = ulx; - a_y = 0; - b_x = ulx - 1; - b_y = -1; - break; - case 6: - // left boundary line - a_x = lx; - a_y = 0; - b_x = lx; - b_y = -1; - break; - case 7: - // lower left boundary line - a_x = llx; - a_y = 0; - b_x = llx + 1; - b_y = -1; - break; - default: - throw new IllegalArgumentException - ("IntOctagon.edge_line: p_no out of range"); - } - return new Line(a_x, a_y, b_x, b_y); - } - - public IntOctagon translate_by(Vector p_rel_coor) - { - // This function is at the moment only implemented for Vectors - // with integer coordinates. - // The general implementation is still missing. - - if (p_rel_coor.equals(Vector.ZERO)) - { - return this; - } - IntVector rel_coor = (IntVector) p_rel_coor; - return new IntOctagon(lx + rel_coor.x, ly + rel_coor.y, rx + rel_coor.x, uy + rel_coor.y, - ulx + rel_coor.x - rel_coor.y, lrx + rel_coor.x - rel_coor.y, - llx + rel_coor.x + rel_coor.y, urx + rel_coor.x + rel_coor.y); - } - - public double max_width() - { - double width_1 = Math.max(rx - lx, uy - ly); - double width2 = Math.max(urx - llx, lrx - ulx); - double result = Math.max(width_1, width2/ Limits.sqrt2); - return result; - } - - public double min_width() - { - double width_1 = Math.min(rx - lx, uy - ly); - double width2 = Math.min(urx - llx, lrx - ulx); - double result = Math.min(width_1, width2/ Limits.sqrt2); - return result; - } - - public IntOctagon offset(double p_distance) - { - int width = (int) Math.round(p_distance); - if (width == 0) - { - return this; - } - int dia_width = (int) Math.round(Limits.sqrt2 * p_distance); - IntOctagon result = - new IntOctagon(lx - width, ly - width, rx + width, uy + width, - ulx - dia_width, lrx + dia_width, - llx - dia_width, urx + dia_width); - return result.normalize(); - } - - public IntOctagon enlarge(double p_offset) - { - return offset(p_offset); - } - - public boolean contains(RegularTileShape p_other) - { - return p_other.is_contained_in(this); - } - - public RegularTileShape union(RegularTileShape p_other) - { - return p_other.union(this); - } - - public TileShape intersection(TileShape p_other) - { - return p_other.intersection(this); - } - - public IntOctagon normalize() - { - if (lx > rx || ly > uy || llx > urx || ulx > lrx) - { - return EMPTY; - } - int new_lx = lx; - int new_rx = rx; - int new_ly = ly; - int new_uy = uy; - int new_llx = llx; - int new_ulx = ulx; - int new_lrx = lrx; - int new_urx = urx; - - if (new_lx < new_llx - new_uy) - // the point new_lx, new_uy is the the lower left border line of - // this octagon - // change new_lx , that the the lower left border line runs through - // this point - { - new_lx = new_llx - new_uy; - } - - if (new_lx < new_ulx + new_ly) - // the point new_lx, new_ly is above the the upper left border line of - // this octagon - // change new_lx , that the the upper left border line runs through - // this point - { - new_lx = new_ulx + new_ly; - } - - if (new_rx > new_urx - new_ly) - // the point new_rx, new_ly is above the the upper right border line of - // this octagon - // change new_rx , that the the upper right border line runs through - // this point - { - new_rx = new_urx - new_ly; - } - - if (new_rx > new_lrx + new_uy) - // the point new_rx, new_uy is below the the lower right border line of - // this octagon - // change rx , that the the lower right border line runs through - // this point - - { - new_rx = new_lrx + new_uy; - } - - if (new_ly < new_lx - new_lrx) - // the point lx, ly is below the lower right border line of this - // octagon - // change ly, so that the lower right border line runs through - // this point - { - new_ly = new_lx - new_lrx; - } - - if (new_ly < new_llx - new_rx) - // the point rx, ly is below the lower left border line of - // this octagon. - // change ly, so that the lower left border line runs through - // this point - { - new_ly = new_llx - new_rx; - } - - if (new_uy > new_urx - new_lx) - // the point lx, uy is above the upper right border line of - // this octagon. - // Change the uy, so that the upper right border line runs through - // this point. - { - new_uy = new_urx - new_lx; - } - - if (new_uy > new_rx - new_ulx) - // the point rx, uy is above the upper left border line of - // this octagon. - // Change the uy, so that the upper left border line runs through - // this point. - { - new_uy = new_rx - new_ulx; - } - - if (new_llx - new_lx < new_ly) - // The point lx, ly is above the lower left border line of - // this octagon. - // Change the lower left line, so that it runs through this point. - { - new_llx = new_lx + new_ly; - } - - if (new_rx - new_lrx < new_ly) - // the point rx, ly is above the lower right border line of - // this octagon. - // Change the lower right line, so that it runs through this point. - { - new_lrx = new_rx - new_ly; - } - - if (new_urx - new_rx > new_uy) - // the point rx, uy is below the upper right border line of p_oct. - // Change the upper right line, so that it runs through this point. - { - new_urx = new_uy + new_rx; - } - - if (new_lx - new_ulx > new_uy) - // the point lx, uy is below the upper left border line of - // this octagon. - // Change the upper left line, so that it runs through this point. - { - new_ulx = new_lx - new_uy; - } - - int diag_upper_y = (int)Math.ceil((new_urx - new_ulx) / 2.0); - - if (new_uy > diag_upper_y) - // the intersection of the upper right and the upper left border - // line is below new_uy. Adjust new_uy to diag_upper_y. - { - new_uy = diag_upper_y; - } - - int diag_lower_y = (int)Math.floor((new_llx - new_lrx) / 2.0); - - if (new_ly < diag_lower_y) - // the intersection of the lower right and the lower left border - // line is above new_ly. Adjust new_ly to diag_lower_y. - { - new_ly = diag_lower_y; - } - - int diag_right_x = (int)Math.ceil((new_urx + new_lrx)/ 2.0); - - if (new_rx > diag_right_x) - // the intersection of the upper right and the lower right border - // line is to the left of right x. Adjust new_rx to diag_right_x. - { - new_rx = diag_right_x; - } - - int diag_left_x = (int)Math.floor((new_llx + new_ulx) / 2.0); - - if (new_lx < diag_left_x) - // the intersection of the lower left and the upper left border - // line is to the right of left x. Ajust new_lx to diag_left_x. - { - new_lx = diag_left_x; - } - if (new_lx > new_rx || new_ly > new_uy || new_llx > new_urx - || new_ulx > new_lrx) - { - return EMPTY; - } - return new IntOctagon(new_lx, new_ly, new_rx, new_uy, new_ulx, - new_lrx, new_llx, new_urx); - } - - /** - * Checks, if this IntOctagon is normalized. - */ - public boolean is_normalized() - { - IntOctagon on = this.normalize(); - boolean result = - lx == on.lx && ly == on.ly && rx == on.rx && uy == on.uy && - llx == on.llx && lrx == on.lrx && ulx == on.ulx && urx == on.urx; - return result; - } - - - public Simplex to_Simplex() - { - if (is_empty()) - { - return Simplex.EMPTY; - } - if (precalculated_to_simplex == null) - { - Line [] line_arr = new Line[8]; - for (int i = 0; i < 8; ++i) - { - line_arr[i] = border_line(i); - } - Simplex curr_simplex = new Simplex(line_arr); - precalculated_to_simplex = curr_simplex.remove_redundant_lines(); - } - return precalculated_to_simplex; - } - - public RegularTileShape bounding_shape(ShapeBoundingDirections p_dirs) - { - return p_dirs.bounds(this); - } - - public boolean intersects(Shape p_other) - { - return p_other.intersects(this); - } - - /** - * Returns true, if p_point is contained in this octagon. - * Because of the parameter type FloatPoint, the function may not - * be exact close to the border. - */ - public boolean contains(FloatPoint p_point) - { - if (lx > p_point.x || ly > p_point.y - || rx < p_point.x || uy < p_point.y) - { - return false; - } - double tmp_1 = p_point.x - p_point.y; - double tmp_2 = p_point.x + p_point.y; - if (ulx > tmp_1 || lrx < tmp_1 || llx > tmp_2 || urx < tmp_2) - { - return false; - } - return true; - } - - /** - * Calculates the side of the point (p_x, p_y) of the border line with index p_border_line_no. - * The border lines are located in counterclock sense around this octagon. - */ - public Side side_of_border_line(int p_x, int p_y, int p_border_line_no) - { - - int tmp; - if (p_border_line_no == 0) - { - tmp = this.ly - p_y; - } - else if (p_border_line_no == 2) - { - tmp = p_x - this.rx; - } - else if (p_border_line_no == 4) - { - tmp = p_y - this.uy; - } - else if (p_border_line_no == 6) - { - tmp = this.lx - p_x; - } - else if (p_border_line_no == 1) - { - tmp = p_x - p_y - this.lrx; - } - else if (p_border_line_no == 3) - { - tmp = p_x + p_y - this.urx; - } - else if (p_border_line_no == 5) - { - tmp = this.ulx + p_y - p_x; - } - else if (p_border_line_no == 7) - { - tmp = this.llx - p_x - p_y; - } - else - { - System.out.println("IntOctagon.side_of_border_line: p_border_line_no out of range"); - tmp = 0; - } - Side result; - if (tmp < 0) - { - result = Side.ON_THE_LEFT; - } - else if (tmp > 0) - { - result = Side.ON_THE_RIGHT; - } - else - { - result = Side.COLLINEAR; - } - return result; - } - - Simplex intersection(Simplex p_other) - { - return p_other.intersection(this); - } - - - public IntOctagon intersection(IntOctagon p_other) - { - IntOctagon result = - new IntOctagon(Math.max(lx, p_other.lx), Math.max(ly, p_other.ly), - Math.min(rx, p_other.rx), Math.min(uy, p_other.uy), - Math.max(ulx, p_other.ulx), Math.min(lrx, p_other.lrx), - Math.max(llx, p_other.llx), Math.min(urx, p_other.urx)); - return result.normalize(); - } - - IntOctagon intersection(IntBox p_other) - { - return intersection(p_other.to_IntOctagon()); - } - - /** - * checkes if this (normalized) octagon is contained in p_box - */ - public boolean is_contained_in(IntBox p_box) - { - return (lx >= p_box.ll.x && ly >= p_box.ll.y && - rx <= p_box.ur.x && uy <=p_box.ur.y); - } - - public boolean is_contained_in(IntOctagon p_other) - { - boolean result = lx >= p_other.lx && ly >= p_other.ly && - rx <= p_other.rx && uy <= p_other.uy && - llx >= p_other.llx && ulx >= p_other.ulx && - lrx <= p_other.lrx && urx <= p_other.urx; - - return result; - } - - public IntOctagon union(IntOctagon p_other) - { - IntOctagon result = - new IntOctagon(Math.min(lx, p_other.lx), Math.min(ly, p_other.ly), - Math.max(rx, p_other.rx), Math.max(uy, p_other.uy), - Math.min(ulx, p_other.ulx), Math.max(lrx, p_other.lrx), - Math.min(llx, p_other.llx), Math.max(urx, p_other.urx)); - return result; - } - - public boolean intersects(IntBox p_other) - { - return intersects(p_other.to_IntOctagon()); - } - - /** - * checks, if two normalized Octagons intersect. - */ - public boolean intersects(IntOctagon p_other) - { - int is_lx; - int is_rx; - if (p_other.lx > this.lx) - { - is_lx = p_other.lx; - } - else - { - is_lx = this.lx; - } - if (p_other.rx < this.rx) - { - is_rx = p_other.rx; - } - else - { - is_rx = this.rx; - } - if (is_lx > is_rx) - { - return false; - } - - int is_ly; - int is_uy; - if (p_other.ly > this.ly) - { - is_ly = p_other.ly; - } - else - { - is_ly = this.ly; - } - if (p_other.uy < this.uy) - { - is_uy = p_other.uy; - } - else - { - is_uy = this.uy; - } - if (is_ly > is_uy) - { - return false; - } - - int is_llx; - int is_urx; - if (p_other.llx > this.llx) - { - is_llx = p_other.llx; - } - else - { - is_llx = this.llx; - } - if (p_other.urx < this.urx) - { - is_urx = p_other.urx; - } - else - { - is_urx = this.urx; - } - if (is_llx > is_urx) - { - return false; - } - - int is_ulx; - int is_lrx; - if (p_other.ulx > this.ulx) - { - is_ulx = p_other.ulx; - } - else - { - is_ulx = this.ulx; - } - if (p_other.lrx < this.lrx) - { - is_lrx = p_other.lrx; - } - else - { - is_lrx = this.lrx; - } - if (is_ulx > is_lrx) - { - return false; - } - return true; - } - - /** - * Returns true, if this octagon intersects with p_other and the intersection is 2-dimensional. - */ - public boolean overlaps(IntOctagon p_other) - { - int is_lx; - int is_rx; - if (p_other.lx > this.lx) - { - is_lx = p_other.lx; - } - else - { - is_lx = this.lx; - } - if (p_other.rx < this.rx) - { - is_rx = p_other.rx; - } - else - { - is_rx = this.rx; - } - if (is_lx >= is_rx) - { - return false; - } - - int is_ly; - int is_uy; - if (p_other.ly > this.ly) - { - is_ly = p_other.ly; - } - else - { - is_ly = this.ly; - } - if (p_other.uy < this.uy) - { - is_uy = p_other.uy; - } - else - { - is_uy = this.uy; - } - if (is_ly >= is_uy) - { - return false; - } - - int is_llx; - int is_urx; - if (p_other.llx > this.llx) - { - is_llx = p_other.llx; - } - else - { - is_llx = this.llx; - } - if (p_other.urx < this.urx) - { - is_urx = p_other.urx; - } - else - { - is_urx = this.urx; - } - if (is_llx >= is_urx) - { - return false; - } - - int is_ulx; - int is_lrx; - if (p_other.ulx > this.ulx) - { - is_ulx = p_other.ulx; - } - else - { - is_ulx = this.ulx; - } - if (p_other.lrx < this.lrx) - { - is_lrx = p_other.lrx; - } - else - { - is_lrx = this.lrx; - } - if (is_ulx >= is_lrx) - { - return false; - } - return true; - } - - public boolean intersects(Simplex p_other) - { - return p_other.intersects(this); - } - - public boolean intersects(Circle p_other) - { - return p_other.intersects(this); - } - - - public IntOctagon union(IntBox p_other) - { - return union(p_other.to_IntOctagon()); - } - - /** - * computes the x value of the left boundary of this Octagon at p_y - */ - public int left_x_value(int p_y) - { - int result = Math.max(lx, ulx + p_y); - return Math.max(result, llx - p_y); - } - - /** - * computes the x value of the right boundary of this Octagon at p_y - */ - public int right_x_value(int p_y) - { - int result = Math.min(rx, urx - p_y); - return Math.min(result, lrx + p_y); - } - - /** - * computes the y value of the lower boundary of this Octagon at p_x - */ - public int lower_y_value(int p_x) - { - int result = Math.max(ly, llx - p_x); - return Math.max(result, p_x - lrx); - } - - /** - * computes the y value of the upper boundary of this Octagon at p_x - */ - public int upper_y_value(int p_x) - { - int result = Math.min(uy, p_x - ulx); - return Math.min(result, urx - p_x); - } - - public Side compare(RegularTileShape p_other, int p_edge_no) - { - Side result = p_other.compare(this, p_edge_no); - return result.negate(); - } - - public Side compare(IntOctagon p_other, int p_edge_no) - { - Side result; - switch (p_edge_no) - { - case 0: - // compare the lower edge line - if (ly > p_other.ly) - { - result = Side.ON_THE_LEFT; - } - else if (ly < p_other.ly) - { - result = Side.ON_THE_RIGHT; - } - else - { - result = Side.COLLINEAR; - } - break; - - case 1: - // compare the lower right edge line - if (lrx < p_other.lrx) - { - result = Side.ON_THE_LEFT; - } - else if (lrx > p_other.lrx) - { - result = Side.ON_THE_RIGHT; - } - else - { - result = Side.COLLINEAR; - } - break; - - case 2: - // compare the right edge line - if (rx < p_other.rx) - { - result = Side.ON_THE_LEFT; - } - else if (rx > p_other.rx) - { - result = Side.ON_THE_RIGHT; - } - else - { - result = Side.COLLINEAR; - } - break; - - - case 3: - // compare the upper right edge line - if (urx < p_other.urx) - { - result = Side.ON_THE_LEFT; - } - else if (urx > p_other.urx) - { - result = Side.ON_THE_RIGHT; - } - else - { - result = Side.COLLINEAR; - } - break; - - case 4: - // compare the upper edge line - if (uy < p_other.uy) - { - result = Side.ON_THE_LEFT; - } - else if (uy > p_other.uy) - { - result = Side.ON_THE_RIGHT; - } - else - { - result = Side.COLLINEAR; - } - break; - - - case 5: - // compare the upper left edge line - if (ulx > p_other.ulx) - { - result = Side.ON_THE_LEFT; - } - else if (ulx < p_other.ulx) - { - result = Side.ON_THE_RIGHT; - } - else - { - result = Side.COLLINEAR; - } - break; - - case 6: - // compare the left edge line - if (lx > p_other.lx) - { - result = Side.ON_THE_LEFT; - } - else if (lx < p_other.lx) - { - result = Side.ON_THE_RIGHT; - } - else - { - result = Side.COLLINEAR; - } - break; - - case 7: - // compare the lower left edge line - if (llx > p_other.llx) - { - result = Side.ON_THE_LEFT; - } - else if (llx < p_other.llx) - { - result = Side.ON_THE_RIGHT; - } - else - { - result = Side.COLLINEAR; - } - break; - default: - throw new IllegalArgumentException - ("IntBox.compare: p_edge_no out of range"); - - } - return result; - } - - public Side compare(IntBox p_other, int p_edge_no) - { - return compare(p_other.to_IntOctagon(), p_edge_no); - } - - public int border_line_index(Line p_line) - { - System.out.println("edge_index_of_line not yet implemented for octagons"); - return -1; - } - /** - * Calculates the border point of this octagon from p_point into the 45 degree direction p_dir. - * If this border point is not an IntPoint, the nearest outside IntPoint of the octagon is returned. - */ - public IntPoint border_point(IntPoint p_point, FortyfiveDegreeDirection p_dir) - { - int result_x; - int result_y; - switch (p_dir) - { - case RIGHT: - result_x = Math.min(rx, urx - p_point.y); - result_x = Math.min(result_x, lrx + p_point.y); - result_y = p_point.y; - break; - case LEFT: - result_x = Math.max(lx, ulx + p_point.y); - result_x = Math.max(result_x, llx - p_point.y); - result_y = p_point.y; - break; - case UP: - result_x = p_point.x; - result_y = Math.min(uy, p_point.x - ulx); - result_y = Math.min(result_y, urx - p_point.x); - break; - case DOWN: - result_x = p_point.x; - result_y = Math.max(ly, llx - p_point.x); - result_y = Math.max(result_y, p_point.x - lrx); - break; - case RIGHT45: - result_x = (int) (Math.ceil(0.5 * (p_point.x - p_point.y + urx))); - result_x = Math.min(result_x, rx); - result_x = Math.min(result_x, p_point.x - p_point.x + uy); - result_y = p_point.y - p_point.x + result_x; - break; - case UP45: - result_x = (int)(Math.floor(0.5 * (p_point.x + p_point.y + ulx))); - result_x = Math.max(result_x, lx); - result_x = Math.max(result_x, p_point.x + p_point.y - uy); - result_y = p_point.y + p_point.x - result_x; - break; - case LEFT45: - result_x = (int)(Math.floor(0.5 * (p_point.x - p_point.y + llx))); - result_x = Math.max(result_x, lx); - result_x = Math.max(result_x, p_point.x - p_point.y + ly); - result_y = p_point.y - p_point.x + result_x; - break; - case DOWN45: - result_x = (int) (Math.ceil(0.5 * (p_point.x + p_point.y + lrx))); - result_x = Math.min(result_x, rx); - result_x = Math.min(result_x, p_point.x + p_point.y - ly); - result_y = p_point.y + p_point.x - result_x; - break; - default: - System.out.println("IntOctagon.border_point: unexpected 45 degree direction"); - result_x = 0; - result_y = 0; - } - return new IntPoint(result_x, result_y); - } - - /** - * Calculates the sorted p_max_result_points nearest points on the - * border of this octagon in the 45-degree directions. - * p_point is assumed to be located in the interiour of this octagon. - */ - public IntPoint[] nearest_border_projections(IntPoint p_point, int p_max_result_points) - { - if (!this.contains(p_point) || p_max_result_points <= 0) - { - return new IntPoint[0]; - } - p_max_result_points = Math.min(p_max_result_points, 8); - IntPoint [] result = new IntPoint[p_max_result_points]; - double [] min_dist = new double [p_max_result_points]; - for (int i = 0; i < p_max_result_points; ++i) - { - min_dist[i] = Double.MAX_VALUE; - } - FloatPoint inside_point = p_point.to_float(); - for (FortyfiveDegreeDirection curr_dir : FortyfiveDegreeDirection.values()) - { - IntPoint curr_border_point = border_point(p_point, curr_dir); - double curr_dist = inside_point.distance_square(curr_border_point.to_float()); - for (int i = 0; i < p_max_result_points; ++i) - { - if (curr_dist < min_dist[i]) - { - for (int k = p_max_result_points - 1; k > i; --k) - { - min_dist[k] = min_dist[k - 1]; - result[k] = result[k - 1]; - } - min_dist[i] = curr_dist; - result[i] = curr_border_point; - break; - } - } - } - return result; - } - - Side border_line_side_of( FloatPoint p_point, int p_line_no, double p_tolerance) - { - Side result; - if (p_line_no == 0) - { - if (p_point.y > this.ly + p_tolerance) - { - result = Side.ON_THE_RIGHT; - } - else if (p_point.y < this.ly - p_tolerance) - { - result = Side.ON_THE_LEFT; - } - else - { - result = Side.COLLINEAR; - } - } - else if (p_line_no == 2) - { - if (p_point.x < this.rx - p_tolerance) - { - result = Side.ON_THE_RIGHT; - } - else if (p_point.x > this.rx + p_tolerance) - { - result = Side.ON_THE_LEFT; - } - else - { - result = Side.COLLINEAR; - } - } - else if (p_line_no == 4) - { - if (p_point.y < this.uy - p_tolerance) - { - result = Side.ON_THE_RIGHT; - } - else if (p_point.y > this.uy + p_tolerance ) - { - result = Side.ON_THE_LEFT; - } - else - { - result = Side.COLLINEAR; - } - } - else if (p_line_no == 6) - { - if (p_point.x > this.lx + p_tolerance ) - { - result = Side.ON_THE_RIGHT; - } - else if (p_point.x < this.lx - p_tolerance ) - { - result = Side.ON_THE_LEFT; - } - else - { - result = Side.COLLINEAR; - } - } - else if (p_line_no == 1) - { - double tmp = p_point.y - p_point.x + lrx; - if (tmp > p_tolerance) - // the p_point is above the the lower right border line of this octagon - { - result = Side.ON_THE_RIGHT; - } - else if (tmp < -p_tolerance) - // the p_point is below the the lower right border line of this octagon - { - result = Side.ON_THE_LEFT; - } - else - { - result = Side.COLLINEAR; - } - } - else if (p_line_no == 3) - { - double tmp = p_point.x + p_point.y - urx; - if (tmp < -p_tolerance) - { - // the p_point is below the the upper right border line of this octagon - result = Side.ON_THE_RIGHT; - } - else if (tmp > p_tolerance) - { - // the p_point is above the the upper right border line of this octagon - result = Side.ON_THE_LEFT; - } - else - { - result = Side.COLLINEAR; - } - } - else if (p_line_no == 5) - { - double tmp = p_point.y - p_point.x + ulx; - if (tmp < -p_tolerance) - // the p_point is below the the upper left border line of this octagon - { - result = Side.ON_THE_RIGHT; - } - else if (tmp > p_tolerance) - // the p_point is above the the upper left border line of this octagon - { - result = Side.ON_THE_LEFT; - } - else - { - result = Side.COLLINEAR; - } - } - else if (p_line_no == 7) - { - double tmp = p_point.x + p_point.y - llx; - if (tmp > p_tolerance) - { - // the p_point is above the the lower left border line of this octagon - result = Side.ON_THE_RIGHT; - } - else if (tmp < -p_tolerance) - { - // the p_point is below the the lower left border line of this octagon - result = Side.ON_THE_LEFT; - } - else - { - result = Side.COLLINEAR; - } - } - else - { - System.out.println("IntOctagon.border_line_side_of: p_line_no out of range"); - result = Side.COLLINEAR; - } - return result; - } - - /** - * Checks, if this octagon can be converted to an IntBox. - */ - public boolean is_IntBox() - { - if (llx != lx + ly) - return false; - if (lrx != rx - ly) - return false; - if (urx != rx + uy) - return false; - if (ulx != lx - uy) - return false; - return true; - - } - - public TileShape simplify() - { - if (this.is_IntBox()) - { - return this.bounding_box(); - } - return this; - } - - public TileShape[] cutout(TileShape p_shape) - { - return p_shape.cutout_from(this); - } - - /** - * Divide p_d minus this octagon into 8 convex pieces, - * from which 4 have cut off a corner. - */ - IntOctagon[] cutout_from(IntBox p_d) - { - IntOctagon c = this.intersection(p_d); - - if (this.is_empty() || c.dimension() < this.dimension()) - { - // there is only an overlap at the border - IntOctagon [] result = new IntOctagon[1]; - result[0] = p_d.to_IntOctagon(); - return result; - } - - IntBox [] boxes = new IntBox[4]; - - // construct left box - - boxes[0] = new IntBox(p_d.ll.x, c.llx - c.lx, c.lx, c.lx - c.ulx); - - // construct right box - - boxes[1] = new IntBox(c.rx, c.rx - c.lrx, p_d.ur.x, c.urx - c.rx); - - // construct lower box - - boxes[2] = new IntBox(c.llx - c.ly, p_d.ll.y, c.lrx + c.ly, c.ly); - - // construct upper box - - boxes[3] = new IntBox(c.ulx + c.uy, c.uy, c.urx - c.uy, p_d.ur.y); - - IntOctagon[] octagons = new IntOctagon[4]; - - // construct upper left octagon - - IntOctagon curr_oct = new IntOctagon(p_d.ll.x, boxes[0].ur.y, boxes[3].ll.x, - p_d.ur.y, -Limits.CRIT_INT, c.ulx, -Limits.CRIT_INT, Limits.CRIT_INT); - octagons[0] = curr_oct.normalize(); - - // construct lower left octagon - - curr_oct = new IntOctagon(p_d.ll.x, p_d.ll.y, boxes[2].ll.x, boxes[0].ll.y, - -Limits.CRIT_INT, Limits.CRIT_INT, -Limits.CRIT_INT, c.llx); - octagons[1] = curr_oct.normalize(); - - // construct lower right octagon - - curr_oct = new IntOctagon(boxes[2].ur.x, p_d.ll.y, p_d.ur.x, boxes[1].ll.y, - c.lrx, Limits.CRIT_INT, -Limits.CRIT_INT, Limits.CRIT_INT); - octagons[2] = curr_oct.normalize(); - - // construct upper right octagon - - curr_oct = new IntOctagon(boxes[3].ur.x, boxes[1].ur.y, p_d.ur.x, p_d.ur.y, - -Limits.CRIT_INT, Limits.CRIT_INT, c.urx, Limits.CRIT_INT); - octagons[3] = curr_oct.normalize(); - - // optimise the result to minimum cumulative circumference - - IntBox b = boxes[0]; - IntOctagon o = octagons[0]; - if (b.ur.x - b.ll.x > o.uy - o.ly) - { - // switch the horizontal upper left divide line to vertical - - boxes[0] = new IntBox(b.ll.x, b.ll.y, b.ur.x, o.uy); - curr_oct = new IntOctagon(b.ur.x, o.ly, o.rx, o.uy, o.ulx, o.lrx, o.llx, o.urx); - octagons[0] = curr_oct.normalize(); - } - - b = boxes[3]; - o = octagons[0]; - if (b.ur.y - b.ll.y > o.rx - o.lx) - { - // switch the vertical upper left divide line to horizontal - - boxes[3] = new IntBox(o.lx, b.ll.y, b.ur.x, b.ur.y); - curr_oct = new IntOctagon(o.lx, o.ly, o.rx, b.ll.y, o.ulx, o.lrx, o.llx, o.urx); - octagons[0] = curr_oct.normalize(); - } - b = boxes[3]; - o = octagons[3]; - if (b.ur.y - b.ll.y > o.rx - o.lx) - { - // switch the vertical upper right divide line to horizontal - - boxes[3] = new IntBox(b.ll.x, b.ll.y, o.rx, b.ur.y); - curr_oct = new IntOctagon(o.lx, o.ly, o.rx, o.uy, o.ulx, o.lrx, o.llx, o.urx); - octagons[3] = curr_oct.normalize(); - } - b = boxes[1]; - o = octagons[3]; - if (b.ur.x - b.ll.x > o.uy - o.ly) - { - // switch the horizontal upper right divide line to vertical - - boxes[1] = new IntBox(b.ll.x, b.ll.y, b.ur.x, o.uy); - curr_oct = new IntOctagon(o.lx, o.ly, b.ll.x, o.uy, o.ulx, o.lrx, o.llx, o.urx); - octagons[3] = curr_oct.normalize(); - } - b = boxes[1]; - o = octagons[2]; - if (b.ur.x - b.ll.x > o.uy - o.ly) - { - // switch the horizontal lower right divide line to vertical - - boxes[1] = new IntBox(b.ll.x, o.ly, b.ur.x, b.ur.y); - curr_oct = new IntOctagon(o.lx, o.ly, b.ll.x, o.uy, o.ulx, o.lrx, o.llx, o.urx); - octagons[2] = curr_oct.normalize(); - } - b = boxes[2]; - o = octagons[2]; - if (b.ur.y - b.ll.y > o.rx - o.lx) - { - // switch the vertical lower right divide line to horizontal - - boxes[2] = new IntBox(b.ll.x, b.ll.y, o.rx, b.ur.y); - curr_oct = new IntOctagon(o.lx, b.ur.y, o.rx, o.uy, o.ulx, o.lrx, o.llx, o.urx); - octagons[2] = curr_oct.normalize(); - } - b = boxes[2]; - o = octagons[1]; - if (b.ur.y - b.ll.y > o.rx - o.lx) - { - // switch the vertical lower left divide line to horizontal - - boxes[2] = new IntBox(o.lx, b.ll.y, b.ur.x, b.ur.y); - curr_oct = new IntOctagon(o.lx, b.ur.y, o.rx, o.uy, o.ulx, o.lrx, o.llx, o.urx); - octagons[1] = curr_oct.normalize(); - } - b = boxes[0]; - o = octagons[1]; - if (b.ur.x - b.ll.x > o.uy - o.ly) - { - // switch the horizontal lower left divide line to vertical - boxes[0] = new IntBox(b.ll.x, o.ly, b.ur.x, b.ur.y); - curr_oct = new IntOctagon(b.ur.x, o.ly, o.rx, o.uy, o.ulx, o.lrx, o.llx, o.urx); - octagons[1] = curr_oct.normalize(); - } - - IntOctagon[] result = new IntOctagon[8]; - - // add the 4 boxes to the result - for (int i = 0; i < 4; ++i) - { - result[i] = boxes[i].to_IntOctagon(); - } - - // add the 4 octagons to the result - for (int i = 0; i < 4; ++i) - { - result[4 + i] = octagons[i]; - } - return result; - } - - /** - * Divide p_divide_octagon minus cut_octagon into 8 convex - * pieces without sharp angles. - */ - IntOctagon[] cutout_from(IntOctagon p_d) - { - IntOctagon c = this.intersection(p_d); - - if (this.is_empty() || c.dimension() < this.dimension()) - { - // there is only an overlap at the border - IntOctagon [] result = new IntOctagon[1]; - result[0] = p_d; - return result; - } - - IntOctagon [] result = new IntOctagon[8]; - - int tmp = c.llx - c.lx; - - result[0] = new - IntOctagon(p_d.lx, tmp, c.lx, c.lx - c.ulx, p_d.ulx, p_d.lrx, p_d.llx, p_d.urx); - - int tmp2 = c.llx - c.ly; - - result[1] = new - IntOctagon(p_d.lx, p_d.ly, tmp2, tmp, p_d.ulx, p_d.lrx, p_d.llx, c.llx); - - tmp = c.lrx + c.ly; - - result[2] = new - IntOctagon(tmp2, p_d.ly, tmp, c.ly, p_d.ulx, p_d.lrx, p_d.llx, p_d.urx); - - tmp2 = c.rx - c.lrx; - - result[3] = new - IntOctagon(tmp, p_d.ly, p_d.rx, tmp2, c.lrx, p_d.lrx, p_d.llx, p_d.urx); - - tmp = c.urx - c.rx; - - result[4] = new - IntOctagon(c.rx, tmp2, p_d.rx, tmp, p_d.ulx, p_d.lrx, p_d.llx, p_d.urx); - - tmp2 = c.urx - c.uy; - - result[5] = new - IntOctagon(tmp2, tmp, p_d.rx, p_d.uy, p_d.ulx, p_d.lrx, c.urx, p_d.urx); - - tmp = c.ulx + c.uy; - - result[6] = new - IntOctagon(tmp, c.uy, tmp2, p_d.uy, p_d.ulx, p_d.lrx, p_d.llx, p_d.urx); - - tmp2 = c.lx - c.ulx; - - result[7] = new - IntOctagon(p_d.lx, tmp2, tmp, p_d.uy, p_d.ulx, c.ulx, p_d.llx, p_d.urx); - - for (int i = 0; i < 8; ++i) - { - result[i] = result[i].normalize(); - } - - IntOctagon curr_1 = result[0]; - IntOctagon curr_2 = result[7]; - - if (!(curr_1.is_empty() || curr_2.is_empty()) && - curr_1.rx - curr_1.left_x_value(curr_1.uy) - > curr_2.upper_y_value(curr_1.rx) - curr_2.ly) - { - // switch the horizontal upper left divide line to vertical - curr_1 = new IntOctagon(Math.min(curr_1.lx, curr_2.lx), curr_1.ly, - curr_1.rx, curr_2.uy, curr_2.ulx, curr_1.lrx,curr_1.llx, curr_2.urx); - - curr_2 = new IntOctagon(curr_1.rx, curr_2.ly, curr_2.rx, curr_2.uy, - curr_2.ulx, curr_2.lrx, curr_2.llx, curr_2.urx); - - result[0] = curr_1.normalize(); - result[7] = curr_2.normalize(); - } - curr_1 = result[7]; - curr_2 = result[6]; - if (!(curr_1.is_empty() || curr_2.is_empty()) && - curr_2.upper_y_value(curr_1.rx) - curr_2.ly - > curr_1.rx - curr_1.left_x_value(curr_2.ly)) - // switch the vertical upper left divide line to horizontal - { - curr_2 = new IntOctagon(curr_1.lx, curr_2.ly, curr_2.rx, - Math.max(curr_2.uy, curr_1.uy), curr_1.ulx, curr_2.lrx, curr_1.llx, curr_2.urx); - - curr_1 = new IntOctagon(curr_1.lx, curr_1.ly, curr_1.rx, curr_2.ly, - curr_1.ulx, curr_1.lrx, curr_1.llx, curr_1.urx); - - result[7] = curr_1.normalize(); - result[6] = curr_2.normalize(); - } - curr_1 = result[6]; - curr_2 = result[5]; - if (!(curr_1.is_empty() || curr_2.is_empty()) && - curr_2.upper_y_value(curr_1.rx) - curr_1.ly - > curr_2.right_x_value(curr_1.ly) - curr_2.lx) - // switch the vertical upper right divide line to horizontal - { - curr_1 = new IntOctagon(curr_1.lx, curr_1.ly, curr_2.rx, - Math.max(curr_2.uy, curr_1.uy), curr_1.ulx, curr_2.lrx, curr_1.llx, curr_2.urx); - - curr_2 = new IntOctagon(curr_2.lx, curr_2.ly, curr_2.rx, curr_1.ly, - curr_2.ulx, curr_2.lrx, curr_2.llx, curr_2.urx); - - result[6] = curr_1.normalize(); - result[5] = curr_2.normalize(); - } - curr_1 = result[5]; - curr_2 = result[4]; - if (!(curr_1.is_empty() || curr_2.is_empty()) && - curr_2.right_x_value(curr_2.uy) - curr_2.lx - > curr_1.upper_y_value(curr_2.lx) - curr_2.uy) - // switch the horizontal upper right divide line to vertical - { - curr_2 = new IntOctagon(curr_2.lx, curr_2.ly, Math.max(curr_2.rx, curr_1.rx), - curr_1.uy, curr_1.ulx, curr_2.lrx, curr_2.llx, curr_1.urx); - - curr_1 = new IntOctagon(curr_1.lx, curr_1.ly, curr_2.lx, curr_1.uy, - curr_1.ulx, curr_1.lrx, curr_1.llx, curr_1.urx); - - result[5] = curr_1.normalize(); - result[4] = curr_2.normalize(); - } - curr_1 = result[4]; - curr_2 = result[3]; - if (!(curr_1.is_empty() || curr_2.is_empty()) && - curr_1.right_x_value(curr_1.ly) - curr_1.lx - > curr_1.ly - curr_2.lower_y_value(curr_1.lx)) - // switch the horizontal lower right divide line to vertical - { - curr_1 = new IntOctagon(curr_1.lx, curr_2.ly, Math.max(curr_2.rx, curr_1.rx), - curr_1.uy, curr_1.ulx, curr_2.lrx, curr_2.llx, curr_1.urx); - - curr_2 = new IntOctagon(curr_2.lx, curr_2.ly, curr_1.lx, curr_2.uy, - curr_2.ulx, curr_2.lrx, curr_2.llx, curr_2.urx); - - result[4] = curr_1.normalize(); - result[3] = curr_2.normalize(); - } - - curr_1 = result[3]; - curr_2 = result[2]; - - if (!(curr_1.is_empty() || curr_2.is_empty()) && - curr_2.uy - curr_2.lower_y_value(curr_2.rx) - > curr_1.right_x_value(curr_2.uy) - curr_2.rx) - // switch the vertical lower right divide line to horizontal - { - curr_2 = new IntOctagon(curr_2.lx, Math.min(curr_1.ly, curr_2.ly), - curr_1.rx, curr_2.uy, curr_2.ulx, curr_1.lrx, curr_2.llx, curr_1.urx); - - curr_1 = new IntOctagon(curr_1.lx, curr_2.uy, curr_1.rx, curr_1.uy, - curr_1.ulx, curr_1.lrx, curr_1.llx, curr_1.urx); - - result[3] = curr_1.normalize(); - result[2] = curr_2.normalize(); - } - - curr_1 = result[2]; - curr_2 = result[1]; - - if (!(curr_1.is_empty() || curr_2.is_empty()) && - curr_1.uy - curr_1.lower_y_value(curr_1.lx) - > curr_1.lx - curr_2.left_x_value(curr_1.uy)) - // switch the vertical lower left divide line to horizontal - { - curr_1 = new IntOctagon(curr_2.lx, Math.min(curr_1.ly, curr_2.ly), - curr_1.rx, curr_1.uy, curr_2.ulx, curr_1.lrx, curr_2.llx, curr_1.urx); - - curr_2 = new IntOctagon(curr_2.lx, curr_1.uy, curr_2.rx, curr_2.uy, - curr_2.ulx, curr_2.lrx, curr_2.llx, curr_2.urx); - - result[2] = curr_1.normalize(); - result[1] = curr_2.normalize(); - } - - curr_1 = result[1]; - curr_2 = result[0]; - - if (!(curr_1.is_empty() || curr_2.is_empty()) && - curr_2.rx - curr_2.left_x_value(curr_2.ly) - > curr_2.ly - curr_1.lower_y_value(curr_2.rx)) - // switch the horizontal lower left divide line to vertical - { - curr_2 = new IntOctagon(Math.min(curr_2.lx, curr_1.lx), curr_1.ly, - curr_2.rx, curr_2.uy, curr_2.ulx, curr_1.lrx, curr_1.llx, curr_2.urx); - - curr_1 = new IntOctagon(curr_2.rx, curr_1.ly, curr_1.rx, curr_1.uy, - curr_1.ulx, curr_1.lrx, curr_1.llx, curr_1.urx); - - result[1] = curr_1.normalize(); - result[0] = curr_2.normalize(); - } - - return result; - } - - - Simplex[] cutout_from(Simplex p_simplex) - { - return this.to_Simplex().cutout_from(p_simplex); - } - - /** - * x coordinate of the left border line - */ - public final int lx; - - /** - * y coordinate of the lower border line - */ - public final int ly; - - /** - * x coordinate of the right border line - */ - public final int rx; - - /** - * y coordinate of the upper border line - */ - public final int uy; - - /** - * x axis intersection of the upper left border line - */ - public final int ulx; - - /** - * x axis intersection of the lower right border line - */ - public final int lrx; - - /** - * x axis intersection of the lower left border line - */ - public final int llx; - - /** - * x axis intersection of the upper right border line - */ - public final int urx; - - /** - * Result of to_simplex() memorized for performance reasons. - */ - private Simplex precalculated_to_simplex = null; - -} \ No newline at end of file +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + */ + +package geometry.planar; + +/** + * + * Implements functionality for convex shapes, whose borderline directions are + * multiples of 45 degree and defined with integer coordinates. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class IntOctagon extends RegularTileShape implements java.io.Serializable +{ + /** + * Reusable instance of an empty octagon. + */ + public static final IntOctagon EMPTY = + new IntOctagon(Limits.CRIT_INT, Limits.CRIT_INT, -Limits.CRIT_INT, + -Limits.CRIT_INT, Limits.CRIT_INT, -Limits.CRIT_INT, + Limits.CRIT_INT, -Limits.CRIT_INT); + + /** + * Creates an IntOctagon from 8 integer values. + * p_lx is the smallest x value of the shape. + * p_ly is the smallest y value of the shape. + * p_rx is the biggest x valuje af the shape. + * p_uy is the biggest y value of the shape. + * p_ulx is the intersection of the upper left diagonal boundary line + * with the x axis. + * p_lrx is the intersection of the lower right diagonal boundary line + * with the x axis. + * p_llx is the intersection of the lower left diagonal boundary line + * with the x axis. + * p_urx is the intersection of the upper right diagonal boundary line + * with the x axis. + * + * @param p_lx a int. + * @param p_ly a int. + * @param p_rx a int. + * @param p_uy a int. + * @param p_ulx a int. + * @param p_lrx a int. + * @param p_llx a int. + * @param p_urx a int. + */ + public IntOctagon(int p_lx, int p_ly, int p_rx, int p_uy, + int p_ulx, int p_lrx, int p_llx, int p_urx) + { + lx = p_lx; + ly = p_ly; + rx = p_rx; + uy = p_uy; + ulx = p_ulx; + lrx = p_lrx; + llx = p_llx; + urx = p_urx; + } + + /** + *

is_empty.

+ * + * @return a boolean. + */ + public boolean is_empty() + { + return this == EMPTY; + } + + /** + *

is_IntOctagon.

+ * + * @return a boolean. + */ + public boolean is_IntOctagon() + { + return true; + } + + /** + *

is_bounded.

+ * + * @return a boolean. + */ + public boolean is_bounded() + { + return true; + } + + /** {@inheritDoc} */ + public boolean corner_is_bounded(int p_no) + { + return true; + } + + /** + *

bounding_box.

+ * + * @return a {@link geometry.planar.IntBox} object. + */ + public IntBox bounding_box() + { + return new IntBox(lx, ly, rx, uy); + } + + /** + *

bounding_octagon.

+ * + * @return a {@link geometry.planar.IntOctagon} object. + */ + public IntOctagon bounding_octagon() + { + return this; + } + + /** + *

bounding_tile.

+ * + * @return a {@link geometry.planar.IntOctagon} object. + */ + public IntOctagon bounding_tile() + { + return this; + } + + /** + *

dimension.

+ * + * @return a int. + */ + public int dimension() + { + if (this == EMPTY) + { + return -1; + } + int result; + + if (rx > lx && uy > ly && lrx > ulx && urx > llx) + { + result = 2; + } + else if (rx == lx && uy == ly) + { + result = 0; + } + else + { + result = 1; + } + return result; + } + + /** {@inheritDoc} */ + public IntPoint corner(int p_no) + { + + int x; + int y; + switch (p_no) + { + case 0: + x = llx - ly; + y = ly; + break; + case 1: + x = lrx + ly; + y = ly; + break; + case 2: + x = rx; + y = rx - lrx; + break; + case 3: + x = rx; + y = urx - rx; + break; + case 4: + x = urx - uy; + y = uy; + break; + case 5: + x = ulx + uy; + y = uy; + break; + case 6: + x = lx; + y = lx - ulx; + break; + case 7: + x = lx; + y = llx - lx; + break; + default: + throw new IllegalArgumentException + ("IntOctagon.corner: p_no out of range"); + } + return new IntPoint(x,y); + } + + /** + * Additional to the function corner() for performance reasons to avoid allocation of an IntPoint. + * + * @param p_no a int. + * @return a int. + */ + public int corner_y(int p_no) + { + int y; + switch (p_no) + { + case 0: + y = ly; + break; + case 1: + y = ly; + break; + case 2: + y = rx - lrx; + break; + case 3: + y = urx - rx; + break; + case 4: + y = uy; + break; + case 5: + y = uy; + break; + case 6: + y = lx - ulx; + break; + case 7: + y = llx - lx; + break; + default: + throw new IllegalArgumentException + ("IntOctagon.corner: p_no out of range"); + } + return y; + } + + /** + * Additional to the function corner() for performance reasons to avoid allocation of an IntPoint. + * + * @param p_no a int. + * @return a int. + */ + public int corner_x(int p_no) + { + + int x; + switch (p_no) + { + case 0: + x = llx - ly; + break; + case 1: + x = lrx + ly; + break; + case 2: + x = rx; + break; + case 3: + x = rx; + break; + case 4: + x = urx - uy; + break; + case 5: + x = ulx + uy; + break; + case 6: + x = lx; + break; + case 7: + x = lx; + break; + default: + throw new IllegalArgumentException + ("IntOctagon.corner: p_no out of range"); + } + return x; + } + + /** + *

area.

+ * + * @return a double. + */ + public double area() + { + + // calculate half of the absolute value of + // x0 (y1 - y7) + x1 (y2 - y0) + x2 (y3 - y1) + ...+ x7( y0 - y6) + // where xi, yi are the coordinates of the i-th corner of this Octagon. + + // Overwrites the same implementation in TileShape for performence + // reasons to avoid Point allocation. + + double result = (double) (llx - ly) * (double) (ly - llx + lx); + result += (double) (lrx + ly) * (double) (rx - lrx - ly); + result += (double) rx * (double) (urx - 2 * rx - ly + uy + lrx); + result += (double) (urx - uy) * (double) (uy - urx + rx); + result += (double) (ulx + uy) * (double) (lx - ulx - uy); + result += (double) lx * (double) (llx - 2 * lx - uy + ly + ulx); + + return 0.5 * Math.abs(result); + } + + /** + *

border_line_count.

+ * + * @return a int. + */ + public int border_line_count() + { + return 8; + } + + /** {@inheritDoc} */ + public Line border_line(int p_no) + { + int a_x; + int a_y; + int b_x; + int b_y; + switch (p_no) + { + case 0: + // lower boundary line + a_x = 0; + a_y = ly; + b_x = 1; + b_y = ly; + break; + case 1: + // lower right boundary line + a_x = lrx; + a_y = 0; + b_x = lrx + 1; + b_y = 1; + break; + case 2: + // right boundary line + a_x = rx; + a_y = 0; + b_x = rx; + b_y = 1; + break; + case 3: + // upper right boundary line + a_x = urx; + a_y = 0; + b_x = urx - 1; + b_y = 1; + break; + case 4: + // upper boundary line + a_x = 0; + a_y = uy; + b_x = -1; + b_y = uy; + break; + case 5: + // upper left boundary line + a_x = ulx; + a_y = 0; + b_x = ulx - 1; + b_y = -1; + break; + case 6: + // left boundary line + a_x = lx; + a_y = 0; + b_x = lx; + b_y = -1; + break; + case 7: + // lower left boundary line + a_x = llx; + a_y = 0; + b_x = llx + 1; + b_y = -1; + break; + default: + throw new IllegalArgumentException + ("IntOctagon.edge_line: p_no out of range"); + } + return new Line(a_x, a_y, b_x, b_y); + } + + /** {@inheritDoc} */ + public IntOctagon translate_by(Vector p_rel_coor) + { + // This function is at the moment only implemented for Vectors + // with integer coordinates. + // The general implementation is still missing. + + if (p_rel_coor.equals(Vector.ZERO)) + { + return this; + } + IntVector rel_coor = (IntVector) p_rel_coor; + return new IntOctagon(lx + rel_coor.x, ly + rel_coor.y, rx + rel_coor.x, uy + rel_coor.y, + ulx + rel_coor.x - rel_coor.y, lrx + rel_coor.x - rel_coor.y, + llx + rel_coor.x + rel_coor.y, urx + rel_coor.x + rel_coor.y); + } + + /** + *

max_width.

+ * + * @return a double. + */ + public double max_width() + { + double width_1 = Math.max(rx - lx, uy - ly); + double width2 = Math.max(urx - llx, lrx - ulx); + double result = Math.max(width_1, width2/ Limits.sqrt2); + return result; + } + + /** + *

min_width.

+ * + * @return a double. + */ + public double min_width() + { + double width_1 = Math.min(rx - lx, uy - ly); + double width2 = Math.min(urx - llx, lrx - ulx); + double result = Math.min(width_1, width2/ Limits.sqrt2); + return result; + } + + /** {@inheritDoc} */ + public IntOctagon offset(double p_distance) + { + int width = (int) Math.round(p_distance); + if (width == 0) + { + return this; + } + int dia_width = (int) Math.round(Limits.sqrt2 * p_distance); + IntOctagon result = + new IntOctagon(lx - width, ly - width, rx + width, uy + width, + ulx - dia_width, lrx + dia_width, + llx - dia_width, urx + dia_width); + return result.normalize(); + } + + /** {@inheritDoc} */ + public IntOctagon enlarge(double p_offset) + { + return offset(p_offset); + } + + /** {@inheritDoc} */ + public boolean contains(RegularTileShape p_other) + { + return p_other.is_contained_in(this); + } + + /** + * {@inheritDoc} + * + *

union.

+ */ + public RegularTileShape union(RegularTileShape p_other) + { + return p_other.union(this); + } + + /** + * {@inheritDoc} + * + *

intersection.

+ */ + public TileShape intersection(TileShape p_other) + { + return p_other.intersection(this); + } + + /** + *

normalize.

+ * + * @return a {@link geometry.planar.IntOctagon} object. + */ + public IntOctagon normalize() + { + if (lx > rx || ly > uy || llx > urx || ulx > lrx) + { + return EMPTY; + } + int new_lx = lx; + int new_rx = rx; + int new_ly = ly; + int new_uy = uy; + int new_llx = llx; + int new_ulx = ulx; + int new_lrx = lrx; + int new_urx = urx; + + if (new_lx < new_llx - new_uy) + // the point new_lx, new_uy is the the lower left border line of + // this octagon + // change new_lx , that the the lower left border line runs through + // this point + { + new_lx = new_llx - new_uy; + } + + if (new_lx < new_ulx + new_ly) + // the point new_lx, new_ly is above the the upper left border line of + // this octagon + // change new_lx , that the the upper left border line runs through + // this point + { + new_lx = new_ulx + new_ly; + } + + if (new_rx > new_urx - new_ly) + // the point new_rx, new_ly is above the the upper right border line of + // this octagon + // change new_rx , that the the upper right border line runs through + // this point + { + new_rx = new_urx - new_ly; + } + + if (new_rx > new_lrx + new_uy) + // the point new_rx, new_uy is below the the lower right border line of + // this octagon + // change rx , that the the lower right border line runs through + // this point + + { + new_rx = new_lrx + new_uy; + } + + if (new_ly < new_lx - new_lrx) + // the point lx, ly is below the lower right border line of this + // octagon + // change ly, so that the lower right border line runs through + // this point + { + new_ly = new_lx - new_lrx; + } + + if (new_ly < new_llx - new_rx) + // the point rx, ly is below the lower left border line of + // this octagon. + // change ly, so that the lower left border line runs through + // this point + { + new_ly = new_llx - new_rx; + } + + if (new_uy > new_urx - new_lx) + // the point lx, uy is above the upper right border line of + // this octagon. + // Change the uy, so that the upper right border line runs through + // this point. + { + new_uy = new_urx - new_lx; + } + + if (new_uy > new_rx - new_ulx) + // the point rx, uy is above the upper left border line of + // this octagon. + // Change the uy, so that the upper left border line runs through + // this point. + { + new_uy = new_rx - new_ulx; + } + + if (new_llx - new_lx < new_ly) + // The point lx, ly is above the lower left border line of + // this octagon. + // Change the lower left line, so that it runs through this point. + { + new_llx = new_lx + new_ly; + } + + if (new_rx - new_lrx < new_ly) + // the point rx, ly is above the lower right border line of + // this octagon. + // Change the lower right line, so that it runs through this point. + { + new_lrx = new_rx - new_ly; + } + + if (new_urx - new_rx > new_uy) + // the point rx, uy is below the upper right border line of p_oct. + // Change the upper right line, so that it runs through this point. + { + new_urx = new_uy + new_rx; + } + + if (new_lx - new_ulx > new_uy) + // the point lx, uy is below the upper left border line of + // this octagon. + // Change the upper left line, so that it runs through this point. + { + new_ulx = new_lx - new_uy; + } + + int diag_upper_y = (int)Math.ceil((new_urx - new_ulx) / 2.0); + + if (new_uy > diag_upper_y) + // the intersection of the upper right and the upper left border + // line is below new_uy. Adjust new_uy to diag_upper_y. + { + new_uy = diag_upper_y; + } + + int diag_lower_y = (int)Math.floor((new_llx - new_lrx) / 2.0); + + if (new_ly < diag_lower_y) + // the intersection of the lower right and the lower left border + // line is above new_ly. Adjust new_ly to diag_lower_y. + { + new_ly = diag_lower_y; + } + + int diag_right_x = (int)Math.ceil((new_urx + new_lrx)/ 2.0); + + if (new_rx > diag_right_x) + // the intersection of the upper right and the lower right border + // line is to the left of right x. Adjust new_rx to diag_right_x. + { + new_rx = diag_right_x; + } + + int diag_left_x = (int)Math.floor((new_llx + new_ulx) / 2.0); + + if (new_lx < diag_left_x) + // the intersection of the lower left and the upper left border + // line is to the right of left x. Ajust new_lx to diag_left_x. + { + new_lx = diag_left_x; + } + if (new_lx > new_rx || new_ly > new_uy || new_llx > new_urx + || new_ulx > new_lrx) + { + return EMPTY; + } + return new IntOctagon(new_lx, new_ly, new_rx, new_uy, new_ulx, + new_lrx, new_llx, new_urx); + } + + /** + * Checks, if this IntOctagon is normalized. + * + * @return a boolean. + */ + public boolean is_normalized() + { + IntOctagon on = this.normalize(); + boolean result = + lx == on.lx && ly == on.ly && rx == on.rx && uy == on.uy && + llx == on.llx && lrx == on.lrx && ulx == on.ulx && urx == on.urx; + return result; + } + + + /** + *

to_Simplex.

+ * + * @return a {@link geometry.planar.Simplex} object. + */ + public Simplex to_Simplex() + { + if (is_empty()) + { + return Simplex.EMPTY; + } + if (precalculated_to_simplex == null) + { + Line [] line_arr = new Line[8]; + for (int i = 0; i < 8; ++i) + { + line_arr[i] = border_line(i); + } + Simplex curr_simplex = new Simplex(line_arr); + precalculated_to_simplex = curr_simplex.remove_redundant_lines(); + } + return precalculated_to_simplex; + } + + /** {@inheritDoc} */ + public RegularTileShape bounding_shape(ShapeBoundingDirections p_dirs) + { + return p_dirs.bounds(this); + } + + /** + *

intersects.

+ * + * @param p_other a {@link geometry.planar.Shape} object. + * @return a boolean. + */ + public boolean intersects(Shape p_other) + { + return p_other.intersects(this); + } + + /** + * Returns true, if p_point is contained in this octagon. + * Because of the parameter type FloatPoint, the function may not + * be exact close to the border. + * + * @param p_point a {@link geometry.planar.FloatPoint} object. + * @return a boolean. + */ + public boolean contains(FloatPoint p_point) + { + if (lx > p_point.x || ly > p_point.y + || rx < p_point.x || uy < p_point.y) + { + return false; + } + double tmp_1 = p_point.x - p_point.y; + double tmp_2 = p_point.x + p_point.y; + if (ulx > tmp_1 || lrx < tmp_1 || llx > tmp_2 || urx < tmp_2) + { + return false; + } + return true; + } + + /** + * Calculates the side of the point (p_x, p_y) of the border line with index p_border_line_no. + * The border lines are located in counterclock sense around this octagon. + * + * @param p_x a int. + * @param p_y a int. + * @param p_border_line_no a int. + * @return a {@link geometry.planar.Side} object. + */ + public Side side_of_border_line(int p_x, int p_y, int p_border_line_no) + { + + int tmp; + if (p_border_line_no == 0) + { + tmp = this.ly - p_y; + } + else if (p_border_line_no == 2) + { + tmp = p_x - this.rx; + } + else if (p_border_line_no == 4) + { + tmp = p_y - this.uy; + } + else if (p_border_line_no == 6) + { + tmp = this.lx - p_x; + } + else if (p_border_line_no == 1) + { + tmp = p_x - p_y - this.lrx; + } + else if (p_border_line_no == 3) + { + tmp = p_x + p_y - this.urx; + } + else if (p_border_line_no == 5) + { + tmp = this.ulx + p_y - p_x; + } + else if (p_border_line_no == 7) + { + tmp = this.llx - p_x - p_y; + } + else + { + System.out.println("IntOctagon.side_of_border_line: p_border_line_no out of range"); + tmp = 0; + } + Side result; + if (tmp < 0) + { + result = Side.ON_THE_LEFT; + } + else if (tmp > 0) + { + result = Side.ON_THE_RIGHT; + } + else + { + result = Side.COLLINEAR; + } + return result; + } + + Simplex intersection(Simplex p_other) + { + return p_other.intersection(this); + } + + + /** + *

intersection.

+ * + * @param p_other a {@link geometry.planar.IntOctagon} object. + * @return a {@link geometry.planar.IntOctagon} object. + */ + public IntOctagon intersection(IntOctagon p_other) + { + IntOctagon result = + new IntOctagon(Math.max(lx, p_other.lx), Math.max(ly, p_other.ly), + Math.min(rx, p_other.rx), Math.min(uy, p_other.uy), + Math.max(ulx, p_other.ulx), Math.min(lrx, p_other.lrx), + Math.max(llx, p_other.llx), Math.min(urx, p_other.urx)); + return result.normalize(); + } + + IntOctagon intersection(IntBox p_other) + { + return intersection(p_other.to_IntOctagon()); + } + + /** + * {@inheritDoc} + * + * checkes if this (normalized) octagon is contained in p_box + */ + public boolean is_contained_in(IntBox p_box) + { + return (lx >= p_box.ll.x && ly >= p_box.ll.y && + rx <= p_box.ur.x && uy <=p_box.ur.y); + } + + /** + *

is_contained_in.

+ * + * @param p_other a {@link geometry.planar.IntOctagon} object. + * @return a boolean. + */ + public boolean is_contained_in(IntOctagon p_other) + { + boolean result = lx >= p_other.lx && ly >= p_other.ly && + rx <= p_other.rx && uy <= p_other.uy && + llx >= p_other.llx && ulx >= p_other.ulx && + lrx <= p_other.lrx && urx <= p_other.urx; + + return result; + } + + /** + * {@inheritDoc} + * + * @param p_other a {@link geometry.planar.IntOctagon} object. + * @return a {@link geometry.planar.IntOctagon} object. + */ + public IntOctagon union(IntOctagon p_other) + { + IntOctagon result = + new IntOctagon(Math.min(lx, p_other.lx), Math.min(ly, p_other.ly), + Math.max(rx, p_other.rx), Math.max(uy, p_other.uy), + Math.min(ulx, p_other.ulx), Math.max(lrx, p_other.lrx), + Math.min(llx, p_other.llx), Math.max(urx, p_other.urx)); + return result; + } + + /** + *

intersects.

+ * + * @param p_other a {@link geometry.planar.IntBox} object. + * @return a boolean. + */ + public boolean intersects(IntBox p_other) + { + return intersects(p_other.to_IntOctagon()); + } + + /** + * {@inheritDoc} + * + * checks, if two normalized Octagons intersect. + */ + public boolean intersects(IntOctagon p_other) + { + int is_lx; + int is_rx; + if (p_other.lx > this.lx) + { + is_lx = p_other.lx; + } + else + { + is_lx = this.lx; + } + if (p_other.rx < this.rx) + { + is_rx = p_other.rx; + } + else + { + is_rx = this.rx; + } + if (is_lx > is_rx) + { + return false; + } + + int is_ly; + int is_uy; + if (p_other.ly > this.ly) + { + is_ly = p_other.ly; + } + else + { + is_ly = this.ly; + } + if (p_other.uy < this.uy) + { + is_uy = p_other.uy; + } + else + { + is_uy = this.uy; + } + if (is_ly > is_uy) + { + return false; + } + + int is_llx; + int is_urx; + if (p_other.llx > this.llx) + { + is_llx = p_other.llx; + } + else + { + is_llx = this.llx; + } + if (p_other.urx < this.urx) + { + is_urx = p_other.urx; + } + else + { + is_urx = this.urx; + } + if (is_llx > is_urx) + { + return false; + } + + int is_ulx; + int is_lrx; + if (p_other.ulx > this.ulx) + { + is_ulx = p_other.ulx; + } + else + { + is_ulx = this.ulx; + } + if (p_other.lrx < this.lrx) + { + is_lrx = p_other.lrx; + } + else + { + is_lrx = this.lrx; + } + if (is_ulx > is_lrx) + { + return false; + } + return true; + } + + /** + * Returns true, if this octagon intersects with p_other and the intersection is 2-dimensional. + * + * @param p_other a {@link geometry.planar.IntOctagon} object. + * @return a boolean. + */ + public boolean overlaps(IntOctagon p_other) + { + int is_lx; + int is_rx; + if (p_other.lx > this.lx) + { + is_lx = p_other.lx; + } + else + { + is_lx = this.lx; + } + if (p_other.rx < this.rx) + { + is_rx = p_other.rx; + } + else + { + is_rx = this.rx; + } + if (is_lx >= is_rx) + { + return false; + } + + int is_ly; + int is_uy; + if (p_other.ly > this.ly) + { + is_ly = p_other.ly; + } + else + { + is_ly = this.ly; + } + if (p_other.uy < this.uy) + { + is_uy = p_other.uy; + } + else + { + is_uy = this.uy; + } + if (is_ly >= is_uy) + { + return false; + } + + int is_llx; + int is_urx; + if (p_other.llx > this.llx) + { + is_llx = p_other.llx; + } + else + { + is_llx = this.llx; + } + if (p_other.urx < this.urx) + { + is_urx = p_other.urx; + } + else + { + is_urx = this.urx; + } + if (is_llx >= is_urx) + { + return false; + } + + int is_ulx; + int is_lrx; + if (p_other.ulx > this.ulx) + { + is_ulx = p_other.ulx; + } + else + { + is_ulx = this.ulx; + } + if (p_other.lrx < this.lrx) + { + is_lrx = p_other.lrx; + } + else + { + is_lrx = this.lrx; + } + if (is_ulx >= is_lrx) + { + return false; + } + return true; + } + + /** + *

intersects.

+ * + * @param p_other a {@link geometry.planar.Simplex} object. + * @return a boolean. + */ + public boolean intersects(Simplex p_other) + { + return p_other.intersects(this); + } + + /** + *

intersects.

+ * + * @param p_other a {@link geometry.planar.Circle} object. + * @return a boolean. + */ + public boolean intersects(Circle p_other) + { + return p_other.intersects(this); + } + + + /** + *

union.

+ * + * @param p_other a {@link geometry.planar.IntBox} object. + * @return a {@link geometry.planar.IntOctagon} object. + */ + public IntOctagon union(IntBox p_other) + { + return union(p_other.to_IntOctagon()); + } + + /** + * computes the x value of the left boundary of this Octagon at p_y + * + * @param p_y a int. + * @return a int. + */ + public int left_x_value(int p_y) + { + int result = Math.max(lx, ulx + p_y); + return Math.max(result, llx - p_y); + } + + /** + * computes the x value of the right boundary of this Octagon at p_y + * + * @param p_y a int. + * @return a int. + */ + public int right_x_value(int p_y) + { + int result = Math.min(rx, urx - p_y); + return Math.min(result, lrx + p_y); + } + + /** + * computes the y value of the lower boundary of this Octagon at p_x + * + * @param p_x a int. + * @return a int. + */ + public int lower_y_value(int p_x) + { + int result = Math.max(ly, llx - p_x); + return Math.max(result, p_x - lrx); + } + + /** + * computes the y value of the upper boundary of this Octagon at p_x + * + * @param p_x a int. + * @return a int. + */ + public int upper_y_value(int p_x) + { + int result = Math.min(uy, p_x - ulx); + return Math.min(result, urx - p_x); + } + + /** {@inheritDoc} */ + public Side compare(RegularTileShape p_other, int p_edge_no) + { + Side result = p_other.compare(this, p_edge_no); + return result.negate(); + } + + /** {@inheritDoc} */ + public Side compare(IntOctagon p_other, int p_edge_no) + { + Side result; + switch (p_edge_no) + { + case 0: + // compare the lower edge line + if (ly > p_other.ly) + { + result = Side.ON_THE_LEFT; + } + else if (ly < p_other.ly) + { + result = Side.ON_THE_RIGHT; + } + else + { + result = Side.COLLINEAR; + } + break; + + case 1: + // compare the lower right edge line + if (lrx < p_other.lrx) + { + result = Side.ON_THE_LEFT; + } + else if (lrx > p_other.lrx) + { + result = Side.ON_THE_RIGHT; + } + else + { + result = Side.COLLINEAR; + } + break; + + case 2: + // compare the right edge line + if (rx < p_other.rx) + { + result = Side.ON_THE_LEFT; + } + else if (rx > p_other.rx) + { + result = Side.ON_THE_RIGHT; + } + else + { + result = Side.COLLINEAR; + } + break; + + + case 3: + // compare the upper right edge line + if (urx < p_other.urx) + { + result = Side.ON_THE_LEFT; + } + else if (urx > p_other.urx) + { + result = Side.ON_THE_RIGHT; + } + else + { + result = Side.COLLINEAR; + } + break; + + case 4: + // compare the upper edge line + if (uy < p_other.uy) + { + result = Side.ON_THE_LEFT; + } + else if (uy > p_other.uy) + { + result = Side.ON_THE_RIGHT; + } + else + { + result = Side.COLLINEAR; + } + break; + + + case 5: + // compare the upper left edge line + if (ulx > p_other.ulx) + { + result = Side.ON_THE_LEFT; + } + else if (ulx < p_other.ulx) + { + result = Side.ON_THE_RIGHT; + } + else + { + result = Side.COLLINEAR; + } + break; + + case 6: + // compare the left edge line + if (lx > p_other.lx) + { + result = Side.ON_THE_LEFT; + } + else if (lx < p_other.lx) + { + result = Side.ON_THE_RIGHT; + } + else + { + result = Side.COLLINEAR; + } + break; + + case 7: + // compare the lower left edge line + if (llx > p_other.llx) + { + result = Side.ON_THE_LEFT; + } + else if (llx < p_other.llx) + { + result = Side.ON_THE_RIGHT; + } + else + { + result = Side.COLLINEAR; + } + break; + default: + throw new IllegalArgumentException + ("IntBox.compare: p_edge_no out of range"); + + } + return result; + } + + /** {@inheritDoc} */ + public Side compare(IntBox p_other, int p_edge_no) + { + return compare(p_other.to_IntOctagon(), p_edge_no); + } + + /** {@inheritDoc} */ + public int border_line_index(Line p_line) + { + System.out.println("edge_index_of_line not yet implemented for octagons"); + return -1; + } + /** + * Calculates the border point of this octagon from p_point into the 45 degree direction p_dir. + * If this border point is not an IntPoint, the nearest outside IntPoint of the octagon is returned. + * + * @param p_point a {@link geometry.planar.IntPoint} object. + * @param p_dir a {@link geometry.planar.FortyfiveDegreeDirection} object. + * @return a {@link geometry.planar.IntPoint} object. + */ + public IntPoint border_point(IntPoint p_point, FortyfiveDegreeDirection p_dir) + { + int result_x; + int result_y; + switch (p_dir) + { + case RIGHT: + result_x = Math.min(rx, urx - p_point.y); + result_x = Math.min(result_x, lrx + p_point.y); + result_y = p_point.y; + break; + case LEFT: + result_x = Math.max(lx, ulx + p_point.y); + result_x = Math.max(result_x, llx - p_point.y); + result_y = p_point.y; + break; + case UP: + result_x = p_point.x; + result_y = Math.min(uy, p_point.x - ulx); + result_y = Math.min(result_y, urx - p_point.x); + break; + case DOWN: + result_x = p_point.x; + result_y = Math.max(ly, llx - p_point.x); + result_y = Math.max(result_y, p_point.x - lrx); + break; + case RIGHT45: + result_x = (int) (Math.ceil(0.5 * (p_point.x - p_point.y + urx))); + result_x = Math.min(result_x, rx); + result_x = Math.min(result_x, p_point.x - p_point.x + uy); + result_y = p_point.y - p_point.x + result_x; + break; + case UP45: + result_x = (int)(Math.floor(0.5 * (p_point.x + p_point.y + ulx))); + result_x = Math.max(result_x, lx); + result_x = Math.max(result_x, p_point.x + p_point.y - uy); + result_y = p_point.y + p_point.x - result_x; + break; + case LEFT45: + result_x = (int)(Math.floor(0.5 * (p_point.x - p_point.y + llx))); + result_x = Math.max(result_x, lx); + result_x = Math.max(result_x, p_point.x - p_point.y + ly); + result_y = p_point.y - p_point.x + result_x; + break; + case DOWN45: + result_x = (int) (Math.ceil(0.5 * (p_point.x + p_point.y + lrx))); + result_x = Math.min(result_x, rx); + result_x = Math.min(result_x, p_point.x + p_point.y - ly); + result_y = p_point.y + p_point.x - result_x; + break; + default: + System.out.println("IntOctagon.border_point: unexpected 45 degree direction"); + result_x = 0; + result_y = 0; + } + return new IntPoint(result_x, result_y); + } + + /** + * Calculates the sorted p_max_result_points nearest points on the + * border of this octagon in the 45-degree directions. + * p_point is assumed to be located in the interiour of this octagon. + * + * @param p_point a {@link geometry.planar.IntPoint} object. + * @param p_max_result_points a int. + * @return an array of {@link geometry.planar.IntPoint} objects. + */ + public IntPoint[] nearest_border_projections(IntPoint p_point, int p_max_result_points) + { + if (!this.contains(p_point) || p_max_result_points <= 0) + { + return new IntPoint[0]; + } + p_max_result_points = Math.min(p_max_result_points, 8); + IntPoint [] result = new IntPoint[p_max_result_points]; + double [] min_dist = new double [p_max_result_points]; + for (int i = 0; i < p_max_result_points; ++i) + { + min_dist[i] = Double.MAX_VALUE; + } + FloatPoint inside_point = p_point.to_float(); + for (FortyfiveDegreeDirection curr_dir : FortyfiveDegreeDirection.values()) + { + IntPoint curr_border_point = border_point(p_point, curr_dir); + double curr_dist = inside_point.distance_square(curr_border_point.to_float()); + for (int i = 0; i < p_max_result_points; ++i) + { + if (curr_dist < min_dist[i]) + { + for (int k = p_max_result_points - 1; k > i; --k) + { + min_dist[k] = min_dist[k - 1]; + result[k] = result[k - 1]; + } + min_dist[i] = curr_dist; + result[i] = curr_border_point; + break; + } + } + } + return result; + } + + Side border_line_side_of( FloatPoint p_point, int p_line_no, double p_tolerance) + { + Side result; + if (p_line_no == 0) + { + if (p_point.y > this.ly + p_tolerance) + { + result = Side.ON_THE_RIGHT; + } + else if (p_point.y < this.ly - p_tolerance) + { + result = Side.ON_THE_LEFT; + } + else + { + result = Side.COLLINEAR; + } + } + else if (p_line_no == 2) + { + if (p_point.x < this.rx - p_tolerance) + { + result = Side.ON_THE_RIGHT; + } + else if (p_point.x > this.rx + p_tolerance) + { + result = Side.ON_THE_LEFT; + } + else + { + result = Side.COLLINEAR; + } + } + else if (p_line_no == 4) + { + if (p_point.y < this.uy - p_tolerance) + { + result = Side.ON_THE_RIGHT; + } + else if (p_point.y > this.uy + p_tolerance ) + { + result = Side.ON_THE_LEFT; + } + else + { + result = Side.COLLINEAR; + } + } + else if (p_line_no == 6) + { + if (p_point.x > this.lx + p_tolerance ) + { + result = Side.ON_THE_RIGHT; + } + else if (p_point.x < this.lx - p_tolerance ) + { + result = Side.ON_THE_LEFT; + } + else + { + result = Side.COLLINEAR; + } + } + else if (p_line_no == 1) + { + double tmp = p_point.y - p_point.x + lrx; + if (tmp > p_tolerance) + // the p_point is above the the lower right border line of this octagon + { + result = Side.ON_THE_RIGHT; + } + else if (tmp < -p_tolerance) + // the p_point is below the the lower right border line of this octagon + { + result = Side.ON_THE_LEFT; + } + else + { + result = Side.COLLINEAR; + } + } + else if (p_line_no == 3) + { + double tmp = p_point.x + p_point.y - urx; + if (tmp < -p_tolerance) + { + // the p_point is below the the upper right border line of this octagon + result = Side.ON_THE_RIGHT; + } + else if (tmp > p_tolerance) + { + // the p_point is above the the upper right border line of this octagon + result = Side.ON_THE_LEFT; + } + else + { + result = Side.COLLINEAR; + } + } + else if (p_line_no == 5) + { + double tmp = p_point.y - p_point.x + ulx; + if (tmp < -p_tolerance) + // the p_point is below the the upper left border line of this octagon + { + result = Side.ON_THE_RIGHT; + } + else if (tmp > p_tolerance) + // the p_point is above the the upper left border line of this octagon + { + result = Side.ON_THE_LEFT; + } + else + { + result = Side.COLLINEAR; + } + } + else if (p_line_no == 7) + { + double tmp = p_point.x + p_point.y - llx; + if (tmp > p_tolerance) + { + // the p_point is above the the lower left border line of this octagon + result = Side.ON_THE_RIGHT; + } + else if (tmp < -p_tolerance) + { + // the p_point is below the the lower left border line of this octagon + result = Side.ON_THE_LEFT; + } + else + { + result = Side.COLLINEAR; + } + } + else + { + System.out.println("IntOctagon.border_line_side_of: p_line_no out of range"); + result = Side.COLLINEAR; + } + return result; + } + + /** + * Checks, if this octagon can be converted to an IntBox. + * + * @return a boolean. + */ + public boolean is_IntBox() + { + if (llx != lx + ly) + return false; + if (lrx != rx - ly) + return false; + if (urx != rx + uy) + return false; + if (ulx != lx - uy) + return false; + return true; + + } + + /** + *

simplify.

+ * + * @return a {@link geometry.planar.TileShape} object. + */ + public TileShape simplify() + { + if (this.is_IntBox()) + { + return this.bounding_box(); + } + return this; + } + + /** + *

cutout.

+ * + * @param p_shape a {@link geometry.planar.TileShape} object. + * @return an array of {@link geometry.planar.TileShape} objects. + */ + public TileShape[] cutout(TileShape p_shape) + { + return p_shape.cutout_from(this); + } + + /** + * Divide p_d minus this octagon into 8 convex pieces, + * from which 4 have cut off a corner. + */ + IntOctagon[] cutout_from(IntBox p_d) + { + IntOctagon c = this.intersection(p_d); + + if (this.is_empty() || c.dimension() < this.dimension()) + { + // there is only an overlap at the border + IntOctagon [] result = new IntOctagon[1]; + result[0] = p_d.to_IntOctagon(); + return result; + } + + IntBox [] boxes = new IntBox[4]; + + // construct left box + + boxes[0] = new IntBox(p_d.ll.x, c.llx - c.lx, c.lx, c.lx - c.ulx); + + // construct right box + + boxes[1] = new IntBox(c.rx, c.rx - c.lrx, p_d.ur.x, c.urx - c.rx); + + // construct lower box + + boxes[2] = new IntBox(c.llx - c.ly, p_d.ll.y, c.lrx + c.ly, c.ly); + + // construct upper box + + boxes[3] = new IntBox(c.ulx + c.uy, c.uy, c.urx - c.uy, p_d.ur.y); + + IntOctagon[] octagons = new IntOctagon[4]; + + // construct upper left octagon + + IntOctagon curr_oct = new IntOctagon(p_d.ll.x, boxes[0].ur.y, boxes[3].ll.x, + p_d.ur.y, -Limits.CRIT_INT, c.ulx, -Limits.CRIT_INT, Limits.CRIT_INT); + octagons[0] = curr_oct.normalize(); + + // construct lower left octagon + + curr_oct = new IntOctagon(p_d.ll.x, p_d.ll.y, boxes[2].ll.x, boxes[0].ll.y, + -Limits.CRIT_INT, Limits.CRIT_INT, -Limits.CRIT_INT, c.llx); + octagons[1] = curr_oct.normalize(); + + // construct lower right octagon + + curr_oct = new IntOctagon(boxes[2].ur.x, p_d.ll.y, p_d.ur.x, boxes[1].ll.y, + c.lrx, Limits.CRIT_INT, -Limits.CRIT_INT, Limits.CRIT_INT); + octagons[2] = curr_oct.normalize(); + + // construct upper right octagon + + curr_oct = new IntOctagon(boxes[3].ur.x, boxes[1].ur.y, p_d.ur.x, p_d.ur.y, + -Limits.CRIT_INT, Limits.CRIT_INT, c.urx, Limits.CRIT_INT); + octagons[3] = curr_oct.normalize(); + + // optimise the result to minimum cumulative circumference + + IntBox b = boxes[0]; + IntOctagon o = octagons[0]; + if (b.ur.x - b.ll.x > o.uy - o.ly) + { + // switch the horizontal upper left divide line to vertical + + boxes[0] = new IntBox(b.ll.x, b.ll.y, b.ur.x, o.uy); + curr_oct = new IntOctagon(b.ur.x, o.ly, o.rx, o.uy, o.ulx, o.lrx, o.llx, o.urx); + octagons[0] = curr_oct.normalize(); + } + + b = boxes[3]; + o = octagons[0]; + if (b.ur.y - b.ll.y > o.rx - o.lx) + { + // switch the vertical upper left divide line to horizontal + + boxes[3] = new IntBox(o.lx, b.ll.y, b.ur.x, b.ur.y); + curr_oct = new IntOctagon(o.lx, o.ly, o.rx, b.ll.y, o.ulx, o.lrx, o.llx, o.urx); + octagons[0] = curr_oct.normalize(); + } + b = boxes[3]; + o = octagons[3]; + if (b.ur.y - b.ll.y > o.rx - o.lx) + { + // switch the vertical upper right divide line to horizontal + + boxes[3] = new IntBox(b.ll.x, b.ll.y, o.rx, b.ur.y); + curr_oct = new IntOctagon(o.lx, o.ly, o.rx, o.uy, o.ulx, o.lrx, o.llx, o.urx); + octagons[3] = curr_oct.normalize(); + } + b = boxes[1]; + o = octagons[3]; + if (b.ur.x - b.ll.x > o.uy - o.ly) + { + // switch the horizontal upper right divide line to vertical + + boxes[1] = new IntBox(b.ll.x, b.ll.y, b.ur.x, o.uy); + curr_oct = new IntOctagon(o.lx, o.ly, b.ll.x, o.uy, o.ulx, o.lrx, o.llx, o.urx); + octagons[3] = curr_oct.normalize(); + } + b = boxes[1]; + o = octagons[2]; + if (b.ur.x - b.ll.x > o.uy - o.ly) + { + // switch the horizontal lower right divide line to vertical + + boxes[1] = new IntBox(b.ll.x, o.ly, b.ur.x, b.ur.y); + curr_oct = new IntOctagon(o.lx, o.ly, b.ll.x, o.uy, o.ulx, o.lrx, o.llx, o.urx); + octagons[2] = curr_oct.normalize(); + } + b = boxes[2]; + o = octagons[2]; + if (b.ur.y - b.ll.y > o.rx - o.lx) + { + // switch the vertical lower right divide line to horizontal + + boxes[2] = new IntBox(b.ll.x, b.ll.y, o.rx, b.ur.y); + curr_oct = new IntOctagon(o.lx, b.ur.y, o.rx, o.uy, o.ulx, o.lrx, o.llx, o.urx); + octagons[2] = curr_oct.normalize(); + } + b = boxes[2]; + o = octagons[1]; + if (b.ur.y - b.ll.y > o.rx - o.lx) + { + // switch the vertical lower left divide line to horizontal + + boxes[2] = new IntBox(o.lx, b.ll.y, b.ur.x, b.ur.y); + curr_oct = new IntOctagon(o.lx, b.ur.y, o.rx, o.uy, o.ulx, o.lrx, o.llx, o.urx); + octagons[1] = curr_oct.normalize(); + } + b = boxes[0]; + o = octagons[1]; + if (b.ur.x - b.ll.x > o.uy - o.ly) + { + // switch the horizontal lower left divide line to vertical + boxes[0] = new IntBox(b.ll.x, o.ly, b.ur.x, b.ur.y); + curr_oct = new IntOctagon(b.ur.x, o.ly, o.rx, o.uy, o.ulx, o.lrx, o.llx, o.urx); + octagons[1] = curr_oct.normalize(); + } + + IntOctagon[] result = new IntOctagon[8]; + + // add the 4 boxes to the result + for (int i = 0; i < 4; ++i) + { + result[i] = boxes[i].to_IntOctagon(); + } + + // add the 4 octagons to the result + for (int i = 0; i < 4; ++i) + { + result[4 + i] = octagons[i]; + } + return result; + } + + /** + * Divide p_divide_octagon minus cut_octagon into 8 convex + * pieces without sharp angles. + */ + IntOctagon[] cutout_from(IntOctagon p_d) + { + IntOctagon c = this.intersection(p_d); + + if (this.is_empty() || c.dimension() < this.dimension()) + { + // there is only an overlap at the border + IntOctagon [] result = new IntOctagon[1]; + result[0] = p_d; + return result; + } + + IntOctagon [] result = new IntOctagon[8]; + + int tmp = c.llx - c.lx; + + result[0] = new + IntOctagon(p_d.lx, tmp, c.lx, c.lx - c.ulx, p_d.ulx, p_d.lrx, p_d.llx, p_d.urx); + + int tmp2 = c.llx - c.ly; + + result[1] = new + IntOctagon(p_d.lx, p_d.ly, tmp2, tmp, p_d.ulx, p_d.lrx, p_d.llx, c.llx); + + tmp = c.lrx + c.ly; + + result[2] = new + IntOctagon(tmp2, p_d.ly, tmp, c.ly, p_d.ulx, p_d.lrx, p_d.llx, p_d.urx); + + tmp2 = c.rx - c.lrx; + + result[3] = new + IntOctagon(tmp, p_d.ly, p_d.rx, tmp2, c.lrx, p_d.lrx, p_d.llx, p_d.urx); + + tmp = c.urx - c.rx; + + result[4] = new + IntOctagon(c.rx, tmp2, p_d.rx, tmp, p_d.ulx, p_d.lrx, p_d.llx, p_d.urx); + + tmp2 = c.urx - c.uy; + + result[5] = new + IntOctagon(tmp2, tmp, p_d.rx, p_d.uy, p_d.ulx, p_d.lrx, c.urx, p_d.urx); + + tmp = c.ulx + c.uy; + + result[6] = new + IntOctagon(tmp, c.uy, tmp2, p_d.uy, p_d.ulx, p_d.lrx, p_d.llx, p_d.urx); + + tmp2 = c.lx - c.ulx; + + result[7] = new + IntOctagon(p_d.lx, tmp2, tmp, p_d.uy, p_d.ulx, c.ulx, p_d.llx, p_d.urx); + + for (int i = 0; i < 8; ++i) + { + result[i] = result[i].normalize(); + } + + IntOctagon curr_1 = result[0]; + IntOctagon curr_2 = result[7]; + + if (!(curr_1.is_empty() || curr_2.is_empty()) && + curr_1.rx - curr_1.left_x_value(curr_1.uy) + > curr_2.upper_y_value(curr_1.rx) - curr_2.ly) + { + // switch the horizontal upper left divide line to vertical + curr_1 = new IntOctagon(Math.min(curr_1.lx, curr_2.lx), curr_1.ly, + curr_1.rx, curr_2.uy, curr_2.ulx, curr_1.lrx,curr_1.llx, curr_2.urx); + + curr_2 = new IntOctagon(curr_1.rx, curr_2.ly, curr_2.rx, curr_2.uy, + curr_2.ulx, curr_2.lrx, curr_2.llx, curr_2.urx); + + result[0] = curr_1.normalize(); + result[7] = curr_2.normalize(); + } + curr_1 = result[7]; + curr_2 = result[6]; + if (!(curr_1.is_empty() || curr_2.is_empty()) && + curr_2.upper_y_value(curr_1.rx) - curr_2.ly + > curr_1.rx - curr_1.left_x_value(curr_2.ly)) + // switch the vertical upper left divide line to horizontal + { + curr_2 = new IntOctagon(curr_1.lx, curr_2.ly, curr_2.rx, + Math.max(curr_2.uy, curr_1.uy), curr_1.ulx, curr_2.lrx, curr_1.llx, curr_2.urx); + + curr_1 = new IntOctagon(curr_1.lx, curr_1.ly, curr_1.rx, curr_2.ly, + curr_1.ulx, curr_1.lrx, curr_1.llx, curr_1.urx); + + result[7] = curr_1.normalize(); + result[6] = curr_2.normalize(); + } + curr_1 = result[6]; + curr_2 = result[5]; + if (!(curr_1.is_empty() || curr_2.is_empty()) && + curr_2.upper_y_value(curr_1.rx) - curr_1.ly + > curr_2.right_x_value(curr_1.ly) - curr_2.lx) + // switch the vertical upper right divide line to horizontal + { + curr_1 = new IntOctagon(curr_1.lx, curr_1.ly, curr_2.rx, + Math.max(curr_2.uy, curr_1.uy), curr_1.ulx, curr_2.lrx, curr_1.llx, curr_2.urx); + + curr_2 = new IntOctagon(curr_2.lx, curr_2.ly, curr_2.rx, curr_1.ly, + curr_2.ulx, curr_2.lrx, curr_2.llx, curr_2.urx); + + result[6] = curr_1.normalize(); + result[5] = curr_2.normalize(); + } + curr_1 = result[5]; + curr_2 = result[4]; + if (!(curr_1.is_empty() || curr_2.is_empty()) && + curr_2.right_x_value(curr_2.uy) - curr_2.lx + > curr_1.upper_y_value(curr_2.lx) - curr_2.uy) + // switch the horizontal upper right divide line to vertical + { + curr_2 = new IntOctagon(curr_2.lx, curr_2.ly, Math.max(curr_2.rx, curr_1.rx), + curr_1.uy, curr_1.ulx, curr_2.lrx, curr_2.llx, curr_1.urx); + + curr_1 = new IntOctagon(curr_1.lx, curr_1.ly, curr_2.lx, curr_1.uy, + curr_1.ulx, curr_1.lrx, curr_1.llx, curr_1.urx); + + result[5] = curr_1.normalize(); + result[4] = curr_2.normalize(); + } + curr_1 = result[4]; + curr_2 = result[3]; + if (!(curr_1.is_empty() || curr_2.is_empty()) && + curr_1.right_x_value(curr_1.ly) - curr_1.lx + > curr_1.ly - curr_2.lower_y_value(curr_1.lx)) + // switch the horizontal lower right divide line to vertical + { + curr_1 = new IntOctagon(curr_1.lx, curr_2.ly, Math.max(curr_2.rx, curr_1.rx), + curr_1.uy, curr_1.ulx, curr_2.lrx, curr_2.llx, curr_1.urx); + + curr_2 = new IntOctagon(curr_2.lx, curr_2.ly, curr_1.lx, curr_2.uy, + curr_2.ulx, curr_2.lrx, curr_2.llx, curr_2.urx); + + result[4] = curr_1.normalize(); + result[3] = curr_2.normalize(); + } + + curr_1 = result[3]; + curr_2 = result[2]; + + if (!(curr_1.is_empty() || curr_2.is_empty()) && + curr_2.uy - curr_2.lower_y_value(curr_2.rx) + > curr_1.right_x_value(curr_2.uy) - curr_2.rx) + // switch the vertical lower right divide line to horizontal + { + curr_2 = new IntOctagon(curr_2.lx, Math.min(curr_1.ly, curr_2.ly), + curr_1.rx, curr_2.uy, curr_2.ulx, curr_1.lrx, curr_2.llx, curr_1.urx); + + curr_1 = new IntOctagon(curr_1.lx, curr_2.uy, curr_1.rx, curr_1.uy, + curr_1.ulx, curr_1.lrx, curr_1.llx, curr_1.urx); + + result[3] = curr_1.normalize(); + result[2] = curr_2.normalize(); + } + + curr_1 = result[2]; + curr_2 = result[1]; + + if (!(curr_1.is_empty() || curr_2.is_empty()) && + curr_1.uy - curr_1.lower_y_value(curr_1.lx) + > curr_1.lx - curr_2.left_x_value(curr_1.uy)) + // switch the vertical lower left divide line to horizontal + { + curr_1 = new IntOctagon(curr_2.lx, Math.min(curr_1.ly, curr_2.ly), + curr_1.rx, curr_1.uy, curr_2.ulx, curr_1.lrx, curr_2.llx, curr_1.urx); + + curr_2 = new IntOctagon(curr_2.lx, curr_1.uy, curr_2.rx, curr_2.uy, + curr_2.ulx, curr_2.lrx, curr_2.llx, curr_2.urx); + + result[2] = curr_1.normalize(); + result[1] = curr_2.normalize(); + } + + curr_1 = result[1]; + curr_2 = result[0]; + + if (!(curr_1.is_empty() || curr_2.is_empty()) && + curr_2.rx - curr_2.left_x_value(curr_2.ly) + > curr_2.ly - curr_1.lower_y_value(curr_2.rx)) + // switch the horizontal lower left divide line to vertical + { + curr_2 = new IntOctagon(Math.min(curr_2.lx, curr_1.lx), curr_1.ly, + curr_2.rx, curr_2.uy, curr_2.ulx, curr_1.lrx, curr_1.llx, curr_2.urx); + + curr_1 = new IntOctagon(curr_2.rx, curr_1.ly, curr_1.rx, curr_1.uy, + curr_1.ulx, curr_1.lrx, curr_1.llx, curr_1.urx); + + result[1] = curr_1.normalize(); + result[0] = curr_2.normalize(); + } + + return result; + } + + + Simplex[] cutout_from(Simplex p_simplex) + { + return this.to_Simplex().cutout_from(p_simplex); + } + + /** + * x coordinate of the left border line + */ + public final int lx; + + /** + * y coordinate of the lower border line + */ + public final int ly; + + /** + * x coordinate of the right border line + */ + public final int rx; + + /** + * y coordinate of the upper border line + */ + public final int uy; + + /** + * x axis intersection of the upper left border line + */ + public final int ulx; + + /** + * x axis intersection of the lower right border line + */ + public final int lrx; + + /** + * x axis intersection of the lower left border line + */ + public final int llx; + + /** + * x axis intersection of the upper right border line + */ + public final int urx; + + /** + * Result of to_simplex() memorized for performance reasons. + */ + private Simplex precalculated_to_simplex = null; + +} diff --git a/geometry/planar/IntPoint.java b/src/main/java/geometry/planar/IntPoint.java similarity index 87% rename from geometry/planar/IntPoint.java rename to src/main/java/geometry/planar/IntPoint.java index 3182367..476fa19 100644 --- a/geometry/planar/IntPoint.java +++ b/src/main/java/geometry/planar/IntPoint.java @@ -1,534 +1,605 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * IntPoint.java - * - * Created on 1. Februar 2003, 10:31 - */ - -package geometry.planar; - -import java.math.BigInteger; - -/** - * Implementation of the abstract class Point - * as a tuple of integers. - * - * - * @author Alfons Wirtz - */ - -public class IntPoint extends Point implements java.io.Serializable -{ - - /** - * create an IntPoint from two integer coordinates - */ - public IntPoint(int p_x, int p_y) - { - if (Math.abs(p_x) > Limits.CRIT_INT || Math.abs(p_y) > Limits.CRIT_INT) - { - System.out.println("Warning in IntPoint: p_x or p_y to big"); - } - x = p_x; - y = p_y; - } - - /** - * Returns true, if this IntPoint is equal to p_ob - */ - public final boolean equals( Object p_ob ) - { - if ( this == p_ob ) - { - return true; - } - if ( p_ob == null ) - { - return false; - } - if ( getClass() != p_ob.getClass() ) - { - return false ; - } - IntPoint other = (IntPoint)p_ob ; - return ( x == other.x && y == other.y ) ; - } - - public boolean is_infinite() - { - return false; - } - - public IntBox surrounding_box() - { - return new IntBox(this, this); - } - - public IntOctagon surrounding_octagon() - { - int tmp_1 = x - y; - int tmp_2 = x + y; - - return new IntOctagon(x, y, x, y, tmp_1, tmp_1, tmp_2, tmp_2); - } - - public boolean is_contained_in(IntBox p_box) - { - return x >= p_box.ll.x && y >= p_box.ll.y - && x <= p_box.ur.x && y <= p_box.ur.y; - } - - /** - * returns the translation of this point by p_vector - */ - public final Point translate_by( Vector p_vector ) - { - if (p_vector.equals(Vector.ZERO)) - { - return this; - } - return p_vector.add_to(this) ; - } - - Point translate_by( IntVector p_vector ) - { - return ( new IntPoint( x + p_vector.x, y + p_vector.y ) ) ; - } - - Point translate_by( RationalVector p_vector ) - { - return p_vector.add_to(this); - } - - - /** - * returns the difference vector of this point and p_other - */ - public Vector difference_by(Point p_other) - { - Vector tmp = p_other.difference_by(this); - return tmp.negate(); - } - - Vector difference_by(RationalPoint p_other) - { - Vector tmp = p_other.difference_by(this); - return tmp.negate(); - } - - IntVector difference_by(IntPoint p_other) - { - return new IntVector(x - p_other.x, y - p_other.y); - } - - public Side side_of(Line p_line) - { - Vector v1 = difference_by(p_line.a); - Vector v2 = p_line.b.difference_by(p_line.a); - return v1.side_of(v2); - } - - /** - * converts this point to a FloatPoint. - */ - public FloatPoint to_float() - { - return new FloatPoint(x, y); - } - - /** - * returns the determinant of the vectors (x, y) and (p_other.x, p_other.y) - */ - public final long determinant(IntPoint p_other) - { - return (long)x * p_other.y - (long)y * p_other.x; - } - - - public Point perpendicular_projection(Line p_line) - { - // this function is at the moment only implemented for lines - // consisting of IntPoints. - // The general implementation is still missing. - IntVector v = (IntVector)p_line.b.difference_by(p_line.a); - BigInteger vxvx = BigInteger.valueOf((long)v.x * v.x); - BigInteger vyvy = BigInteger.valueOf((long)v.y * v.y); - BigInteger vxvy = BigInteger.valueOf((long) v.x * v.y); - BigInteger denominator = vxvx.add(vyvy); - BigInteger det = - BigInteger.valueOf(((IntPoint)p_line.a).determinant((IntPoint)p_line.b)); - BigInteger point_x = BigInteger.valueOf(x); - BigInteger point_y = BigInteger.valueOf(y); - - BigInteger tmp1 = vxvx.multiply(point_x); - BigInteger tmp2 = vxvy.multiply(point_y); - tmp1 = tmp1.add(tmp2); - tmp2 = det.multiply(BigInteger.valueOf(v.y)); - BigInteger proj_x = tmp1.add(tmp2); - - tmp1 = vxvy.multiply(point_x); - tmp2 = vyvy.multiply(point_y); - tmp1 = tmp1.add(tmp2); - tmp2 = det.multiply(BigInteger.valueOf(v.x)); - BigInteger proj_y = tmp1.subtract(tmp2); - - int signum = denominator.signum(); - if (signum != 0) - { - if (signum < 0) - { - denominator = denominator.negate(); - proj_x = proj_x.negate(); - proj_y = proj_y.negate(); - } - if ((proj_x.mod(denominator)).signum() == 0 && - (proj_y.mod(denominator)).signum() == 0) - { - proj_x = proj_x.divide(denominator); - proj_y = proj_y.divide(denominator); - return new IntPoint(proj_x.intValue(), proj_y.intValue()); - } - } - return new RationalPoint(proj_x, proj_y, denominator); - } - - /** - * Returns the signed area of the parallelogramm spanned by the vectors - * p_2 - p_1 and this - p_1 - */ - public double signed_area( IntPoint p_1, IntPoint p_2 ) - { - IntVector d21 = (IntVector) p_2.difference_by(p_1) ; - IntVector d01 = (IntVector) this.difference_by(p_1) ; - return d21.determinant(d01) ; - } - - /** - * calculates the square of the distance between this point and p_to_point - */ - public double distance_square(IntPoint p_to_point) - { - double dx = p_to_point.x - this.x; - double dy = p_to_point.y - this.y; - return dx * dx + dy * dy; - } - - /** - * calculates the distance between this point and p_to_point - */ - public double distance(IntPoint p_to_point) - { - return Math.sqrt(distance_square(p_to_point)); - } - - /** - * Calculates the nearest point to this point on the horizontal or - * vertical line through p_other (Snaps this point to on ortogonal line - * through p_other). - */ - public IntPoint orthogonal_projection(IntPoint p_other) - { - IntPoint result; - int horizontal_distance = Math.abs(this.x -p_other.x); - int vertical_distance = Math.abs(this.y -p_other.y); - if (horizontal_distance <= vertical_distance) - { - // projection onto the vertical line through p_other - result = new IntPoint(p_other.x, this.y); - } - else - { - // projection onto the horizontal line through p_other - result = new IntPoint(this.x, p_other.y); - } - return result; - } - - /** - * Calculates the nearest point to this point on an orthogonal or - * diagonal line through p_other (Snaps this point to on 45 degree line - * through p_other). - */ - public IntPoint fortyfive_degree_projection(IntPoint p_other) - { - int dx = this.x -p_other.x; - int dy = this.y -p_other.y; - double[] dist_arr = new double[4]; - dist_arr[0] = Math.abs(dx); - dist_arr[1] = Math.abs(dy); - double diagonal_1 = ((double)dy - (double)dx) / 2; - double diagonal_2 = ((double)dy + (double)dx) / 2; - dist_arr[2] = Math.abs(diagonal_1); - dist_arr[3] = Math.abs(diagonal_2); - double min_dist = dist_arr[0]; - for (int i = 1; i < 4; ++i) - { - if (dist_arr[i] < min_dist) - { - min_dist = dist_arr[i]; - } - } - IntPoint result; - if (min_dist == dist_arr[0]) - { - // projection onto the vertical line through p_other - result = new IntPoint(p_other.x, this.y); - } - else if (min_dist == dist_arr[1]) - { - // projection onto the horizontal line through p_other - result = new IntPoint(this.x, p_other.y); - } - else if (min_dist == dist_arr[2]) - { - // projection onto the right diagonal line through p_other - int diagonal_value = (int)diagonal_2; - result = new IntPoint(p_other.x + diagonal_value, p_other.y + diagonal_value); - } - else - { - // projection onto the left diagonal line through p_other - int diagonal_value = (int)diagonal_1; - result = new IntPoint(p_other.x - diagonal_value, p_other.y + diagonal_value); - } - return result; - } - - /** - * Calculates a corner point p so that the lines through this point and p and from - * p to p_to_point are multiples of 45 degree, and that the angle at p will be - * 45 degree. If p_left_turn, p_to_point will be on the left of the line - * from this point to p, else on the right. - * Returns null, if the line from this point to p_to_point is already a multiple - * of 45 degree. - */ - public IntPoint fortyfive_degree_corner( IntPoint p_to_point, boolean p_left_turn) - { - int dx = p_to_point.x - this.x; - int dy = p_to_point.y - this.y; - IntPoint result; - - // handle the 8 sections between the 45 degree lines - - if (dy > 0 && dy < dx) - { - if (p_left_turn) - { - result = new IntPoint(p_to_point.x - dy, this.y); - } - else - { - result = new IntPoint(this.x + dy, p_to_point.y); - } - } - else if (dx > 0 && dy > dx) - { - if (p_left_turn) - { - result = new IntPoint(p_to_point.x, this.y + dx); - } - else - { - result = new IntPoint(this.x, p_to_point.y - dx); - } - } - else if (dx < 0 && dy > -dx) - { - if (p_left_turn) - { - result = new IntPoint(this.x, p_to_point.y + dx); - } - else - { - result = new IntPoint(p_to_point.x, this.y - dx); - } - } - else if (dy > 0 && dy < -dx) - { - if (p_left_turn) - { - result = new IntPoint(this.x - dy, p_to_point.y); - } - else - { - result = new IntPoint(p_to_point.x + dy, this.y); - } - } - else if (dy < 0 && dy > dx) - { - if (p_left_turn) - { - result = new IntPoint(p_to_point.x - dy, this.y); - } - else - { - result = new IntPoint(this.x + dy, p_to_point.y); - } - } - else if (dx < 0 && dy < dx) - { - if (p_left_turn) - { - result = new IntPoint(p_to_point.x, this.y + dx); - } - else - { - result = new IntPoint(this.x, p_to_point.y - dx); - } - } - else if (dx > 0 && dy < -dx) - { - if (p_left_turn) - { - result = new IntPoint(this.x, p_to_point.y + dx); - } - else - { - result = new IntPoint(p_to_point.x, this.y - dx); - } - } - else if (dy < 0 && dy > -dx) - { - if (p_left_turn) - { - result = new IntPoint(this.x - dy, p_to_point.y); - } - else - { - result = new IntPoint(p_to_point.x + dy, this.y); - } - } - else - { - // the line from this point to p_to_point is already a multiple of 45 degree - result = null; - } - return result; - } - - /** - * Calculates a corner point p so that the lines through this point and p and from - * p to p_to_point are hprizontal or vertical, and that the angle at p will be - * 90 degree. If p_left_turn, p_to_point will be on the left of the line - * from this point to p, else on the right. - * Returns null, if the line from this point to p_to_point is already orthogonal. - */ - public IntPoint ninety_degree_corner( IntPoint p_to_point, boolean p_left_turn) - { - int dx = p_to_point.x - this.x; - int dy = p_to_point.y - this.y; - IntPoint result; - - // handle the 4 quadrants - - if (dx > 0 && dy > 0 || dx < 0 && dy < 0) - { - if (p_left_turn) - { - result = new IntPoint(p_to_point.x, this.y); - } - else - { - result = new IntPoint(this.x, p_to_point.y); - } - } - else if (dx < 0 && dy > 0 || dx > 0 && dy < 0) - { - if (p_left_turn) - { - result = new IntPoint(this.x, p_to_point.y); - } - else - { - result = new IntPoint(p_to_point.x, this.y); - } - } - else - { - //the line from this point to p_to_point is already orthogonal - result = null; - } - return result; - } - - public int compare_x(Point p_other) - { - return -p_other.compare_x(this); - } - - public int compare_y(Point p_other) - { - return -p_other.compare_y(this); - } - - - int compare_x(IntPoint p_other) - { - int result; - if (this.x > p_other.x) - { - result = 1; - } - else if (this.x == p_other.x) - { - result = 0; - } - else - { - result = -1; - } - return result; - } - - int compare_y(IntPoint p_other) - { - int result; - if (this.y > p_other.y) - { - result = 1; - } - else if (this.y == p_other.y) - { - result = 0; - } - else - { - result = -1; - } - return result; - } - - int compare_x(RationalPoint p_other) - { - return -p_other.compare_x(this); - } - - int compare_y(RationalPoint p_other) - { - return -p_other.compare_y(this); - } - - /** - * the x coordinate of this point - */ - public final int x; - - /** - * the y coordinate of this point - */ - public final int y; -} - +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * IntPoint.java + * + * Created on 1. Februar 2003, 10:31 + */ + +package geometry.planar; + +import java.math.BigInteger; + +/** + * Implementation of the abstract class Point + * as a tuple of integers. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class IntPoint extends Point implements java.io.Serializable +{ + + /** + * create an IntPoint from two integer coordinates + * + * @param p_x a int. + * @param p_y a int. + */ + public IntPoint(int p_x, int p_y) + { + if (Math.abs(p_x) > Limits.CRIT_INT || Math.abs(p_y) > Limits.CRIT_INT) + { + System.out.println("Warning in IntPoint: p_x or p_y to big"); + } + x = p_x; + y = p_y; + } + + /** + * {@inheritDoc} + * + * Returns true, if this IntPoint is equal to p_ob + */ + public final boolean equals( Object p_ob ) + { + if ( this == p_ob ) + { + return true; + } + if ( p_ob == null ) + { + return false; + } + if ( getClass() != p_ob.getClass() ) + { + return false ; + } + IntPoint other = (IntPoint)p_ob ; + return ( x == other.x && y == other.y ) ; + } + + /** + *

is_infinite.

+ * + * @return a boolean. + */ + public boolean is_infinite() + { + return false; + } + + /** + *

surrounding_box.

+ * + * @return a {@link geometry.planar.IntBox} object. + */ + public IntBox surrounding_box() + { + return new IntBox(this, this); + } + + /** + *

surrounding_octagon.

+ * + * @return a {@link geometry.planar.IntOctagon} object. + */ + public IntOctagon surrounding_octagon() + { + int tmp_1 = x - y; + int tmp_2 = x + y; + + return new IntOctagon(x, y, x, y, tmp_1, tmp_1, tmp_2, tmp_2); + } + + /** {@inheritDoc} */ + public boolean is_contained_in(IntBox p_box) + { + return x >= p_box.ll.x && y >= p_box.ll.y + && x <= p_box.ur.x && y <= p_box.ur.y; + } + + /** + * {@inheritDoc} + * + * returns the translation of this point by p_vector + * + * @param p_vector a {@link geometry.planar.Vector} object. + * @return a {@link geometry.planar.Point} object. + */ + public final Point translate_by( Vector p_vector ) + { + if (p_vector.equals(Vector.ZERO)) + { + return this; + } + return p_vector.add_to(this) ; + } + + Point translate_by( IntVector p_vector ) + { + return ( new IntPoint( x + p_vector.x, y + p_vector.y ) ) ; + } + + Point translate_by( RationalVector p_vector ) + { + return p_vector.add_to(this); + } + + + /** + * returns the difference vector of this point and p_other + * + * @param p_other a {@link geometry.planar.Point} object. + * @return a {@link geometry.planar.Vector} object. + */ + public Vector difference_by(Point p_other) + { + Vector tmp = p_other.difference_by(this); + return tmp.negate(); + } + + Vector difference_by(RationalPoint p_other) + { + Vector tmp = p_other.difference_by(this); + return tmp.negate(); + } + + IntVector difference_by(IntPoint p_other) + { + return new IntVector(x - p_other.x, y - p_other.y); + } + + /** {@inheritDoc} */ + public Side side_of(Line p_line) + { + Vector v1 = difference_by(p_line.a); + Vector v2 = p_line.b.difference_by(p_line.a); + return v1.side_of(v2); + } + + /** + * converts this point to a FloatPoint. + * + * @return a {@link geometry.planar.FloatPoint} object. + */ + public FloatPoint to_float() + { + return new FloatPoint(x, y); + } + + /** + * returns the determinant of the vectors (x, y) and (p_other.x, p_other.y) + * + * @param p_other a {@link geometry.planar.IntPoint} object. + * @return a long. + */ + public final long determinant(IntPoint p_other) + { + return (long)x * p_other.y - (long)y * p_other.x; + } + + + /** {@inheritDoc} */ + public Point perpendicular_projection(Line p_line) + { + // this function is at the moment only implemented for lines + // consisting of IntPoints. + // The general implementation is still missing. + IntVector v = (IntVector)p_line.b.difference_by(p_line.a); + BigInteger vxvx = BigInteger.valueOf((long)v.x * v.x); + BigInteger vyvy = BigInteger.valueOf((long)v.y * v.y); + BigInteger vxvy = BigInteger.valueOf((long) v.x * v.y); + BigInteger denominator = vxvx.add(vyvy); + BigInteger det = + BigInteger.valueOf(((IntPoint)p_line.a).determinant((IntPoint)p_line.b)); + BigInteger point_x = BigInteger.valueOf(x); + BigInteger point_y = BigInteger.valueOf(y); + + BigInteger tmp1 = vxvx.multiply(point_x); + BigInteger tmp2 = vxvy.multiply(point_y); + tmp1 = tmp1.add(tmp2); + tmp2 = det.multiply(BigInteger.valueOf(v.y)); + BigInteger proj_x = tmp1.add(tmp2); + + tmp1 = vxvy.multiply(point_x); + tmp2 = vyvy.multiply(point_y); + tmp1 = tmp1.add(tmp2); + tmp2 = det.multiply(BigInteger.valueOf(v.x)); + BigInteger proj_y = tmp1.subtract(tmp2); + + int signum = denominator.signum(); + if (signum != 0) + { + if (signum < 0) + { + denominator = denominator.negate(); + proj_x = proj_x.negate(); + proj_y = proj_y.negate(); + } + if ((proj_x.mod(denominator)).signum() == 0 && + (proj_y.mod(denominator)).signum() == 0) + { + proj_x = proj_x.divide(denominator); + proj_y = proj_y.divide(denominator); + return new IntPoint(proj_x.intValue(), proj_y.intValue()); + } + } + return new RationalPoint(proj_x, proj_y, denominator); + } + + /** + * Returns the signed area of the parallelogramm spanned by the vectors + * p_2 - p_1 and this - p_1 + * + * @param p_1 a {@link geometry.planar.IntPoint} object. + * @param p_2 a {@link geometry.planar.IntPoint} object. + * @return a double. + */ + public double signed_area( IntPoint p_1, IntPoint p_2 ) + { + IntVector d21 = (IntVector) p_2.difference_by(p_1) ; + IntVector d01 = (IntVector) this.difference_by(p_1) ; + return d21.determinant(d01) ; + } + + /** + * calculates the square of the distance between this point and p_to_point + * + * @param p_to_point a {@link geometry.planar.IntPoint} object. + * @return a double. + */ + public double distance_square(IntPoint p_to_point) + { + double dx = p_to_point.x - this.x; + double dy = p_to_point.y - this.y; + return dx * dx + dy * dy; + } + + /** + * calculates the distance between this point and p_to_point + * + * @param p_to_point a {@link geometry.planar.IntPoint} object. + * @return a double. + */ + public double distance(IntPoint p_to_point) + { + return Math.sqrt(distance_square(p_to_point)); + } + + /** + * Calculates the nearest point to this point on the horizontal or + * vertical line through p_other (Snaps this point to on ortogonal line + * through p_other). + * + * @param p_other a {@link geometry.planar.IntPoint} object. + * @return a {@link geometry.planar.IntPoint} object. + */ + public IntPoint orthogonal_projection(IntPoint p_other) + { + IntPoint result; + int horizontal_distance = Math.abs(this.x -p_other.x); + int vertical_distance = Math.abs(this.y -p_other.y); + if (horizontal_distance <= vertical_distance) + { + // projection onto the vertical line through p_other + result = new IntPoint(p_other.x, this.y); + } + else + { + // projection onto the horizontal line through p_other + result = new IntPoint(this.x, p_other.y); + } + return result; + } + + /** + * Calculates the nearest point to this point on an orthogonal or + * diagonal line through p_other (Snaps this point to on 45 degree line + * through p_other). + * + * @param p_other a {@link geometry.planar.IntPoint} object. + * @return a {@link geometry.planar.IntPoint} object. + */ + public IntPoint fortyfive_degree_projection(IntPoint p_other) + { + int dx = this.x -p_other.x; + int dy = this.y -p_other.y; + double[] dist_arr = new double[4]; + dist_arr[0] = Math.abs(dx); + dist_arr[1] = Math.abs(dy); + double diagonal_1 = ((double)dy - (double)dx) / 2; + double diagonal_2 = ((double)dy + (double)dx) / 2; + dist_arr[2] = Math.abs(diagonal_1); + dist_arr[3] = Math.abs(diagonal_2); + double min_dist = dist_arr[0]; + for (int i = 1; i < 4; ++i) + { + if (dist_arr[i] < min_dist) + { + min_dist = dist_arr[i]; + } + } + IntPoint result; + if (min_dist == dist_arr[0]) + { + // projection onto the vertical line through p_other + result = new IntPoint(p_other.x, this.y); + } + else if (min_dist == dist_arr[1]) + { + // projection onto the horizontal line through p_other + result = new IntPoint(this.x, p_other.y); + } + else if (min_dist == dist_arr[2]) + { + // projection onto the right diagonal line through p_other + int diagonal_value = (int)diagonal_2; + result = new IntPoint(p_other.x + diagonal_value, p_other.y + diagonal_value); + } + else + { + // projection onto the left diagonal line through p_other + int diagonal_value = (int)diagonal_1; + result = new IntPoint(p_other.x - diagonal_value, p_other.y + diagonal_value); + } + return result; + } + + /** + * Calculates a corner point p so that the lines through this point and p and from + * p to p_to_point are multiples of 45 degree, and that the angle at p will be + * 45 degree. If p_left_turn, p_to_point will be on the left of the line + * from this point to p, else on the right. + * Returns null, if the line from this point to p_to_point is already a multiple + * of 45 degree. + * + * @param p_to_point a {@link geometry.planar.IntPoint} object. + * @param p_left_turn a boolean. + * @return a {@link geometry.planar.IntPoint} object. + */ + public IntPoint fortyfive_degree_corner( IntPoint p_to_point, boolean p_left_turn) + { + int dx = p_to_point.x - this.x; + int dy = p_to_point.y - this.y; + IntPoint result; + + // handle the 8 sections between the 45 degree lines + + if (dy > 0 && dy < dx) + { + if (p_left_turn) + { + result = new IntPoint(p_to_point.x - dy, this.y); + } + else + { + result = new IntPoint(this.x + dy, p_to_point.y); + } + } + else if (dx > 0 && dy > dx) + { + if (p_left_turn) + { + result = new IntPoint(p_to_point.x, this.y + dx); + } + else + { + result = new IntPoint(this.x, p_to_point.y - dx); + } + } + else if (dx < 0 && dy > -dx) + { + if (p_left_turn) + { + result = new IntPoint(this.x, p_to_point.y + dx); + } + else + { + result = new IntPoint(p_to_point.x, this.y - dx); + } + } + else if (dy > 0 && dy < -dx) + { + if (p_left_turn) + { + result = new IntPoint(this.x - dy, p_to_point.y); + } + else + { + result = new IntPoint(p_to_point.x + dy, this.y); + } + } + else if (dy < 0 && dy > dx) + { + if (p_left_turn) + { + result = new IntPoint(p_to_point.x - dy, this.y); + } + else + { + result = new IntPoint(this.x + dy, p_to_point.y); + } + } + else if (dx < 0 && dy < dx) + { + if (p_left_turn) + { + result = new IntPoint(p_to_point.x, this.y + dx); + } + else + { + result = new IntPoint(this.x, p_to_point.y - dx); + } + } + else if (dx > 0 && dy < -dx) + { + if (p_left_turn) + { + result = new IntPoint(this.x, p_to_point.y + dx); + } + else + { + result = new IntPoint(p_to_point.x, this.y - dx); + } + } + else if (dy < 0 && dy > -dx) + { + if (p_left_turn) + { + result = new IntPoint(this.x - dy, p_to_point.y); + } + else + { + result = new IntPoint(p_to_point.x + dy, this.y); + } + } + else + { + // the line from this point to p_to_point is already a multiple of 45 degree + result = null; + } + return result; + } + + /** + * Calculates a corner point p so that the lines through this point and p and from + * p to p_to_point are hprizontal or vertical, and that the angle at p will be + * 90 degree. If p_left_turn, p_to_point will be on the left of the line + * from this point to p, else on the right. + * Returns null, if the line from this point to p_to_point is already orthogonal. + * + * @param p_to_point a {@link geometry.planar.IntPoint} object. + * @param p_left_turn a boolean. + * @return a {@link geometry.planar.IntPoint} object. + */ + public IntPoint ninety_degree_corner( IntPoint p_to_point, boolean p_left_turn) + { + int dx = p_to_point.x - this.x; + int dy = p_to_point.y - this.y; + IntPoint result; + + // handle the 4 quadrants + + if (dx > 0 && dy > 0 || dx < 0 && dy < 0) + { + if (p_left_turn) + { + result = new IntPoint(p_to_point.x, this.y); + } + else + { + result = new IntPoint(this.x, p_to_point.y); + } + } + else if (dx < 0 && dy > 0 || dx > 0 && dy < 0) + { + if (p_left_turn) + { + result = new IntPoint(this.x, p_to_point.y); + } + else + { + result = new IntPoint(p_to_point.x, this.y); + } + } + else + { + //the line from this point to p_to_point is already orthogonal + result = null; + } + return result; + } + + /** + *

compare_x.

+ * + * @param p_other a {@link geometry.planar.Point} object. + * @return a int. + */ + public int compare_x(Point p_other) + { + return -p_other.compare_x(this); + } + + /** + *

compare_y.

+ * + * @param p_other a {@link geometry.planar.Point} object. + * @return a int. + */ + public int compare_y(Point p_other) + { + return -p_other.compare_y(this); + } + + + int compare_x(IntPoint p_other) + { + int result; + if (this.x > p_other.x) + { + result = 1; + } + else if (this.x == p_other.x) + { + result = 0; + } + else + { + result = -1; + } + return result; + } + + int compare_y(IntPoint p_other) + { + int result; + if (this.y > p_other.y) + { + result = 1; + } + else if (this.y == p_other.y) + { + result = 0; + } + else + { + result = -1; + } + return result; + } + + int compare_x(RationalPoint p_other) + { + return -p_other.compare_x(this); + } + + int compare_y(RationalPoint p_other) + { + return -p_other.compare_y(this); + } + + /** + * the x coordinate of this point + */ + public final int x; + + /** + * the y coordinate of this point + */ + public final int y; +} + diff --git a/geometry/planar/IntVector.java b/src/main/java/geometry/planar/IntVector.java similarity index 84% rename from geometry/planar/IntVector.java rename to src/main/java/geometry/planar/IntVector.java index 2724d70..6ee0a6d 100644 --- a/geometry/planar/IntVector.java +++ b/src/main/java/geometry/planar/IntVector.java @@ -1,293 +1,343 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * IntVector.java - * - * Created on 1. Februar 2003, 14:47 - */ - -package geometry.planar; -import datastructures.BigIntAux; -import datastructures.Signum; - -/** - * - * Implementation of the interface Vector via a tuple of integers - * - * @author Alfons Wirtz - */ - -public class IntVector extends Vector implements java.io.Serializable -{ - - /** - * creates an IntVector from two integer coordinates - */ - public IntVector(int p_x, int p_y) - { - // range check ommitet for performance reasons - x = p_x; - y = p_y; - } - - /** - * returns true, if this IntVector is equal to p_ob - */ - public final boolean equals( Object p_ob ) - { - if ( this == p_ob ) - { - return true; - } - if ( p_ob == null ) - { - return false; - } - if ( getClass() != p_ob.getClass() ) - { - return false ; - } - IntVector other = (IntVector)p_ob ; - return ( x == other.x && y == other.y ) ; - } - - /** - * returns true, if both coordinates of this vector are 0 - */ - public final boolean is_zero() - { - return x == 0 && y == 0; - } - - /** - * returns the Vector such that this plus this.minus() is zero - */ - public Vector negate() - { - return new IntVector(-x, -y); - } - - public boolean is_orthogonal() - { - return ( x == 0 || y == 0 ) ; - } - - public boolean is_diagonal() - { - return ( Math.abs(x) == Math.abs(y) ) ; - } - - /** - * Calculates the determinant of the matrix consisting of this - * Vector and p_other. - */ - public final long determinant(IntVector p_other) - { - return (long)x * p_other.y - (long)y * p_other.x; - } - - public Vector turn_90_degree(int p_factor) - { - int n = p_factor; - while (n < 0) - { - n += 4; - } - while (n >= 4) - { - n -= 4; - } - int new_x ; - int new_y ; - switch (n) - { - case 0: // 0 degree - new_x = x; - new_y = y; - break; - case 1: // 90 degree - new_x = -y ; - new_y = x ; - break; - case 2: // 180 degree - new_x = -x ; - new_y = -y ; - break; - case 3: // 270 degree - new_x = y ; - new_y = -x ; - break; - default: - new_x = 0 ; - new_y = 0 ; - } - return new IntVector(new_x, new_y) ; - } - - - public Vector mirror_at_y_axis() - { - return new IntVector(-this.x, this.y); - } - - public Vector mirror_at_x_axis() - { - return new IntVector(this.x, -this.y); - } - - /** - * adds p_other to this vector - */ - public final Vector add( Vector p_other) - { - return p_other.add(this); - } - - final Vector add( IntVector p_other) - { - return new IntVector(x + p_other.x, y + p_other.y); - } - - final Vector add( RationalVector p_other) - { - return p_other.add(this); - } - - /** - * returns the Point, which results from adding this vector to p_point - */ - final Point add_to(IntPoint p_point) - { - return new IntPoint(p_point.x + x, p_point.y + y); - } - - final Point add_to(RationalPoint p_point) - { - return p_point.translate_by(this); - } - - - - /** - * Let L be the line from the Zero Vector to p_other. - * The function returns - * Side.ON_THE_LEFT, if this Vector is on the left of L - * Side.ON_THE_RIGHT, if this Vector is on the right of L - * and Side.COLLINEAR, if this Vector is collinear with L. - */ - public Side side_of(Vector p_other) - { - Side tmp = p_other.side_of(this); - return tmp.negate(); - } - - Side side_of(IntVector p_other) - { - double determinant = (double) p_other.x * y - (double) p_other.y * x; - return Side.of(determinant); - } - - Side side_of(RationalVector p_other) - { - Side tmp = p_other.side_of(this); - return tmp.negate(); - } - - /** - * The function returns - * Signum.POSITIVE, if the scalar product of this vector and p_other > 0, - * Signum.NEGATIVE, if the scalar product Vector is < 0, - * and Signum.ZERO, if the scalar product is equal 0. - */ - public Signum projection(Vector p_other) - { - return p_other.projection(this); - } - - public double scalar_product(Vector p_other) - { - return p_other.scalar_product(this); - } - - - - /** - * converts this vector to a PointFloat. - */ - public FloatPoint to_float() - { - return new FloatPoint(x, y); - } - - public Vector change_length_approx(double p_length) - { - FloatPoint new_point = this.to_float().change_size(p_length); - return new_point.round().difference_by(Point.ZERO); - } - - Direction to_normalized_direction() - { - int dx = x; - int dy = y; - - int gcd = BigIntAux.binaryGcd(Math.abs(dx), Math.abs(dy)); - if (gcd > 1) - { - dx /= gcd; - dy /= gcd; - } - return new IntDirection(dx, dy); - } - - - /** - * The function returns - * Signum.POSITIVE, if the scalar product of this vector and p_other > 0, - * Signum.NEGATIVE, if the scalar product Vector is < 0, - * and Signum.ZERO, if the scalar product is equal 0. - */ - Signum projection(IntVector p_other) - { - double tmp = (double) x * p_other.x + (double) y * p_other.y; - return Signum.of(tmp); - } - - double scalar_product(IntVector p_other) - { - return (double) x * p_other.x + (double) y * p_other.y; - } - - double scalar_product(RationalVector p_other) - { - return p_other.scalar_product(this); - } - - - Signum projection(RationalVector p_other) - { - return p_other.projection(this); - } - - - /** - * the x coordinate of this vector - */ - public final int x; - - /** - * the y coordinate of this vector - */ - public final int y; -} \ No newline at end of file +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * IntVector.java + * + * Created on 1. Februar 2003, 14:47 + */ + +package geometry.planar; +import datastructures.BigIntAux; +import datastructures.Signum; + +/** + * + * Implementation of the interface Vector via a tuple of integers + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class IntVector extends Vector implements java.io.Serializable +{ + + /** + * creates an IntVector from two integer coordinates + * + * @param p_x a int. + * @param p_y a int. + */ + public IntVector(int p_x, int p_y) + { + // range check ommitet for performance reasons + x = p_x; + y = p_y; + } + + /** + * {@inheritDoc} + * + * returns true, if this IntVector is equal to p_ob + */ + public final boolean equals( Object p_ob ) + { + if ( this == p_ob ) + { + return true; + } + if ( p_ob == null ) + { + return false; + } + if ( getClass() != p_ob.getClass() ) + { + return false ; + } + IntVector other = (IntVector)p_ob ; + return ( x == other.x && y == other.y ) ; + } + + /** + * returns true, if both coordinates of this vector are 0 + * + * @return a boolean. + */ + public final boolean is_zero() + { + return x == 0 && y == 0; + } + + /** + * returns the Vector such that this plus this.minus() is zero + * + * @return a {@link geometry.planar.Vector} object. + */ + public Vector negate() + { + return new IntVector(-x, -y); + } + + /** + *

is_orthogonal.

+ * + * @return a boolean. + */ + public boolean is_orthogonal() + { + return ( x == 0 || y == 0 ) ; + } + + /** + *

is_diagonal.

+ * + * @return a boolean. + */ + public boolean is_diagonal() + { + return ( Math.abs(x) == Math.abs(y) ) ; + } + + /** + * Calculates the determinant of the matrix consisting of this + * Vector and p_other. + * + * @param p_other a {@link geometry.planar.IntVector} object. + * @return a long. + */ + public final long determinant(IntVector p_other) + { + return (long)x * p_other.y - (long)y * p_other.x; + } + + /** {@inheritDoc} */ + public Vector turn_90_degree(int p_factor) + { + int n = p_factor; + while (n < 0) + { + n += 4; + } + while (n >= 4) + { + n -= 4; + } + int new_x ; + int new_y ; + switch (n) + { + case 0: // 0 degree + new_x = x; + new_y = y; + break; + case 1: // 90 degree + new_x = -y ; + new_y = x ; + break; + case 2: // 180 degree + new_x = -x ; + new_y = -y ; + break; + case 3: // 270 degree + new_x = y ; + new_y = -x ; + break; + default: + new_x = 0 ; + new_y = 0 ; + } + return new IntVector(new_x, new_y) ; + } + + + /** + *

mirror_at_y_axis.

+ * + * @return a {@link geometry.planar.Vector} object. + */ + public Vector mirror_at_y_axis() + { + return new IntVector(-this.x, this.y); + } + + /** + *

mirror_at_x_axis.

+ * + * @return a {@link geometry.planar.Vector} object. + */ + public Vector mirror_at_x_axis() + { + return new IntVector(this.x, -this.y); + } + + /** + * adds p_other to this vector + * + * @param p_other a {@link geometry.planar.Vector} object. + * @return a {@link geometry.planar.Vector} object. + */ + public final Vector add( Vector p_other) + { + return p_other.add(this); + } + + final Vector add( IntVector p_other) + { + return new IntVector(x + p_other.x, y + p_other.y); + } + + final Vector add( RationalVector p_other) + { + return p_other.add(this); + } + + /** + * returns the Point, which results from adding this vector to p_point + */ + final Point add_to(IntPoint p_point) + { + return new IntPoint(p_point.x + x, p_point.y + y); + } + + final Point add_to(RationalPoint p_point) + { + return p_point.translate_by(this); + } + + + + /** + * Let L be the line from the Zero Vector to p_other. + * The function returns + * Side.ON_THE_LEFT, if this Vector is on the left of L + * Side.ON_THE_RIGHT, if this Vector is on the right of L + * and Side.COLLINEAR, if this Vector is collinear with L. + * + * @param p_other a {@link geometry.planar.Vector} object. + * @return a {@link geometry.planar.Side} object. + */ + public Side side_of(Vector p_other) + { + Side tmp = p_other.side_of(this); + return tmp.negate(); + } + + Side side_of(IntVector p_other) + { + double determinant = (double) p_other.x * y - (double) p_other.y * x; + return Side.of(determinant); + } + + Side side_of(RationalVector p_other) + { + Side tmp = p_other.side_of(this); + return tmp.negate(); + } + + /** + * {@inheritDoc} + * + * The function returns + * Signum.POSITIVE, if the scalar product of this vector and {@code p_other > 0}, + * Signum.NEGATIVE, if the scalar product Vector is {@code < 0}, + * and Signum.ZERO, if the scalar product is equal 0. + */ + public Signum projection(Vector p_other) + { + return p_other.projection(this); + } + + /** + * {@inheritDoc} + * + * @param p_other a {@link geometry.planar.Vector} object. + * @return a double. + */ + public double scalar_product(Vector p_other) + { + return p_other.scalar_product(this); + } + + + + /** + * converts this vector to a PointFloat. + * + * @return a {@link geometry.planar.FloatPoint} object. + */ + public FloatPoint to_float() + { + return new FloatPoint(x, y); + } + + /** {@inheritDoc} */ + public Vector change_length_approx(double p_length) + { + FloatPoint new_point = this.to_float().change_size(p_length); + return new_point.round().difference_by(Point.ZERO); + } + + Direction to_normalized_direction() + { + int dx = x; + int dy = y; + + int gcd = BigIntAux.binaryGcd(Math.abs(dx), Math.abs(dy)); + if (gcd > 1) + { + dx /= gcd; + dy /= gcd; + } + return new IntDirection(dx, dy); + } + + + /** + * The function returns + * Signum.POSITIVE, if the scalar product of this vector and p_other > 0, + * Signum.NEGATIVE, if the scalar product Vector is < 0, + * and Signum.ZERO, if the scalar product is equal 0. + */ + Signum projection(IntVector p_other) + { + double tmp = (double) x * p_other.x + (double) y * p_other.y; + return Signum.of(tmp); + } + + double scalar_product(IntVector p_other) + { + return (double) x * p_other.x + (double) y * p_other.y; + } + + double scalar_product(RationalVector p_other) + { + return p_other.scalar_product(this); + } + + + Signum projection(RationalVector p_other) + { + return p_other.projection(this); + } + + + /** + * the x coordinate of this vector + */ + public final int x; + + /** + * the y coordinate of this vector + */ + public final int y; +} diff --git a/geometry/planar/Limits.java b/src/main/java/geometry/planar/Limits.java similarity index 92% rename from geometry/planar/Limits.java rename to src/main/java/geometry/planar/Limits.java index cd023e8..a48786e 100644 --- a/geometry/planar/Limits.java +++ b/src/main/java/geometry/planar/Limits.java @@ -1,51 +1,52 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - */ - -package geometry.planar; -import java.math.BigInteger; - -/** - * - * Some numerical limits and values are stored here. - * - - * @author Alfons Wirtz - */ - -public class Limits -{ - - /** - * An upper bound (2^25) so that the product of two integers with absolut - * value at most CRIT_COOR is contained in the mantissa of a double with - * some space left for addition. - */ - public static final int CRIT_INT = 33554432; - - /** - * the biggest double value ( 2 ^53) , so that all integers smaller than - * this value are exact represented as double value - */ - public static final double CRIT_DOUBLE = 9007199254740992.0; - - public static final BigInteger CRIT_INT_BIG = BigInteger.valueOf(CRIT_INT); - - public static final double sqrt2 = Math.sqrt(2); - - private Limits() // disallow instantiation - { - } -} \ No newline at end of file +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + */ + +package geometry.planar; +import java.math.BigInteger; + +/** + * + * Some numerical limits and values are stored here. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class Limits +{ + + /** + * An upper bound (2^25) so that the product of two integers with absolut + * value at most CRIT_COOR is contained in the mantissa of a double with + * some space left for addition. + */ + public static final int CRIT_INT = 33554432; + + /** + * the biggest double value ( 2 ^53) , so that all integers smaller than + * this value are exact represented as double value + */ + public static final double CRIT_DOUBLE = 9007199254740992.0; + + /** Constant CRIT_INT_BIG */ + public static final BigInteger CRIT_INT_BIG = BigInteger.valueOf(CRIT_INT); + + /** Constant sqrt2=Math.sqrt(2) */ + public static final double sqrt2 = Math.sqrt(2); + + private Limits() // disallow instantiation + { + } +} diff --git a/geometry/planar/Line.java b/src/main/java/geometry/planar/Line.java similarity index 85% rename from geometry/planar/Line.java rename to src/main/java/geometry/planar/Line.java index 79a6138..bd570e8 100644 --- a/geometry/planar/Line.java +++ b/src/main/java/geometry/planar/Line.java @@ -1,731 +1,840 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - */ - -package geometry.planar; - -import java.math.BigInteger; - -import datastructures.Signum; - -/** - * - * Implements functionality for lines in the plane. - * - * @author Alfons Wirtz - */ - -public class Line implements Comparable, java.io.Serializable -{ - - /** - * creates a directed Line from two Points - */ - public Line(Point p_a, Point p_b) - { - a = p_a; - b = p_b; - dir = null; - if (!(a instanceof IntPoint && b instanceof IntPoint)) - { - System.out.println("Line(p_a, p_b) only implemented for IntPoints till now"); - } - } - - /** - * creates a directed Line from four integer Coordinates - */ - public Line(int p_a_x, int p_a_y, int p_b_x, int p_b_y) - { - a = new IntPoint(p_a_x, p_a_y); - b = new IntPoint(p_b_x, p_b_y); - dir = null; - } - - /** - * creates a directed Line from a Point and a Direction - */ - public Line(Point p_a, Direction p_dir) - { - a = p_a; - b = p_a.translate_by(p_dir.get_vector()); - dir = p_dir; - if (!(a instanceof IntPoint && b instanceof IntPoint)) - { - System.out.println("Line(p_a, p_dir) only implemented for IntPoints till now"); - } - } - - /** - * create a directed line from an IntPoint and an IntDirection - */ - public static Line get_instance(Point p_a, Direction p_dir) - { - Point b = p_a.translate_by(p_dir.get_vector()); - return new Line(p_a, b); - } - - /** - * returns true, if this and p_ob define the same line - */ - public final boolean equals( Object p_ob ) - { - if ( this == p_ob ) - { - return true; - } - if ( p_ob == null ) - { - return false; - } - if (!(p_ob instanceof Line)) - { - return false; - } - Line other = (Line)p_ob ; - if (side_of(other.a) != Side.COLLINEAR) - { - return false; - } - return direction().equals(other.direction()); - } - - /** - * Returns true, if this and p_other define the same line. - * Is designed for good performance, but - * works only for lines consisting of IntPoints. - */ - public final boolean fast_equals(Line p_other) - { - IntPoint this_a = (IntPoint)a; - IntPoint this_b = (IntPoint)b; - IntPoint other_a = (IntPoint)p_other.a; - double dx1 = other_a.x - this_a.x; - double dy1 = other_a.y - this_a.y; - double dx2 = this_b.x - this_a.x; - double dy2 = this_b.y - this_a.y; - double det = dx1 * dy2 - dx2 * dy1; - if (det != 0) - { - return false; - } - return direction().equals(p_other.direction()); - } - - - /** - * get the direction of this directed line - */ - public Direction direction() - { - if (dir == null) - { - Vector d = b.difference_by(a); - dir = Direction.get_instance(d); - } - return dir; - } - - /** - * The function returns - * Side.ON_THE_LEFT, if this Line is on the left of p_point, - * Side.ON_THE_RIGHT, if this Line is on the right of p_point - * and Side.COLLINEAR, if this Line contains p_point. - */ - public Side side_of(Point p_point) - { - Side result = p_point.side_of(this); - return result.negate(); - } - - - /** - * Returns Side.COLLINEAR, if p_point is on the line with tolerance p_tolerance. - * Otherwise Side.ON_THE_LEFT, if this line is on the left of p_point, - * or Side.ON_THE_RIGHT, if this line is on the right of p_point, - */ - public Side side_of(FloatPoint p_point, double p_tolerance) - { - // only implemented for IntPoint lines for performance reasons - IntPoint this_a = (IntPoint)a; - IntPoint this_b = (IntPoint)b; - double det = - (this_b.y - this_a.y) * (p_point.x - this_a.x) - - (this_b.x - this_a.x) * (p_point.y - this_a.y); - Side result; - if (det - p_tolerance > 0) - { - result = Side.ON_THE_LEFT; - } - else if (det + p_tolerance < 0) - { - result = Side.ON_THE_RIGHT; - } - else - { - result = Side.COLLINEAR; - } - - return result; - } - - /** - * returns Side.ON_THE_LEFT, if this line is on the left of p_point, - * Side.ON_THE_RIGHT, if this line is on the right of p_point, - * Side.COLLINEAR otherwise. - */ - public Side side_of(FloatPoint p_point) - { - return side_of(p_point, 0); - } - - /** - * Returns Side.ON_THE_LEFT, if this line is on the left of the intersection - * of p_1 and p_2, Side.ON_THE_RIGHT, if this line is on the right of the intersection, - * and Side.COLLINEAR, if all 3 lines intersect in exacly 1 point. - */ - public Side side_of_intersection(Line p_1, Line p_2) - { - - FloatPoint intersection_approx = p_1.intersection_approx(p_2); - Side result = this.side_of(intersection_approx, 1.0); - if (result == Side.COLLINEAR) - { - // Previous calculation was with FloatPoints and a tolerance - // for performance reasons. Make an exact check for - // collinearity now with class Point instead of FloatPoint. - Point intersection = p_1.intersection(p_2); - result = this.side_of(intersection); - } - return result; - } - - /** - * Looks, if all interiour points of p_tile are on the right side of this line. - */ - public boolean is_on_the_left(TileShape p_tile) - { - for ( int i = 0; i < p_tile.border_line_count(); ++i) - { - if (this.side_of(p_tile.corner(i)) == Side.ON_THE_RIGHT) - { - return false; - } - } - return true; - } - - /** - * Looks, if all interiour points of p_tile are on the left side of this line. - */ - public boolean is_on_the_right(TileShape p_tile) - { - for ( int i = 0; i < p_tile.border_line_count(); ++i) - { - if (this.side_of(p_tile.corner(i)) == Side.ON_THE_LEFT) - { - return false; - } - } - return true; - } - - /** - * Returns the signed distance of this line from p_point. - * The result will be positive, if the line is on the left of p_point, - * else negative. - */ - public double signed_distance(FloatPoint p_point) - { - // only implemented for IntPoint lines for performance reasons - IntPoint this_a = (IntPoint)a; - IntPoint this_b = (IntPoint)b; - double dx = this_b.x - this_a.x; - double dy = this_b.y - this_a.y; - double det = - dy * (p_point.x - this_a.x) - - dx * (p_point.y - this_a.y); - // area of the parallelogramm spanned by the 3 points - double length = Math.sqrt(dx * dx + dy * dy); - return det / length; - } - - /** - * returns true, if the 2 lines defins the same set of points, but may - * have opposite directions - */ - public boolean overlaps(Line p_other) - { - return side_of(p_other.a) == Side.COLLINEAR - && side_of(p_other.b) == Side.COLLINEAR; - } - - /** - * Returns the line defining the same set of points, but - * with opposite direction - */ - public Line opposite() - { - return new Line(b, a); - } - - /** - * Returns the intersection point of the 2 lines. - * If the lines are parallel result.is_infinite() will be true. - */ - public Point intersection(Line p_other) - { - // this function is at the moment only implemented for lines - // consisting of IntPoints. - // The general implementation is still missing. - IntVector delta_1 = (IntVector)b.difference_by(a); - IntVector delta_2 = (IntVector)p_other.b.difference_by(p_other.a); - // Separate handling for orthogonal and 45 degree lines for better perpormance - if (delta_1.x == 0 ) // this line is vertical - { - if (delta_2.y == 0) // other line is horizontal - { - return new IntPoint(((IntPoint)this.a).x, ((IntPoint)p_other.a).y); - } - if (delta_2.x == delta_2.y) // other line is right diagonal - { - int this_x = ((IntPoint)this.a).x; - IntPoint other_a = (IntPoint) p_other.a; - return new IntPoint(this_x, other_a.y + this_x - other_a.x); - } - if (delta_2.x == -delta_2.y) // other line is left diagonal - { - int this_x = ((IntPoint)this.a).x; - IntPoint other_a = (IntPoint) p_other.a; - return new IntPoint(this_x, other_a.y + other_a.x - this_x); - } - } - else if (delta_1.y == 0) // this line is horizontal - { - if (delta_2.x == 0) // other line is vertical - { - return new IntPoint(((IntPoint)p_other.a).x, ((IntPoint)this.a).y); - } - if (delta_2.x == delta_2.y) // other line is right diagonal - { - int this_y = ((IntPoint)this.a).y; - IntPoint other_a = (IntPoint) p_other.a; - return new IntPoint(other_a.x + this_y - other_a.y, this_y); - } - if (delta_2.x == -delta_2.y) // other line is left diagonal - { - int this_y = ((IntPoint)this.a).y; - IntPoint other_a = (IntPoint) p_other.a; - return new IntPoint(other_a.x + other_a.y - this_y, this_y); - } - } - else if (delta_1.x == delta_1.y) // this line is right diagonal - { - if (delta_2.x == 0) // other line is vertical - { - int other_x = ((IntPoint)p_other.a).x; - IntPoint this_a = (IntPoint) this.a; - return new IntPoint(other_x, this_a.y + other_x - this_a.x); - } - if (delta_2.y == 0) // other line is horizontal - { - int other_y = ((IntPoint)p_other.a).y; - IntPoint this_a = (IntPoint) this.a; - return new IntPoint(this_a.x + other_y - this_a.y, other_y); - } - } - else if (delta_1.x == -delta_1.y) // this line is left diagonal - { - if (delta_2.x == 0) // other line is vertical - { - int other_x = ((IntPoint)p_other.a).x; - IntPoint this_a = (IntPoint) this.a; - return new IntPoint(other_x, this_a.y + this_a.x - other_x); - } - if (delta_2.y == 0) // other line is horizontal - { - int other_y = ((IntPoint)p_other.a).y; - IntPoint this_a = (IntPoint) this.a; - return new IntPoint(this_a.x + this_a.y - other_y, other_y); - } - } - - BigInteger det_1 = - BigInteger.valueOf(((IntPoint)a).determinant((IntPoint)b)); - BigInteger det_2 = - BigInteger.valueOf(((IntPoint)p_other.a).determinant((IntPoint)p_other.b)); - BigInteger det = BigInteger.valueOf(delta_2.determinant(delta_1)); - BigInteger tmp_1 = det_1.multiply(BigInteger.valueOf(delta_2.x)); - BigInteger tmp_2 = det_2.multiply(BigInteger.valueOf(delta_1.x)); - BigInteger is_x = tmp_1.subtract(tmp_2); - tmp_1 = det_1.multiply(BigInteger.valueOf(delta_2.y)); - tmp_2 = det_2.multiply(BigInteger.valueOf(delta_1.y)); - BigInteger is_y = tmp_1.subtract(tmp_2); - int signum = det.signum(); - if (signum != 0) - { - if (signum < 0) - { - det = det.negate(); - is_x = is_x.negate(); - is_y = is_y.negate(); - } - if ((is_x.mod(det)).signum() == 0 && (is_y.mod(det)).signum() == 0) - { - is_x = is_x.divide(det); - is_y = is_y.divide(det); - if (Math.abs(is_x.doubleValue()) <= Limits.CRIT_INT - && Math.abs(is_y.doubleValue()) <= Limits.CRIT_INT) - { - return new IntPoint(is_x.intValue(), is_y.intValue()); - } - det = BigInteger.ONE; - } - } - return new RationalPoint(is_x, is_y, det); - } - - /** - * Returns an approximation of the intersection of the 2 lines by a - * FloatPoint. If the lines are parallel the result coordinates will be - * Integer.MAX_VALUE. Useful in situations ehere performance is - * more important than accuracy. - */ - public FloatPoint intersection_approx(Line p_other) - { - // this function is at the moment only implemented for lines - // consisting of IntPoints. - // The general implementation is still missing. - IntPoint this_a = (IntPoint) a; - IntPoint this_b = (IntPoint) b; - IntPoint other_a = (IntPoint) p_other.a; - IntPoint other_b = (IntPoint) p_other.b; - double d1x = this_b.x - this_a.x; - double d1y = this_b.y - this_a.y; - double d2x = other_b.x - other_a.x; - double d2y = other_b.y - other_a.y; - double det_1 = (double)this_a.x * this_b.y - (double)this_a.y * this_b.x; - double det_2 = (double)other_a.x * other_b.y - (double)other_a.y * other_b.x; - double det = d2x * d1y - d2y * d1x; - double is_x; - double is_y; - if(det == 0) - { - is_x = Integer.MAX_VALUE; - is_y = Integer.MAX_VALUE; - } - else - { - is_x = (d2x * det_1 - d1x * det_2) / det; - is_y = (d2y * det_1 - d1y * det_2) / det; - } - return new FloatPoint(is_x, is_y); - } - - /** - * returns the perpendicular projection of p_point onto this line - */ - public Point perpendicular_projection(Point p_point) - { - return p_point.perpendicular_projection(this); - } - - /** - * translates the line perpendicular at about p_dist. - * If p_dist > 0, the line will be translated to the left, else to the right - */ - public Line translate(double p_dist) - { - // this function is at the moment only implemented for lines - // consisting of IntPoints. - // The general implementation is still missing. - IntPoint ai = (IntPoint) a; - IntVector v = (IntVector)direction().get_vector(); - double vxvx = (double)v.x * v.x; - double vyvy = (double)v.y * v.y; - double lenght = Math.sqrt(vxvx + vyvy); - IntPoint new_a; - if (vxvx <= vyvy) - { - // translate along the x axis - int rel_x = (int) Math.round((p_dist * lenght) / v.y); - new_a = new IntPoint(ai.x - rel_x, ai.y); - } - else - { - // translate along the y axis - int rel_y = (int) Math.round((p_dist * lenght) / v.x); - new_a = new IntPoint(ai.x, ai.y + rel_y); - } - return Line.get_instance(new_a, direction()); - } - - /** - * translates the line by p_vector - */ - public Line translate_by(Vector p_vector) - { - if (p_vector.equals(Vector.ZERO)) - { - return this; - } - Point new_a = a.translate_by(p_vector); - Point new_b = b.translate_by(p_vector); - return new Line(new_a, new_b); - } - - - /** - * returns true, if the line is axis_parallel - */ - public boolean is_orthogonal() - { - return direction().is_orthogonal(); - } - - /** - * returns true, if this line is diagonal - */ - public boolean is_diagonal() - { - return direction().is_diagonal(); - } - - /** - * returns true, if the direction of this line is a multiple of 45 degree - */ - public boolean is_multiple_of_45_degree() - { - return direction().is_multiple_of_45_degree(); - } - - /** - * checks, if this Line and p_other are parallel - */ - public boolean is_parallel(Line p_other) - { - return this.direction().side_of(p_other.direction()) == Side.COLLINEAR; - } - - /** - * checks, if this Line and p_other are perpendicular - */ - public boolean is_perpendicular(Line p_other) - { - Vector v1 = direction().get_vector(); - Vector v2 = p_other.direction().get_vector(); - return v1.projection(v2) == Signum.ZERO; - } - - /** - * returns true, if this and p_ob define the same line - */ - public boolean is_equal_or_opposite(Line p_other ) - { - - return(side_of(p_other.a) == Side.COLLINEAR && - side_of(p_other.b) == Side.COLLINEAR); - } - - - /** - * calculates the cosinus of the angle between this line and p_other - */ - public double cos_angle( Line p_other) - { - Vector v1 = b.difference_by(a); - Vector v2 = p_other.b.difference_by(p_other.a); - return v1.cos_angle(v2); - } - - /** - * A line l_1 is defined bigger than a line l_2, if the direction of l_1 - * is bigger than the direction of l_2. - * Implements the comparable interface. - * Throws a cast exception, if p_other is not a Line. - * Fast implementation only for lines consisting of IntPoints - * because of critical performance - */ - public int compareTo(Line p_other) - { - IntPoint this_a = (IntPoint) a; - IntPoint this_b = (IntPoint) b; - IntPoint other_a = (IntPoint) p_other.a; - IntPoint other_b = (IntPoint) p_other.b; - int dx1 = this_b.x - this_a.x; - int dy1 = this_b.y - this_a.y; - int dx2 = other_b.x - other_a.x; - int dy2 = other_b.y - other_a.y; - if (dy1 > 0) - { - if (dy2 < 0) - { - return -1 ; - } - if (dy2 == 0) - { - if (dx2 > 0) - { - return 1 ; - } - return -1 ; - } - } - else if (dy1 < 0) - { - if (dy2 >= 0) - { - return 1 ; - } - } - else // dy1 == 0 - { - if (dx1 > 0) - { - if (dy2 != 0 || dx2 < 0) - { - return -1 ; - } - return 0 ; - } - // dx1 < 0 - if (dy2 > 0 || dy2 == 0 && dx2 > 0) - { - return 1 ; - } - if (dy2 < 0) - { - return -1 ; - } - return 0; - } - - // now this direction and p_other are located in the same - // open horizontal half plane - - double determinant = (double) dx2 * dy1 - (double) dy2 * dx1; - return Signum.as_int(determinant); - } - - /** - * Calculates an approximation of the function value of this line at p_x, - * if the line is not vertical. - */ - public double function_value_approx(double p_x) - { - FloatPoint p1 = a.to_float(); - FloatPoint p2 = b.to_float(); - double dx = p2.x - p1.x; - if (dx == 0) - { - System.out.println("function_value_approx: line is vertical"); - return 0; - } - double dy = p2.y - p1.y; - double det = p1.x * p2.y - p2.x * p1.y; - double result = (dy * p_x - det) /dx; - return result; - } - - /** - * Calculates an approximation of the function value in y of this line at p_y, - * if the line is not horizontal. - */ - public double function_in_y_value_approx(double p_y) - { - FloatPoint p1 = a.to_float(); - FloatPoint p2 = b.to_float(); - double dy = p2.y - p1.y; - if (dy == 0) - { - System.out.println("function_in_y_value_approx: line is horizontal"); - return 0; - } - double dx = p2.x - p1.x; - double det = p1.x * p2.y - p2.x * p1.y; - double result = (dx * p_y + det) /dy; - return result; - } - - /** - * Calculates the direction from p_from_point to the nearest point on - * this line to p_fro_point. - * Returns null, if p_from_point is contained in this line. - */ - public Direction perpendicular_direction(Point p_from_point) - { - Side line_side = this.side_of(p_from_point); - if (line_side == Side.COLLINEAR) - { - return null; - } - Direction dir1 = this.direction().turn_45_degree(2); - Direction dir2 = this.direction().turn_45_degree(6); - - Point check_point_1 = p_from_point.translate_by(dir1.get_vector()); - if (this.side_of(check_point_1) != line_side) - { - return dir1; - } - Point check_point_2 = p_from_point.translate_by(dir2.get_vector()); - if (this.side_of(check_point_2) != line_side) - { - return dir2; - } - FloatPoint nearest_line_point = p_from_point.to_float().projection_approx(this); - Direction result; - if (nearest_line_point.distance_square(check_point_1.to_float()) <= - nearest_line_point.distance_square(check_point_2.to_float())) - { - result = dir1; - } - else - { - result = dir2; - } - return result; - } - - /** - * Turns this line by p_factor times 90 degree around p_pole. - */ - public Line turn_90_degree(int p_factor, IntPoint p_pole) - { - Point new_a = a.turn_90_degree(p_factor, p_pole); - Point new_b = b.turn_90_degree(p_factor, p_pole); - return new Line(new_a, new_b); - } - - /** Mirrors this line at the vertical line through p_pole */ - public Line mirror_vertical(IntPoint p_pole) - { - Point new_a = b.mirror_vertical(p_pole); - Point new_b = a.mirror_vertical(p_pole); - return new Line(new_a, new_b); - } - - /** Mirrors this line at the horizontal line through p_pole */ - public Line mirror_horizontal(IntPoint p_pole) - { - Point new_a = b.mirror_horizontal(p_pole); - Point new_b = a.mirror_horizontal(p_pole); - return new Line(new_a, new_b); - } - - - public final Point a; - public final Point b; - transient private Direction dir; // should only be accessed from get_direction(). -} \ No newline at end of file +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + */ + +package geometry.planar; + +import java.math.BigInteger; + +import datastructures.Signum; + +/** + * + * Implements functionality for lines in the plane. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class Line implements Comparable, java.io.Serializable +{ + + /** + * creates a directed Line from two Points + * + * @param p_a a {@link geometry.planar.Point} object. + * @param p_b a {@link geometry.planar.Point} object. + */ + public Line(Point p_a, Point p_b) + { + a = p_a; + b = p_b; + dir = null; + if (!(a instanceof IntPoint && b instanceof IntPoint)) + { + System.out.println("Line(p_a, p_b) only implemented for IntPoints till now"); + } + } + + /** + * creates a directed Line from four integer Coordinates + * + * @param p_a_x a int. + * @param p_a_y a int. + * @param p_b_x a int. + * @param p_b_y a int. + */ + public Line(int p_a_x, int p_a_y, int p_b_x, int p_b_y) + { + a = new IntPoint(p_a_x, p_a_y); + b = new IntPoint(p_b_x, p_b_y); + dir = null; + } + + /** + * creates a directed Line from a Point and a Direction + * + * @param p_a a {@link geometry.planar.Point} object. + * @param p_dir a {@link geometry.planar.Direction} object. + */ + public Line(Point p_a, Direction p_dir) + { + a = p_a; + b = p_a.translate_by(p_dir.get_vector()); + dir = p_dir; + if (!(a instanceof IntPoint && b instanceof IntPoint)) + { + System.out.println("Line(p_a, p_dir) only implemented for IntPoints till now"); + } + } + + /** + * create a directed line from an IntPoint and an IntDirection + * + * @param p_a a {@link geometry.planar.Point} object. + * @param p_dir a {@link geometry.planar.Direction} object. + * @return a {@link geometry.planar.Line} object. + */ + public static Line get_instance(Point p_a, Direction p_dir) + { + Point b = p_a.translate_by(p_dir.get_vector()); + return new Line(p_a, b); + } + + /** + * {@inheritDoc} + * + * returns true, if this and p_ob define the same line + */ + public final boolean equals( Object p_ob ) + { + if ( this == p_ob ) + { + return true; + } + if ( p_ob == null ) + { + return false; + } + if (!(p_ob instanceof Line)) + { + return false; + } + Line other = (Line)p_ob ; + if (side_of(other.a) != Side.COLLINEAR) + { + return false; + } + return direction().equals(other.direction()); + } + + /** + * Returns true, if this and p_other define the same line. + * Is designed for good performance, but + * works only for lines consisting of IntPoints. + * + * @param p_other a {@link geometry.planar.Line} object. + * @return a boolean. + */ + public final boolean fast_equals(Line p_other) + { + IntPoint this_a = (IntPoint)a; + IntPoint this_b = (IntPoint)b; + IntPoint other_a = (IntPoint)p_other.a; + double dx1 = other_a.x - this_a.x; + double dy1 = other_a.y - this_a.y; + double dx2 = this_b.x - this_a.x; + double dy2 = this_b.y - this_a.y; + double det = dx1 * dy2 - dx2 * dy1; + if (det != 0) + { + return false; + } + return direction().equals(p_other.direction()); + } + + + /** + * get the direction of this directed line + * + * @return a {@link geometry.planar.Direction} object. + */ + public Direction direction() + { + if (dir == null) + { + Vector d = b.difference_by(a); + dir = Direction.get_instance(d); + } + return dir; + } + + /** + * The function returns + * Side.ON_THE_LEFT, if this Line is on the left of p_point, + * Side.ON_THE_RIGHT, if this Line is on the right of p_point + * and Side.COLLINEAR, if this Line contains p_point. + * + * @param p_point a {@link geometry.planar.Point} object. + * @return a {@link geometry.planar.Side} object. + */ + public Side side_of(Point p_point) + { + Side result = p_point.side_of(this); + return result.negate(); + } + + + /** + * Returns Side.COLLINEAR, if p_point is on the line with tolerance p_tolerance. + * Otherwise Side.ON_THE_LEFT, if this line is on the left of p_point, + * or Side.ON_THE_RIGHT, if this line is on the right of p_point, + * + * @param p_point a {@link geometry.planar.FloatPoint} object. + * @param p_tolerance a double. + * @return a {@link geometry.planar.Side} object. + */ + public Side side_of(FloatPoint p_point, double p_tolerance) + { + // only implemented for IntPoint lines for performance reasons + IntPoint this_a = (IntPoint)a; + IntPoint this_b = (IntPoint)b; + double det = + (this_b.y - this_a.y) * (p_point.x - this_a.x) - + (this_b.x - this_a.x) * (p_point.y - this_a.y); + Side result; + if (det - p_tolerance > 0) + { + result = Side.ON_THE_LEFT; + } + else if (det + p_tolerance < 0) + { + result = Side.ON_THE_RIGHT; + } + else + { + result = Side.COLLINEAR; + } + + return result; + } + + /** + * returns Side.ON_THE_LEFT, if this line is on the left of p_point, + * Side.ON_THE_RIGHT, if this line is on the right of p_point, + * Side.COLLINEAR otherwise. + * + * @param p_point a {@link geometry.planar.FloatPoint} object. + * @return a {@link geometry.planar.Side} object. + */ + public Side side_of(FloatPoint p_point) + { + return side_of(p_point, 0); + } + + /** + * Returns Side.ON_THE_LEFT, if this line is on the left of the intersection + * of p_1 and p_2, Side.ON_THE_RIGHT, if this line is on the right of the intersection, + * and Side.COLLINEAR, if all 3 lines intersect in exacly 1 point. + * + * @param p_1 a {@link geometry.planar.Line} object. + * @param p_2 a {@link geometry.planar.Line} object. + * @return a {@link geometry.planar.Side} object. + */ + public Side side_of_intersection(Line p_1, Line p_2) + { + + FloatPoint intersection_approx = p_1.intersection_approx(p_2); + Side result = this.side_of(intersection_approx, 1.0); + if (result == Side.COLLINEAR) + { + // Previous calculation was with FloatPoints and a tolerance + // for performance reasons. Make an exact check for + // collinearity now with class Point instead of FloatPoint. + Point intersection = p_1.intersection(p_2); + result = this.side_of(intersection); + } + return result; + } + + /** + * Looks, if all interiour points of p_tile are on the right side of this line. + * + * @param p_tile a {@link geometry.planar.TileShape} object. + * @return a boolean. + */ + public boolean is_on_the_left(TileShape p_tile) + { + for ( int i = 0; i < p_tile.border_line_count(); ++i) + { + if (this.side_of(p_tile.corner(i)) == Side.ON_THE_RIGHT) + { + return false; + } + } + return true; + } + + /** + * Looks, if all interiour points of p_tile are on the left side of this line. + * + * @param p_tile a {@link geometry.planar.TileShape} object. + * @return a boolean. + */ + public boolean is_on_the_right(TileShape p_tile) + { + for ( int i = 0; i < p_tile.border_line_count(); ++i) + { + if (this.side_of(p_tile.corner(i)) == Side.ON_THE_LEFT) + { + return false; + } + } + return true; + } + + /** + * Returns the signed distance of this line from p_point. + * The result will be positive, if the line is on the left of p_point, + * else negative. + * + * @param p_point a {@link geometry.planar.FloatPoint} object. + * @return a double. + */ + public double signed_distance(FloatPoint p_point) + { + // only implemented for IntPoint lines for performance reasons + IntPoint this_a = (IntPoint)a; + IntPoint this_b = (IntPoint)b; + double dx = this_b.x - this_a.x; + double dy = this_b.y - this_a.y; + double det = + dy * (p_point.x - this_a.x) - + dx * (p_point.y - this_a.y); + // area of the parallelogramm spanned by the 3 points + double length = Math.sqrt(dx * dx + dy * dy); + return det / length; + } + + /** + * returns true, if the 2 lines defins the same set of points, but may + * have opposite directions + * + * @param p_other a {@link geometry.planar.Line} object. + * @return a boolean. + */ + public boolean overlaps(Line p_other) + { + return side_of(p_other.a) == Side.COLLINEAR + && side_of(p_other.b) == Side.COLLINEAR; + } + + /** + * Returns the line defining the same set of points, but + * with opposite direction + * + * @return a {@link geometry.planar.Line} object. + */ + public Line opposite() + { + return new Line(b, a); + } + + /** + * Returns the intersection point of the 2 lines. + * If the lines are parallel result.is_infinite() will be true. + * + * @param p_other a {@link geometry.planar.Line} object. + * @return a {@link geometry.planar.Point} object. + */ + public Point intersection(Line p_other) + { + // this function is at the moment only implemented for lines + // consisting of IntPoints. + // The general implementation is still missing. + IntVector delta_1 = (IntVector)b.difference_by(a); + IntVector delta_2 = (IntVector)p_other.b.difference_by(p_other.a); + // Separate handling for orthogonal and 45 degree lines for better perpormance + if (delta_1.x == 0 ) // this line is vertical + { + if (delta_2.y == 0) // other line is horizontal + { + return new IntPoint(((IntPoint)this.a).x, ((IntPoint)p_other.a).y); + } + if (delta_2.x == delta_2.y) // other line is right diagonal + { + int this_x = ((IntPoint)this.a).x; + IntPoint other_a = (IntPoint) p_other.a; + return new IntPoint(this_x, other_a.y + this_x - other_a.x); + } + if (delta_2.x == -delta_2.y) // other line is left diagonal + { + int this_x = ((IntPoint)this.a).x; + IntPoint other_a = (IntPoint) p_other.a; + return new IntPoint(this_x, other_a.y + other_a.x - this_x); + } + } + else if (delta_1.y == 0) // this line is horizontal + { + if (delta_2.x == 0) // other line is vertical + { + return new IntPoint(((IntPoint)p_other.a).x, ((IntPoint)this.a).y); + } + if (delta_2.x == delta_2.y) // other line is right diagonal + { + int this_y = ((IntPoint)this.a).y; + IntPoint other_a = (IntPoint) p_other.a; + return new IntPoint(other_a.x + this_y - other_a.y, this_y); + } + if (delta_2.x == -delta_2.y) // other line is left diagonal + { + int this_y = ((IntPoint)this.a).y; + IntPoint other_a = (IntPoint) p_other.a; + return new IntPoint(other_a.x + other_a.y - this_y, this_y); + } + } + else if (delta_1.x == delta_1.y) // this line is right diagonal + { + if (delta_2.x == 0) // other line is vertical + { + int other_x = ((IntPoint)p_other.a).x; + IntPoint this_a = (IntPoint) this.a; + return new IntPoint(other_x, this_a.y + other_x - this_a.x); + } + if (delta_2.y == 0) // other line is horizontal + { + int other_y = ((IntPoint)p_other.a).y; + IntPoint this_a = (IntPoint) this.a; + return new IntPoint(this_a.x + other_y - this_a.y, other_y); + } + } + else if (delta_1.x == -delta_1.y) // this line is left diagonal + { + if (delta_2.x == 0) // other line is vertical + { + int other_x = ((IntPoint)p_other.a).x; + IntPoint this_a = (IntPoint) this.a; + return new IntPoint(other_x, this_a.y + this_a.x - other_x); + } + if (delta_2.y == 0) // other line is horizontal + { + int other_y = ((IntPoint)p_other.a).y; + IntPoint this_a = (IntPoint) this.a; + return new IntPoint(this_a.x + this_a.y - other_y, other_y); + } + } + + BigInteger det_1 = + BigInteger.valueOf(((IntPoint)a).determinant((IntPoint)b)); + BigInteger det_2 = + BigInteger.valueOf(((IntPoint)p_other.a).determinant((IntPoint)p_other.b)); + BigInteger det = BigInteger.valueOf(delta_2.determinant(delta_1)); + BigInteger tmp_1 = det_1.multiply(BigInteger.valueOf(delta_2.x)); + BigInteger tmp_2 = det_2.multiply(BigInteger.valueOf(delta_1.x)); + BigInteger is_x = tmp_1.subtract(tmp_2); + tmp_1 = det_1.multiply(BigInteger.valueOf(delta_2.y)); + tmp_2 = det_2.multiply(BigInteger.valueOf(delta_1.y)); + BigInteger is_y = tmp_1.subtract(tmp_2); + int signum = det.signum(); + if (signum != 0) + { + if (signum < 0) + { + det = det.negate(); + is_x = is_x.negate(); + is_y = is_y.negate(); + } + if ((is_x.mod(det)).signum() == 0 && (is_y.mod(det)).signum() == 0) + { + is_x = is_x.divide(det); + is_y = is_y.divide(det); + if (Math.abs(is_x.doubleValue()) <= Limits.CRIT_INT + && Math.abs(is_y.doubleValue()) <= Limits.CRIT_INT) + { + return new IntPoint(is_x.intValue(), is_y.intValue()); + } + det = BigInteger.ONE; + } + } + return new RationalPoint(is_x, is_y, det); + } + + /** + * Returns an approximation of the intersection of the 2 lines by a + * FloatPoint. If the lines are parallel the result coordinates will be + * Integer.MAX_VALUE. Useful in situations ehere performance is + * more important than accuracy. + * + * @param p_other a {@link geometry.planar.Line} object. + * @return a {@link geometry.planar.FloatPoint} object. + */ + public FloatPoint intersection_approx(Line p_other) + { + // this function is at the moment only implemented for lines + // consisting of IntPoints. + // The general implementation is still missing. + IntPoint this_a = (IntPoint) a; + IntPoint this_b = (IntPoint) b; + IntPoint other_a = (IntPoint) p_other.a; + IntPoint other_b = (IntPoint) p_other.b; + double d1x = this_b.x - this_a.x; + double d1y = this_b.y - this_a.y; + double d2x = other_b.x - other_a.x; + double d2y = other_b.y - other_a.y; + double det_1 = (double)this_a.x * this_b.y - (double)this_a.y * this_b.x; + double det_2 = (double)other_a.x * other_b.y - (double)other_a.y * other_b.x; + double det = d2x * d1y - d2y * d1x; + double is_x; + double is_y; + if(det == 0) + { + is_x = Integer.MAX_VALUE; + is_y = Integer.MAX_VALUE; + } + else + { + is_x = (d2x * det_1 - d1x * det_2) / det; + is_y = (d2y * det_1 - d1y * det_2) / det; + } + return new FloatPoint(is_x, is_y); + } + + /** + * returns the perpendicular projection of p_point onto this line + * + * @param p_point a {@link geometry.planar.Point} object. + * @return a {@link geometry.planar.Point} object. + */ + public Point perpendicular_projection(Point p_point) + { + return p_point.perpendicular_projection(this); + } + + /** + * translates the line perpendicular at about p_dist. + * If {@code p_dist > 0}, the line will be translated to the left, else to the right + * + * @param p_dist a double. + * @return a {@link geometry.planar.Line} object. + */ + public Line translate(double p_dist) + { + // this function is at the moment only implemented for lines + // consisting of IntPoints. + // The general implementation is still missing. + IntPoint ai = (IntPoint) a; + IntVector v = (IntVector)direction().get_vector(); + double vxvx = (double)v.x * v.x; + double vyvy = (double)v.y * v.y; + double lenght = Math.sqrt(vxvx + vyvy); + IntPoint new_a; + if (vxvx <= vyvy) + { + // translate along the x axis + int rel_x = (int) Math.round((p_dist * lenght) / v.y); + new_a = new IntPoint(ai.x - rel_x, ai.y); + } + else + { + // translate along the y axis + int rel_y = (int) Math.round((p_dist * lenght) / v.x); + new_a = new IntPoint(ai.x, ai.y + rel_y); + } + return Line.get_instance(new_a, direction()); + } + + /** + * translates the line by p_vector + * + * @param p_vector a {@link geometry.planar.Vector} object. + * @return a {@link geometry.planar.Line} object. + */ + public Line translate_by(Vector p_vector) + { + if (p_vector.equals(Vector.ZERO)) + { + return this; + } + Point new_a = a.translate_by(p_vector); + Point new_b = b.translate_by(p_vector); + return new Line(new_a, new_b); + } + + + /** + * returns true, if the line is axis_parallel + * + * @return a boolean. + */ + public boolean is_orthogonal() + { + return direction().is_orthogonal(); + } + + /** + * returns true, if this line is diagonal + * + * @return a boolean. + */ + public boolean is_diagonal() + { + return direction().is_diagonal(); + } + + /** + * returns true, if the direction of this line is a multiple of 45 degree + * + * @return a boolean. + */ + public boolean is_multiple_of_45_degree() + { + return direction().is_multiple_of_45_degree(); + } + + /** + * checks, if this Line and p_other are parallel + * + * @param p_other a {@link geometry.planar.Line} object. + * @return a boolean. + */ + public boolean is_parallel(Line p_other) + { + return this.direction().side_of(p_other.direction()) == Side.COLLINEAR; + } + + /** + * checks, if this Line and p_other are perpendicular + * + * @param p_other a {@link geometry.planar.Line} object. + * @return a boolean. + */ + public boolean is_perpendicular(Line p_other) + { + Vector v1 = direction().get_vector(); + Vector v2 = p_other.direction().get_vector(); + return v1.projection(v2) == Signum.ZERO; + } + + /** + * returns true, if this and p_ob define the same line + * + * @param p_other a {@link geometry.planar.Line} object. + * @return a boolean. + */ + public boolean is_equal_or_opposite(Line p_other ) + { + + return(side_of(p_other.a) == Side.COLLINEAR && + side_of(p_other.b) == Side.COLLINEAR); + } + + + /** + * calculates the cosinus of the angle between this line and p_other + * + * @param p_other a {@link geometry.planar.Line} object. + * @return a double. + */ + public double cos_angle( Line p_other) + { + Vector v1 = b.difference_by(a); + Vector v2 = p_other.b.difference_by(p_other.a); + return v1.cos_angle(v2); + } + + /** + * A line l_1 is defined bigger than a line l_2, if the direction of l_1 + * is bigger than the direction of l_2. + * Implements the comparable interface. + * Throws a cast exception, if p_other is not a Line. + * Fast implementation only for lines consisting of IntPoints + * because of critical performance + * + * @param p_other a {@link geometry.planar.Line} object. + * @return a int. + */ + public int compareTo(Line p_other) + { + IntPoint this_a = (IntPoint) a; + IntPoint this_b = (IntPoint) b; + IntPoint other_a = (IntPoint) p_other.a; + IntPoint other_b = (IntPoint) p_other.b; + int dx1 = this_b.x - this_a.x; + int dy1 = this_b.y - this_a.y; + int dx2 = other_b.x - other_a.x; + int dy2 = other_b.y - other_a.y; + if (dy1 > 0) + { + if (dy2 < 0) + { + return -1 ; + } + if (dy2 == 0) + { + if (dx2 > 0) + { + return 1 ; + } + return -1 ; + } + } + else if (dy1 < 0) + { + if (dy2 >= 0) + { + return 1 ; + } + } + else // dy1 == 0 + { + if (dx1 > 0) + { + if (dy2 != 0 || dx2 < 0) + { + return -1 ; + } + return 0 ; + } + // dx1 < 0 + if (dy2 > 0 || dy2 == 0 && dx2 > 0) + { + return 1 ; + } + if (dy2 < 0) + { + return -1 ; + } + return 0; + } + + // now this direction and p_other are located in the same + // open horizontal half plane + + double determinant = (double) dx2 * dy1 - (double) dy2 * dx1; + return Signum.as_int(determinant); + } + + /** + * Calculates an approximation of the function value of this line at p_x, + * if the line is not vertical. + * + * @param p_x a double. + * @return a double. + */ + public double function_value_approx(double p_x) + { + FloatPoint p1 = a.to_float(); + FloatPoint p2 = b.to_float(); + double dx = p2.x - p1.x; + if (dx == 0) + { + System.out.println("function_value_approx: line is vertical"); + return 0; + } + double dy = p2.y - p1.y; + double det = p1.x * p2.y - p2.x * p1.y; + double result = (dy * p_x - det) /dx; + return result; + } + + /** + * Calculates an approximation of the function value in y of this line at p_y, + * if the line is not horizontal. + * + * @param p_y a double. + * @return a double. + */ + public double function_in_y_value_approx(double p_y) + { + FloatPoint p1 = a.to_float(); + FloatPoint p2 = b.to_float(); + double dy = p2.y - p1.y; + if (dy == 0) + { + System.out.println("function_in_y_value_approx: line is horizontal"); + return 0; + } + double dx = p2.x - p1.x; + double det = p1.x * p2.y - p2.x * p1.y; + double result = (dx * p_y + det) /dy; + return result; + } + + /** + * Calculates the direction from p_from_point to the nearest point on + * this line to p_fro_point. + * Returns null, if p_from_point is contained in this line. + * + * @param p_from_point a {@link geometry.planar.Point} object. + * @return a {@link geometry.planar.Direction} object. + */ + public Direction perpendicular_direction(Point p_from_point) + { + Side line_side = this.side_of(p_from_point); + if (line_side == Side.COLLINEAR) + { + return null; + } + Direction dir1 = this.direction().turn_45_degree(2); + Direction dir2 = this.direction().turn_45_degree(6); + + Point check_point_1 = p_from_point.translate_by(dir1.get_vector()); + if (this.side_of(check_point_1) != line_side) + { + return dir1; + } + Point check_point_2 = p_from_point.translate_by(dir2.get_vector()); + if (this.side_of(check_point_2) != line_side) + { + return dir2; + } + FloatPoint nearest_line_point = p_from_point.to_float().projection_approx(this); + Direction result; + if (nearest_line_point.distance_square(check_point_1.to_float()) <= + nearest_line_point.distance_square(check_point_2.to_float())) + { + result = dir1; + } + else + { + result = dir2; + } + return result; + } + + /** + * Turns this line by p_factor times 90 degree around p_pole. + * + * @param p_factor a int. + * @param p_pole a {@link geometry.planar.IntPoint} object. + * @return a {@link geometry.planar.Line} object. + */ + public Line turn_90_degree(int p_factor, IntPoint p_pole) + { + Point new_a = a.turn_90_degree(p_factor, p_pole); + Point new_b = b.turn_90_degree(p_factor, p_pole); + return new Line(new_a, new_b); + } + + /** + * Mirrors this line at the vertical line through p_pole + * + * @param p_pole a {@link geometry.planar.IntPoint} object. + * @return a {@link geometry.planar.Line} object. + */ + public Line mirror_vertical(IntPoint p_pole) + { + Point new_a = b.mirror_vertical(p_pole); + Point new_b = a.mirror_vertical(p_pole); + return new Line(new_a, new_b); + } + + /** + * Mirrors this line at the horizontal line through p_pole + * + * @param p_pole a {@link geometry.planar.IntPoint} object. + * @return a {@link geometry.planar.Line} object. + */ + public Line mirror_horizontal(IntPoint p_pole) + { + Point new_a = b.mirror_horizontal(p_pole); + Point new_b = a.mirror_horizontal(p_pole); + return new Line(new_a, new_b); + } + + + public final Point a; + public final Point b; + transient private Direction dir; // should only be accessed from get_direction(). +} diff --git a/geometry/planar/LineSegment.java b/src/main/java/geometry/planar/LineSegment.java similarity index 93% rename from geometry/planar/LineSegment.java rename to src/main/java/geometry/planar/LineSegment.java index 8585d18..e210783 100644 --- a/geometry/planar/LineSegment.java +++ b/src/main/java/geometry/planar/LineSegment.java @@ -1,880 +1,942 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - */ -package geometry.planar; - -import datastructures.Signum; - -/** - * Implements functionality for line segments. - * The difference between a LineSegment and a - * Line is, that a Line is infinite and a - * LineSegment has a start and an endpoint. - * - * - * @author Alfons Wirtz - */ -public class LineSegment implements java.io.Serializable -{ - - /** - * Creates a line segment from the 3 input lines. - * It starts at the intersection of p_start_line and p_middle_line - * and ends at the intersection of p_middle_line and p_end_line. - * p_start_line and p_end_line must not be parallel to p_middle_line. - */ - public LineSegment(Line p_start_line, Line p_middle_line, Line p_end_line) - { - start = p_start_line; - middle = p_middle_line; - end = p_end_line; - } - - /** - * creates the p_no-th line segment of p_polyline - * for p_no between 1 and p_polyline.line_count - 2. - */ - public LineSegment(Polyline p_polyline, int p_no) - { - if (p_no <= 0 || p_no >= p_polyline.arr.length - 1) - { - System.out.println("LineSegment from Polyline: p_no out of range"); - start = null; - middle = null; - end = null; - return; - } - start = p_polyline.arr[p_no - 1]; - middle = p_polyline.arr[p_no]; - end = p_polyline.arr[p_no + 1]; - } - - /** - * Creates the p_no-th line segment of p_shape - * for p_no between 0 and p_shape.line_count - 1. - */ - public LineSegment(PolylineShape p_shape, int p_no) - { - int line_count = p_shape.border_line_count(); - if (p_no < 0 || p_no >= line_count) - { - System.out.println("LineSegment from TileShape: p_no out of range"); - start = null; - middle = null; - end = null; - return; - } - if (p_no == 0) - { - start = p_shape.border_line(line_count - 1); - } - else - { - start = p_shape.border_line(p_no - 1); - } - middle = p_shape.border_line(p_no); - if (p_no == line_count - 1) - { - end = p_shape.border_line(0); - } - else - { - end = p_shape.border_line(p_no + 1); - } - } - - /** - * Returns the intersection of the first 2 lines of this segment - */ - public Point start_point() - { - if (precalculated_start_point == null) - { - precalculated_start_point = middle.intersection(start); - } - return precalculated_start_point; - } - - /** - * Returns the intersection of the last 2 lines of this segment - */ - public Point end_point() - { - if (precalculated_end_point == null) - { - precalculated_end_point = middle.intersection(end); - } - return precalculated_end_point; - } - - /** - * Returns an approximation of the intersection of the first 2 lines of this segment - */ - public FloatPoint start_point_approx() - { - FloatPoint result; - if (precalculated_start_point != null) - { - result = precalculated_start_point.to_float(); - } - else - { - result = this.start.intersection_approx(this.middle); - } - return result; - } - - /** - * Returns an approximation of the intersection of the last 2 lines of this segment - */ - public FloatPoint end_point_approx() - { - FloatPoint result; - if (precalculated_end_point != null) - { - result = precalculated_end_point.to_float(); - } - else - { - result = this.end.intersection_approx(this.middle); - } - return result; - } - - /** - * Returns the (infinite) line of this segment. - */ - public Line get_line() - { - return middle; - } - - /** - * Returns the start closing line of this segment. - */ - public Line get_start_closing_line() - { - return start; - } - - /** - * Returns the end closing line of this segment. - */ - public Line get_end_closing_line() - { - return end; - } - - /** - * Returns the line segment with tje opposite direction. - */ - public LineSegment opposite() - { - return new LineSegment(end.opposite(), middle.opposite(), start.opposite()); - } - - /** - * Transforms this LinsSegment into a polyline of lenght 3. - */ - public Polyline to_polyline() - { - Line[] lines = new Line[3]; - lines[0] = start; - lines[1] = middle; - lines[2] = end; - return new Polyline(lines); - } - - /** - * Creates a 1 dimensional simplex rom this line segment, which - * has the same shape as the line sgment. - */ - public Simplex to_simplex() - { - Line[] line_arr = new Line[4]; - if (this.end_point().side_of(this.start) == Side.ON_THE_RIGHT) - { - line_arr[0] = this.start.opposite(); - } - else - { - line_arr[0] = this.start; - } - line_arr[1] = this.middle; - line_arr[2] = this.middle.opposite(); - if (this.start_point().side_of(this.end) == Side.ON_THE_RIGHT) - { - line_arr[3] = this.end.opposite(); - } - else - { - line_arr[3] = this.end; - } - Simplex result = Simplex.get_instance(line_arr); - return result; - } - - /** - * Checks if p_point is contained in this line segment - */ - public boolean contains(Point p_point) - { - if (!(p_point instanceof IntPoint)) - { - System.out.println("LineSegments.contains currently only implementet for IntPoints"); - return false; - } - if (middle.side_of(p_point) != Side.COLLINEAR) - { - return false; - } - // create a perpendicular line at p_point and check, that the two - // endpoints of this segment are on difcferent sides of that line. - Direction perpendicular_direction = middle.direction().turn_45_degree(2); - Line perpendicular_line = new Line(p_point, perpendicular_direction); - Side start_point_side = perpendicular_line.side_of(this.start_point()); - Side end_point_side = perpendicular_line.side_of(this.end_point()); - if (start_point_side != Side.COLLINEAR && end_point_side != Side.COLLINEAR && start_point_side == end_point_side) - { - return false; - } - return true; - } - - /** - * calculates the smallest surrounding box of this line segmant - */ - public IntBox bounding_box() - { - FloatPoint start_corner = middle.intersection_approx(start); - FloatPoint end_corner = middle.intersection_approx(end); - double llx = Math.min(start_corner.x, end_corner.x); - double lly = Math.min(start_corner.y, end_corner.y); - double urx = Math.max(start_corner.x, end_corner.x); - double ury = Math.max(start_corner.y, end_corner.y); - IntPoint lower_left = new IntPoint((int) Math.floor(llx), (int) Math.floor(lly)); - IntPoint upper_right = new IntPoint((int) Math.ceil(urx), (int) Math.ceil(ury)); - return new IntBox(lower_left, upper_right); - } - - /** - * calculates the smallest surrounding octagon of this line segmant - */ - public IntOctagon bounding_octagon() - { - FloatPoint start_corner = middle.intersection_approx(start); - FloatPoint end_corner = middle.intersection_approx(end); - double lx = Math.floor(Math.min(start_corner.x, end_corner.x)); - double ly = Math.floor(Math.min(start_corner.y, end_corner.y)); - double rx = Math.ceil(Math.max(start_corner.x, end_corner.x)); - double uy = Math.ceil(Math.max(start_corner.y, end_corner.y)); - double start_x_minus_y = start_corner.x - start_corner.y; - double end_x_minus_y = end_corner.x - end_corner.y; - double ulx = Math.floor(Math.min(start_x_minus_y, end_x_minus_y)); - double lrx = Math.ceil(Math.max(start_x_minus_y, end_x_minus_y)); - double start_x_plus_y = start_corner.x + start_corner.y; - double end_x_plus_y = end_corner.x + end_corner.y; - double llx = Math.floor(Math.min(start_x_plus_y, end_x_plus_y)); - double urx = Math.ceil(Math.max(start_x_plus_y, end_x_plus_y)); - IntOctagon result = - new IntOctagon((int) lx, (int) ly, (int) rx, (int) uy, (int) ulx, (int) lrx, (int) llx, (int) urx); - return result.normalize(); - } - - /** - * Creates a new line segment with the same start and middle line and an end line, - * so that the length of the new line segment is about p_new_length. - */ - public LineSegment change_length_approx(double p_new_length) - { - FloatPoint new_end_point = - start_point_approx().change_length(end_point_approx(), p_new_length); - Direction perpendicular_direction = this.middle.direction().turn_45_degree(2); - Line new_end_line = new Line(new_end_point.round(), perpendicular_direction); - LineSegment result = new LineSegment(this.start, this.middle, new_end_line); - return result; - } - - /** - * Looks up the intersections of this line segment with p_other. - * The result array may have length 0, 1 or 2. - * If the segments do not intersect the result array will have length 0. - * The result lines are so that the intersections of the result lines with - * this line segment will deliver the intersection points. - * If the segments overlap, the result array has length 2 and the intersection - * points are the first and the last overlap point. - * Otherwise the result array has length 1 and the intersection point is the - * the unique intersection or touching point. - * The result is not symmetric in this and p_other, because intersecting lines - * and not the intersection points are returned. - */ - public Line[] intersection(LineSegment p_other) - { - if (!this.bounding_box().intersects(p_other.bounding_box())) - { - return new Line[0]; - } - Side start_point_side = start_point().side_of(p_other.middle); - Side end_point_side = end_point().side_of(p_other.middle); - if (start_point_side == Side.COLLINEAR && end_point_side == Side.COLLINEAR) - { - // there may be an overlap - LineSegment this_sorted = this.sort_endpoints_in_x_y(); - LineSegment other_sorted = p_other.sort_endpoints_in_x_y(); - LineSegment left_line; - LineSegment right_line; - if (this_sorted.start_point().compare_x_y(other_sorted.start_point()) <= 0) - { - left_line = this_sorted; - right_line = other_sorted; - } - else - { - left_line = other_sorted; - right_line = this_sorted; - } - int cmp = left_line.end_point().compare_x_y(right_line.start_point()); - if (cmp < 0) - { - // end point of the left line is to the lsft of the start point of the right line - return new Line[0]; - } - if (cmp == 0) - { - // end point of the left line is equal to the start point of the right line - Line[] result = new Line[1]; - result[0] = left_line.end; - return result; - } - // now there is a real overlap - Line[] result = new Line[2]; - result[0] = right_line.start; - if (right_line.end_point().compare_x_y(left_line.end_point()) >= 0) - { - result[1] = left_line.end; - } - else - { - result[1] = right_line.end; - } - return result; - } - if (start_point_side == end_point_side || - p_other.start_point().side_of(this.middle) == p_other.end_point().side_of(this.middle)) - { - return new Line[0]; // no intersection possible - } - // now both start points and both end points are on different sides of the middle - // line of the other segment. - Line[] result = new Line[1]; - result[0] = p_other.middle; - return result; - } - - /** - * Checks if this LineSegment and p_other contain a commen point - */ - public boolean intersects(LineSegment p_other) - { - Line[] intersections = this.intersection(p_other); - return intersections.length > 0; - } - - /** - * Checks if this LineSegment and p_other contain a common LineSegment, - * which is not reduced to a point. - */ - public boolean overlaps(LineSegment p_other) - { - Line[] intersections = this.intersection(p_other); - return intersections.length > 1; - } - - /** - * Constructs an approximation of this line segment by orthogonal stairs with integer coordinates. - * The length of the stairs will be at most p_stair_width. - * If p_to_the_right, the stairs will be to the right of this line segment, else to the left. - */ - public IntPoint[] stair_approximation(double p_width, boolean p_to_the_right) - { - IntPoint start_point = this.start_point().to_float().round(); - IntPoint end_point = this.end_point().to_float().round(); - if (start_point.equals(end_point)) - { - return new IntPoint[0]; - - } - - if (start_point.x == end_point.x || start_point.y == end_point.y) - { - IntPoint[] result = new IntPoint[2]; - result[0] = start_point; - result[1] = end_point; - return result; - } - - int dx = end_point.x - start_point.x; - int dy = end_point.y - start_point.y; - int abs_dx = Math.abs(dx); - int abs_dy = Math.abs(dy); - boolean function_of_x = abs_dx >= abs_dy; - // use otherwise function of y for better numerical stability - - int stair_width; - int stair_count; - - - if (function_of_x) - { - stair_width = (int) Math.round(((p_width * (double) abs_dx) / (double) abs_dy)); - stair_count = (abs_dx - 1) / stair_width + 1; - if (end_point.x < start_point.x) - { - stair_width = -stair_width; - } - } - else - { - stair_width = (int) Math.round((p_width * (double) abs_dy) / (double) abs_dx); - stair_count = (abs_dy - 1) / stair_width + 1; - if (end_point.y < start_point.y) - { - stair_width = -stair_width; - } - } - IntPoint[] result = new IntPoint[2 * stair_count + 1]; - - result[0] = start_point; - double det = (double) dx * (double) dy; - boolean change_x_first = p_to_the_right && det > 0 || !p_to_the_right && det < 0; - int curr_index = 0; - - int prev_line_point_x = start_point.x; - int prev_line_point_y = start_point.y; - for (int i = 1; i < stair_count; ++i) - { - int curr_line_point_x; - int curr_line_point_y; - if (function_of_x) - { - curr_line_point_x = start_point.x + i * stair_width; - curr_line_point_y = (int) Math.round(this.get_line().function_value_approx(curr_line_point_x)); - } - else - { - curr_line_point_y = start_point.y + i * stair_width; - curr_line_point_x = (int) Math.round(this.get_line().function_in_y_value_approx(curr_line_point_y)); - } - ++curr_index; - if (change_x_first) - { - result[curr_index] = new IntPoint(curr_line_point_x, prev_line_point_y); - } - else - { - result[curr_index] = new IntPoint(prev_line_point_x, curr_line_point_y); - } - ++curr_index; - result[curr_index] = new IntPoint(curr_line_point_x, curr_line_point_y); - prev_line_point_x = curr_line_point_x; - prev_line_point_y = curr_line_point_y; - } - ++curr_index; - if (change_x_first) - { - result[curr_index] = new IntPoint(end_point.x, prev_line_point_y); - } - else - { - result[curr_index] = new IntPoint(prev_line_point_x, end_point.y); - } - ++curr_index; - result[curr_index] = end_point; - return result; - } - - /** - * Constructs an approximation of this line segment by 45 degree stairs with integer coordinates. - * The length of the stairs will be at most p_stair_width. - * If p_to_the_right, the stairs will be to the right of this line segment, else to the left. - */ - public IntPoint[] stair_approximation_45(double p_width, boolean p_to_the_right) - { - IntPoint start_point = this.start_point().to_float().round(); - IntPoint end_point = this.end_point().to_float().round(); - if (start_point.equals(end_point)) - { - return new IntPoint[0]; - - } - IntVector delta = end_point.difference_by(start_point); - if (delta.is_multiple_of_45_degree()) - { - IntPoint[] result = new IntPoint[2]; - result[0] = start_point; - result[1] = end_point; - return result; - } - IntVector abs_delta = new IntVector(Math.abs(delta.x), Math.abs(delta.y)); - boolean function_of_x = abs_delta.x >= abs_delta.y; - // use otherwise function of y for better numerical stability - double det = (double) delta.x * (double) delta.y; - int stair_width; - int stair_count; - if (function_of_x) - { - stair_width = (int) Math.round((p_width * (double) abs_delta.x) / (double) abs_delta.y); - stair_count = (abs_delta.x - 1) / stair_width + 1; - if (end_point.x < start_point.x) - { - stair_width = -stair_width; - } - } - else - { - stair_width = (int) Math.round((p_width * (double) abs_delta.y) / (double) abs_delta.x); - stair_count = (abs_delta.y - 1) / stair_width + 1; - if (end_point.y < start_point.y) - { - stair_width = -stair_width; - } - - } - IntPoint[] result = new IntPoint[2 * stair_count + 1]; - result[0] = start_point; - IntPoint prev_line_point = start_point; - int curr_index = 0; - for (int i = 1; i <= stair_count; ++i) - { - IntPoint curr_line_point; - int curr_x; - int curr_y; - if (i == stair_count) - { - curr_line_point = end_point; - } - else - { - if (function_of_x) - { - curr_x = start_point.x + i * stair_width; - curr_y = (int) Math.round(this.get_line().function_value_approx(curr_x)); - } - else - { - curr_y = start_point.y + i * stair_width; - curr_x = (int) Math.round(this.get_line().function_value_approx(curr_y)); - } - curr_line_point = new IntPoint(curr_x, curr_y); - } - if (function_of_x) - { - boolean diagonal_first = p_to_the_right && det < 0 || !p_to_the_right && det > 0; - - if (diagonal_first) - { - curr_x = prev_line_point.x + Signum.as_int(stair_width) * Math.abs(curr_line_point.y - prev_line_point.y); - curr_y = curr_line_point.y; - } - else - // horizontal first - { - curr_x = curr_line_point.x - Signum.as_int(stair_width) * Math.abs(curr_line_point.y - prev_line_point.y); - curr_y = prev_line_point.y; - } - } - else - // function of y - { - boolean diagonal_first = p_to_the_right && det > 0 || !p_to_the_right && det < 0; - - if (diagonal_first) - { - curr_x = curr_line_point.x; - curr_y = prev_line_point.y + Signum.as_int(stair_width) * Math.abs(curr_line_point.x - prev_line_point.x); - } - else - { - curr_x = prev_line_point.x; - curr_y = curr_line_point.y - Signum.as_int(stair_width) * Math.abs(curr_line_point.x - prev_line_point.x); - } - - } - ++curr_index; - result[curr_index] = new IntPoint (curr_x, curr_y); - ++curr_index; - result[curr_index] = curr_line_point; - prev_line_point = curr_line_point; - } - return result; - } - - /** - * Returns an array with the borderline numbers of p_shape, - * which are intersected by this line segment. Intersections at an endpoint - * of this line segment are only counted, if the line segment intersects - * with the interiour of p_shape. - * The result array may have lenght 0, 1 or 2. - * With 2 intersections the intersection which is nearest to the start - * point of the line segment comes first. - */ - public int[] border_intersections(TileShape p_shape) - { - int[] empty_result = new int[0]; - if (!this.bounding_box().intersects(p_shape.bounding_box())) - { - return empty_result; - } - - int edge_count = p_shape.border_line_count(); - Line prev_line = p_shape.border_line(edge_count - 1); - Line curr_line = p_shape.border_line(0); - int[] result = new int[2]; - Point[] intersection = new Point[2]; - int intersection_count = 0; - Point line_start = this.start_point(); - Point line_end = this.end_point(); - - for (int edge_line_no = 0; edge_line_no < - edge_count; ++edge_line_no) - { - Line next_line; - if (edge_line_no == edge_count - 1) - { - next_line = p_shape.border_line(0); - } - else - { - next_line = p_shape.border_line(edge_line_no + 1); - } - - Side start_point_side = curr_line.side_of(line_start); - Side end_point_side = curr_line.side_of(line_end); - if (start_point_side == Side.ON_THE_LEFT && - end_point_side == Side.ON_THE_LEFT) - { - // both endpoints are outside the border_line, - // no intersection possible - return empty_result; - } - - if (start_point_side == Side.COLLINEAR) - { - // the start is on curr_line, check that the end point is inside - // the halfplane, because touches count only, if the interiour - // is entered - if (end_point_side != Side.ON_THE_RIGHT) - { - return empty_result; - } - - } - - if (end_point_side == Side.COLLINEAR) - { - // the end is on curr_line, check that the start point is inside - // the halfplane, because touches count only, if the interiour - // is entered - if (start_point_side != Side.ON_THE_RIGHT) - { - return empty_result; - } - - } - - if (start_point_side != Side.ON_THE_RIGHT || - end_point_side != Side.ON_THE_RIGHT) - { - // not both points are inside the halplane defined by curr_line - Point is = this.middle.intersection(curr_line); - Side prev_line_side_of_is = prev_line.side_of(is); - Side next_line_side_of_is = next_line.side_of(is); - if (prev_line_side_of_is != Side.ON_THE_LEFT && - next_line_side_of_is != Side.ON_THE_LEFT) - { - // this line segment intersects curr_line between the - // previous and the next corner of p_simplex - - if (prev_line_side_of_is == Side.COLLINEAR) - { - // this line segment goes through the previous - // corner of p_simplex. Check, that the intersection - // isn't merely a touch. - Point prev_prev_corner; - if (edge_line_no == 0) - { - prev_prev_corner = p_shape.corner(edge_count - 1); - } - else - { - prev_prev_corner = p_shape.corner(edge_line_no - 1); - } - - Point next_corner; - if (edge_line_no == edge_count - 1) - { - next_corner = p_shape.corner(0); - } - else - { - next_corner = p_shape.corner(edge_line_no + 1); - } -// check, that prev_prev_corner and next_corner -// are on different sides of this line segment. - Side prev_prev_corner_side = - this.middle.side_of(prev_prev_corner); - Side next_corner_side = - this.middle.side_of(next_corner); - if (prev_prev_corner_side == Side.COLLINEAR || - next_corner_side == Side.COLLINEAR || - prev_prev_corner_side == next_corner_side) - { - return empty_result; - } - - } - if (next_line_side_of_is == Side.COLLINEAR) - { - // this line segment goes through the next - // corner of p_simplex. Check, that the intersection - // isn't merely a touch. - Point prev_corner = p_shape.corner(edge_line_no); - Point next_next_corner; - - if (edge_line_no == edge_count - 2) - { - next_next_corner = p_shape.corner(0); - } - else if (edge_line_no == edge_count - 1) - { - next_next_corner = p_shape.corner(1); - } - else - { - next_next_corner = p_shape.corner(edge_line_no + 2); - } -// check, that prev_corner and next_next_corner -// are on different sides of this line segment. - Side prev_corner_side = - this.middle.side_of(prev_corner); - Side next_next_corner_side = - this.middle.side_of(next_next_corner); - if (prev_corner_side == Side.COLLINEAR || - next_next_corner_side == Side.COLLINEAR || - prev_corner_side == next_next_corner_side) - { - return empty_result; - } - - } - boolean intersection_already_handeled = false; - for (int i = 0; i < - intersection_count; ++i) - { - if (is.equals(intersection[i])) - { - intersection_already_handeled = true; - break; - - } - - - - - } - if (!intersection_already_handeled) - { - if (intersection_count < result.length) - { - // a new intersection is found - result[intersection_count] = edge_line_no; - intersection[intersection_count] = is; - ++intersection_count; - } - else - { - System.out.println("border_intersections: intersection_count to big!"); - } - - } - } - } - - prev_line = curr_line; - curr_line = - next_line; - } - - if (intersection_count == 0) - { - return empty_result; - } - - if (intersection_count == 2) - { - // assure the correct order - FloatPoint is0 = intersection[0].to_float(); - FloatPoint is1 = intersection[1].to_float(); - FloatPoint curr_start = line_start.to_float(); - if (curr_start.distance_square(is1) < curr_start.distance_square(is0)) - // swap the result points - { - int tmp = result[0]; - result[0] = result[1]; - result[1] = tmp; - } - - return result; - } - - if (intersection_count != 1) - { - System.out.println( - "LineSegment.border_intersections: intersection_count 1 expected"); - } - - int[] normalised_result = new int[1]; - normalised_result[0] = result[0]; - return normalised_result; - } - - /** - * Inverts the direction of this.middle, if start_point() has a bigger - * x coordinate than end_point(), or an equal x coordinate and a bigger y coordinate. - */ - public LineSegment sort_endpoints_in_x_y() - { - boolean swap_endlines = (start_point().compare_x_y(end_point()) > 0); - LineSegment result; - - if (swap_endlines) - { - result = new LineSegment(this.end, this.middle, this.start); - result.precalculated_start_point = this.precalculated_end_point; - result.precalculated_end_point = this.precalculated_start_point; - } - else - { - result = this; - } - - return result; - } - private final Line start; - private final Line middle; - private final Line end; - transient private Point precalculated_start_point = null; - transient private Point precalculated_end_point = null; -} \ No newline at end of file +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + */ +package geometry.planar; + +import datastructures.Signum; + +/** + * Implements functionality for line segments. + * The difference between a LineSegment and a + * Line is, that a Line is infinite and a + * LineSegment has a start and an endpoint. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class LineSegment implements java.io.Serializable +{ + + /** + * Creates a line segment from the 3 input lines. + * It starts at the intersection of p_start_line and p_middle_line + * and ends at the intersection of p_middle_line and p_end_line. + * p_start_line and p_end_line must not be parallel to p_middle_line. + * + * @param p_start_line a {@link geometry.planar.Line} object. + * @param p_middle_line a {@link geometry.planar.Line} object. + * @param p_end_line a {@link geometry.planar.Line} object. + */ + public LineSegment(Line p_start_line, Line p_middle_line, Line p_end_line) + { + start = p_start_line; + middle = p_middle_line; + end = p_end_line; + } + + /** + * creates the p_no-th line segment of p_polyline + * for p_no between 1 and p_polyline.line_count - 2. + * + * @param p_polyline a {@link geometry.planar.Polyline} object. + * @param p_no a int. + */ + public LineSegment(Polyline p_polyline, int p_no) + { + if (p_no <= 0 || p_no >= p_polyline.arr.length - 1) + { + System.out.println("LineSegment from Polyline: p_no out of range"); + start = null; + middle = null; + end = null; + return; + } + start = p_polyline.arr[p_no - 1]; + middle = p_polyline.arr[p_no]; + end = p_polyline.arr[p_no + 1]; + } + + /** + * Creates the p_no-th line segment of p_shape + * for p_no between 0 and p_shape.line_count - 1. + * + * @param p_shape a {@link geometry.planar.PolylineShape} object. + * @param p_no a int. + */ + public LineSegment(PolylineShape p_shape, int p_no) + { + int line_count = p_shape.border_line_count(); + if (p_no < 0 || p_no >= line_count) + { + System.out.println("LineSegment from TileShape: p_no out of range"); + start = null; + middle = null; + end = null; + return; + } + if (p_no == 0) + { + start = p_shape.border_line(line_count - 1); + } + else + { + start = p_shape.border_line(p_no - 1); + } + middle = p_shape.border_line(p_no); + if (p_no == line_count - 1) + { + end = p_shape.border_line(0); + } + else + { + end = p_shape.border_line(p_no + 1); + } + } + + /** + * Returns the intersection of the first 2 lines of this segment + * + * @return a {@link geometry.planar.Point} object. + */ + public Point start_point() + { + if (precalculated_start_point == null) + { + precalculated_start_point = middle.intersection(start); + } + return precalculated_start_point; + } + + /** + * Returns the intersection of the last 2 lines of this segment + * + * @return a {@link geometry.planar.Point} object. + */ + public Point end_point() + { + if (precalculated_end_point == null) + { + precalculated_end_point = middle.intersection(end); + } + return precalculated_end_point; + } + + /** + * Returns an approximation of the intersection of the first 2 lines of this segment + * + * @return a {@link geometry.planar.FloatPoint} object. + */ + public FloatPoint start_point_approx() + { + FloatPoint result; + if (precalculated_start_point != null) + { + result = precalculated_start_point.to_float(); + } + else + { + result = this.start.intersection_approx(this.middle); + } + return result; + } + + /** + * Returns an approximation of the intersection of the last 2 lines of this segment + * + * @return a {@link geometry.planar.FloatPoint} object. + */ + public FloatPoint end_point_approx() + { + FloatPoint result; + if (precalculated_end_point != null) + { + result = precalculated_end_point.to_float(); + } + else + { + result = this.end.intersection_approx(this.middle); + } + return result; + } + + /** + * Returns the (infinite) line of this segment. + * + * @return a {@link geometry.planar.Line} object. + */ + public Line get_line() + { + return middle; + } + + /** + * Returns the start closing line of this segment. + * + * @return a {@link geometry.planar.Line} object. + */ + public Line get_start_closing_line() + { + return start; + } + + /** + * Returns the end closing line of this segment. + * + * @return a {@link geometry.planar.Line} object. + */ + public Line get_end_closing_line() + { + return end; + } + + /** + * Returns the line segment with tje opposite direction. + * + * @return a {@link geometry.planar.LineSegment} object. + */ + public LineSegment opposite() + { + return new LineSegment(end.opposite(), middle.opposite(), start.opposite()); + } + + /** + * Transforms this LinsSegment into a polyline of lenght 3. + * + * @return a {@link geometry.planar.Polyline} object. + */ + public Polyline to_polyline() + { + Line[] lines = new Line[3]; + lines[0] = start; + lines[1] = middle; + lines[2] = end; + return new Polyline(lines); + } + + /** + * Creates a 1 dimensional simplex rom this line segment, which + * has the same shape as the line sgment. + * + * @return a {@link geometry.planar.Simplex} object. + */ + public Simplex to_simplex() + { + Line[] line_arr = new Line[4]; + if (this.end_point().side_of(this.start) == Side.ON_THE_RIGHT) + { + line_arr[0] = this.start.opposite(); + } + else + { + line_arr[0] = this.start; + } + line_arr[1] = this.middle; + line_arr[2] = this.middle.opposite(); + if (this.start_point().side_of(this.end) == Side.ON_THE_RIGHT) + { + line_arr[3] = this.end.opposite(); + } + else + { + line_arr[3] = this.end; + } + Simplex result = Simplex.get_instance(line_arr); + return result; + } + + /** + * Checks if p_point is contained in this line segment + * + * @param p_point a {@link geometry.planar.Point} object. + * @return a boolean. + */ + public boolean contains(Point p_point) + { + if (!(p_point instanceof IntPoint)) + { + System.out.println("LineSegments.contains currently only implementet for IntPoints"); + return false; + } + if (middle.side_of(p_point) != Side.COLLINEAR) + { + return false; + } + // create a perpendicular line at p_point and check, that the two + // endpoints of this segment are on difcferent sides of that line. + Direction perpendicular_direction = middle.direction().turn_45_degree(2); + Line perpendicular_line = new Line(p_point, perpendicular_direction); + Side start_point_side = perpendicular_line.side_of(this.start_point()); + Side end_point_side = perpendicular_line.side_of(this.end_point()); + if (start_point_side != Side.COLLINEAR && end_point_side != Side.COLLINEAR && start_point_side == end_point_side) + { + return false; + } + return true; + } + + /** + * calculates the smallest surrounding box of this line segmant + * + * @return a {@link geometry.planar.IntBox} object. + */ + public IntBox bounding_box() + { + FloatPoint start_corner = middle.intersection_approx(start); + FloatPoint end_corner = middle.intersection_approx(end); + double llx = Math.min(start_corner.x, end_corner.x); + double lly = Math.min(start_corner.y, end_corner.y); + double urx = Math.max(start_corner.x, end_corner.x); + double ury = Math.max(start_corner.y, end_corner.y); + IntPoint lower_left = new IntPoint((int) Math.floor(llx), (int) Math.floor(lly)); + IntPoint upper_right = new IntPoint((int) Math.ceil(urx), (int) Math.ceil(ury)); + return new IntBox(lower_left, upper_right); + } + + /** + * calculates the smallest surrounding octagon of this line segmant + * + * @return a {@link geometry.planar.IntOctagon} object. + */ + public IntOctagon bounding_octagon() + { + FloatPoint start_corner = middle.intersection_approx(start); + FloatPoint end_corner = middle.intersection_approx(end); + double lx = Math.floor(Math.min(start_corner.x, end_corner.x)); + double ly = Math.floor(Math.min(start_corner.y, end_corner.y)); + double rx = Math.ceil(Math.max(start_corner.x, end_corner.x)); + double uy = Math.ceil(Math.max(start_corner.y, end_corner.y)); + double start_x_minus_y = start_corner.x - start_corner.y; + double end_x_minus_y = end_corner.x - end_corner.y; + double ulx = Math.floor(Math.min(start_x_minus_y, end_x_minus_y)); + double lrx = Math.ceil(Math.max(start_x_minus_y, end_x_minus_y)); + double start_x_plus_y = start_corner.x + start_corner.y; + double end_x_plus_y = end_corner.x + end_corner.y; + double llx = Math.floor(Math.min(start_x_plus_y, end_x_plus_y)); + double urx = Math.ceil(Math.max(start_x_plus_y, end_x_plus_y)); + IntOctagon result = + new IntOctagon((int) lx, (int) ly, (int) rx, (int) uy, (int) ulx, (int) lrx, (int) llx, (int) urx); + return result.normalize(); + } + + /** + * Creates a new line segment with the same start and middle line and an end line, + * so that the length of the new line segment is about p_new_length. + * + * @param p_new_length a double. + * @return a {@link geometry.planar.LineSegment} object. + */ + public LineSegment change_length_approx(double p_new_length) + { + FloatPoint new_end_point = + start_point_approx().change_length(end_point_approx(), p_new_length); + Direction perpendicular_direction = this.middle.direction().turn_45_degree(2); + Line new_end_line = new Line(new_end_point.round(), perpendicular_direction); + LineSegment result = new LineSegment(this.start, this.middle, new_end_line); + return result; + } + + /** + * Looks up the intersections of this line segment with p_other. + * The result array may have length 0, 1 or 2. + * If the segments do not intersect the result array will have length 0. + * The result lines are so that the intersections of the result lines with + * this line segment will deliver the intersection points. + * If the segments overlap, the result array has length 2 and the intersection + * points are the first and the last overlap point. + * Otherwise the result array has length 1 and the intersection point is the + * the unique intersection or touching point. + * The result is not symmetric in this and p_other, because intersecting lines + * and not the intersection points are returned. + * + * @param p_other a {@link geometry.planar.LineSegment} object. + * @return an array of {@link geometry.planar.Line} objects. + */ + public Line[] intersection(LineSegment p_other) + { + if (!this.bounding_box().intersects(p_other.bounding_box())) + { + return new Line[0]; + } + Side start_point_side = start_point().side_of(p_other.middle); + Side end_point_side = end_point().side_of(p_other.middle); + if (start_point_side == Side.COLLINEAR && end_point_side == Side.COLLINEAR) + { + // there may be an overlap + LineSegment this_sorted = this.sort_endpoints_in_x_y(); + LineSegment other_sorted = p_other.sort_endpoints_in_x_y(); + LineSegment left_line; + LineSegment right_line; + if (this_sorted.start_point().compare_x_y(other_sorted.start_point()) <= 0) + { + left_line = this_sorted; + right_line = other_sorted; + } + else + { + left_line = other_sorted; + right_line = this_sorted; + } + int cmp = left_line.end_point().compare_x_y(right_line.start_point()); + if (cmp < 0) + { + // end point of the left line is to the lsft of the start point of the right line + return new Line[0]; + } + if (cmp == 0) + { + // end point of the left line is equal to the start point of the right line + Line[] result = new Line[1]; + result[0] = left_line.end; + return result; + } + // now there is a real overlap + Line[] result = new Line[2]; + result[0] = right_line.start; + if (right_line.end_point().compare_x_y(left_line.end_point()) >= 0) + { + result[1] = left_line.end; + } + else + { + result[1] = right_line.end; + } + return result; + } + if (start_point_side == end_point_side || + p_other.start_point().side_of(this.middle) == p_other.end_point().side_of(this.middle)) + { + return new Line[0]; // no intersection possible + } + // now both start points and both end points are on different sides of the middle + // line of the other segment. + Line[] result = new Line[1]; + result[0] = p_other.middle; + return result; + } + + /** + * Checks if this LineSegment and p_other contain a commen point + * + * @param p_other a {@link geometry.planar.LineSegment} object. + * @return a boolean. + */ + public boolean intersects(LineSegment p_other) + { + Line[] intersections = this.intersection(p_other); + return intersections.length > 0; + } + + /** + * Checks if this LineSegment and p_other contain a common LineSegment, + * which is not reduced to a point. + * + * @param p_other a {@link geometry.planar.LineSegment} object. + * @return a boolean. + */ + public boolean overlaps(LineSegment p_other) + { + Line[] intersections = this.intersection(p_other); + return intersections.length > 1; + } + + /** + * Constructs an approximation of this line segment by orthogonal stairs with integer coordinates. + * The length of the stairs will be at most p_stair_width. + * If p_to_the_right, the stairs will be to the right of this line segment, else to the left. + * + * @param p_width a double. + * @param p_to_the_right a boolean. + * @return an array of {@link geometry.planar.IntPoint} objects. + */ + public IntPoint[] stair_approximation(double p_width, boolean p_to_the_right) + { + IntPoint start_point = this.start_point().to_float().round(); + IntPoint end_point = this.end_point().to_float().round(); + if (start_point.equals(end_point)) + { + return new IntPoint[0]; + + } + + if (start_point.x == end_point.x || start_point.y == end_point.y) + { + IntPoint[] result = new IntPoint[2]; + result[0] = start_point; + result[1] = end_point; + return result; + } + + int dx = end_point.x - start_point.x; + int dy = end_point.y - start_point.y; + int abs_dx = Math.abs(dx); + int abs_dy = Math.abs(dy); + boolean function_of_x = abs_dx >= abs_dy; + // use otherwise function of y for better numerical stability + + int stair_width; + int stair_count; + + + if (function_of_x) + { + stair_width = (int) Math.round(((p_width * (double) abs_dx) / (double) abs_dy)); + stair_count = (abs_dx - 1) / stair_width + 1; + if (end_point.x < start_point.x) + { + stair_width = -stair_width; + } + } + else + { + stair_width = (int) Math.round((p_width * (double) abs_dy) / (double) abs_dx); + stair_count = (abs_dy - 1) / stair_width + 1; + if (end_point.y < start_point.y) + { + stair_width = -stair_width; + } + } + IntPoint[] result = new IntPoint[2 * stair_count + 1]; + + result[0] = start_point; + double det = (double) dx * (double) dy; + boolean change_x_first = p_to_the_right && det > 0 || !p_to_the_right && det < 0; + int curr_index = 0; + + int prev_line_point_x = start_point.x; + int prev_line_point_y = start_point.y; + for (int i = 1; i < stair_count; ++i) + { + int curr_line_point_x; + int curr_line_point_y; + if (function_of_x) + { + curr_line_point_x = start_point.x + i * stair_width; + curr_line_point_y = (int) Math.round(this.get_line().function_value_approx(curr_line_point_x)); + } + else + { + curr_line_point_y = start_point.y + i * stair_width; + curr_line_point_x = (int) Math.round(this.get_line().function_in_y_value_approx(curr_line_point_y)); + } + ++curr_index; + if (change_x_first) + { + result[curr_index] = new IntPoint(curr_line_point_x, prev_line_point_y); + } + else + { + result[curr_index] = new IntPoint(prev_line_point_x, curr_line_point_y); + } + ++curr_index; + result[curr_index] = new IntPoint(curr_line_point_x, curr_line_point_y); + prev_line_point_x = curr_line_point_x; + prev_line_point_y = curr_line_point_y; + } + ++curr_index; + if (change_x_first) + { + result[curr_index] = new IntPoint(end_point.x, prev_line_point_y); + } + else + { + result[curr_index] = new IntPoint(prev_line_point_x, end_point.y); + } + ++curr_index; + result[curr_index] = end_point; + return result; + } + + /** + * Constructs an approximation of this line segment by 45 degree stairs with integer coordinates. + * The length of the stairs will be at most p_stair_width. + * If p_to_the_right, the stairs will be to the right of this line segment, else to the left. + * + * @param p_width a double. + * @param p_to_the_right a boolean. + * @return an array of {@link geometry.planar.IntPoint} objects. + */ + public IntPoint[] stair_approximation_45(double p_width, boolean p_to_the_right) + { + IntPoint start_point = this.start_point().to_float().round(); + IntPoint end_point = this.end_point().to_float().round(); + if (start_point.equals(end_point)) + { + return new IntPoint[0]; + + } + IntVector delta = end_point.difference_by(start_point); + if (delta.is_multiple_of_45_degree()) + { + IntPoint[] result = new IntPoint[2]; + result[0] = start_point; + result[1] = end_point; + return result; + } + IntVector abs_delta = new IntVector(Math.abs(delta.x), Math.abs(delta.y)); + boolean function_of_x = abs_delta.x >= abs_delta.y; + // use otherwise function of y for better numerical stability + double det = (double) delta.x * (double) delta.y; + int stair_width; + int stair_count; + if (function_of_x) + { + stair_width = (int) Math.round((p_width * (double) abs_delta.x) / (double) abs_delta.y); + stair_count = (abs_delta.x - 1) / stair_width + 1; + if (end_point.x < start_point.x) + { + stair_width = -stair_width; + } + } + else + { + stair_width = (int) Math.round((p_width * (double) abs_delta.y) / (double) abs_delta.x); + stair_count = (abs_delta.y - 1) / stair_width + 1; + if (end_point.y < start_point.y) + { + stair_width = -stair_width; + } + + } + IntPoint[] result = new IntPoint[2 * stair_count + 1]; + result[0] = start_point; + IntPoint prev_line_point = start_point; + int curr_index = 0; + for (int i = 1; i <= stair_count; ++i) + { + IntPoint curr_line_point; + int curr_x; + int curr_y; + if (i == stair_count) + { + curr_line_point = end_point; + } + else + { + if (function_of_x) + { + curr_x = start_point.x + i * stair_width; + curr_y = (int) Math.round(this.get_line().function_value_approx(curr_x)); + } + else + { + curr_y = start_point.y + i * stair_width; + curr_x = (int) Math.round(this.get_line().function_value_approx(curr_y)); + } + curr_line_point = new IntPoint(curr_x, curr_y); + } + if (function_of_x) + { + boolean diagonal_first = p_to_the_right && det < 0 || !p_to_the_right && det > 0; + + if (diagonal_first) + { + curr_x = prev_line_point.x + Signum.as_int(stair_width) * Math.abs(curr_line_point.y - prev_line_point.y); + curr_y = curr_line_point.y; + } + else + // horizontal first + { + curr_x = curr_line_point.x - Signum.as_int(stair_width) * Math.abs(curr_line_point.y - prev_line_point.y); + curr_y = prev_line_point.y; + } + } + else + // function of y + { + boolean diagonal_first = p_to_the_right && det > 0 || !p_to_the_right && det < 0; + + if (diagonal_first) + { + curr_x = curr_line_point.x; + curr_y = prev_line_point.y + Signum.as_int(stair_width) * Math.abs(curr_line_point.x - prev_line_point.x); + } + else + { + curr_x = prev_line_point.x; + curr_y = curr_line_point.y - Signum.as_int(stair_width) * Math.abs(curr_line_point.x - prev_line_point.x); + } + + } + ++curr_index; + result[curr_index] = new IntPoint (curr_x, curr_y); + ++curr_index; + result[curr_index] = curr_line_point; + prev_line_point = curr_line_point; + } + return result; + } + + /** + * Returns an array with the borderline numbers of p_shape, + * which are intersected by this line segment. Intersections at an endpoint + * of this line segment are only counted, if the line segment intersects + * with the interiour of p_shape. + * The result array may have lenght 0, 1 or 2. + * With 2 intersections the intersection which is nearest to the start + * point of the line segment comes first. + * + * @param p_shape a {@link geometry.planar.TileShape} object. + * @return an array of int. + */ + public int[] border_intersections(TileShape p_shape) + { + int[] empty_result = new int[0]; + if (!this.bounding_box().intersects(p_shape.bounding_box())) + { + return empty_result; + } + + int edge_count = p_shape.border_line_count(); + Line prev_line = p_shape.border_line(edge_count - 1); + Line curr_line = p_shape.border_line(0); + int[] result = new int[2]; + Point[] intersection = new Point[2]; + int intersection_count = 0; + Point line_start = this.start_point(); + Point line_end = this.end_point(); + + for (int edge_line_no = 0; edge_line_no < + edge_count; ++edge_line_no) + { + Line next_line; + if (edge_line_no == edge_count - 1) + { + next_line = p_shape.border_line(0); + } + else + { + next_line = p_shape.border_line(edge_line_no + 1); + } + + Side start_point_side = curr_line.side_of(line_start); + Side end_point_side = curr_line.side_of(line_end); + if (start_point_side == Side.ON_THE_LEFT && + end_point_side == Side.ON_THE_LEFT) + { + // both endpoints are outside the border_line, + // no intersection possible + return empty_result; + } + + if (start_point_side == Side.COLLINEAR) + { + // the start is on curr_line, check that the end point is inside + // the halfplane, because touches count only, if the interiour + // is entered + if (end_point_side != Side.ON_THE_RIGHT) + { + return empty_result; + } + + } + + if (end_point_side == Side.COLLINEAR) + { + // the end is on curr_line, check that the start point is inside + // the halfplane, because touches count only, if the interiour + // is entered + if (start_point_side != Side.ON_THE_RIGHT) + { + return empty_result; + } + + } + + if (start_point_side != Side.ON_THE_RIGHT || + end_point_side != Side.ON_THE_RIGHT) + { + // not both points are inside the halplane defined by curr_line + Point is = this.middle.intersection(curr_line); + Side prev_line_side_of_is = prev_line.side_of(is); + Side next_line_side_of_is = next_line.side_of(is); + if (prev_line_side_of_is != Side.ON_THE_LEFT && + next_line_side_of_is != Side.ON_THE_LEFT) + { + // this line segment intersects curr_line between the + // previous and the next corner of p_simplex + + if (prev_line_side_of_is == Side.COLLINEAR) + { + // this line segment goes through the previous + // corner of p_simplex. Check, that the intersection + // isn't merely a touch. + Point prev_prev_corner; + if (edge_line_no == 0) + { + prev_prev_corner = p_shape.corner(edge_count - 1); + } + else + { + prev_prev_corner = p_shape.corner(edge_line_no - 1); + } + + Point next_corner; + if (edge_line_no == edge_count - 1) + { + next_corner = p_shape.corner(0); + } + else + { + next_corner = p_shape.corner(edge_line_no + 1); + } +// check, that prev_prev_corner and next_corner +// are on different sides of this line segment. + Side prev_prev_corner_side = + this.middle.side_of(prev_prev_corner); + Side next_corner_side = + this.middle.side_of(next_corner); + if (prev_prev_corner_side == Side.COLLINEAR || + next_corner_side == Side.COLLINEAR || + prev_prev_corner_side == next_corner_side) + { + return empty_result; + } + + } + if (next_line_side_of_is == Side.COLLINEAR) + { + // this line segment goes through the next + // corner of p_simplex. Check, that the intersection + // isn't merely a touch. + Point prev_corner = p_shape.corner(edge_line_no); + Point next_next_corner; + + if (edge_line_no == edge_count - 2) + { + next_next_corner = p_shape.corner(0); + } + else if (edge_line_no == edge_count - 1) + { + next_next_corner = p_shape.corner(1); + } + else + { + next_next_corner = p_shape.corner(edge_line_no + 2); + } +// check, that prev_corner and next_next_corner +// are on different sides of this line segment. + Side prev_corner_side = + this.middle.side_of(prev_corner); + Side next_next_corner_side = + this.middle.side_of(next_next_corner); + if (prev_corner_side == Side.COLLINEAR || + next_next_corner_side == Side.COLLINEAR || + prev_corner_side == next_next_corner_side) + { + return empty_result; + } + + } + boolean intersection_already_handeled = false; + for (int i = 0; i < + intersection_count; ++i) + { + if (is.equals(intersection[i])) + { + intersection_already_handeled = true; + break; + + } + + + + + } + if (!intersection_already_handeled) + { + if (intersection_count < result.length) + { + // a new intersection is found + result[intersection_count] = edge_line_no; + intersection[intersection_count] = is; + ++intersection_count; + } + else + { + System.out.println("border_intersections: intersection_count to big!"); + } + + } + } + } + + prev_line = curr_line; + curr_line = + next_line; + } + + if (intersection_count == 0) + { + return empty_result; + } + + if (intersection_count == 2) + { + // assure the correct order + FloatPoint is0 = intersection[0].to_float(); + FloatPoint is1 = intersection[1].to_float(); + FloatPoint curr_start = line_start.to_float(); + if (curr_start.distance_square(is1) < curr_start.distance_square(is0)) + // swap the result points + { + int tmp = result[0]; + result[0] = result[1]; + result[1] = tmp; + } + + return result; + } + + if (intersection_count != 1) + { + System.out.println( + "LineSegment.border_intersections: intersection_count 1 expected"); + } + + int[] normalised_result = new int[1]; + normalised_result[0] = result[0]; + return normalised_result; + } + + /** + * Inverts the direction of this.middle, if start_point() has a bigger + * x coordinate than end_point(), or an equal x coordinate and a bigger y coordinate. + * + * @return a {@link geometry.planar.LineSegment} object. + */ + public LineSegment sort_endpoints_in_x_y() + { + boolean swap_endlines = (start_point().compare_x_y(end_point()) > 0); + LineSegment result; + + if (swap_endlines) + { + result = new LineSegment(this.end, this.middle, this.start); + result.precalculated_start_point = this.precalculated_end_point; + result.precalculated_end_point = this.precalculated_start_point; + } + else + { + result = this; + } + + return result; + } + private final Line start; + private final Line middle; + private final Line end; + transient private Point precalculated_start_point = null; + transient private Point precalculated_end_point = null; +} diff --git a/geometry/planar/OrthogonalBoundingDirections.java b/src/main/java/geometry/planar/OrthogonalBoundingDirections.java similarity index 65% rename from geometry/planar/OrthogonalBoundingDirections.java rename to src/main/java/geometry/planar/OrthogonalBoundingDirections.java index 29fd25c..4e5f6ae 100644 --- a/geometry/planar/OrthogonalBoundingDirections.java +++ b/src/main/java/geometry/planar/OrthogonalBoundingDirections.java @@ -1,77 +1,113 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - */ - -package geometry.planar; - -/** - * - * Implements the abstract class ShapeDirections as - * the 4 orthogonal directions. - * The class is a singleton with the only instanciation INSTANCE. - * - - * @author Alfons Wirtz - */ -public class OrthogonalBoundingDirections implements ShapeBoundingDirections -{ - /** - * the one and only instantiation - */ - public static final OrthogonalBoundingDirections - INSTANCE = new OrthogonalBoundingDirections(); - - public int count() - { - return 4; - } - - public RegularTileShape bounds (ConvexShape p_shape) - { - return p_shape.bounding_shape(this); - } - - public RegularTileShape bounds (IntBox p_box) - { - return p_box; - } - - public RegularTileShape bounds (IntOctagon p_oct) - { - return p_oct.bounding_box(); - } - - public RegularTileShape bounds (Simplex p_simplex) - { - return p_simplex.bounding_box(); - } - - public RegularTileShape bounds (Circle p_circle) - { - return p_circle.bounding_box(); - } - - public RegularTileShape bounds (PolygonShape p_polygon) - { - return p_polygon.bounding_box(); - } - - /** - * prevent instantiation - */ - private OrthogonalBoundingDirections() - { - } -} \ No newline at end of file +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + */ + +package geometry.planar; + +/** + * + * Implements the abstract class ShapeDirections as + * the 4 orthogonal directions. + * The class is a singleton with the only instanciation INSTANCE. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class OrthogonalBoundingDirections implements ShapeBoundingDirections +{ + /** + * the one and only instantiation + */ + public static final OrthogonalBoundingDirections + INSTANCE = new OrthogonalBoundingDirections(); + + /** + *

count.

+ * + * @return a int. + */ + public int count() + { + return 4; + } + + /** + *

bounds.

+ * + * @param p_shape a {@link geometry.planar.ConvexShape} object. + * @return a {@link geometry.planar.RegularTileShape} object. + */ + public RegularTileShape bounds (ConvexShape p_shape) + { + return p_shape.bounding_shape(this); + } + + /** + *

bounds.

+ * + * @param p_box a {@link geometry.planar.IntBox} object. + * @return a {@link geometry.planar.RegularTileShape} object. + */ + public RegularTileShape bounds (IntBox p_box) + { + return p_box; + } + + /** + *

bounds.

+ * + * @param p_oct a {@link geometry.planar.IntOctagon} object. + * @return a {@link geometry.planar.RegularTileShape} object. + */ + public RegularTileShape bounds (IntOctagon p_oct) + { + return p_oct.bounding_box(); + } + + /** {@inheritDoc} */ + public RegularTileShape bounds (Simplex p_simplex) + { + return p_simplex.bounding_box(); + } + + /** + *

bounds.

+ * + * @param p_circle a {@link geometry.planar.Circle} object. + * @return a {@link geometry.planar.RegularTileShape} object. + */ + public RegularTileShape bounds (Circle p_circle) + { + return p_circle.bounding_box(); + } + + /** + *

bounds.

+ * + * @param p_polygon a {@link geometry.planar.PolygonShape} object. + * @return a {@link geometry.planar.RegularTileShape} object. + */ + public RegularTileShape bounds (PolygonShape p_polygon) + { + return p_polygon.bounding_box(); + } + + /** + * prevent instantiation + */ + private OrthogonalBoundingDirections() + { + } +} diff --git a/geometry/planar/Point.java b/src/main/java/geometry/planar/Point.java similarity index 76% rename from geometry/planar/Point.java rename to src/main/java/geometry/planar/Point.java index 88150ad..55b89f7 100644 --- a/geometry/planar/Point.java +++ b/src/main/java/geometry/planar/Point.java @@ -1,239 +1,300 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * Point.java - * - * Created on 1. Februar 2003, 11:38 - */ - -package geometry.planar; - -import java.math.BigInteger; - -/** - * Abstract class describing functionality for Points in the plane. - * - * @author Alfons Wirtz - */ - -public abstract class Point implements java.io.Serializable -{ - - /** - * returns the translation of this point by p_vector - */ - public abstract Point translate_by(Vector p_vector ); - - /** - * returns the difference vector of this point and p_other - */ - public abstract Vector difference_by(Point p_other); - - - /** - * approximates the coordinates of this point by float coordinates - */ - public abstract FloatPoint to_float(); - - /** - * returns true, if this Point is a RationalPoint with denominator z = 0. - */ - public abstract boolean is_infinite(); - - /** - * creates the smallest Box with integer coordinates containing this point. - */ - public abstract IntBox surrounding_box(); - - - /** - * creates the smallest Octagon with integer coordinates containing this point. - */ - public abstract IntOctagon surrounding_octagon(); - - /** - * Returns true, if this point lies in the interiour or on the border - * of p_box. - */ - public abstract boolean is_contained_in( IntBox p_box); - - - public abstract Side side_of(Line p_line); - - /** - * returns the nearest point to this point on p_line - */ - public abstract Point perpendicular_projection(Line p_line); - - /** - * Standard implementation of the zero point . - */ - public static final IntPoint ZERO = new IntPoint(0, 0); - - /** - * creates an IntPoint from p_x and p_y. If p_x or p_y is to big for - * an IntPoint, a RationalPoint is created. - */ - public static Point get_instance(int p_x, int p_y) - { - IntPoint result = new IntPoint(p_x, p_y); - if ( Math.abs(p_x) > Limits.CRIT_INT || - Math.abs(p_x) > Limits.CRIT_INT ) - { - return new RationalPoint(result); - } - return result; - } - - /** - * factory method for creating a Point from 3 BigIntegers - */ - public static Point get_instance(BigInteger p_x, BigInteger p_y, - BigInteger p_z) - { - if (p_z.signum() < 0) - { - // the dominator z of a RationalPoint is expected to be positive - p_x = p_x.negate(); - p_y = p_y.negate(); - p_z = p_z.negate(); - - } - if ((p_x.mod(p_z)).signum() == 0 && (p_x.mod(p_z)).signum() == 0) - { - // p_x and p_y can be divided by p_z - p_x = p_x.divide(p_z); - p_y = p_y.divide(p_z); - p_z = BigInteger.ONE; - } - if (p_z.equals(BigInteger.ONE)) - { - if ( (p_x.abs()).compareTo(Limits.CRIT_INT_BIG) <= 0 && - (p_y.abs()).compareTo(Limits.CRIT_INT_BIG) <= 0 ) - { - // the Point fits into an IntPoint - return new IntPoint(p_x.intValue(), p_y.intValue()); - } - } - return new RationalPoint(p_x, p_y, p_z); - } - - /** - * The function returns - * Side.ON_THE_LEFT, if this Point is on the left of the line from p_1 to p_2; - * Side.ON_THE_RIGHT, if this Point is on the right of the line from p_1 to p_2; - * and Side.COLLINEAR, if this Point is collinear with p_1 and p_2. - */ - public Side side_of(Point p_1, Point p_2) - { - Vector v1 = difference_by(p_1); - Vector v2 = p_2.difference_by(p_1); - return v1.side_of(v2); - } - - /** - * Calculates the perpendicular direction froma this point - * to p_line. Returns Direction.NULL, if this point lies on p_line. - */ - public Direction perpendicular_direction(Line p_line) - { - Side side = this.side_of(p_line); - if (side == Side.COLLINEAR) - { - return Direction.NULL; - } - Direction result; - if (side == Side.ON_THE_RIGHT) - { - result = p_line.direction().turn_45_degree(2); - } - else - { - result = p_line.direction().turn_45_degree(6); - } - return result; - } - - /** - * Returns 1, if this Point has a strict bigger x coordinate than p_other, - * 0, if the x cooordinates are equal, and -1 otherwise. - */ - public abstract int compare_x(Point p_other); - - /** - * Returns 1, if this Point has a strict bigger y coordinate than p_other, - * 0, if the y cooordinates are equal, and -1 otherwise. - */ - public abstract int compare_y(Point p_other); - - /** - * The function returns compare_x (p_other), if the result is not 0. - * Otherwise it returns compare_y (p_other). - */ - public int compare_x_y(Point p_other) - { - int result = compare_x(p_other); - if (result == 0) - { - result = compare_y(p_other); - } - return result; - } - - /** - * Turns this point by p_factor times 90 degree around p_pole. - */ - public Point turn_90_degree(int p_factor, Point p_pole) - { - Vector v = this.difference_by(p_pole); - v = v.turn_90_degree(p_factor); - return p_pole.translate_by(v); - } - - /** - * Mirrors this point at the vertical line through p_pole. - */ - public Point mirror_vertical(Point p_pole) - { - Vector v = this.difference_by(p_pole); - v = v. mirror_at_y_axis(); - return p_pole.translate_by(v); - } - - /** - * Mirrors this point at the horizontal line through p_pole. - */ - public Point mirror_horizontal(Point p_pole) - { - Vector v = this.difference_by(p_pole); - v = v. mirror_at_x_axis(); - return p_pole.translate_by(v); - } - - // auxiliary functions needed because the virtual function mechanism - // does not work in parameter position - - abstract Point translate_by(IntVector p_vector ); - abstract Point translate_by(RationalVector p_vector ); - - abstract Vector difference_by(IntPoint p_other); - abstract Vector difference_by(RationalPoint p_other); - - abstract int compare_x(IntPoint p_other); - abstract int compare_x(RationalPoint p_other); - - abstract int compare_y(IntPoint p_other); - abstract int compare_y(RationalPoint p_other); -} \ No newline at end of file +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * Point.java + * + * Created on 1. Februar 2003, 11:38 + */ + +package geometry.planar; + +import java.math.BigInteger; + +/** + * Abstract class describing functionality for Points in the plane. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public abstract class Point implements java.io.Serializable +{ + + /** + * returns the translation of this point by p_vector + * + * @param p_vector a {@link geometry.planar.Vector} object. + * @return a {@link geometry.planar.Point} object. + */ + public abstract Point translate_by(Vector p_vector ); + + /** + * returns the difference vector of this point and p_other + * + * @param p_other a {@link geometry.planar.Point} object. + * @return a {@link geometry.planar.Vector} object. + */ + public abstract Vector difference_by(Point p_other); + + + /** + * approximates the coordinates of this point by float coordinates + * + * @return a {@link geometry.planar.FloatPoint} object. + */ + public abstract FloatPoint to_float(); + + /** + * returns true, if this Point is a RationalPoint with denominator z = 0. + * + * @return a boolean. + */ + public abstract boolean is_infinite(); + + /** + * creates the smallest Box with integer coordinates containing this point. + * + * @return a {@link geometry.planar.IntBox} object. + */ + public abstract IntBox surrounding_box(); + + + /** + * creates the smallest Octagon with integer coordinates containing this point. + * + * @return a {@link geometry.planar.IntOctagon} object. + */ + public abstract IntOctagon surrounding_octagon(); + + /** + * Returns true, if this point lies in the interiour or on the border + * of p_box. + * + * @param p_box a {@link geometry.planar.IntBox} object. + * @return a boolean. + */ + public abstract boolean is_contained_in( IntBox p_box); + + + /** + *

side_of.

+ * + * @param p_line a {@link geometry.planar.Line} object. + * @return a {@link geometry.planar.Side} object. + */ + public abstract Side side_of(Line p_line); + + /** + * returns the nearest point to this point on p_line + * + * @param p_line a {@link geometry.planar.Line} object. + * @return a {@link geometry.planar.Point} object. + */ + public abstract Point perpendicular_projection(Line p_line); + + /** + * Standard implementation of the zero point . + */ + public static final IntPoint ZERO = new IntPoint(0, 0); + + /** + * creates an IntPoint from p_x and p_y. If p_x or p_y is to big for + * an IntPoint, a RationalPoint is created. + * + * @param p_x a int. + * @param p_y a int. + * @return a {@link geometry.planar.Point} object. + */ + public static Point get_instance(int p_x, int p_y) + { + IntPoint result = new IntPoint(p_x, p_y); + if ( Math.abs(p_x) > Limits.CRIT_INT || + Math.abs(p_x) > Limits.CRIT_INT ) + { + return new RationalPoint(result); + } + return result; + } + + /** + * factory method for creating a Point from 3 BigIntegers + * + * @param p_x a {@link java.math.BigInteger} object. + * @param p_y a {@link java.math.BigInteger} object. + * @param p_z a {@link java.math.BigInteger} object. + * @return a {@link geometry.planar.Point} object. + */ + public static Point get_instance(BigInteger p_x, BigInteger p_y, + BigInteger p_z) + { + if (p_z.signum() < 0) + { + // the dominator z of a RationalPoint is expected to be positive + p_x = p_x.negate(); + p_y = p_y.negate(); + p_z = p_z.negate(); + + } + if ((p_x.mod(p_z)).signum() == 0 && (p_x.mod(p_z)).signum() == 0) + { + // p_x and p_y can be divided by p_z + p_x = p_x.divide(p_z); + p_y = p_y.divide(p_z); + p_z = BigInteger.ONE; + } + if (p_z.equals(BigInteger.ONE)) + { + if ( (p_x.abs()).compareTo(Limits.CRIT_INT_BIG) <= 0 && + (p_y.abs()).compareTo(Limits.CRIT_INT_BIG) <= 0 ) + { + // the Point fits into an IntPoint + return new IntPoint(p_x.intValue(), p_y.intValue()); + } + } + return new RationalPoint(p_x, p_y, p_z); + } + + /** + * The function returns + * Side.ON_THE_LEFT, if this Point is on the left of the line from p_1 to p_2; + * Side.ON_THE_RIGHT, if this Point is on the right of the line from p_1 to p_2; + * and Side.COLLINEAR, if this Point is collinear with p_1 and p_2. + * + * @param p_1 a {@link geometry.planar.Point} object. + * @param p_2 a {@link geometry.planar.Point} object. + * @return a {@link geometry.planar.Side} object. + */ + public Side side_of(Point p_1, Point p_2) + { + Vector v1 = difference_by(p_1); + Vector v2 = p_2.difference_by(p_1); + return v1.side_of(v2); + } + + /** + * Calculates the perpendicular direction froma this point + * to p_line. Returns Direction.NULL, if this point lies on p_line. + * + * @param p_line a {@link geometry.planar.Line} object. + * @return a {@link geometry.planar.Direction} object. + */ + public Direction perpendicular_direction(Line p_line) + { + Side side = this.side_of(p_line); + if (side == Side.COLLINEAR) + { + return Direction.NULL; + } + Direction result; + if (side == Side.ON_THE_RIGHT) + { + result = p_line.direction().turn_45_degree(2); + } + else + { + result = p_line.direction().turn_45_degree(6); + } + return result; + } + + /** + * Returns 1, if this Point has a strict bigger x coordinate than p_other, + * 0, if the x cooordinates are equal, and -1 otherwise. + * + * @param p_other a {@link geometry.planar.Point} object. + * @return a int. + */ + public abstract int compare_x(Point p_other); + + /** + * Returns 1, if this Point has a strict bigger y coordinate than p_other, + * 0, if the y cooordinates are equal, and -1 otherwise. + * + * @param p_other a {@link geometry.planar.Point} object. + * @return a int. + */ + public abstract int compare_y(Point p_other); + + /** + * The function returns compare_x (p_other), if the result is not 0. + * Otherwise it returns compare_y (p_other). + * + * @param p_other a {@link geometry.planar.Point} object. + * @return a int. + */ + public int compare_x_y(Point p_other) + { + int result = compare_x(p_other); + if (result == 0) + { + result = compare_y(p_other); + } + return result; + } + + /** + * Turns this point by p_factor times 90 degree around p_pole. + * + * @param p_factor a int. + * @param p_pole a {@link geometry.planar.Point} object. + * @return a {@link geometry.planar.Point} object. + */ + public Point turn_90_degree(int p_factor, Point p_pole) + { + Vector v = this.difference_by(p_pole); + v = v.turn_90_degree(p_factor); + return p_pole.translate_by(v); + } + + /** + * Mirrors this point at the vertical line through p_pole. + * + * @param p_pole a {@link geometry.planar.Point} object. + * @return a {@link geometry.planar.Point} object. + */ + public Point mirror_vertical(Point p_pole) + { + Vector v = this.difference_by(p_pole); + v = v. mirror_at_y_axis(); + return p_pole.translate_by(v); + } + + /** + * Mirrors this point at the horizontal line through p_pole. + * + * @param p_pole a {@link geometry.planar.Point} object. + * @return a {@link geometry.planar.Point} object. + */ + public Point mirror_horizontal(Point p_pole) + { + Vector v = this.difference_by(p_pole); + v = v. mirror_at_x_axis(); + return p_pole.translate_by(v); + } + + // auxiliary functions needed because the virtual function mechanism + // does not work in parameter position + + abstract Point translate_by(IntVector p_vector ); + abstract Point translate_by(RationalVector p_vector ); + + abstract Vector difference_by(IntPoint p_other); + abstract Vector difference_by(RationalPoint p_other); + + abstract int compare_x(IntPoint p_other); + abstract int compare_x(RationalPoint p_other); + + abstract int compare_y(IntPoint p_other); + abstract int compare_y(RationalPoint p_other); +} diff --git a/geometry/planar/Polygon.java b/src/main/java/geometry/planar/Polygon.java similarity index 92% rename from geometry/planar/Polygon.java rename to src/main/java/geometry/planar/Polygon.java index 7e4af31..f012b20 100644 --- a/geometry/planar/Polygon.java +++ b/src/main/java/geometry/planar/Polygon.java @@ -1,181 +1,188 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - */ - -package geometry.planar; - -import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedList; - -/** - * - * A Polygon is a list of points in the plane, where no 2 consecutive - * points may be equal and no 3 consecutive points collinear. - * - * @author Alfons Wirtz# - */ - - -public class Polygon implements java.io.Serializable -{ - /** - * Creates a polygon from p_point_arr. - * Multiple points and points, which are collinear with its previous - * and next point will be removed. - */ - public Polygon(Point [] p_point_arr) - { - corners = new LinkedList(); - if (p_point_arr.length == 0) - { - return; - } - for (int i = 0; i < p_point_arr.length; ++i) - { - corners.add(p_point_arr[i]); - } - - boolean corner_removed = true; - while (corner_removed) - { - corner_removed = false; - // remove multiple points - - if (corners.isEmpty()) - { - return; - } - Iterator i = corners.iterator(); - Point curr_ob = i.next(); - while(i.hasNext()) - { - Point next_ob = i.next(); - if(next_ob.equals(curr_ob)) - { - i.remove(); - corner_removed = true; - } - else - { - curr_ob = next_ob; - } - } - - // remove points which are collinear with the previous - // and next point. - i = corners.iterator(); - Point prev = i.next(); - Iterator prev_i = corners.iterator(); - if (!i.hasNext()) - { - continue; - } - Point curr = i.next(); - prev_i.next(); - while(i.hasNext()) - { - Point next = i.next(); - prev_i.next(); - - if(curr.side_of(prev, next) == Side.COLLINEAR) - { - prev_i.remove(); - corner_removed = true; - break; - } - prev = curr; - curr = next; - } - } - } - - /** - * returns the array of corners of this polygon - */ - public Point[] corner_array() - { - int corner_count = corners.size(); - Point[] result = new Point[corner_count]; - Iterator it = corners.iterator(); - for (int i = 0; i < corner_count; ++i) - { - result[i] = it.next(); - } - return result; - } - - /** - * Reverts the order of the corners of this polygon. - */ - public Polygon revert_corners() - { - Point [] corner_arr = corner_array(); - Point [] reverse_corner_arr = new Point[corner_arr.length]; - for (int i = 0; i < corner_arr.length; ++i) - { - reverse_corner_arr[i] = corner_arr [corner_arr.length - i - 1]; - } - return new Polygon(reverse_corner_arr); - } - /** - * Returns the winding number of this polygon, treated as closed. - * It will be > 0, if the corners are in countercock sense, - * and < 0, if the corners are in clockwise sense. - */ - public int winding_number_after_closing() - { - Point [] corner_arr = corner_array(); - if (corner_arr.length < 2) - { - return 0; - } - Vector first_side_vector = corner_arr[1].difference_by(corner_arr[0]); - Vector prev_side_vector = first_side_vector; - int corner_count = corner_arr.length; - // Skip the last corner, if it is equal to the first corner. - if (corner_arr[0].equals(corner_arr[corner_count - 1])) - { - --corner_count; - } - double angle_sum = 0; - for (int i = 1; i <= corner_count; ++i) - { - Vector next_side_vector; - if (i == corner_count - 1) - { - next_side_vector = corner_arr[0].difference_by(corner_arr[i]); - } - else if (i == corner_count) - { - next_side_vector = first_side_vector; - } - else - { - next_side_vector = corner_arr[i + 1].difference_by(corner_arr[i]); - } - angle_sum += prev_side_vector.angle_approx(next_side_vector); - prev_side_vector = next_side_vector; - } - angle_sum /= 2.0 * Math.PI; - if (Math.abs(angle_sum) < 0.5) - { - System.out.println ("Polygon.winding_number_after_closing: winding number != 0 expected"); - } - return (int) Math.round(angle_sum); - } - - private final Collection corners; -} \ No newline at end of file +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + */ + +package geometry.planar; + +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; + +/** + * + * A Polygon is a list of points in the plane, where no 2 consecutive + * points may be equal and no 3 consecutive points collinear. + * + * @author Alfons Wirtz# + * @version $Id: $Id + */ +public class Polygon implements java.io.Serializable +{ + /** + * Creates a polygon from p_point_arr. + * Multiple points and points, which are collinear with its previous + * and next point will be removed. + * + * @param p_point_arr an array of {@link geometry.planar.Point} objects. + */ + public Polygon(Point [] p_point_arr) + { + corners = new LinkedList(); + if (p_point_arr.length == 0) + { + return; + } + for (int i = 0; i < p_point_arr.length; ++i) + { + corners.add(p_point_arr[i]); + } + + boolean corner_removed = true; + while (corner_removed) + { + corner_removed = false; + // remove multiple points + + if (corners.isEmpty()) + { + return; + } + Iterator i = corners.iterator(); + Point curr_ob = i.next(); + while(i.hasNext()) + { + Point next_ob = i.next(); + if(next_ob.equals(curr_ob)) + { + i.remove(); + corner_removed = true; + } + else + { + curr_ob = next_ob; + } + } + + // remove points which are collinear with the previous + // and next point. + i = corners.iterator(); + Point prev = i.next(); + Iterator prev_i = corners.iterator(); + if (!i.hasNext()) + { + continue; + } + Point curr = i.next(); + prev_i.next(); + while(i.hasNext()) + { + Point next = i.next(); + prev_i.next(); + + if(curr.side_of(prev, next) == Side.COLLINEAR) + { + prev_i.remove(); + corner_removed = true; + break; + } + prev = curr; + curr = next; + } + } + } + + /** + * returns the array of corners of this polygon + * + * @return an array of {@link geometry.planar.Point} objects. + */ + public Point[] corner_array() + { + int corner_count = corners.size(); + Point[] result = new Point[corner_count]; + Iterator it = corners.iterator(); + for (int i = 0; i < corner_count; ++i) + { + result[i] = it.next(); + } + return result; + } + + /** + * Reverts the order of the corners of this polygon. + * + * @return a {@link geometry.planar.Polygon} object. + */ + public Polygon revert_corners() + { + Point [] corner_arr = corner_array(); + Point [] reverse_corner_arr = new Point[corner_arr.length]; + for (int i = 0; i < corner_arr.length; ++i) + { + reverse_corner_arr[i] = corner_arr [corner_arr.length - i - 1]; + } + return new Polygon(reverse_corner_arr); + } + /** + * Returns the winding number of this polygon, treated as closed. + * {@code It will be > 0, if the corners are in countercock sense, + * and < 0, if the corners are in clockwise sense.} + * + * @return a int. + */ + public int winding_number_after_closing() + { + Point [] corner_arr = corner_array(); + if (corner_arr.length < 2) + { + return 0; + } + Vector first_side_vector = corner_arr[1].difference_by(corner_arr[0]); + Vector prev_side_vector = first_side_vector; + int corner_count = corner_arr.length; + // Skip the last corner, if it is equal to the first corner. + if (corner_arr[0].equals(corner_arr[corner_count - 1])) + { + --corner_count; + } + double angle_sum = 0; + for (int i = 1; i <= corner_count; ++i) + { + Vector next_side_vector; + if (i == corner_count - 1) + { + next_side_vector = corner_arr[0].difference_by(corner_arr[i]); + } + else if (i == corner_count) + { + next_side_vector = first_side_vector; + } + else + { + next_side_vector = corner_arr[i + 1].difference_by(corner_arr[i]); + } + angle_sum += prev_side_vector.angle_approx(next_side_vector); + prev_side_vector = next_side_vector; + } + angle_sum /= 2.0 * Math.PI; + if (Math.abs(angle_sum) < 0.5) + { + System.out.println ("Polygon.winding_number_after_closing: winding number != 0 expected"); + } + return (int) Math.round(angle_sum); + } + + private final Collection corners; +} diff --git a/geometry/planar/PolygonShape.java b/src/main/java/geometry/planar/PolygonShape.java similarity index 92% rename from geometry/planar/PolygonShape.java rename to src/main/java/geometry/planar/PolygonShape.java index 9330a15..0c465b6 100644 --- a/geometry/planar/PolygonShape.java +++ b/src/main/java/geometry/planar/PolygonShape.java @@ -31,11 +31,16 @@ * In case of equal y-value the corner with the lowest x-value comes first. * * @author Alfons Wirtz + * @version $Id: $Id */ public class PolygonShape extends PolylineShape { - /** Creates a new instance of PolygonShape */ + /** + * Creates a new instance of PolygonShape + * + * @param p_polygon a {@link geometry.planar.Polygon} object. + */ public PolygonShape(Polygon p_polygon) { Polygon curr_polygon = p_polygon; @@ -115,12 +120,18 @@ public PolygonShape(Polygon p_polygon) } + /** + *

Constructor for PolygonShape.

+ * + * @param p_corner_arr an array of {@link geometry.planar.Point} objects. + */ public PolygonShape(Point[] p_corner_arr) { this(new Polygon(p_corner_arr)); } + /** {@inheritDoc} */ public Point corner(int p_no) { if (p_no < 0 || p_no >= corners.length) @@ -131,21 +142,39 @@ public Point corner(int p_no) return corners[p_no]; } + /** + *

border_line_count.

+ * + * @return a int. + */ public int border_line_count() { return corners.length; } + /** {@inheritDoc} */ public boolean corner_is_bounded(int p_no) { return true; } + /** + *

intersects.

+ * + * @param p_shape a {@link geometry.planar.Shape} object. + * @return a boolean. + */ public boolean intersects(Shape p_shape) { return p_shape.intersects(this); } + /** + *

intersects.

+ * + * @param p_circle a {@link geometry.planar.Circle} object. + * @return a boolean. + */ public boolean intersects(Circle p_circle) { TileShape[] convex_pieces = split_to_convex(); @@ -157,6 +186,12 @@ public boolean intersects(Circle p_circle) return false; } + /** + *

intersects.

+ * + * @param p_simplex a {@link geometry.planar.Simplex} object. + * @return a boolean. + */ public boolean intersects(Simplex p_simplex) { TileShape[] convex_pieces = split_to_convex(); @@ -168,6 +203,7 @@ public boolean intersects(Simplex p_simplex) return false; } + /** {@inheritDoc} */ public boolean intersects(IntOctagon p_oct) { TileShape[] convex_pieces = split_to_convex(); @@ -179,6 +215,12 @@ public boolean intersects(IntOctagon p_oct) return false; } + /** + *

intersects.

+ * + * @param p_box a {@link geometry.planar.IntBox} object. + * @return a boolean. + */ public boolean intersects(IntBox p_box) { TileShape[] convex_pieces = split_to_convex(); @@ -190,12 +232,14 @@ public boolean intersects(IntBox p_box) return false; } + /** {@inheritDoc} */ public Polyline[] cutout(Polyline p_polyline) { System.out.println("PolygonShape.cutout not yet implemented"); return null; } + /** {@inheritDoc} */ public PolygonShape enlarge(double p_offset) { if (p_offset == 0) @@ -206,17 +250,29 @@ public PolygonShape enlarge(double p_offset) return null; } + /** {@inheritDoc} */ public double border_distance(FloatPoint p_point) { System.out.println("PolygonShape.border_distance not yet implemented"); return 0; } + /** + *

smallest_radius.

+ * + * @return a double. + */ public double smallest_radius() { return border_distance(centre_of_gravity()); } + /** + *

contains.

+ * + * @param p_point a {@link geometry.planar.FloatPoint} object. + * @return a boolean. + */ public boolean contains(FloatPoint p_point) { TileShape[] convex_pieces = split_to_convex(); @@ -228,6 +284,7 @@ public boolean contains(FloatPoint p_point) return false; } + /** {@inheritDoc} */ public boolean contains_inside(Point p_point) { if (contains_on_border(p_point)) @@ -237,6 +294,7 @@ public boolean contains_inside(Point p_point) return !is_outside(p_point); } + /** {@inheritDoc} */ public boolean is_outside(Point p_point) { TileShape[] convex_pieces = split_to_convex(); @@ -248,22 +306,26 @@ public boolean is_outside(Point p_point) return true; } + /** {@inheritDoc} */ public boolean contains(Point p_point) { return !is_outside(p_point); } + /** {@inheritDoc} */ public boolean contains_on_border(Point p_point) { //System.out.println("PolygonShape.contains_on_edge not yet implemented"); return false; } + /** {@inheritDoc} */ public double distance(FloatPoint p_point) { System.out.println("PolygonShape.distance not yet implemented"); return 0; } + /** {@inheritDoc} */ public PolygonShape translate_by(Vector p_vector) { if (p_vector.equals(Vector.ZERO)) @@ -278,11 +340,17 @@ public PolygonShape translate_by(Vector p_vector) return new PolygonShape(new_corners); } + /** {@inheritDoc} */ public RegularTileShape bounding_shape(ShapeBoundingDirections p_dirs) { return p_dirs.bounds(this); } + /** + *

bounding_box.

+ * + * @return a {@link geometry.planar.IntBox} object. + */ public IntBox bounding_box() { if (precalculated_bounding_box == null) @@ -305,6 +373,11 @@ public IntBox bounding_box() } return precalculated_bounding_box; } + /** + *

bounding_octagon.

+ * + * @return a {@link geometry.planar.IntOctagon} object. + */ public IntOctagon bounding_octagon() { if (precalculated_bounding_octagon == null) @@ -345,6 +418,8 @@ public IntOctagon bounding_octagon() /** * Checks, if every line segment between 2 points of the shape is contained * completely in the shape. + * + * @return a boolean. */ public boolean is_comvex() { @@ -386,6 +461,11 @@ public boolean is_comvex() return true; } + /** + *

convex_hull.

+ * + * @return a {@link geometry.planar.PolygonShape} object. + */ public PolygonShape convex_hull() { if (corners.length <= 2) @@ -424,6 +504,11 @@ public PolygonShape convex_hull() return this; } + /** + *

bounding_tile.

+ * + * @return a {@link geometry.planar.TileShape} object. + */ public TileShape bounding_tile() { PolygonShape hull = convex_hull(); @@ -437,6 +522,11 @@ public TileShape bounding_tile() return TileShape.get_instance(bounding_lines); } + /** + *

area.

+ * + * @return a double. + */ public double area() { @@ -462,6 +552,11 @@ public double area() return result; } + /** + *

dimension.

+ * + * @return a int. + */ public int dimension() { if (corners.length == 0) @@ -473,16 +568,27 @@ public int dimension() return 2; } + /** + *

is_bounded.

+ * + * @return a boolean. + */ public boolean is_bounded() { return true; } + /** + *

is_empty.

+ * + * @return a boolean. + */ public boolean is_empty() { return corners.length == 0; } + /** {@inheritDoc} */ public Line border_line(int p_no) { if (p_no < 0 || p_no >= corners.length) @@ -502,6 +608,7 @@ public Line border_line(int p_no) return new Line(corners[p_no], next_corner); } + /** {@inheritDoc} */ public FloatPoint nearest_point_approx(FloatPoint p_from_point) { double min_dist = Double.MAX_VALUE; @@ -520,6 +627,7 @@ public FloatPoint nearest_point_approx(FloatPoint p_from_point) return result; } + /** {@inheritDoc} */ public PolygonShape turn_90_degree(int p_factor, IntPoint p_pole) { Point[] new_corners = new Point[corners.length]; @@ -530,6 +638,7 @@ public PolygonShape turn_90_degree(int p_factor, IntPoint p_pole) return new PolygonShape(new_corners); } + /** {@inheritDoc} */ public PolygonShape rotate_approx(double p_angle, FloatPoint p_pole) { if (p_angle == 0) @@ -544,6 +653,7 @@ public PolygonShape rotate_approx(double p_angle, FloatPoint p_pole) return new PolygonShape(new_corners); } + /** {@inheritDoc} */ public PolygonShape mirror_vertical(IntPoint p_pole) { Point[] new_corners = new Point[corners.length]; @@ -554,6 +664,7 @@ public PolygonShape mirror_vertical(IntPoint p_pole) return new PolygonShape(new_corners); } + /** {@inheritDoc} */ public PolygonShape mirror_horizontal(IntPoint p_pole) { Point[] new_corners = new Point[corners.length]; @@ -569,6 +680,8 @@ public PolygonShape mirror_horizontal(IntPoint p_pole) * The result is not exact, because rounded intersections of lines are * used in the result pieces. It can be made exact, if Polylines are returned * instead of Polygons, so that no intersection points are needed in the result. + * + * @return an array of {@link geometry.planar.TileShape} objects. */ public TileShape[] split_to_convex() { diff --git a/geometry/planar/Polyline.java b/src/main/java/geometry/planar/Polyline.java similarity index 90% rename from geometry/planar/Polyline.java rename to src/main/java/geometry/planar/Polyline.java index cdb3c06..dfeba57 100644 --- a/geometry/planar/Polyline.java +++ b/src/main/java/geometry/planar/Polyline.java @@ -1,1190 +1,1316 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - */ - -package geometry.planar; - -import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedList; - -/** - * - * A Polyline is a sequence of lines, where no 2 consecutive - * lines may be parallel. A Polyline of n lines defines a Polygon of - * n-1 intersection points of consecutive lines. - * The lines of the objects of class Polyline are normally defined - * by points with integer coordinates, wheras the intersections - * of Lines can be representated in general only by infinite precision - * rational points. We use polylines with integer coordinates instead - * of polygons with infinite precision rational coordinates - * because of its better performance in geometric calculations. - * - * - * @author Alfons Wirtz - */ - -public class Polyline implements java.io.Serializable -{ - /** - * creates a polyline of length p_polygon.corner_count + 1 from p_polygon, - * so that the i-th corner of p_polygon will be the intersection of - * the i-th and the i+1-th lines of the new created p_polyline - * for 0 <= i < p_point_arr.length. p_polygon must have at least 2 corners - */ - public Polyline(Polygon p_polygon) - { - Point[] point_arr = p_polygon.corner_array(); - if (point_arr.length < 2) - { - System.out.println("Polyline: must contain at least 2 different points"); - arr = new Line[0]; - return; - } - arr = new Line [point_arr.length + 1]; - for (int i = 1; i < point_arr.length; ++i) - { - arr[i] = new Line(point_arr[i - 1], point_arr[i]); - } - // construct perpendicular lines at the start and at the end to represent - // the first and the last point of point_arr as intersection of lines. - - Direction dir = Direction.get_instance(point_arr[0], point_arr[1]); - arr [0] = Line.get_instance(point_arr[0], dir.turn_45_degree(2)); - - dir = Direction.get_instance(point_arr[point_arr.length - 1], point_arr[point_arr.length - 2]); - arr[point_arr.length] = - Line.get_instance(point_arr[point_arr.length - 1], dir.turn_45_degree(2)); - } - - public Polyline(Point[] p_points) - { - this(new Polygon(p_points)); - } - - /** - * creates a polyline consisting of 3 lines - */ - public Polyline(Point p_from_corner, Point p_to_corner) - { - if (p_from_corner.equals(p_to_corner)) - { - arr = new Line [0]; - return; - } - arr = new Line [3]; - Direction dir = Direction.get_instance(p_from_corner, p_to_corner); - arr [0] = Line.get_instance(p_from_corner, dir.turn_45_degree(2)); - arr[1] = new Line(p_from_corner, p_to_corner); - dir = Direction.get_instance(p_from_corner, p_to_corner); - arr [2] = Line.get_instance(p_to_corner, dir.turn_45_degree(2)); - } - - /** - * Creates a polyline from an array of lines. - * Lines, which are parallel to the previous line are skipped. - * The directed lines are normalized, so that they intersect - * the previous line before the next line - */ - public Polyline(Line[] p_line_arr) - { - Line [] lines = remove_consecutive_parallel_lines(p_line_arr); - lines = remove_overlaps(lines); - if (lines.length < 3 ) - { - arr = new Line[0]; - return; - } - precalculated_float_corners = new FloatPoint [lines.length - 1]; - - // turn evtl the direction of the lines that they point always - // from the previous corner to the next corner - for (int i = 1; i < lines.length - 1; ++i) - { - precalculated_float_corners[i] = lines[i].intersection_approx(lines[i + 1]); - Side side_of_line = lines[i - 1].side_of(precalculated_float_corners[i]); - if (side_of_line != Side.COLLINEAR) - { - Direction d0 = lines[i - 1].direction(); - Direction d1 = lines[i].direction(); - Side side1 = d0.side_of(d1); - if (side1 != side_of_line) - { - lines[i] = lines[i].opposite(); - } - } - } - arr = lines; - } - - /** - * Returns the number of lines minus 1 - */ - public int corner_count() - { - return arr.length - 1; - } - - public boolean is_empty() - { - return arr.length < 3; - } - - /** - * Checks, if this polyline is empty or if all corner points are equal. - */ - public boolean is_point() - { - if ( arr.length < 3) - { - return true; - } - Point first_corner = this.corner(0); - for (int i = 1; i < arr.length - 1; ++i) - { - if (!(this.corner(i).equals(first_corner))) - { - return false; - } - } - return true; - } - - /** - * checks, if all lines of this polyline are orthogonal - */ - public boolean is_orthogonal() - { - for (int i = 0; i < arr.length; ++i) - { - if (!arr[i].is_orthogonal()) - { - return false; - } - } - return true; - } - - /** - * checks, if all lines of this polyline are multiples of 45 degree - */ - public boolean is_multiple_of_45_degree() - { - for (int i = 0; i < arr.length; ++i) - { - if (!arr[i].is_multiple_of_45_degree()) - { - return false; - } - } - return true; - } - - /** - * returns the intersection of the first line with the second line - */ - public Point first_corner() - { - return corner(0); - } - - /** - * returns the intersection of the last line with the line before - * the last line - */ - public Point last_corner() - { - return corner(arr.length - 2); - } - - /** - * returns the array of the intersection of two consecutive lines - * approximated by FloatPoint's. - */ - public Point [] corner_arr() - { - if (arr.length < 2) - { - return new Point[0]; - } - if (precalculated_corners == null) - // corner array is not yet allocated - { - precalculated_corners = new Point[arr.length - 1]; - } - for (int i = 0; i < precalculated_corners.length; ++i) - { - if (precalculated_corners[i] == null) - { - precalculated_corners[i] = arr[i].intersection(arr[i + 1]); - } - } - return precalculated_corners; - } - - /** - * returns the array of the intersection of two consecutive lines - * approximated by FloatPoint's. - */ - public FloatPoint [] corner_approx_arr() - { - if (arr.length < 2) - { - return new FloatPoint[0]; - } - if (precalculated_float_corners == null) - // corner array is not yet allocated - { - precalculated_float_corners = new FloatPoint[arr.length - 1]; - } - for (int i = 0; i < precalculated_float_corners.length; ++i) - { - if (precalculated_float_corners[i] == null) - { - precalculated_float_corners[i] = arr[i].intersection_approx(arr[i + 1]); - } - } - return precalculated_float_corners; - } - - /** - * Returns an approximation of the intersection of the p_no-th with - * the (p_no - 1)-th line by a FloatPoint. - */ - public FloatPoint corner_approx(int p_no) - { - int no; - if (p_no < 0) - { - System.out.println("Polyline.corner_approx: p_no is < 0"); - no = 0; - } - else if (p_no >= arr.length - 1) - { - System.out.println("Polyline.corner_approx: p_no must be less than arr.length - 1"); - no = arr.length - 2; - } - else - { - no = p_no; - } - if (precalculated_float_corners == null) - // corner array is not yet allocated - { - precalculated_float_corners = new FloatPoint[arr.length - 1]; - for (int i = 0; i < precalculated_float_corners.length; ++i) - { - precalculated_float_corners[i] = null; - } - } - if (precalculated_float_corners [no] == null) - // corner is not yet calculated - { - precalculated_float_corners[no] = arr[no].intersection_approx(arr[no + 1]); - } - return precalculated_float_corners [no]; - } - - /** - * Returns the intersection of the p_no-th with the (p_no - 1)-th edge line. - */ - public Point corner(int p_no) - { - if (arr.length < 2) - { - System.out.println("Polyline.corner: arr.length is < 2"); - return null; - } - int no; - if (p_no < 0) - { - System.out.println("Polyline.corner: p_no is < 0"); - no = 0; - } - else if (p_no >= arr.length - 1) - { - System.out.println("Polyline.corner: p_no must be less than arr.length - 1"); - no = arr.length - 2; - } - else - { - no = p_no; - } - if (precalculated_corners == null) - // corner array is not yet allocated - { - precalculated_corners = new Point[arr.length - 1]; - for (int i = 0; i < precalculated_corners.length; ++i) - { - precalculated_corners[i] = null; - } - } - if (precalculated_corners [no] == null) - // corner is not yet calculated - { - precalculated_corners[no] = arr[no].intersection(arr[no + 1]); - } - return precalculated_corners [no]; - } - - /** - * return the polyline with the reversed order of lines - */ - public Polyline reverse() - { - Line [] reversed_lines = new Line[arr.length]; - for (int i = 0; i < arr.length; ++i) - { - reversed_lines[i] = arr[arr.length - i - 1].opposite(); - } - return new Polyline(reversed_lines); - } - - /** - * Calculates the length of this polyline from p_from_corner - * to p_to_corner. - */ - public double length_approx(int p_from_corner, int p_to_corner) - { - int from_corner = Math.max(p_from_corner, 0); - int to_corner = Math.min(p_to_corner, arr.length - 2); - double result = 0; - for (int i = from_corner; i < to_corner; ++i) - { - result += this.corner_approx(i + 1).distance(this.corner_approx(i)); - } - return result; - } - - /** - * Calculates the cumulative distance between consecutive corners of - * this polyline. - */ - public double length_approx() - { - return length_approx(0, arr.length - 2); - } - - /** - * calculates for each line a shape around this line - * where the right and left edge lines have the distance p_half_width - * from the center line - * Returns an array of convex shapes of length line_count - 2 - */ - public TileShape[] offset_shapes(int p_half_width) - { - return offset_shapes(p_half_width, 0, arr.length -1); - } - - /** - * calculates for each line between p_from_no and p_to_no a shape around - * this line, where the right and left edge lines have the distance p_half_width - * from the center line - */ - public TileShape[] offset_shapes(int p_half_width, - int p_from_no, int p_to_no) - { - int from_no = Math.max(p_from_no, 0); - int to_no = Math.min(p_to_no, arr.length -1); - int shape_count = Math.max(to_no - from_no -1, 0); - TileShape[] shape_arr = new TileShape[shape_count]; - if (shape_count == 0) - { - return shape_arr; - } - Vector prev_dir = arr[from_no].direction().get_vector(); - Vector curr_dir = arr[from_no + 1].direction().get_vector(); - for (int i = from_no + 1; i < to_no; ++i) - { - Vector next_dir = arr[i + 1].direction().get_vector(); - - Line[] lines = new Line[4]; - - lines[0] = arr[i].translate(-p_half_width); - // current center line translated to the right - - // create the front line of the offset shape - Side next_dir_from_curr_dir = next_dir.side_of(curr_dir); - // left turn from curr_line to next_line - if (next_dir_from_curr_dir == Side.ON_THE_LEFT) - { - lines[1] = arr[i + 1].translate(-p_half_width); - // next right line - } - else - { - lines[1] = arr[i + 1].opposite().translate(-p_half_width); - // next left line in opposite direction - } - - lines[2] = arr[i].opposite().translate(-p_half_width); - // current left line in opposite direction - - // create the back line of the offset shape - Side curr_dir_from_prev_dir = curr_dir.side_of(prev_dir); - // left turn from prev_line to curr_line - if (curr_dir_from_prev_dir == Side.ON_THE_LEFT) - { - lines[3] = arr[i - 1].translate(-p_half_width); - // previous line translated to the right - } - else - { - lines[3] = arr[i - 1].opposite().translate(-p_half_width); - // previous left line in opposite direction - } - // cut off outstanding corners with following shapes - FloatPoint corner_to_check = null; - Line curr_line = lines[1]; - Line check_line = null; - if (next_dir_from_curr_dir == Side.ON_THE_LEFT) - { - check_line = lines[2]; - } - else - { - check_line = lines[0]; - } - FloatPoint check_distance_corner = corner_approx(i); - final double check_dist_square = 2.0 * p_half_width * p_half_width; - Collection cut_dog_ear_lines = new LinkedList(); - Vector tmp_curr_dir = next_dir; - boolean direction_changed = false; - for (int j = i + 2; j < arr.length - 1; ++j) - { - if (corner_approx(j - 1).distance_square(check_distance_corner) - > check_dist_square) - { - break; - } - if (!direction_changed) - { - corner_to_check = curr_line.intersection_approx(check_line); - } - Vector tmp_next_dir = arr[j].direction().get_vector(); - Line next_border_line = null; - Side tmp_next_dir_from_tmp_curr_dir = tmp_next_dir.side_of(tmp_curr_dir); - direction_changed = - tmp_next_dir_from_tmp_curr_dir != next_dir_from_curr_dir; - if (!direction_changed) - { - if (tmp_next_dir_from_tmp_curr_dir == Side.ON_THE_LEFT) - { - next_border_line = arr[j].translate(-p_half_width); - } - else - { - next_border_line = arr[j].opposite().translate(-p_half_width); - } - - if (next_border_line.side_of(corner_to_check) == Side.ON_THE_LEFT - && next_border_line.side_of(this.corner(i)) == Side.ON_THE_RIGHT - && next_border_line.side_of(this.corner(i - 1)) == Side.ON_THE_RIGHT) - // an outstanding corner - { - cut_dog_ear_lines.add(next_border_line); - } - tmp_curr_dir = tmp_next_dir; - curr_line = next_border_line; - } - } - // cut off outstanding corners with previous shapes - check_distance_corner = corner_approx(i - 1); - if (curr_dir_from_prev_dir == Side.ON_THE_LEFT) - { - check_line = lines[2]; - } - else - { - check_line = lines[0]; - } - curr_line = lines [3]; - tmp_curr_dir = prev_dir; - direction_changed = false; - for (int j = i - 2; j >= 1; --j) - { - if (corner_approx(j).distance_square(check_distance_corner) - > check_dist_square) - { - break; - } - if (!direction_changed) - { - corner_to_check = curr_line.intersection_approx(check_line); - } - Vector tmp_prev_dir = arr[j].direction().get_vector(); - Line prev_border_line = null; - Side tmp_curr_dir_from_tmp_prev_dir = tmp_curr_dir.side_of(tmp_prev_dir); - direction_changed = - tmp_curr_dir_from_tmp_prev_dir != curr_dir_from_prev_dir; - if (!direction_changed) - { - if (tmp_curr_dir.side_of(tmp_prev_dir) == Side.ON_THE_LEFT) - { - prev_border_line = arr[j].translate(-p_half_width); - } - else - { - prev_border_line = arr[j].opposite().translate(-p_half_width); - } - if (prev_border_line.side_of(corner_to_check) == Side.ON_THE_LEFT - && prev_border_line.side_of(this.corner(i)) == Side.ON_THE_RIGHT - && prev_border_line.side_of(this.corner(i - 1)) == Side.ON_THE_RIGHT) - // an outstanding corner - { - cut_dog_ear_lines.add(prev_border_line); - } - tmp_curr_dir = tmp_prev_dir; - curr_line = prev_border_line; - } - } - TileShape s1 = TileShape.get_instance(lines); - int cut_line_count = cut_dog_ear_lines.size(); - if (cut_line_count > 0) - { - Line[] cut_lines = new Line[cut_line_count]; - Iterator it = cut_dog_ear_lines.iterator(); - for (int j = 0; j < cut_line_count; ++j) - { - cut_lines[j] = it.next(); - } - s1 = s1.intersection(TileShape.get_instance(cut_lines)); - } - int curr_shape_no = i - from_no - 1; - TileShape bounding_shape; - if (USE_BOUNDING_OCTAGON_FOR_OFFSET_SHAPES) - // intersect with the bounding octagon - { - IntOctagon surr_oct = bounding_octagon(i-1, i); - bounding_shape = surr_oct.offset(p_half_width); - - } - else - // intersect with the bounding box - { - IntBox surr_box = bounding_box(i-1, i); - IntBox offset_box = surr_box.offset(p_half_width); - bounding_shape = offset_box.to_Simplex(); - } - shape_arr[curr_shape_no] = bounding_shape.intersection_with_simplify(s1); - if (shape_arr[curr_shape_no].is_empty()) - { - System.out.println("offset_shapes: shape is empty"); - } - - prev_dir = curr_dir; - curr_dir = next_dir; - - } - return shape_arr; - } - - /** - * Calculates for the p_no-th line segment a shape around this line - * where the right and left edge lines have the distance p_half_width - * from the center line. 0 <= p_no <= arr.length - 3 - */ - public TileShape offset_shape(int p_half_width, int p_no) - { - if (p_no < 0 || p_no > arr.length - 3) - { - System.out.println("Polyline.offset_shape: p_no out of range"); - return null; - } - TileShape[] result = offset_shapes(p_half_width, p_no, p_no + 2); - return result[0]; - } - - /** - * Calculates for the p_no-th line segment a box shape around this line - * where the border lines have the distance p_half_width - * from the center line. 0 <= p_no <= arr.length - 3 - */ - public IntBox offset_box(int p_half_width, int p_no) - { - LineSegment curr_line_segment = new LineSegment(this, p_no + 1); - IntBox result = curr_line_segment.bounding_box().offset(p_half_width); - return result; - } - - /** - * Returns the by p_vector translated polyline - */ - public Polyline translate_by(Vector p_vector) - { - if (p_vector.equals(Vector.ZERO)) - { - return this; - } - Line [] new_arr = new Line[arr.length]; - for (int i = 0; i < new_arr.length; ++i) - { - new_arr[i] = arr[i].translate_by(p_vector); - } - return new Polyline(new_arr); - } - - /** - * Returns the polyline turned by p_factor times 90 degree around p_pole. - */ - public Polyline turn_90_degree(int p_factor, IntPoint p_pole) - { - Line [] new_arr = new Line[arr.length]; - for (int i = 0; i < new_arr.length; ++i) - { - new_arr[i] = arr[i].turn_90_degree(p_factor, p_pole); - } - return new Polyline(new_arr); - } - - public Polyline rotate_approx(double p_angle, FloatPoint p_pole) - { - if (p_angle == 0) - { - return this; - } - IntPoint [] new_corners = new IntPoint[this.corner_count()]; - for (int i = 0; i < new_corners.length; ++i) - { - - new_corners[i] = this.corner_approx(i).rotate(p_angle, p_pole).round(); - } - return new Polyline(new_corners); - } - - /** Mirrors this polyline at the vertical line through p_pole */ - public Polyline mirror_vertical(IntPoint p_pole) - { - Line [] new_arr = new Line[arr.length]; - for (int i = 0; i < new_arr.length; ++i) - { - new_arr[i] = arr[i].mirror_vertical(p_pole); - } - return new Polyline(new_arr); - } - - /** Mirrors this polyline at the horizontal line through p_pole */ - public Polyline mirror_horizontal(IntPoint p_pole) - { - Line [] new_arr = new Line[arr.length]; - for (int i = 0; i < new_arr.length; ++i) - { - new_arr[i] = arr[i].mirror_horizontal(p_pole); - } - return new Polyline(new_arr); - } - - - /** - * Returns the smallest box containing the intersection points - * from index p_from_corner_no to index p_to_corner_no - * of the lines of this polyline - */ - public IntBox bounding_box(int p_from_corner_no, int p_to_corner_no) - { - int from_corner_no = Math.max(p_from_corner_no, 0); - int to_corner_no = Math.min(p_to_corner_no, arr.length - 2); - double llx = Integer.MAX_VALUE; - double lly = llx; - double urx = Integer.MIN_VALUE; - double ury = urx; - for (int i = from_corner_no; i <= to_corner_no; ++i) - { - FloatPoint curr_corner = corner_approx(i); - llx = Math.min(llx, curr_corner.x); - lly = Math.min(lly, curr_corner.y); - urx = Math.max(urx, curr_corner.x); - ury = Math.max(ury, curr_corner.y); - } - IntPoint lower_left = new IntPoint((int)Math.floor(llx), (int)Math.floor(lly)); - IntPoint upper_right = new IntPoint((int)Math.ceil(urx), (int)Math.ceil(ury)); - return new IntBox(lower_left, upper_right); - } - - /** - * Returns the smallest box containing the intersection points - * of the lines of this polyline - */ - public IntBox bounding_box() - { - if (precalculated_bounding_box == null) - { - precalculated_bounding_box = bounding_box(0, corner_count() - 1); - } - return precalculated_bounding_box; - } - - /** - * Returns the smallest octagon containing the intersection points - * from index p_from_corner_no to index p_to_corner_no - * of the lines of this polyline - */ - public IntOctagon bounding_octagon(int p_from_corner_no, int p_to_corner_no) - { - int from_corner_no = Math.max(p_from_corner_no, 0); - int to_corner_no = Math.min(p_to_corner_no, arr.length - 2); - double lx = Integer.MAX_VALUE; - double ly = Integer.MAX_VALUE; - double rx = Integer.MIN_VALUE; - double uy = Integer.MIN_VALUE; - double ulx = Integer.MAX_VALUE; - double lrx = Integer.MIN_VALUE; - double llx = Integer.MAX_VALUE; - double urx = Integer.MIN_VALUE; - for (int i = from_corner_no; i <= to_corner_no; ++i) - { - FloatPoint curr = corner_approx(i); - lx = Math.min(lx, curr.x); - ly = Math.min(ly, curr.y); - rx = Math.max(rx, curr.x); - uy = Math.max(uy, curr.y); - double tmp = curr.x - curr.y; - ulx = Math.min(ulx, tmp); - lrx = Math.max(lrx, tmp); - tmp = curr.x + curr.y; - llx = Math.min(llx, tmp); - urx = Math.max(urx, tmp); - } - IntOctagon surrounding_octagon = new - IntOctagon((int)Math.floor(lx), (int)Math.floor(ly), - (int)Math.ceil(rx), (int)Math.ceil(uy), - (int)Math.floor(ulx), (int)Math.ceil(lrx), - (int)Math.floor(llx), (int)Math.ceil(urx)); - return surrounding_octagon; - } - - /** - * Calculates an aproximation of the nearest point on this - * polyline to p_from_point. - */ - public FloatPoint nearest_point_approx(FloatPoint p_from_point) - { - double min_distance = Double.MAX_VALUE; - FloatPoint nearest_point = null; - // calculate the nearest corner point - FloatPoint[] corners = corner_approx_arr(); - for (int i = 0; i < corners.length; ++i) - { - double curr_distance = corners[i].distance(p_from_point); - if (curr_distance < min_distance) - { - min_distance = curr_distance; - nearest_point = corners[i]; - } - } - final double c_tolerance = 1; - for (int i = 1; i < arr.length - 1; ++i) - { - FloatPoint projection = p_from_point.projection_approx(arr[i]); - double curr_distance = projection.distance(p_from_point); - if (curr_distance < min_distance) - { - // look, if the projection is inside the segment - double segment_length = corners[i].distance(corners[i - 1]); - if (projection.distance(corners[i]) + projection.distance(corners[i - 1]) - < segment_length + c_tolerance) - { - min_distance = curr_distance; - nearest_point = projection; - } - } - } - return nearest_point; - } - - /** - * Calculates the distance of p_from_point to the the nearest point - * on this polyline - */ - public double distance(FloatPoint p_from_point) - { - double result = p_from_point.distance(nearest_point_approx(p_from_point)); - return result; - } - - /** - * Combines the two polylines, if they have a common end corner. - * The order of lines in this polyline will be preserved. - * Returns the combined polyline or this polyline, if this polyline - * and p_other have no common end corner. - * If there is something to combine at the start of this polyline, - * p_other is inserted in front of this polyline. - * If there is something to combine at the end of this polyline, - * this polyline is inserted in front of p_other. - */ - public Polyline combine(Polyline p_other) - { - if (p_other == null || arr.length < 3 - || p_other.arr.length < 3) - { - return this; - } - boolean combine_at_start; - boolean combine_other_at_start; - if (first_corner().equals(p_other.first_corner())) - { - combine_at_start = true; - combine_other_at_start = true; - } - else if (first_corner().equals(p_other.last_corner())) - { - combine_at_start = true; - combine_other_at_start = false; - } - else if (last_corner().equals(p_other.first_corner())) - { - combine_at_start = false; - combine_other_at_start = true; - } - else if (last_corner().equals(p_other.last_corner())) - { - combine_at_start = false; - combine_other_at_start = false; - } - else - { - return this; // no common endpoint - } - Line [] line_arr = new Line [arr.length + p_other.arr.length - 2]; - if (combine_at_start) - { - // insert the lines of p_other in front - if (combine_other_at_start) - { - // insert in reverse order, skip the first line of p_other - for (int i = 0; i < p_other.arr.length - 1; ++i) - { - line_arr[i] = p_other.arr[p_other.arr.length - i - 1].opposite(); - } - } - else - { - // skip the last line of p_other - for (int i = 0; i < p_other.arr.length - 1; ++i) - { - line_arr[i] = p_other.arr[i]; - } - } - // append the lines of this polyline, skip the first line - for (int i = 1; i < arr.length; ++i) - { - line_arr[p_other.arr.length + i - 2] = arr[i]; - } - } - else - { - // insert the lines of this polyline in front, skip the last line - for (int i = 0; i < arr.length - 1; ++i) - { - line_arr[i] = arr[i]; - } - if (combine_other_at_start) - { - // skip the first line of p_other - for (int i = 1; i < p_other.arr.length; ++i) - { - line_arr[arr.length + i - 2] = p_other.arr[i]; - } - } - else - { - // insert in reverse order, skip the last line of p_other - for (int i = 1; i < p_other.arr.length; ++i) - { - line_arr[arr.length + i - 2] = - p_other.arr[p_other.arr.length - i - 1].opposite(); - } - } - } - return new Polyline(line_arr); - } - - /** - * Splits this polyline at the line with number p_line_no - * into two by inserting p_endline as concluding line of the first split piece - * and as the start line of the second split piece. - * p_endline and the line with number p_line_no must not be parallel. - * The order of the lines ins the two result pieces is preserved. - * p_line_no must be bigger than 0 and less then arr.length - 1. - * Returns null, if nothing was split. - */ - public Polyline[] split(int p_line_no, Line p_end_line) - { - if (p_line_no < 1 || p_line_no > arr.length - 2) - { - System.out.println("Polyline.split: p_line_no out of range"); - return null; - } - if (this.arr[p_line_no].is_parallel(p_end_line)) - { - return null; - } - Point new_end_corner = this.arr[p_line_no].intersection(p_end_line); - if (p_line_no <= 1 && new_end_corner.equals(this.first_corner()) || - p_line_no >= arr.length - 2 && new_end_corner.equals(this.last_corner())) - { - // No split, if p_end_line does not intersect, but touches - // only tnis Polyline at an end point. - return null; - } - Line[] first_piece; - if (this.corner(p_line_no - 1).equals(new_end_corner)) - { - // skip line segment of length 0 at the end of the first piece - first_piece = new Line [p_line_no + 1]; - System.arraycopy(arr, 0, first_piece, 0, first_piece.length); - - } - else - { - first_piece = new Line [p_line_no + 2]; - System.arraycopy(arr, 0, first_piece, 0, p_line_no + 1); - first_piece[p_line_no + 1] = p_end_line; - } - Line[] second_piece; - if (this.corner(p_line_no).equals(new_end_corner)) - { - // skip line segment of length 0 at the beginning of the second piece - second_piece = new Line [arr.length - p_line_no]; - System.arraycopy(this.arr, p_line_no,second_piece, 0, second_piece.length); - - } - else - { - second_piece = new Line [arr.length - p_line_no + 1]; - second_piece[0] = p_end_line; - System.arraycopy(this.arr, p_line_no, second_piece, 1, second_piece.length - 1); - } - Polyline [] result = new Polyline[2]; - result[0] = new Polyline(first_piece); - result[1] = new Polyline(second_piece); - if (result[0].is_point() || result[1].is_point()) - { - return null; - } - return result; - } - - /** - * create a new Polyline by skipping the lines of this Polyline - * from p_from_no to p_to_no - */ - public Polyline skip_lines(int p_from_no, int p_to_no) - { - if (p_from_no < 0 || p_to_no > arr.length - 1 || p_from_no > p_to_no) - { - return this; - } - Line [] new_lines = new Line [arr.length - (p_to_no - p_from_no + 1)]; - System.arraycopy(arr, 0, new_lines, 0, p_from_no); - System.arraycopy(arr, p_to_no + 1, new_lines, p_from_no, new_lines.length - p_from_no); - return new Polyline(new_lines); - } - - public boolean contains(Point p_point) - { - for (int i = 1; i < arr.length - 1; ++i) - { - LineSegment curr_segment = new LineSegment(this, i); - if (curr_segment.contains(p_point)) - { - return true; - } - } - return false; - } - - /** - * Creates a perpendicular line segment from p_from_point onto the nearest - * line segment of this polyline to p_from_side. - * Returns null, if the perpendicular line does not intersect the neares line - * segment inside its segment bounds or if p_from_point is contained in - * this polyline. - */ - public LineSegment projection_line(Point p_from_point) - { - FloatPoint from_point = p_from_point.to_float(); - double min_distance = Double.MAX_VALUE; - Line result_line = null; - Line nearest_line = null; - for (int i = 1; i < arr.length - 1; ++i) - { - FloatPoint projection = from_point.projection_approx(arr[i]); - double curr_distance = projection.distance(from_point); - if (curr_distance < min_distance) - { - Direction direction_towards_line = this.arr[i].perpendicular_direction(p_from_point); - if (direction_towards_line == null) - { - continue; - } - Line curr_result_line = new Line(p_from_point, direction_towards_line); - Point prev_corner = this.corner(i - 1); - Point next_corner = this.corner(i); - Side prev_corner_side = curr_result_line.side_of(prev_corner); - Side next_corner_side = curr_result_line.side_of(next_corner); - if (prev_corner_side != Side.COLLINEAR && next_corner_side != Side.COLLINEAR - && prev_corner_side == next_corner_side) - { - // the projection point is outside the line segment - continue; - } - nearest_line = this.arr[i]; - min_distance = curr_distance; - result_line = curr_result_line; - } - } - if (nearest_line == null) - { - return null; - } - Line start_line = new Line(p_from_point, nearest_line.direction()); - LineSegment result = new LineSegment(start_line, result_line, nearest_line); - return result; - } - - /** - * Shortens this polyline to p_new_line_count lines. Additioanally - * the last line segment will be approximately shortened to p_new_length. - * The last corner of the new polyline will be an IntPoint. - */ - public Polyline shorten(int p_new_line_count, double p_last_segment_length) - { - FloatPoint last_corner = this.corner_approx(p_new_line_count - 2); - FloatPoint prev_last_corner = this.corner_approx(p_new_line_count - 3); - IntPoint new_last_corner = prev_last_corner.change_length(last_corner, p_last_segment_length).round(); - if (new_last_corner.equals(this.corner(this.corner_count() - 2))) - { - // skip the last line - return skip_lines( p_new_line_count - 1, p_new_line_count - 1); - } - Line[] new_lines = new Line [p_new_line_count]; - System.arraycopy(arr, 0, new_lines, 0, p_new_line_count - 2); - // create the last 2 lines of the new polyline - Point first_line_point = arr[p_new_line_count - 2].a; - if (first_line_point.equals(new_last_corner)) - { - first_line_point = arr[p_new_line_count - 2].b; - } - Line new_prev_last_line = new Line(first_line_point, new_last_corner); - new_lines[p_new_line_count - 2] = new_prev_last_line; - new_lines[p_new_line_count - 1] = - Line.get_instance(new_last_corner, new_prev_last_line.direction().turn_45_degree(6)); - return new Polyline(new_lines); - } - - - private static Line[] remove_consecutive_parallel_lines( Line [] p_line_arr) - { - if (p_line_arr.length < 3) - { - // polyline must have at least 3 lines - return p_line_arr; - } - Line [] tmp_arr = new Line [p_line_arr.length]; - int new_length = 0; - tmp_arr[0] = p_line_arr [0]; - for (int i = 1; i < p_line_arr.length; ++i) - { - // skip multiple lines - if (!tmp_arr[new_length].is_parallel(p_line_arr[i])) - { - ++new_length; - tmp_arr[new_length] = p_line_arr[i]; - } - } - ++new_length; - if (new_length == p_line_arr.length) - { - // nothing skipped - return p_line_arr; - } - // at least 1 line is skipped, adjust the array - if (new_length < 3) - { - return new Line[0]; - } - Line [] result = new Line[new_length]; - System.arraycopy(tmp_arr, 0, result, 0, new_length); - return result; - } - - /** - * checks if previous and next line are equal or opposite and - * removes the resulting overlap - */ - private static Line [] remove_overlaps(Line [] p_line_arr) - { - if (p_line_arr.length < 4) - { - return p_line_arr; - } - int new_length = 0; - Line [] tmp_arr = new Line [p_line_arr.length]; - tmp_arr[0] = p_line_arr[0]; - if (!p_line_arr[0].is_equal_or_opposite(p_line_arr[2])) - { - ++new_length; - } - // else skip the first line - tmp_arr[new_length] = p_line_arr[1]; - ++new_length; - for (int i = 2; i < p_line_arr.length - 2; ++i) - { - if (tmp_arr[new_length - 1].is_equal_or_opposite(p_line_arr [i + 1])) - { - // skip 2 lines - --new_length; - } - else - { - tmp_arr[new_length] = p_line_arr [i]; - ++new_length; - } - } - tmp_arr [new_length] = p_line_arr[p_line_arr.length - 2]; - ++new_length; - if (!p_line_arr[p_line_arr.length - 1].is_equal_or_opposite(tmp_arr[new_length - 2])) - { - tmp_arr[new_length] = p_line_arr[p_line_arr.length - 1]; - ++new_length; - } - // else skip the last line - if (new_length == p_line_arr.length) - { - // nothing skipped - return p_line_arr; - } - // at least 1 line is skipped, adjust the array - if (new_length < 3) - { - return new Line[0]; - } - Line [] result = new Line[new_length]; - System.arraycopy(tmp_arr, 0, result, 0, new_length); - return result; - } - - - /** - * the array of lines of this Polyline. - */ - public final Line[] arr; - - transient private FloatPoint[] precalculated_float_corners = null; - transient private Point[] precalculated_corners = null; - transient private IntBox precalculated_bounding_box = null; - private static final boolean USE_BOUNDING_OCTAGON_FOR_OFFSET_SHAPES = true; -} \ No newline at end of file +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + */ + +package geometry.planar; + +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; + +/** + * + * A Polyline is a sequence of lines, where no 2 consecutive + * lines may be parallel. A Polyline of n lines defines a Polygon of + * n-1 intersection points of consecutive lines. + * The lines of the objects of class Polyline are normally defined + * by points with integer coordinates, wheras the intersections + * of Lines can be representated in general only by infinite precision + * rational points. We use polylines with integer coordinates instead + * of polygons with infinite precision rational coordinates + * because of its better performance in geometric calculations. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class Polyline implements java.io.Serializable +{ + /** + * creates a polyline of length p_polygon.corner_count + 1 from p_polygon, + * so that the i-th corner of p_polygon will be the intersection of + * the i-th and the i+1-th lines of the new created p_polyline + * for {@code 0 <= i < p_point_arr.length}. p_polygon must have at least 2 corners + * + * @param p_polygon a {@link geometry.planar.Polygon} object. + */ + public Polyline(Polygon p_polygon) + { + Point[] point_arr = p_polygon.corner_array(); + if (point_arr.length < 2) + { + System.out.println("Polyline: must contain at least 2 different points"); + arr = new Line[0]; + return; + } + arr = new Line [point_arr.length + 1]; + for (int i = 1; i < point_arr.length; ++i) + { + arr[i] = new Line(point_arr[i - 1], point_arr[i]); + } + // construct perpendicular lines at the start and at the end to represent + // the first and the last point of point_arr as intersection of lines. + + Direction dir = Direction.get_instance(point_arr[0], point_arr[1]); + arr [0] = Line.get_instance(point_arr[0], dir.turn_45_degree(2)); + + dir = Direction.get_instance(point_arr[point_arr.length - 1], point_arr[point_arr.length - 2]); + arr[point_arr.length] = + Line.get_instance(point_arr[point_arr.length - 1], dir.turn_45_degree(2)); + } + + /** + *

Constructor for Polyline.

+ * + * @param p_points an array of {@link geometry.planar.Point} objects. + */ + public Polyline(Point[] p_points) + { + this(new Polygon(p_points)); + } + + /** + * creates a polyline consisting of 3 lines + * + * @param p_from_corner a {@link geometry.planar.Point} object. + * @param p_to_corner a {@link geometry.planar.Point} object. + */ + public Polyline(Point p_from_corner, Point p_to_corner) + { + if (p_from_corner.equals(p_to_corner)) + { + arr = new Line [0]; + return; + } + arr = new Line [3]; + Direction dir = Direction.get_instance(p_from_corner, p_to_corner); + arr [0] = Line.get_instance(p_from_corner, dir.turn_45_degree(2)); + arr[1] = new Line(p_from_corner, p_to_corner); + dir = Direction.get_instance(p_from_corner, p_to_corner); + arr [2] = Line.get_instance(p_to_corner, dir.turn_45_degree(2)); + } + + /** + * Creates a polyline from an array of lines. + * Lines, which are parallel to the previous line are skipped. + * The directed lines are normalized, so that they intersect + * the previous line before the next line + * + * @param p_line_arr an array of {@link geometry.planar.Line} objects. + */ + public Polyline(Line[] p_line_arr) + { + Line [] lines = remove_consecutive_parallel_lines(p_line_arr); + lines = remove_overlaps(lines); + if (lines.length < 3 ) + { + arr = new Line[0]; + return; + } + precalculated_float_corners = new FloatPoint [lines.length - 1]; + + // turn evtl the direction of the lines that they point always + // from the previous corner to the next corner + for (int i = 1; i < lines.length - 1; ++i) + { + precalculated_float_corners[i] = lines[i].intersection_approx(lines[i + 1]); + Side side_of_line = lines[i - 1].side_of(precalculated_float_corners[i]); + if (side_of_line != Side.COLLINEAR) + { + Direction d0 = lines[i - 1].direction(); + Direction d1 = lines[i].direction(); + Side side1 = d0.side_of(d1); + if (side1 != side_of_line) + { + lines[i] = lines[i].opposite(); + } + } + } + arr = lines; + } + + /** + * Returns the number of lines minus 1 + * + * @return a int. + */ + public int corner_count() + { + return arr.length - 1; + } + + /** + *

is_empty.

+ * + * @return a boolean. + */ + public boolean is_empty() + { + return arr.length < 3; + } + + /** + * Checks, if this polyline is empty or if all corner points are equal. + * + * @return a boolean. + */ + public boolean is_point() + { + if ( arr.length < 3) + { + return true; + } + Point first_corner = this.corner(0); + for (int i = 1; i < arr.length - 1; ++i) + { + if (!(this.corner(i).equals(first_corner))) + { + return false; + } + } + return true; + } + + /** + * checks, if all lines of this polyline are orthogonal + * + * @return a boolean. + */ + public boolean is_orthogonal() + { + for (int i = 0; i < arr.length; ++i) + { + if (!arr[i].is_orthogonal()) + { + return false; + } + } + return true; + } + + /** + * checks, if all lines of this polyline are multiples of 45 degree + * + * @return a boolean. + */ + public boolean is_multiple_of_45_degree() + { + for (int i = 0; i < arr.length; ++i) + { + if (!arr[i].is_multiple_of_45_degree()) + { + return false; + } + } + return true; + } + + /** + * returns the intersection of the first line with the second line + * + * @return a {@link geometry.planar.Point} object. + */ + public Point first_corner() + { + return corner(0); + } + + /** + * returns the intersection of the last line with the line before + * the last line + * + * @return a {@link geometry.planar.Point} object. + */ + public Point last_corner() + { + return corner(arr.length - 2); + } + + /** + * returns the array of the intersection of two consecutive lines + * approximated by FloatPoint's. + * + * @return an array of {@link geometry.planar.Point} objects. + */ + public Point [] corner_arr() + { + if (arr.length < 2) + { + return new Point[0]; + } + if (precalculated_corners == null) + // corner array is not yet allocated + { + precalculated_corners = new Point[arr.length - 1]; + } + for (int i = 0; i < precalculated_corners.length; ++i) + { + if (precalculated_corners[i] == null) + { + precalculated_corners[i] = arr[i].intersection(arr[i + 1]); + } + } + return precalculated_corners; + } + + /** + * returns the array of the intersection of two consecutive lines + * approximated by FloatPoint's. + * + * @return an array of {@link geometry.planar.FloatPoint} objects. + */ + public FloatPoint [] corner_approx_arr() + { + if (arr.length < 2) + { + return new FloatPoint[0]; + } + if (precalculated_float_corners == null) + // corner array is not yet allocated + { + precalculated_float_corners = new FloatPoint[arr.length - 1]; + } + for (int i = 0; i < precalculated_float_corners.length; ++i) + { + if (precalculated_float_corners[i] == null) + { + precalculated_float_corners[i] = arr[i].intersection_approx(arr[i + 1]); + } + } + return precalculated_float_corners; + } + + /** + * Returns an approximation of the intersection of the p_no-th with + * the (p_no - 1)-th line by a FloatPoint. + * + * @param p_no a int. + * @return a {@link geometry.planar.FloatPoint} object. + */ + public FloatPoint corner_approx(int p_no) + { + int no; + if (p_no < 0) + { + System.out.println("Polyline.corner_approx: p_no is < 0"); + no = 0; + } + else if (p_no >= arr.length - 1) + { + System.out.println("Polyline.corner_approx: p_no must be less than arr.length - 1"); + no = arr.length - 2; + } + else + { + no = p_no; + } + if (precalculated_float_corners == null) + // corner array is not yet allocated + { + precalculated_float_corners = new FloatPoint[arr.length - 1]; + for (int i = 0; i < precalculated_float_corners.length; ++i) + { + precalculated_float_corners[i] = null; + } + } + if (precalculated_float_corners [no] == null) + // corner is not yet calculated + { + precalculated_float_corners[no] = arr[no].intersection_approx(arr[no + 1]); + } + return precalculated_float_corners [no]; + } + + /** + * Returns the intersection of the p_no-th with the (p_no - 1)-th edge line. + * + * @param p_no a int. + * @return a {@link geometry.planar.Point} object. + */ + public Point corner(int p_no) + { + if (arr.length < 2) + { + System.out.println("Polyline.corner: arr.length is < 2"); + return null; + } + int no; + if (p_no < 0) + { + System.out.println("Polyline.corner: p_no is < 0"); + no = 0; + } + else if (p_no >= arr.length - 1) + { + System.out.println("Polyline.corner: p_no must be less than arr.length - 1"); + no = arr.length - 2; + } + else + { + no = p_no; + } + if (precalculated_corners == null) + // corner array is not yet allocated + { + precalculated_corners = new Point[arr.length - 1]; + for (int i = 0; i < precalculated_corners.length; ++i) + { + precalculated_corners[i] = null; + } + } + if (precalculated_corners [no] == null) + // corner is not yet calculated + { + precalculated_corners[no] = arr[no].intersection(arr[no + 1]); + } + return precalculated_corners [no]; + } + + /** + * return the polyline with the reversed order of lines + * + * @return a {@link geometry.planar.Polyline} object. + */ + public Polyline reverse() + { + Line [] reversed_lines = new Line[arr.length]; + for (int i = 0; i < arr.length; ++i) + { + reversed_lines[i] = arr[arr.length - i - 1].opposite(); + } + return new Polyline(reversed_lines); + } + + /** + * Calculates the length of this polyline from p_from_corner + * to p_to_corner. + * + * @param p_from_corner a int. + * @param p_to_corner a int. + * @return a double. + */ + public double length_approx(int p_from_corner, int p_to_corner) + { + int from_corner = Math.max(p_from_corner, 0); + int to_corner = Math.min(p_to_corner, arr.length - 2); + double result = 0; + for (int i = from_corner; i < to_corner; ++i) + { + result += this.corner_approx(i + 1).distance(this.corner_approx(i)); + } + return result; + } + + /** + * Calculates the cumulative distance between consecutive corners of + * this polyline. + * + * @return a double. + */ + public double length_approx() + { + return length_approx(0, arr.length - 2); + } + + /** + * calculates for each line a shape around this line + * where the right and left edge lines have the distance p_half_width + * from the center line + * Returns an array of convex shapes of length line_count - 2 + * + * @param p_half_width a int. + * @return an array of {@link geometry.planar.TileShape} objects. + */ + public TileShape[] offset_shapes(int p_half_width) + { + return offset_shapes(p_half_width, 0, arr.length -1); + } + + /** + * calculates for each line between p_from_no and p_to_no a shape around + * this line, where the right and left edge lines have the distance p_half_width + * from the center line + * + * @param p_half_width a int. + * @param p_from_no a int. + * @param p_to_no a int. + * @return an array of {@link geometry.planar.TileShape} objects. + */ + public TileShape[] offset_shapes(int p_half_width, + int p_from_no, int p_to_no) + { + int from_no = Math.max(p_from_no, 0); + int to_no = Math.min(p_to_no, arr.length -1); + int shape_count = Math.max(to_no - from_no -1, 0); + TileShape[] shape_arr = new TileShape[shape_count]; + if (shape_count == 0) + { + return shape_arr; + } + Vector prev_dir = arr[from_no].direction().get_vector(); + Vector curr_dir = arr[from_no + 1].direction().get_vector(); + for (int i = from_no + 1; i < to_no; ++i) + { + Vector next_dir = arr[i + 1].direction().get_vector(); + + Line[] lines = new Line[4]; + + lines[0] = arr[i].translate(-p_half_width); + // current center line translated to the right + + // create the front line of the offset shape + Side next_dir_from_curr_dir = next_dir.side_of(curr_dir); + // left turn from curr_line to next_line + if (next_dir_from_curr_dir == Side.ON_THE_LEFT) + { + lines[1] = arr[i + 1].translate(-p_half_width); + // next right line + } + else + { + lines[1] = arr[i + 1].opposite().translate(-p_half_width); + // next left line in opposite direction + } + + lines[2] = arr[i].opposite().translate(-p_half_width); + // current left line in opposite direction + + // create the back line of the offset shape + Side curr_dir_from_prev_dir = curr_dir.side_of(prev_dir); + // left turn from prev_line to curr_line + if (curr_dir_from_prev_dir == Side.ON_THE_LEFT) + { + lines[3] = arr[i - 1].translate(-p_half_width); + // previous line translated to the right + } + else + { + lines[3] = arr[i - 1].opposite().translate(-p_half_width); + // previous left line in opposite direction + } + // cut off outstanding corners with following shapes + FloatPoint corner_to_check = null; + Line curr_line = lines[1]; + Line check_line = null; + if (next_dir_from_curr_dir == Side.ON_THE_LEFT) + { + check_line = lines[2]; + } + else + { + check_line = lines[0]; + } + FloatPoint check_distance_corner = corner_approx(i); + final double check_dist_square = 2.0 * p_half_width * p_half_width; + Collection cut_dog_ear_lines = new LinkedList(); + Vector tmp_curr_dir = next_dir; + boolean direction_changed = false; + for (int j = i + 2; j < arr.length - 1; ++j) + { + if (corner_approx(j - 1).distance_square(check_distance_corner) + > check_dist_square) + { + break; + } + if (!direction_changed) + { + corner_to_check = curr_line.intersection_approx(check_line); + } + Vector tmp_next_dir = arr[j].direction().get_vector(); + Line next_border_line = null; + Side tmp_next_dir_from_tmp_curr_dir = tmp_next_dir.side_of(tmp_curr_dir); + direction_changed = + tmp_next_dir_from_tmp_curr_dir != next_dir_from_curr_dir; + if (!direction_changed) + { + if (tmp_next_dir_from_tmp_curr_dir == Side.ON_THE_LEFT) + { + next_border_line = arr[j].translate(-p_half_width); + } + else + { + next_border_line = arr[j].opposite().translate(-p_half_width); + } + + if (next_border_line.side_of(corner_to_check) == Side.ON_THE_LEFT + && next_border_line.side_of(this.corner(i)) == Side.ON_THE_RIGHT + && next_border_line.side_of(this.corner(i - 1)) == Side.ON_THE_RIGHT) + // an outstanding corner + { + cut_dog_ear_lines.add(next_border_line); + } + tmp_curr_dir = tmp_next_dir; + curr_line = next_border_line; + } + } + // cut off outstanding corners with previous shapes + check_distance_corner = corner_approx(i - 1); + if (curr_dir_from_prev_dir == Side.ON_THE_LEFT) + { + check_line = lines[2]; + } + else + { + check_line = lines[0]; + } + curr_line = lines [3]; + tmp_curr_dir = prev_dir; + direction_changed = false; + for (int j = i - 2; j >= 1; --j) + { + if (corner_approx(j).distance_square(check_distance_corner) + > check_dist_square) + { + break; + } + if (!direction_changed) + { + corner_to_check = curr_line.intersection_approx(check_line); + } + Vector tmp_prev_dir = arr[j].direction().get_vector(); + Line prev_border_line = null; + Side tmp_curr_dir_from_tmp_prev_dir = tmp_curr_dir.side_of(tmp_prev_dir); + direction_changed = + tmp_curr_dir_from_tmp_prev_dir != curr_dir_from_prev_dir; + if (!direction_changed) + { + if (tmp_curr_dir.side_of(tmp_prev_dir) == Side.ON_THE_LEFT) + { + prev_border_line = arr[j].translate(-p_half_width); + } + else + { + prev_border_line = arr[j].opposite().translate(-p_half_width); + } + if (prev_border_line.side_of(corner_to_check) == Side.ON_THE_LEFT + && prev_border_line.side_of(this.corner(i)) == Side.ON_THE_RIGHT + && prev_border_line.side_of(this.corner(i - 1)) == Side.ON_THE_RIGHT) + // an outstanding corner + { + cut_dog_ear_lines.add(prev_border_line); + } + tmp_curr_dir = tmp_prev_dir; + curr_line = prev_border_line; + } + } + TileShape s1 = TileShape.get_instance(lines); + int cut_line_count = cut_dog_ear_lines.size(); + if (cut_line_count > 0) + { + Line[] cut_lines = new Line[cut_line_count]; + Iterator it = cut_dog_ear_lines.iterator(); + for (int j = 0; j < cut_line_count; ++j) + { + cut_lines[j] = it.next(); + } + s1 = s1.intersection(TileShape.get_instance(cut_lines)); + } + int curr_shape_no = i - from_no - 1; + TileShape bounding_shape; + if (USE_BOUNDING_OCTAGON_FOR_OFFSET_SHAPES) + // intersect with the bounding octagon + { + IntOctagon surr_oct = bounding_octagon(i-1, i); + bounding_shape = surr_oct.offset(p_half_width); + + } + else + // intersect with the bounding box + { + IntBox surr_box = bounding_box(i-1, i); + IntBox offset_box = surr_box.offset(p_half_width); + bounding_shape = offset_box.to_Simplex(); + } + shape_arr[curr_shape_no] = bounding_shape.intersection_with_simplify(s1); + if (shape_arr[curr_shape_no].is_empty()) + { + System.out.println("offset_shapes: shape is empty"); + } + + prev_dir = curr_dir; + curr_dir = next_dir; + + } + return shape_arr; + } + + /** + * Calculates for the p_no-th line segment a shape around this line + * where the right and left edge lines have the distance p_half_width + * from the center line. {@code 0 <= p_no <= arr.length - 3} + * + * @param p_half_width a int. + * @param p_no a int. + * @return a {@link geometry.planar.TileShape} object. + */ + public TileShape offset_shape(int p_half_width, int p_no) + { + if (p_no < 0 || p_no > arr.length - 3) + { + System.out.println("Polyline.offset_shape: p_no out of range"); + return null; + } + TileShape[] result = offset_shapes(p_half_width, p_no, p_no + 2); + return result[0]; + } + + /** + * Calculates for the p_no-th line segment a box shape around this line + * where the border lines have the distance p_half_width + * from the center line. {@code 0 <= p_no <= arr.length - 3} + * + * @param p_half_width a int. + * @param p_no a int. + * @return a {@link geometry.planar.IntBox} object. + */ + public IntBox offset_box(int p_half_width, int p_no) + { + LineSegment curr_line_segment = new LineSegment(this, p_no + 1); + IntBox result = curr_line_segment.bounding_box().offset(p_half_width); + return result; + } + + /** + * Returns the by p_vector translated polyline + * + * @param p_vector a {@link geometry.planar.Vector} object. + * @return a {@link geometry.planar.Polyline} object. + */ + public Polyline translate_by(Vector p_vector) + { + if (p_vector.equals(Vector.ZERO)) + { + return this; + } + Line [] new_arr = new Line[arr.length]; + for (int i = 0; i < new_arr.length; ++i) + { + new_arr[i] = arr[i].translate_by(p_vector); + } + return new Polyline(new_arr); + } + + /** + * Returns the polyline turned by p_factor times 90 degree around p_pole. + * + * @param p_factor a int. + * @param p_pole a {@link geometry.planar.IntPoint} object. + * @return a {@link geometry.planar.Polyline} object. + */ + public Polyline turn_90_degree(int p_factor, IntPoint p_pole) + { + Line [] new_arr = new Line[arr.length]; + for (int i = 0; i < new_arr.length; ++i) + { + new_arr[i] = arr[i].turn_90_degree(p_factor, p_pole); + } + return new Polyline(new_arr); + } + + /** + *

rotate_approx.

+ * + * @param p_angle a double. + * @param p_pole a {@link geometry.planar.FloatPoint} object. + * @return a {@link geometry.planar.Polyline} object. + */ + public Polyline rotate_approx(double p_angle, FloatPoint p_pole) + { + if (p_angle == 0) + { + return this; + } + IntPoint [] new_corners = new IntPoint[this.corner_count()]; + for (int i = 0; i < new_corners.length; ++i) + { + + new_corners[i] = this.corner_approx(i).rotate(p_angle, p_pole).round(); + } + return new Polyline(new_corners); + } + + /** + * Mirrors this polyline at the vertical line through p_pole + * + * @param p_pole a {@link geometry.planar.IntPoint} object. + * @return a {@link geometry.planar.Polyline} object. + */ + public Polyline mirror_vertical(IntPoint p_pole) + { + Line [] new_arr = new Line[arr.length]; + for (int i = 0; i < new_arr.length; ++i) + { + new_arr[i] = arr[i].mirror_vertical(p_pole); + } + return new Polyline(new_arr); + } + + /** + * Mirrors this polyline at the horizontal line through p_pole + * + * @param p_pole a {@link geometry.planar.IntPoint} object. + * @return a {@link geometry.planar.Polyline} object. + */ + public Polyline mirror_horizontal(IntPoint p_pole) + { + Line [] new_arr = new Line[arr.length]; + for (int i = 0; i < new_arr.length; ++i) + { + new_arr[i] = arr[i].mirror_horizontal(p_pole); + } + return new Polyline(new_arr); + } + + + /** + * Returns the smallest box containing the intersection points + * from index p_from_corner_no to index p_to_corner_no + * of the lines of this polyline + * + * @param p_from_corner_no a int. + * @param p_to_corner_no a int. + * @return a {@link geometry.planar.IntBox} object. + */ + public IntBox bounding_box(int p_from_corner_no, int p_to_corner_no) + { + int from_corner_no = Math.max(p_from_corner_no, 0); + int to_corner_no = Math.min(p_to_corner_no, arr.length - 2); + double llx = Integer.MAX_VALUE; + double lly = llx; + double urx = Integer.MIN_VALUE; + double ury = urx; + for (int i = from_corner_no; i <= to_corner_no; ++i) + { + FloatPoint curr_corner = corner_approx(i); + llx = Math.min(llx, curr_corner.x); + lly = Math.min(lly, curr_corner.y); + urx = Math.max(urx, curr_corner.x); + ury = Math.max(ury, curr_corner.y); + } + IntPoint lower_left = new IntPoint((int)Math.floor(llx), (int)Math.floor(lly)); + IntPoint upper_right = new IntPoint((int)Math.ceil(urx), (int)Math.ceil(ury)); + return new IntBox(lower_left, upper_right); + } + + /** + * Returns the smallest box containing the intersection points + * of the lines of this polyline + * + * @return a {@link geometry.planar.IntBox} object. + */ + public IntBox bounding_box() + { + if (precalculated_bounding_box == null) + { + precalculated_bounding_box = bounding_box(0, corner_count() - 1); + } + return precalculated_bounding_box; + } + + /** + * Returns the smallest octagon containing the intersection points + * from index p_from_corner_no to index p_to_corner_no + * of the lines of this polyline + * + * @param p_from_corner_no a int. + * @param p_to_corner_no a int. + * @return a {@link geometry.planar.IntOctagon} object. + */ + public IntOctagon bounding_octagon(int p_from_corner_no, int p_to_corner_no) + { + int from_corner_no = Math.max(p_from_corner_no, 0); + int to_corner_no = Math.min(p_to_corner_no, arr.length - 2); + double lx = Integer.MAX_VALUE; + double ly = Integer.MAX_VALUE; + double rx = Integer.MIN_VALUE; + double uy = Integer.MIN_VALUE; + double ulx = Integer.MAX_VALUE; + double lrx = Integer.MIN_VALUE; + double llx = Integer.MAX_VALUE; + double urx = Integer.MIN_VALUE; + for (int i = from_corner_no; i <= to_corner_no; ++i) + { + FloatPoint curr = corner_approx(i); + lx = Math.min(lx, curr.x); + ly = Math.min(ly, curr.y); + rx = Math.max(rx, curr.x); + uy = Math.max(uy, curr.y); + double tmp = curr.x - curr.y; + ulx = Math.min(ulx, tmp); + lrx = Math.max(lrx, tmp); + tmp = curr.x + curr.y; + llx = Math.min(llx, tmp); + urx = Math.max(urx, tmp); + } + IntOctagon surrounding_octagon = new + IntOctagon((int)Math.floor(lx), (int)Math.floor(ly), + (int)Math.ceil(rx), (int)Math.ceil(uy), + (int)Math.floor(ulx), (int)Math.ceil(lrx), + (int)Math.floor(llx), (int)Math.ceil(urx)); + return surrounding_octagon; + } + + /** + * Calculates an aproximation of the nearest point on this + * polyline to p_from_point. + * + * @param p_from_point a {@link geometry.planar.FloatPoint} object. + * @return a {@link geometry.planar.FloatPoint} object. + */ + public FloatPoint nearest_point_approx(FloatPoint p_from_point) + { + double min_distance = Double.MAX_VALUE; + FloatPoint nearest_point = null; + // calculate the nearest corner point + FloatPoint[] corners = corner_approx_arr(); + for (int i = 0; i < corners.length; ++i) + { + double curr_distance = corners[i].distance(p_from_point); + if (curr_distance < min_distance) + { + min_distance = curr_distance; + nearest_point = corners[i]; + } + } + final double c_tolerance = 1; + for (int i = 1; i < arr.length - 1; ++i) + { + FloatPoint projection = p_from_point.projection_approx(arr[i]); + double curr_distance = projection.distance(p_from_point); + if (curr_distance < min_distance) + { + // look, if the projection is inside the segment + double segment_length = corners[i].distance(corners[i - 1]); + if (projection.distance(corners[i]) + projection.distance(corners[i - 1]) + < segment_length + c_tolerance) + { + min_distance = curr_distance; + nearest_point = projection; + } + } + } + return nearest_point; + } + + /** + * Calculates the distance of p_from_point to the the nearest point + * on this polyline + * + * @param p_from_point a {@link geometry.planar.FloatPoint} object. + * @return a double. + */ + public double distance(FloatPoint p_from_point) + { + double result = p_from_point.distance(nearest_point_approx(p_from_point)); + return result; + } + + /** + * Combines the two polylines, if they have a common end corner. + * The order of lines in this polyline will be preserved. + * Returns the combined polyline or this polyline, if this polyline + * and p_other have no common end corner. + * If there is something to combine at the start of this polyline, + * p_other is inserted in front of this polyline. + * If there is something to combine at the end of this polyline, + * this polyline is inserted in front of p_other. + * + * @param p_other a {@link geometry.planar.Polyline} object. + * @return a {@link geometry.planar.Polyline} object. + */ + public Polyline combine(Polyline p_other) + { + if (p_other == null || arr.length < 3 + || p_other.arr.length < 3) + { + return this; + } + boolean combine_at_start; + boolean combine_other_at_start; + if (first_corner().equals(p_other.first_corner())) + { + combine_at_start = true; + combine_other_at_start = true; + } + else if (first_corner().equals(p_other.last_corner())) + { + combine_at_start = true; + combine_other_at_start = false; + } + else if (last_corner().equals(p_other.first_corner())) + { + combine_at_start = false; + combine_other_at_start = true; + } + else if (last_corner().equals(p_other.last_corner())) + { + combine_at_start = false; + combine_other_at_start = false; + } + else + { + return this; // no common endpoint + } + Line [] line_arr = new Line [arr.length + p_other.arr.length - 2]; + if (combine_at_start) + { + // insert the lines of p_other in front + if (combine_other_at_start) + { + // insert in reverse order, skip the first line of p_other + for (int i = 0; i < p_other.arr.length - 1; ++i) + { + line_arr[i] = p_other.arr[p_other.arr.length - i - 1].opposite(); + } + } + else + { + // skip the last line of p_other + for (int i = 0; i < p_other.arr.length - 1; ++i) + { + line_arr[i] = p_other.arr[i]; + } + } + // append the lines of this polyline, skip the first line + for (int i = 1; i < arr.length; ++i) + { + line_arr[p_other.arr.length + i - 2] = arr[i]; + } + } + else + { + // insert the lines of this polyline in front, skip the last line + for (int i = 0; i < arr.length - 1; ++i) + { + line_arr[i] = arr[i]; + } + if (combine_other_at_start) + { + // skip the first line of p_other + for (int i = 1; i < p_other.arr.length; ++i) + { + line_arr[arr.length + i - 2] = p_other.arr[i]; + } + } + else + { + // insert in reverse order, skip the last line of p_other + for (int i = 1; i < p_other.arr.length; ++i) + { + line_arr[arr.length + i - 2] = + p_other.arr[p_other.arr.length - i - 1].opposite(); + } + } + } + return new Polyline(line_arr); + } + + /** + * Splits this polyline at the line with number p_line_no + * into two by inserting p_endline as concluding line of the first split piece + * and as the start line of the second split piece. + * p_endline and the line with number p_line_no must not be parallel. + * The order of the lines ins the two result pieces is preserved. + * p_line_no must be bigger than 0 and less then arr.length - 1. + * Returns null, if nothing was split. + * + * @param p_line_no a int. + * @param p_end_line a {@link geometry.planar.Line} object. + * @return an array of {@link geometry.planar.Polyline} objects. + */ + public Polyline[] split(int p_line_no, Line p_end_line) + { + if (p_line_no < 1 || p_line_no > arr.length - 2) + { + System.out.println("Polyline.split: p_line_no out of range"); + return null; + } + if (this.arr[p_line_no].is_parallel(p_end_line)) + { + return null; + } + Point new_end_corner = this.arr[p_line_no].intersection(p_end_line); + if (p_line_no <= 1 && new_end_corner.equals(this.first_corner()) || + p_line_no >= arr.length - 2 && new_end_corner.equals(this.last_corner())) + { + // No split, if p_end_line does not intersect, but touches + // only tnis Polyline at an end point. + return null; + } + Line[] first_piece; + if (this.corner(p_line_no - 1).equals(new_end_corner)) + { + // skip line segment of length 0 at the end of the first piece + first_piece = new Line [p_line_no + 1]; + System.arraycopy(arr, 0, first_piece, 0, first_piece.length); + + } + else + { + first_piece = new Line [p_line_no + 2]; + System.arraycopy(arr, 0, first_piece, 0, p_line_no + 1); + first_piece[p_line_no + 1] = p_end_line; + } + Line[] second_piece; + if (this.corner(p_line_no).equals(new_end_corner)) + { + // skip line segment of length 0 at the beginning of the second piece + second_piece = new Line [arr.length - p_line_no]; + System.arraycopy(this.arr, p_line_no,second_piece, 0, second_piece.length); + + } + else + { + second_piece = new Line [arr.length - p_line_no + 1]; + second_piece[0] = p_end_line; + System.arraycopy(this.arr, p_line_no, second_piece, 1, second_piece.length - 1); + } + Polyline [] result = new Polyline[2]; + result[0] = new Polyline(first_piece); + result[1] = new Polyline(second_piece); + if (result[0].is_point() || result[1].is_point()) + { + return null; + } + return result; + } + + /** + * create a new Polyline by skipping the lines of this Polyline + * from p_from_no to p_to_no + * + * @param p_from_no a int. + * @param p_to_no a int. + * @return a {@link geometry.planar.Polyline} object. + */ + public Polyline skip_lines(int p_from_no, int p_to_no) + { + if (p_from_no < 0 || p_to_no > arr.length - 1 || p_from_no > p_to_no) + { + return this; + } + Line [] new_lines = new Line [arr.length - (p_to_no - p_from_no + 1)]; + System.arraycopy(arr, 0, new_lines, 0, p_from_no); + System.arraycopy(arr, p_to_no + 1, new_lines, p_from_no, new_lines.length - p_from_no); + return new Polyline(new_lines); + } + + /** + *

contains.

+ * + * @param p_point a {@link geometry.planar.Point} object. + * @return a boolean. + */ + public boolean contains(Point p_point) + { + for (int i = 1; i < arr.length - 1; ++i) + { + LineSegment curr_segment = new LineSegment(this, i); + if (curr_segment.contains(p_point)) + { + return true; + } + } + return false; + } + + /** + * Creates a perpendicular line segment from p_from_point onto the nearest + * line segment of this polyline to p_from_side. + * Returns null, if the perpendicular line does not intersect the neares line + * segment inside its segment bounds or if p_from_point is contained in + * this polyline. + * + * @param p_from_point a {@link geometry.planar.Point} object. + * @return a {@link geometry.planar.LineSegment} object. + */ + public LineSegment projection_line(Point p_from_point) + { + FloatPoint from_point = p_from_point.to_float(); + double min_distance = Double.MAX_VALUE; + Line result_line = null; + Line nearest_line = null; + for (int i = 1; i < arr.length - 1; ++i) + { + FloatPoint projection = from_point.projection_approx(arr[i]); + double curr_distance = projection.distance(from_point); + if (curr_distance < min_distance) + { + Direction direction_towards_line = this.arr[i].perpendicular_direction(p_from_point); + if (direction_towards_line == null) + { + continue; + } + Line curr_result_line = new Line(p_from_point, direction_towards_line); + Point prev_corner = this.corner(i - 1); + Point next_corner = this.corner(i); + Side prev_corner_side = curr_result_line.side_of(prev_corner); + Side next_corner_side = curr_result_line.side_of(next_corner); + if (prev_corner_side != Side.COLLINEAR && next_corner_side != Side.COLLINEAR + && prev_corner_side == next_corner_side) + { + // the projection point is outside the line segment + continue; + } + nearest_line = this.arr[i]; + min_distance = curr_distance; + result_line = curr_result_line; + } + } + if (nearest_line == null) + { + return null; + } + Line start_line = new Line(p_from_point, nearest_line.direction()); + LineSegment result = new LineSegment(start_line, result_line, nearest_line); + return result; + } + + /** + * Shortens this polyline to p_new_line_count lines. Additioanally + * the last line segment will be approximately shortened to p_new_length. + * The last corner of the new polyline will be an IntPoint. + * + * @param p_new_line_count a int. + * @param p_last_segment_length a double. + * @return a {@link geometry.planar.Polyline} object. + */ + public Polyline shorten(int p_new_line_count, double p_last_segment_length) + { + FloatPoint last_corner = this.corner_approx(p_new_line_count - 2); + FloatPoint prev_last_corner = this.corner_approx(p_new_line_count - 3); + IntPoint new_last_corner = prev_last_corner.change_length(last_corner, p_last_segment_length).round(); + if (new_last_corner.equals(this.corner(this.corner_count() - 2))) + { + // skip the last line + return skip_lines( p_new_line_count - 1, p_new_line_count - 1); + } + Line[] new_lines = new Line [p_new_line_count]; + System.arraycopy(arr, 0, new_lines, 0, p_new_line_count - 2); + // create the last 2 lines of the new polyline + Point first_line_point = arr[p_new_line_count - 2].a; + if (first_line_point.equals(new_last_corner)) + { + first_line_point = arr[p_new_line_count - 2].b; + } + Line new_prev_last_line = new Line(first_line_point, new_last_corner); + new_lines[p_new_line_count - 2] = new_prev_last_line; + new_lines[p_new_line_count - 1] = + Line.get_instance(new_last_corner, new_prev_last_line.direction().turn_45_degree(6)); + return new Polyline(new_lines); + } + + + private static Line[] remove_consecutive_parallel_lines( Line [] p_line_arr) + { + if (p_line_arr.length < 3) + { + // polyline must have at least 3 lines + return p_line_arr; + } + Line [] tmp_arr = new Line [p_line_arr.length]; + int new_length = 0; + tmp_arr[0] = p_line_arr [0]; + for (int i = 1; i < p_line_arr.length; ++i) + { + // skip multiple lines + if (!tmp_arr[new_length].is_parallel(p_line_arr[i])) + { + ++new_length; + tmp_arr[new_length] = p_line_arr[i]; + } + } + ++new_length; + if (new_length == p_line_arr.length) + { + // nothing skipped + return p_line_arr; + } + // at least 1 line is skipped, adjust the array + if (new_length < 3) + { + return new Line[0]; + } + Line [] result = new Line[new_length]; + System.arraycopy(tmp_arr, 0, result, 0, new_length); + return result; + } + + /** + * checks if previous and next line are equal or opposite and + * removes the resulting overlap + */ + private static Line [] remove_overlaps(Line [] p_line_arr) + { + if (p_line_arr.length < 4) + { + return p_line_arr; + } + int new_length = 0; + Line [] tmp_arr = new Line [p_line_arr.length]; + tmp_arr[0] = p_line_arr[0]; + if (!p_line_arr[0].is_equal_or_opposite(p_line_arr[2])) + { + ++new_length; + } + // else skip the first line + tmp_arr[new_length] = p_line_arr[1]; + ++new_length; + for (int i = 2; i < p_line_arr.length - 2; ++i) + { + if (tmp_arr[new_length - 1].is_equal_or_opposite(p_line_arr [i + 1])) + { + // skip 2 lines + --new_length; + } + else + { + tmp_arr[new_length] = p_line_arr [i]; + ++new_length; + } + } + tmp_arr [new_length] = p_line_arr[p_line_arr.length - 2]; + ++new_length; + if (!p_line_arr[p_line_arr.length - 1].is_equal_or_opposite(tmp_arr[new_length - 2])) + { + tmp_arr[new_length] = p_line_arr[p_line_arr.length - 1]; + ++new_length; + } + // else skip the last line + if (new_length == p_line_arr.length) + { + // nothing skipped + return p_line_arr; + } + // at least 1 line is skipped, adjust the array + if (new_length < 3) + { + return new Line[0]; + } + Line [] result = new Line[new_length]; + System.arraycopy(tmp_arr, 0, result, 0, new_length); + return result; + } + + + /** + * the array of lines of this Polyline. + */ + public final Line[] arr; + + transient private FloatPoint[] precalculated_float_corners = null; + transient private Point[] precalculated_corners = null; + transient private IntBox precalculated_bounding_box = null; + private static final boolean USE_BOUNDING_OCTAGON_FOR_OFFSET_SHAPES = true; +} diff --git a/geometry/planar/PolylineArea.java b/src/main/java/geometry/planar/PolylineArea.java similarity index 86% rename from geometry/planar/PolylineArea.java rename to src/main/java/geometry/planar/PolylineArea.java index a0c21cf..3ee26d0 100644 --- a/geometry/planar/PolylineArea.java +++ b/src/main/java/geometry/planar/PolylineArea.java @@ -28,57 +28,105 @@ * consist of straight lines. * * @author Alfons Wirtz + * @version $Id: $Id */ public class PolylineArea implements Area, java.io.Serializable { - /** Creates a new instance of PolylineShapeWithHoles */ + /** + * Creates a new instance of PolylineShapeWithHoles + * + * @param p_border_shape a {@link geometry.planar.PolylineShape} object. + * @param p_hole_arr an array of {@link geometry.planar.PolylineShape} objects. + */ public PolylineArea(PolylineShape p_border_shape, PolylineShape[] p_hole_arr) { border_shape = p_border_shape; hole_arr = p_hole_arr; } + /** + *

dimension.

+ * + * @return a int. + */ public int dimension() { return border_shape.dimension(); } + /** + *

is_bounded.

+ * + * @return a boolean. + */ public boolean is_bounded() { return border_shape.is_bounded(); } + /** + *

is_empty.

+ * + * @return a boolean. + */ public boolean is_empty() { return border_shape.is_empty(); } + /** {@inheritDoc} */ public boolean is_contained_in(IntBox p_box) { return border_shape.is_contained_in(p_box); } + /** + *

get_border.

+ * + * @return a {@link geometry.planar.PolylineShape} object. + */ public PolylineShape get_border() { return border_shape; } + /** + *

get_holes.

+ * + * @return an array of {@link geometry.planar.PolylineShape} objects. + */ public PolylineShape[] get_holes() { return hole_arr; } + /** + *

bounding_box.

+ * + * @return a {@link geometry.planar.IntBox} object. + */ public IntBox bounding_box() { return border_shape.bounding_box(); } + /** + *

bounding_octagon.

+ * + * @return a {@link geometry.planar.IntOctagon} object. + */ public IntOctagon bounding_octagon() { return border_shape.bounding_octagon(); } + /** + *

contains.

+ * + * @param p_point a {@link geometry.planar.FloatPoint} object. + * @return a boolean. + */ public boolean contains(FloatPoint p_point) { if (!border_shape.contains(p_point)) @@ -95,6 +143,7 @@ public boolean contains(FloatPoint p_point) return true; } + /** {@inheritDoc} */ public boolean contains(Point p_point) { if (!border_shape.contains(p_point)) @@ -111,6 +160,7 @@ public boolean contains(Point p_point) return true; } + /** {@inheritDoc} */ public FloatPoint nearest_point_approx(FloatPoint p_from_point) { double min_dist = Double.MAX_VALUE; @@ -129,6 +179,7 @@ public FloatPoint nearest_point_approx(FloatPoint p_from_point) return result; } + /** {@inheritDoc} */ public PolylineArea translate_by(Vector p_vector) { if (p_vector.equals(Vector.ZERO)) @@ -144,6 +195,11 @@ public PolylineArea translate_by(Vector p_vector) return new PolylineArea(translated_border, translated_holes); } + /** + *

corner_approx_arr.

+ * + * @return an array of {@link geometry.planar.FloatPoint} objects. + */ public FloatPoint[] corner_approx_arr() { int corner_count = border_shape.border_line_count(); @@ -169,6 +225,8 @@ public FloatPoint[] corner_approx_arr() * The result is not exact, because rounded intersections of lines are * used in the result pieces. It can be made exact, if Polylines are returned * instead of Polygons, so that no intersection points are needed in the result. + * + * @return an array of {@link geometry.planar.TileShape} objects. */ public TileShape[] split_to_convex() { @@ -181,6 +239,9 @@ public TileShape[] split_to_convex() * used in the result pieces. It can be made exact, if Polylines are returned * instead of Polygons, so that no intersection points are needed in the result. * If p_stoppable_thread != null, this function can be interrupted. + * + * @param p_stoppable_thread a {@link datastructures.Stoppable} object. + * @return an array of {@link geometry.planar.TileShape} objects. */ public TileShape[] split_to_convex(datastructures.Stoppable p_stoppable_thread) { @@ -236,6 +297,7 @@ public TileShape[] split_to_convex(datastructures.Stoppable p_stoppable_thread) return precalculated_convex_pieces; } + /** {@inheritDoc} */ public PolylineArea turn_90_degree(int p_factor, IntPoint p_pole) { PolylineShape new_border = border_shape.turn_90_degree(p_factor, p_pole); @@ -247,6 +309,7 @@ public PolylineArea turn_90_degree(int p_factor, IntPoint p_pole) return new PolylineArea(new_border, new_hole_arr); } + /** {@inheritDoc} */ public PolylineArea rotate_approx(double p_angle, FloatPoint p_pole) { PolylineShape new_border = border_shape.rotate_approx(p_angle, p_pole); @@ -258,6 +321,7 @@ public PolylineArea rotate_approx(double p_angle, FloatPoint p_pole) return new PolylineArea(new_border, new_hole_arr); } + /** {@inheritDoc} */ public PolylineArea mirror_vertical(IntPoint p_pole) { PolylineShape new_border = border_shape.mirror_vertical(p_pole); @@ -270,6 +334,7 @@ public PolylineArea mirror_vertical(IntPoint p_pole) } + /** {@inheritDoc} */ public PolylineArea mirror_horizontal(IntPoint p_pole) { PolylineShape new_border = border_shape.mirror_horizontal(p_pole); diff --git a/geometry/planar/PolylineShape.java b/src/main/java/geometry/planar/PolylineShape.java similarity index 85% rename from geometry/planar/PolylineShape.java rename to src/main/java/geometry/planar/PolylineShape.java index 9d2e740..173993b 100644 --- a/geometry/planar/PolylineShape.java +++ b/src/main/java/geometry/planar/PolylineShape.java @@ -29,16 +29,22 @@ * ob straight lines. * * @author Alfons Wirtz + * @version $Id: $Id */ public abstract class PolylineShape implements Shape, java.io.Serializable { /** * returns true, if the the shape has no infinite part at this corner + * + * @param p_no a int. + * @return a boolean. */ public abstract boolean corner_is_bounded(int p_no); /** * Returns the number of border lines of the shape + * + * @return a int. */ public abstract int border_line_count(); @@ -50,38 +56,53 @@ public abstract class PolylineShape implements Shape, java.io.Serializable * If there are several corners with the smallest y-coordinate, * the corner with the smallest x-coordinate comes first. * Consecutive corners may be equal. + * + * @param p_no a int. + * @return a {@link geometry.planar.Point} object. */ public abstract Point corner(int p_no); /** + * {@inheritDoc} + * * Turns this shape by p_factor times 90 degree around p_pole. */ public abstract PolylineShape turn_90_degree(int p_factor, IntPoint p_pole); /** + * {@inheritDoc} + * * Rotates this shape around p_pole by p_angle. * The result may be not exact. */ public abstract PolylineShape rotate_approx(double p_angle, FloatPoint p_pole); /** + * {@inheritDoc} + * * Mirrors this shape at the horizontal line through p_pole. */ public abstract PolylineShape mirror_horizontal(IntPoint p_pole); /** + * {@inheritDoc} + * * Mirrors this shape at the vertical line through p_pole. */ public abstract PolylineShape mirror_vertical(IntPoint p_pole); /** + * {@inheritDoc} + * * Returns the affine translation of the area by p_vector */ public abstract PolylineShape translate_by(Vector p_vector); /** * Return all unbounded cornersw of this shape. + * + * @return an array of {@link geometry.planar.Point} objects. */ public Point [] bounded_corners() { @@ -108,6 +129,9 @@ public abstract class PolylineShape implements Shape, java.io.Serializable * for p_no between 0 and border_line_count() - 1. * If the shape is not bounded at this corner, the * coordinates of the result will be set to Integer.MAX_VALUE. + * + * @param p_no a int. + * @return a {@link geometry.planar.FloatPoint} object. */ public FloatPoint corner_approx(int p_no) { @@ -119,6 +143,8 @@ public FloatPoint corner_approx(int p_no) * Returns an approximation of the all corners of this shape. * If the shape is not bounded at a corner, the * coordinates will be set to Integer.MAX_VALUE. + * + * @return an array of {@link geometry.planar.FloatPoint} objects. */ public FloatPoint [] corner_approx_arr() { @@ -134,6 +160,9 @@ public FloatPoint corner_approx(int p_no) /** * If p_point is equal to a corner of this shape, the number * of that corner is returned; -1 otherwise. + * + * @param p_point a {@link geometry.planar.Point} object. + * @return a int. */ public int equals_corner(Point p_point) { @@ -150,6 +179,8 @@ public int equals_corner(Point p_point) /** * Returns the cumulative border line length of the shape. * If the shape is unbounded, Integer.MAX_VALUE is returned. + * + * @return a double. */ public double circumference() { @@ -171,6 +202,8 @@ public double circumference() /** * Returns the arithmetic middle of the corners of this shape + * + * @return a {@link geometry.planar.FloatPoint} object. */ public FloatPoint centre_of_gravity() { @@ -189,6 +222,8 @@ public FloatPoint centre_of_gravity() } /** + * {@inheritDoc} + * * checks, if this shape is completely contained in p_box. */ public boolean is_contained_in(IntBox p_box) @@ -200,6 +235,9 @@ public boolean is_contained_in(IntBox p_box) * Returns the index of the corner of the shape, so that all * other points of the shape are to the right of the line * from p_from_point to this corner + * + * @param p_from_point a {@link geometry.planar.FloatPoint} object. + * @return a int. */ public int index_of_left_most_corner(FloatPoint p_from_point) { @@ -222,6 +260,9 @@ public int index_of_left_most_corner(FloatPoint p_from_point) * Returns the index of the corner of the shape, so that all * other points of the shape are to the left of the line * from p_from_point to this corner + * + * @param p_from_point a {@link geometry.planar.FloatPoint} object. + * @return a int. */ public int index_of_right_most_corner(FloatPoint p_from_point) { @@ -244,6 +285,9 @@ public int index_of_right_most_corner(FloatPoint p_from_point) * Returns a FloatLine result, so that result.a is an approximation of * the left most corner of this shape when viewed from p_from_point, * and result.b is an approximation of the right most corner. + * + * @param p_from_point a {@link geometry.planar.FloatPoint} object. + * @return a {@link geometry.planar.FloatLine} object. */ public FloatLine polar_line_segment(FloatPoint p_from_point) { @@ -272,11 +316,17 @@ public FloatLine polar_line_segment(FloatPoint p_from_point) /** * Returns the p_no-th border line of this shape. + * + * @param p_no a int. + * @return a {@link geometry.planar.Line} object. */ public abstract Line border_line(int p_no); /** * Returns the previos border line or corner number of this shape. + * + * @param p_no a int. + * @return a int. */ public int prev_no(int p_no) { @@ -294,6 +344,9 @@ public int prev_no(int p_no) /** * Returns the next border line or corner number of this shape. + * + * @param p_no a int. + * @return a int. */ public int next_no(int p_no) { @@ -309,11 +362,21 @@ public int next_no(int p_no) return result; } + /** + *

get_border.

+ * + * @return a {@link geometry.planar.PolylineShape} object. + */ public PolylineShape get_border() { return this; } + /** + *

get_holes.

+ * + * @return an array of {@link geometry.planar.Shape} objects. + */ public Shape[] get_holes() { return new Shape[0]; @@ -322,6 +385,9 @@ public Shape[] get_holes() /** * Checks, if this shape and p_line have a common point. + * + * @param p_line a {@link geometry.planar.Line} object. + * @return a boolean. */ public boolean intersects(Line p_line) { @@ -342,6 +408,9 @@ public boolean intersects(Line p_line) /** * Calculates the left most corner of this shape, when looked at from p_from_point. + * + * @param p_from_point a {@link geometry.planar.Point} object. + * @return a {@link geometry.planar.Point} object. */ public Point left_most_corner(Point p_from_point) { @@ -364,6 +433,9 @@ public Point left_most_corner(Point p_from_point) /** * Calculates the left most corner of this shape, when looked at from p_from_point. + * + * @param p_from_point a {@link geometry.planar.Point} object. + * @return a {@link geometry.planar.Point} object. */ public Point right_most_corner(Point p_from_point) { diff --git a/geometry/planar/RationalPoint.java b/src/main/java/geometry/planar/RationalPoint.java similarity index 90% rename from geometry/planar/RationalPoint.java rename to src/main/java/geometry/planar/RationalPoint.java index 262cb25..31d9eae 100644 --- a/geometry/planar/RationalPoint.java +++ b/src/main/java/geometry/planar/RationalPoint.java @@ -1,363 +1,407 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * RationalPoint.java - * - * Created on 1. Februar 2003, 13:12 - */ - -package geometry.planar; -import java.math.BigInteger; - -import datastructures.BigIntAux; - -/** - * - * Implementation of points in the projective plane represented by - * 3 coordinates x, y, z, which are infinite precision integers. - * Two projective points (x1, y1, z1) and (x2, y2 z2) are equal, - * if they are located on the same line through the zero point, - * that means, there exist a number r with x2 = r*x1, - * y2 = r*y1 and z2 = r*z1. - * The affine Point with rational coordinates represented by - * the projective Point (x, y, z) is (x/z, y/z). - * The projective plane with integer coordinates contains in - * addition to the affine plane with rational coordinates the - * so-called line at infinity, which consist of - * all projective points (x, y, z) with z = 0. - * - * @author Alfons Wirtz - */ - -public class RationalPoint extends Point implements java.io.Serializable -{ - - /** - * approximates the coordinates of this point by float coordinates - */ - public FloatPoint to_float() - { - double xd = x.doubleValue(); - double yd = y.doubleValue(); - double zd = z.doubleValue(); - if (zd == 0) - { - xd = Float.MAX_VALUE; - yd = Float.MAX_VALUE; - } - else - { - xd /= zd; - yd /= zd; - } - - return new FloatPoint( xd, yd); - } - - /** - * returns true, if this RationalPoint is equal to p_ob - */ - public final boolean equals( Object p_ob ) - { - if ( this == p_ob ) - { - return true; - } - if ( p_ob == null ) - { - return false; - } - if ( getClass() != p_ob.getClass() ) - { - return false ; - } - RationalPoint other = (RationalPoint)p_ob; - BigInteger det = BigIntAux.determinant(x, other.x, z, other.z); - if (det.signum() != 0) - { - return false; - } - det = BigIntAux.determinant(y, other.y, z, other.z); - - return (det.signum() == 0); - } - - public boolean is_infinite() - { - return z.signum() == 0; - } - - public IntBox surrounding_box() - { - FloatPoint fp = to_float(); - int llx = (int) Math.floor(fp.x); - int lly = (int) Math.floor(fp.y); - int urx = (int) Math.ceil(fp.x); - int ury = (int) Math.ceil(fp.y); - return new IntBox(llx, lly, urx, ury); - } - - public IntOctagon surrounding_octagon() - { - FloatPoint fp = to_float(); - int lx = (int) Math.floor(fp.x); - int ly = (int) Math.floor(fp.y); - int rx = (int) Math.ceil(fp.x); - int uy = (int) Math.ceil(fp.y); - - double tmp = fp.x - fp.y; - int ulx = (int) Math.floor(tmp); - int lrx = (int) Math.ceil(tmp); - - tmp = fp.x + fp.y; - int llx = (int) Math.floor(tmp); - int urx = (int) Math.ceil(tmp); - return new IntOctagon(lx, ly, rx, uy, ulx, lrx, llx, urx); - } - - public boolean is_contained_in(IntBox p_box) - { - BigInteger tmp = BigInteger.valueOf(p_box.ll.x).multiply(z); - if (x.compareTo(tmp) < 0) - { - return false; - } - tmp = BigInteger.valueOf(p_box.ll.y).multiply(z); - if (y.compareTo(tmp) < 0) - { - return false; - } - tmp = BigInteger.valueOf(p_box.ur.x).multiply(z); - if (x.compareTo(tmp) > 0) - { - return false; - } - tmp = BigInteger.valueOf(p_box.ur.y).multiply(z); - if (y.compareTo(tmp) > 0) - { - return false; - } - return true; - } - - /** - * returns the translation of this point by p_vector - */ - public Point translate_by(Vector p_vector) - { - if (p_vector.equals(Vector.ZERO)) - { - return this; - } - return p_vector.add_to(this) ; - } - - Point translate_by(IntVector p_vector) - { - RationalVector vector = new RationalVector(p_vector); - return translate_by(vector); - } - - Point translate_by(RationalVector p_vector) - { - BigInteger v1[] = new BigInteger[3]; - v1[0] = x; - v1[1] = y; - v1[2] = z; - - BigInteger v2[] = new BigInteger[3]; - v2[0] = p_vector.x; - v2[1] = p_vector.y; - v2[2] = p_vector.z; - BigInteger[] result = BigIntAux.add_rational_coordinates(v1, v2); - return new RationalPoint(result[0], result[1], result[2]); - } - - /** - * returns the difference vector of this point and p_other - */ - public Vector difference_by(Point p_other) - { - Vector tmp = p_other.difference_by(this); - return tmp.negate(); - } - - Vector difference_by(IntPoint p_other) - { - RationalPoint other = new RationalPoint(p_other); - return difference_by(other); - } - - Vector difference_by(RationalPoint p_other) - { - BigInteger v1[] = new BigInteger[3]; - v1[0] = x; - v1[1] = y; - v1[2] = z; - - BigInteger v2[] = new BigInteger[3]; - v2[0] = p_other.x.negate(); - v2[1] = p_other.y.negate(); - v2[2] = p_other.z; - BigInteger[] result = BigIntAux.add_rational_coordinates(v1, v2); - return new RationalVector(result[0], result[1], result[2]); - } - - /** - * The function returns - * Side.ON_THE_LEFT, if this Point is on the left - * of the line from p_1 to p_2; - * Side.ON_THE_RIGHT, if this Point is on the right - * f the line from p_1 to p_2; - * and Side.COLLINEAR, if this Point is collinear with p_1 and p_2. - */ - public Side side_of(Point p_1, Point p_2) - { - Vector v1 = difference_by(p_1); - Vector v2 = p_2.difference_by(p_1); - return v1.side_of(v2); - } - - public Side side_of(Line p_line) - { - return side_of(p_line.a, p_line.b); - } - - public Point perpendicular_projection(Line p_line) - { - // this function is at the moment only implemented for lines - // consisting of IntPoints. - // The general implementation is still missing. - IntVector v = (IntVector)p_line.b.difference_by(p_line.a); - BigInteger vxvx = BigInteger.valueOf((long)v.x * v.x); - BigInteger vyvy = BigInteger.valueOf((long)v.y * v.y); - BigInteger vxvy = BigInteger.valueOf((long) v.x * v.y); - BigInteger denominator = vxvx.add(vyvy); - BigInteger det = - BigInteger.valueOf(((IntPoint)p_line.a).determinant((IntPoint)p_line.b)); - - BigInteger tmp1 = vxvx.multiply(x); - BigInteger tmp2 = vxvy.multiply(y); - tmp1 = tmp1.add(tmp2); - tmp2 = det.multiply(BigInteger.valueOf(v.y)); - tmp2 = tmp2.multiply(z); - BigInteger proj_x = tmp1.add(tmp2); - - tmp1 = vxvy.multiply(x); - tmp2 = vyvy.multiply(y); - tmp1 = tmp1.add(tmp2); - tmp2 = det.multiply(BigInteger.valueOf(v.x)); - tmp2 = tmp2.multiply(z); - BigInteger proj_y = tmp1.add(tmp2); - - int signum = denominator.signum(); - if (signum != 0) - { - if (signum < 0) - { - denominator = denominator.negate(); - proj_x = proj_x.negate(); - proj_y = proj_y.negate(); - } - if ((proj_x.mod(denominator)).signum() == 0 && - (proj_y.mod(denominator)).signum() == 0) - { - proj_x = proj_x.divide(denominator); - proj_y = proj_y.divide(denominator); - if (proj_x.abs().compareTo(Limits.CRIT_INT_BIG) <= 0 - && proj_y.abs().compareTo(Limits.CRIT_INT_BIG) <= 0) - { - return new IntPoint(proj_x.intValue(), proj_y.intValue()); - } - denominator = BigInteger.ONE; - } - } - return new RationalPoint(proj_x, proj_y, denominator); - } - - public int compare_x(Point p_other) - { - return -p_other.compare_x(this); - } - - - public int compare_y(Point p_other) - { - return -p_other.compare_y(this); - } - - int compare_x(RationalPoint p_other) - { - BigInteger tmp1 = this.x.multiply(p_other.z); - BigInteger tmp2 = p_other.x.multiply(this.z); - return tmp1.compareTo(tmp2); - } - - int compare_y(RationalPoint p_other) - { - BigInteger tmp1 = this.y.multiply(p_other.z); - BigInteger tmp2 = p_other.y.multiply(this.z); - return tmp1.compareTo(tmp2); - } - - int compare_x(IntPoint p_other) - { - BigInteger tmp1 = this.z.multiply(BigInteger.valueOf(p_other.x)); - return this.x.compareTo(tmp1); - } - - int compare_y(IntPoint p_other) - { - BigInteger tmp1 = this.z.multiply(BigInteger.valueOf(p_other.y)); - return this.y.compareTo(tmp1); - - } - - /** - * creates a RetionalPoint from 3 BigIntegers p_x, p_y and p_z. - * They represent the 2-dimensinal point with the - * rational number Tuple ( p_x / p_z , p_y / p_z). - * Throws IllegalArgumentException if denominator p_z is <= 0 - */ - RationalPoint(BigInteger p_x, BigInteger p_y, BigInteger p_z) - { - x = p_x; - y = p_y; - z = p_z; - if (p_z.signum() < 0) - { - throw new IllegalArgumentException - ("RationalPoint: p_z is expected to be >= 0"); - } - } - - /** - * creates a RetionalPoint from an IntPoint - */ - RationalPoint(IntPoint p_point) - { - x = BigInteger.valueOf(p_point.x); - y = BigInteger.valueOf(p_point.y); - z = BigInteger.ONE; - } - - - - final BigInteger x; - final BigInteger y; - final BigInteger z; - - -} \ No newline at end of file +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * RationalPoint.java + * + * Created on 1. Februar 2003, 13:12 + */ + +package geometry.planar; +import java.math.BigInteger; + +import datastructures.BigIntAux; + +/** + * + * Implementation of points in the projective plane represented by + * 3 coordinates x, y, z, which are infinite precision integers. + * Two projective points (x1, y1, z1) and (x2, y2 z2) are equal, + * if they are located on the same line through the zero point, + * that means, there exist a number r with x2 = r*x1, + * y2 = r*y1 and z2 = r*z1. + * The affine Point with rational coordinates represented by + * the projective Point (x, y, z) is (x/z, y/z). + * The projective plane with integer coordinates contains in + * addition to the affine plane with rational coordinates the + * so-called line at infinity, which consist of + * all projective points (x, y, z) with z = 0. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class RationalPoint extends Point implements java.io.Serializable +{ + + /** + * approximates the coordinates of this point by float coordinates + * + * @return a {@link geometry.planar.FloatPoint} object. + */ + public FloatPoint to_float() + { + double xd = x.doubleValue(); + double yd = y.doubleValue(); + double zd = z.doubleValue(); + if (zd == 0) + { + xd = Float.MAX_VALUE; + yd = Float.MAX_VALUE; + } + else + { + xd /= zd; + yd /= zd; + } + + return new FloatPoint( xd, yd); + } + + /** + * {@inheritDoc} + * + * returns true, if this RationalPoint is equal to p_ob + */ + public final boolean equals( Object p_ob ) + { + if ( this == p_ob ) + { + return true; + } + if ( p_ob == null ) + { + return false; + } + if ( getClass() != p_ob.getClass() ) + { + return false ; + } + RationalPoint other = (RationalPoint)p_ob; + BigInteger det = BigIntAux.determinant(x, other.x, z, other.z); + if (det.signum() != 0) + { + return false; + } + det = BigIntAux.determinant(y, other.y, z, other.z); + + return (det.signum() == 0); + } + + /** + *

is_infinite.

+ * + * @return a boolean. + */ + public boolean is_infinite() + { + return z.signum() == 0; + } + + /** + *

surrounding_box.

+ * + * @return a {@link geometry.planar.IntBox} object. + */ + public IntBox surrounding_box() + { + FloatPoint fp = to_float(); + int llx = (int) Math.floor(fp.x); + int lly = (int) Math.floor(fp.y); + int urx = (int) Math.ceil(fp.x); + int ury = (int) Math.ceil(fp.y); + return new IntBox(llx, lly, urx, ury); + } + + /** + *

surrounding_octagon.

+ * + * @return a {@link geometry.planar.IntOctagon} object. + */ + public IntOctagon surrounding_octagon() + { + FloatPoint fp = to_float(); + int lx = (int) Math.floor(fp.x); + int ly = (int) Math.floor(fp.y); + int rx = (int) Math.ceil(fp.x); + int uy = (int) Math.ceil(fp.y); + + double tmp = fp.x - fp.y; + int ulx = (int) Math.floor(tmp); + int lrx = (int) Math.ceil(tmp); + + tmp = fp.x + fp.y; + int llx = (int) Math.floor(tmp); + int urx = (int) Math.ceil(tmp); + return new IntOctagon(lx, ly, rx, uy, ulx, lrx, llx, urx); + } + + /** {@inheritDoc} */ + public boolean is_contained_in(IntBox p_box) + { + BigInteger tmp = BigInteger.valueOf(p_box.ll.x).multiply(z); + if (x.compareTo(tmp) < 0) + { + return false; + } + tmp = BigInteger.valueOf(p_box.ll.y).multiply(z); + if (y.compareTo(tmp) < 0) + { + return false; + } + tmp = BigInteger.valueOf(p_box.ur.x).multiply(z); + if (x.compareTo(tmp) > 0) + { + return false; + } + tmp = BigInteger.valueOf(p_box.ur.y).multiply(z); + if (y.compareTo(tmp) > 0) + { + return false; + } + return true; + } + + /** + * {@inheritDoc} + * + * returns the translation of this point by p_vector + * + * @param p_vector a {@link geometry.planar.Vector} object. + * @return a {@link geometry.planar.Point} object. + */ + public Point translate_by(Vector p_vector) + { + if (p_vector.equals(Vector.ZERO)) + { + return this; + } + return p_vector.add_to(this) ; + } + + Point translate_by(IntVector p_vector) + { + RationalVector vector = new RationalVector(p_vector); + return translate_by(vector); + } + + Point translate_by(RationalVector p_vector) + { + BigInteger v1[] = new BigInteger[3]; + v1[0] = x; + v1[1] = y; + v1[2] = z; + + BigInteger v2[] = new BigInteger[3]; + v2[0] = p_vector.x; + v2[1] = p_vector.y; + v2[2] = p_vector.z; + BigInteger[] result = BigIntAux.add_rational_coordinates(v1, v2); + return new RationalPoint(result[0], result[1], result[2]); + } + + /** + * returns the difference vector of this point and p_other + * + * @param p_other a {@link geometry.planar.Point} object. + * @return a {@link geometry.planar.Vector} object. + */ + public Vector difference_by(Point p_other) + { + Vector tmp = p_other.difference_by(this); + return tmp.negate(); + } + + Vector difference_by(IntPoint p_other) + { + RationalPoint other = new RationalPoint(p_other); + return difference_by(other); + } + + Vector difference_by(RationalPoint p_other) + { + BigInteger v1[] = new BigInteger[3]; + v1[0] = x; + v1[1] = y; + v1[2] = z; + + BigInteger v2[] = new BigInteger[3]; + v2[0] = p_other.x.negate(); + v2[1] = p_other.y.negate(); + v2[2] = p_other.z; + BigInteger[] result = BigIntAux.add_rational_coordinates(v1, v2); + return new RationalVector(result[0], result[1], result[2]); + } + + /** + * {@inheritDoc} + * + * The function returns + * Side.ON_THE_LEFT, if this Point is on the left + * of the line from p_1 to p_2; + * Side.ON_THE_RIGHT, if this Point is on the right + * f the line from p_1 to p_2; + * and Side.COLLINEAR, if this Point is collinear with p_1 and p_2. + */ + public Side side_of(Point p_1, Point p_2) + { + Vector v1 = difference_by(p_1); + Vector v2 = p_2.difference_by(p_1); + return v1.side_of(v2); + } + + /** {@inheritDoc} */ + public Side side_of(Line p_line) + { + return side_of(p_line.a, p_line.b); + } + + /** {@inheritDoc} */ + public Point perpendicular_projection(Line p_line) + { + // this function is at the moment only implemented for lines + // consisting of IntPoints. + // The general implementation is still missing. + IntVector v = (IntVector)p_line.b.difference_by(p_line.a); + BigInteger vxvx = BigInteger.valueOf((long)v.x * v.x); + BigInteger vyvy = BigInteger.valueOf((long)v.y * v.y); + BigInteger vxvy = BigInteger.valueOf((long) v.x * v.y); + BigInteger denominator = vxvx.add(vyvy); + BigInteger det = + BigInteger.valueOf(((IntPoint)p_line.a).determinant((IntPoint)p_line.b)); + + BigInteger tmp1 = vxvx.multiply(x); + BigInteger tmp2 = vxvy.multiply(y); + tmp1 = tmp1.add(tmp2); + tmp2 = det.multiply(BigInteger.valueOf(v.y)); + tmp2 = tmp2.multiply(z); + BigInteger proj_x = tmp1.add(tmp2); + + tmp1 = vxvy.multiply(x); + tmp2 = vyvy.multiply(y); + tmp1 = tmp1.add(tmp2); + tmp2 = det.multiply(BigInteger.valueOf(v.x)); + tmp2 = tmp2.multiply(z); + BigInteger proj_y = tmp1.add(tmp2); + + int signum = denominator.signum(); + if (signum != 0) + { + if (signum < 0) + { + denominator = denominator.negate(); + proj_x = proj_x.negate(); + proj_y = proj_y.negate(); + } + if ((proj_x.mod(denominator)).signum() == 0 && + (proj_y.mod(denominator)).signum() == 0) + { + proj_x = proj_x.divide(denominator); + proj_y = proj_y.divide(denominator); + if (proj_x.abs().compareTo(Limits.CRIT_INT_BIG) <= 0 + && proj_y.abs().compareTo(Limits.CRIT_INT_BIG) <= 0) + { + return new IntPoint(proj_x.intValue(), proj_y.intValue()); + } + denominator = BigInteger.ONE; + } + } + return new RationalPoint(proj_x, proj_y, denominator); + } + + /** + *

compare_x.

+ * + * @param p_other a {@link geometry.planar.Point} object. + * @return a int. + */ + public int compare_x(Point p_other) + { + return -p_other.compare_x(this); + } + + + /** + *

compare_y.

+ * + * @param p_other a {@link geometry.planar.Point} object. + * @return a int. + */ + public int compare_y(Point p_other) + { + return -p_other.compare_y(this); + } + + int compare_x(RationalPoint p_other) + { + BigInteger tmp1 = this.x.multiply(p_other.z); + BigInteger tmp2 = p_other.x.multiply(this.z); + return tmp1.compareTo(tmp2); + } + + int compare_y(RationalPoint p_other) + { + BigInteger tmp1 = this.y.multiply(p_other.z); + BigInteger tmp2 = p_other.y.multiply(this.z); + return tmp1.compareTo(tmp2); + } + + int compare_x(IntPoint p_other) + { + BigInteger tmp1 = this.z.multiply(BigInteger.valueOf(p_other.x)); + return this.x.compareTo(tmp1); + } + + int compare_y(IntPoint p_other) + { + BigInteger tmp1 = this.z.multiply(BigInteger.valueOf(p_other.y)); + return this.y.compareTo(tmp1); + + } + + /** + * creates a RetionalPoint from 3 BigIntegers p_x, p_y and p_z. + * They represent the 2-dimensinal point with the + * rational number Tuple ( p_x / p_z , p_y / p_z). + * Throws IllegalArgumentException if denominator p_z is <= 0 + */ + RationalPoint(BigInteger p_x, BigInteger p_y, BigInteger p_z) + { + x = p_x; + y = p_y; + z = p_z; + if (p_z.signum() < 0) + { + throw new IllegalArgumentException + ("RationalPoint: p_z is expected to be >= 0"); + } + } + + /** + * creates a RetionalPoint from an IntPoint + */ + RationalPoint(IntPoint p_point) + { + x = BigInteger.valueOf(p_point.x); + y = BigInteger.valueOf(p_point.y); + z = BigInteger.ONE; + } + + + + final BigInteger x; + final BigInteger y; + final BigInteger z; + + +} diff --git a/geometry/planar/RationalVector.java b/src/main/java/geometry/planar/RationalVector.java similarity index 86% rename from geometry/planar/RationalVector.java rename to src/main/java/geometry/planar/RationalVector.java index 874e83c..f704525 100644 --- a/geometry/planar/RationalVector.java +++ b/src/main/java/geometry/planar/RationalVector.java @@ -1,336 +1,383 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * RationalVector.java - * - * Created on 1. Februar 2003, 09:16 - */ - -package geometry.planar; -import java.math.BigInteger; - -import datastructures.BigIntAux; -import datastructures.Signum; - -/** - * - * Analog RationalPoint, but implementing the functionality - * of a Vector instead of the functionality of a Point. - * - * @author Alfons Wirtz - */ - -public class RationalVector extends Vector implements java.io.Serializable -{ - /** - * creates a RetionalVector from 3 BigIntegers p_x, p_y and p_z. - * They represent the 2-dimensional Vector with the - * rational number Tuple ( p_x / p_z , p_y / p_z). - */ - public RationalVector(BigInteger p_x, BigInteger p_y, BigInteger p_z) - { - if (p_z.signum() >= 0) - { - x = p_x; - y = p_y; - z = p_z; - - } - else - { - x = p_x.negate(); - y = p_y.negate(); - z = p_z.negate(); - } - } - - /** - * creates a RetionalVector from an IntVector - */ - RationalVector(IntVector p_vector) - { - x = BigInteger.valueOf(p_vector.x); - y = BigInteger.valueOf(p_vector.y); - z = BigInteger.ONE; - } - - /** - * returns true, if the x and y coordinates of this vector are 0 - */ - public final boolean is_zero() - { - return x.signum() == 0 && y.signum() == 0; - } - - /** - * returns true, if this RationalVector is equal to p_ob - */ - public final boolean equals( Object p_ob ) - { - if ( this == p_ob ) - { - return true; - } - if ( p_ob == null ) - { - return false; - } - if ( getClass() != p_ob.getClass() ) - { - return false ; - } - RationalPoint other = (RationalPoint)p_ob; - BigInteger det = BigIntAux.determinant(x, other.x, z, other.z); - if (det.signum() != 0) - { - return false; - } - det = BigIntAux.determinant(y, other.y, z, other.z); - - return (det.signum() == 0); - } - - /** - * returns the Vector such that this plus this.minus() is zero - */ - public Vector negate() - { - return new RationalVector(x.negate(), y.negate(), z); - } - - /** - * adds p_other to this vector - */ - public final Vector add( Vector p_other) - { - return p_other.add(this); - } - - /** - * Let L be the line from the Zero Vector to p_other. - * The function returns - * Side.ON_THE_LEFT, if this Vector is on the left of L - * Side.ON_THE_RIGHT, if this Vector is on the right of L - * and Side.COLLINEAR, if this Vector is collinear with L. - */ - public Side side_of(Vector p_other) - { - Side tmp = p_other.side_of(this); - return tmp.negate(); - } - - public boolean is_orthogonal() - { - return (x.signum() == 0 || y.signum() == 0); - } - - public boolean is_diagonal() - { - return x.abs().equals(y.abs()); - } - - - /** - * The function returns - * Signum.POSITIVE, if the scalar product of this vector and p_other > 0, - * Signum.NEGATIVE, if the scalar product is < 0, - * and Signum.ZERO, if the scalar product is equal 0. - */ - public Signum projection(Vector p_other) - { - return p_other.projection(this); - } - - /** - * calculates the scalar product of this vector and p_other - */ - public double scalar_product(Vector p_other) - { - return p_other.scalar_product(this); - } - - /** - * approximates the coordinates of this vector by float coordinates - */ - public FloatPoint to_float() - { - double xd = x.doubleValue(); - double yd = y.doubleValue(); - double zd = z.doubleValue(); - return new FloatPoint( xd / zd, yd / zd); - } - - public Vector change_length_approx(double p_lenght) - { - System.out.println("RationalVector: change_length_approx not yet implemented"); - return this; - } - - public Vector turn_90_degree(int p_factor) - { - int n = p_factor; - while (n < 0) - { - n += 4; - } - while (n >= 4) - { - n -= 4; - } - BigInteger new_x ; - BigInteger new_y ; - switch (n) - { - case 0: // 0 degree - new_x = x; - new_y = y; - break; - case 1: // 90 degree - new_x = y.negate(); - new_y = x ; - break; - case 2: // 180 degree - new_x = x.negate() ; - new_y = y.negate() ; - break; - case 3: // 270 degree - new_x = y ; - new_y = x.negate() ; - break; - default: - return this; - } - return new RationalVector(new_x, new_y, this.z); - } - - public Vector mirror_at_y_axis() - { - return new RationalVector(this.x.negate(), this.y, this.z); - } - - public Vector mirror_at_x_axis() - { - return new RationalVector(this.x, this.y.negate(), this.z); - } - - Direction to_normalized_direction() - { - BigInteger dx = x; - BigInteger dy = y; - BigInteger gcd = dx.gcd(y); - dx = dx.divide(gcd); - dy = dy.divide(gcd); - if ( (dx.abs()).compareTo(Limits.CRIT_INT_BIG) <= 0 && - (dy.abs()).compareTo(Limits.CRIT_INT_BIG) <= 0 ) - { - return new IntDirection(dx.intValue(), dy.intValue()); - } - return new BigIntDirection(dx, dy); - } - - double scalar_product(IntVector p_other) - { - Vector other = new RationalVector(p_other); - return other.scalar_product(this); - } - - double scalar_product(RationalVector p_other) - { - FloatPoint v1 = to_float(); - FloatPoint v2 = p_other.to_float(); - return v1.x * v2.x + v1.y * v2.y; - } - - Signum projection(IntVector p_other) - { - Vector other = new RationalVector(p_other); - return other.projection(this); - } - - Signum projection(RationalVector p_other) - { - BigInteger tmp1 = x.multiply(p_other.x); - BigInteger tmp2 = y.multiply(p_other.y); - BigInteger tmp3 = tmp1.add(tmp2); - int result = tmp3.signum(); - return Signum.of(result); - } - - final Vector add(IntVector p_other) - { - RationalVector other = new RationalVector(p_other); - return add(other); - } - - final Vector add(RationalVector p_other) - { - BigInteger v1[] = new BigInteger[3]; - v1[0] = x; - v1[1] = y; - v1[2] = z; - - BigInteger v2[] = new BigInteger[3]; - v2[0] = p_other.x; - v2[1] = p_other.y; - v2[2] = p_other.z; - BigInteger[] result = BigIntAux.add_rational_coordinates(v1, v2); - return new RationalVector(result[0], result[1], result[2]); - } - - Point add_to(IntPoint p_point) - { - BigInteger new_x = z.multiply(BigInteger.valueOf(p_point.x)); - new_x = new_x.add(x); - BigInteger new_y = z.multiply(BigInteger.valueOf(p_point.y)); - new_y = new_y.add(y); - return new RationalPoint(new_x, new_y, z); - } - - Point add_to(RationalPoint p_point) - { - BigInteger v1[] = new BigInteger[3]; - v1[0] = x; - v1[1] = y; - v1[2] = z; - - BigInteger v2[] = new BigInteger[3]; - v2[0] = p_point.x; - v2[1] = p_point.y; - v2[2] = p_point.z; - - BigInteger[] result = BigIntAux.add_rational_coordinates(v1, v2); - return new RationalPoint(result[0], result[1], result[2]); - } - - Side side_of(IntVector p_other) - { - RationalVector other = new RationalVector(p_other); - return side_of(other); - } - - Side side_of(RationalVector p_other) - { - BigInteger tmp_1 = y.multiply(p_other.x); - BigInteger tmp_2 = x.multiply(p_other.y); - BigInteger determinant = tmp_1.subtract(tmp_2); - int signum = determinant.signum(); - return Side.of(signum); - } - - - public final BigInteger x; - public final BigInteger y; - public final BigInteger z; -} \ No newline at end of file +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * RationalVector.java + * + * Created on 1. Februar 2003, 09:16 + */ + +package geometry.planar; +import java.math.BigInteger; + +import datastructures.BigIntAux; +import datastructures.Signum; + +/** + * + * Analog RationalPoint, but implementing the functionality + * of a Vector instead of the functionality of a Point. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class RationalVector extends Vector implements java.io.Serializable +{ + /** + * creates a RetionalVector from 3 BigIntegers p_x, p_y and p_z. + * They represent the 2-dimensional Vector with the + * rational number Tuple ( p_x / p_z , p_y / p_z). + * + * @param p_x a {@link java.math.BigInteger} object. + * @param p_y a {@link java.math.BigInteger} object. + * @param p_z a {@link java.math.BigInteger} object. + */ + public RationalVector(BigInteger p_x, BigInteger p_y, BigInteger p_z) + { + if (p_z.signum() >= 0) + { + x = p_x; + y = p_y; + z = p_z; + + } + else + { + x = p_x.negate(); + y = p_y.negate(); + z = p_z.negate(); + } + } + + /** + * creates a RetionalVector from an IntVector + */ + RationalVector(IntVector p_vector) + { + x = BigInteger.valueOf(p_vector.x); + y = BigInteger.valueOf(p_vector.y); + z = BigInteger.ONE; + } + + /** + * returns true, if the x and y coordinates of this vector are 0 + * + * @return a boolean. + */ + public final boolean is_zero() + { + return x.signum() == 0 && y.signum() == 0; + } + + /** + * {@inheritDoc} + * + * returns true, if this RationalVector is equal to p_ob + */ + public final boolean equals( Object p_ob ) + { + if ( this == p_ob ) + { + return true; + } + if ( p_ob == null ) + { + return false; + } + if ( getClass() != p_ob.getClass() ) + { + return false ; + } + RationalPoint other = (RationalPoint)p_ob; + BigInteger det = BigIntAux.determinant(x, other.x, z, other.z); + if (det.signum() != 0) + { + return false; + } + det = BigIntAux.determinant(y, other.y, z, other.z); + + return (det.signum() == 0); + } + + /** + * returns the Vector such that this plus this.minus() is zero + * + * @return a {@link geometry.planar.Vector} object. + */ + public Vector negate() + { + return new RationalVector(x.negate(), y.negate(), z); + } + + /** + * adds p_other to this vector + * + * @param p_other a {@link geometry.planar.Vector} object. + * @return a {@link geometry.planar.Vector} object. + */ + public final Vector add( Vector p_other) + { + return p_other.add(this); + } + + /** + * Let L be the line from the Zero Vector to p_other. + * The function returns + * Side.ON_THE_LEFT, if this Vector is on the left of L + * Side.ON_THE_RIGHT, if this Vector is on the right of L + * and Side.COLLINEAR, if this Vector is collinear with L. + * + * @param p_other a {@link geometry.planar.Vector} object. + * @return a {@link geometry.planar.Side} object. + */ + public Side side_of(Vector p_other) + { + Side tmp = p_other.side_of(this); + return tmp.negate(); + } + + /** + *

is_orthogonal.

+ * + * @return a boolean. + */ + public boolean is_orthogonal() + { + return (x.signum() == 0 || y.signum() == 0); + } + + /** + *

is_diagonal.

+ * + * @return a boolean. + */ + public boolean is_diagonal() + { + return x.abs().equals(y.abs()); + } + + + /** + * {@inheritDoc} + * + * The function returns + * Signum.POSITIVE, if the scalar product of this vector and {@code p_other > 0}, + * Signum.NEGATIVE, if the scalar product {@code is < 0}, + * and Signum.ZERO, if the scalar product {@code is equal 0}. + */ + public Signum projection(Vector p_other) + { + return p_other.projection(this); + } + + /** + * {@inheritDoc} + * + * calculates the scalar product of this vector and p_other + * + * @param p_other a {@link geometry.planar.Vector} object. + * @return a double. + */ + public double scalar_product(Vector p_other) + { + return p_other.scalar_product(this); + } + + /** + * approximates the coordinates of this vector by float coordinates + * + * @return a {@link geometry.planar.FloatPoint} object. + */ + public FloatPoint to_float() + { + double xd = x.doubleValue(); + double yd = y.doubleValue(); + double zd = z.doubleValue(); + return new FloatPoint( xd / zd, yd / zd); + } + + /** {@inheritDoc} */ + public Vector change_length_approx(double p_lenght) + { + System.out.println("RationalVector: change_length_approx not yet implemented"); + return this; + } + + /** {@inheritDoc} */ + public Vector turn_90_degree(int p_factor) + { + int n = p_factor; + while (n < 0) + { + n += 4; + } + while (n >= 4) + { + n -= 4; + } + BigInteger new_x ; + BigInteger new_y ; + switch (n) + { + case 0: // 0 degree + new_x = x; + new_y = y; + break; + case 1: // 90 degree + new_x = y.negate(); + new_y = x ; + break; + case 2: // 180 degree + new_x = x.negate() ; + new_y = y.negate() ; + break; + case 3: // 270 degree + new_x = y ; + new_y = x.negate() ; + break; + default: + return this; + } + return new RationalVector(new_x, new_y, this.z); + } + + /** + *

mirror_at_y_axis.

+ * + * @return a {@link geometry.planar.Vector} object. + */ + public Vector mirror_at_y_axis() + { + return new RationalVector(this.x.negate(), this.y, this.z); + } + + /** + *

mirror_at_x_axis.

+ * + * @return a {@link geometry.planar.Vector} object. + */ + public Vector mirror_at_x_axis() + { + return new RationalVector(this.x, this.y.negate(), this.z); + } + + Direction to_normalized_direction() + { + BigInteger dx = x; + BigInteger dy = y; + BigInteger gcd = dx.gcd(y); + dx = dx.divide(gcd); + dy = dy.divide(gcd); + if ( (dx.abs()).compareTo(Limits.CRIT_INT_BIG) <= 0 && + (dy.abs()).compareTo(Limits.CRIT_INT_BIG) <= 0 ) + { + return new IntDirection(dx.intValue(), dy.intValue()); + } + return new BigIntDirection(dx, dy); + } + + double scalar_product(IntVector p_other) + { + Vector other = new RationalVector(p_other); + return other.scalar_product(this); + } + + double scalar_product(RationalVector p_other) + { + FloatPoint v1 = to_float(); + FloatPoint v2 = p_other.to_float(); + return v1.x * v2.x + v1.y * v2.y; + } + + Signum projection(IntVector p_other) + { + Vector other = new RationalVector(p_other); + return other.projection(this); + } + + Signum projection(RationalVector p_other) + { + BigInteger tmp1 = x.multiply(p_other.x); + BigInteger tmp2 = y.multiply(p_other.y); + BigInteger tmp3 = tmp1.add(tmp2); + int result = tmp3.signum(); + return Signum.of(result); + } + + final Vector add(IntVector p_other) + { + RationalVector other = new RationalVector(p_other); + return add(other); + } + + final Vector add(RationalVector p_other) + { + BigInteger v1[] = new BigInteger[3]; + v1[0] = x; + v1[1] = y; + v1[2] = z; + + BigInteger v2[] = new BigInteger[3]; + v2[0] = p_other.x; + v2[1] = p_other.y; + v2[2] = p_other.z; + BigInteger[] result = BigIntAux.add_rational_coordinates(v1, v2); + return new RationalVector(result[0], result[1], result[2]); + } + + Point add_to(IntPoint p_point) + { + BigInteger new_x = z.multiply(BigInteger.valueOf(p_point.x)); + new_x = new_x.add(x); + BigInteger new_y = z.multiply(BigInteger.valueOf(p_point.y)); + new_y = new_y.add(y); + return new RationalPoint(new_x, new_y, z); + } + + Point add_to(RationalPoint p_point) + { + BigInteger v1[] = new BigInteger[3]; + v1[0] = x; + v1[1] = y; + v1[2] = z; + + BigInteger v2[] = new BigInteger[3]; + v2[0] = p_point.x; + v2[1] = p_point.y; + v2[2] = p_point.z; + + BigInteger[] result = BigIntAux.add_rational_coordinates(v1, v2); + return new RationalPoint(result[0], result[1], result[2]); + } + + Side side_of(IntVector p_other) + { + RationalVector other = new RationalVector(p_other); + return side_of(other); + } + + Side side_of(RationalVector p_other) + { + BigInteger tmp_1 = y.multiply(p_other.x); + BigInteger tmp_2 = x.multiply(p_other.y); + BigInteger determinant = tmp_1.subtract(tmp_2); + int signum = determinant.signum(); + return Side.of(signum); + } + + + public final BigInteger x; + public final BigInteger y; + public final BigInteger z; +} diff --git a/geometry/planar/RegularTileShape.java b/src/main/java/geometry/planar/RegularTileShape.java similarity index 71% rename from geometry/planar/RegularTileShape.java rename to src/main/java/geometry/planar/RegularTileShape.java index 26bba49..a561ad0 100644 --- a/geometry/planar/RegularTileShape.java +++ b/src/main/java/geometry/planar/RegularTileShape.java @@ -24,30 +24,41 @@ * TileShapes whose border lines may have only directions out of * a fixed set, as for example orthoganal directions, which * define axis parallel box shapes. - * + * * @author Alfons Wirtz + * @version $Id: $Id */ public abstract class RegularTileShape extends TileShape { - /** - * Compares the edglines of index p_edge_no of this regular TileShape - * and p_other. - * returns Side.ON_THE_LEFT, if the edgeline of this simplex is to the left - * of the edgeline of p_other; Side.COLLINEAR, if the edlines are equal, - * and Side.ON_THE_RIGHT, if this edgeline is to the right of the edgeline - * of p_other. - */ + /** + * Compares the edglines of index p_edge_no of this regular TileShape + * and p_other. + * returns Side.ON_THE_LEFT, if the edgeline of this simplex is to the left + * of the edgeline of p_other; Side.COLLINEAR, if the edlines are equal, + * and Side.ON_THE_RIGHT, if this edgeline is to the right of the edgeline + * of p_other. + * + * @param p_other a {@link geometry.planar.RegularTileShape} object. + * @param p_edge_no a int. + * @return a {@link geometry.planar.Side} object. + */ public abstract Side compare(RegularTileShape p_other, int p_edge_no); /** * calculates the smallest RegularTileShape * containing this shape and p_other. + * + * @param p_other a {@link geometry.planar.RegularTileShape} object. + * @return a {@link geometry.planar.RegularTileShape} object. */ public abstract RegularTileShape union(RegularTileShape p_other); /** * returns true, if p_other is completely contained in this shape + * + * @param p_other a {@link geometry.planar.RegularTileShape} object. + * @return a boolean. */ public abstract boolean contains (RegularTileShape p_other); @@ -72,9 +83,11 @@ public abstract class RegularTileShape extends TileShape */ abstract RegularTileShape union(IntOctagon p_other); /** - * Auxiliary function to implement the same function with parameter - * type RegularTileShape. - */ + * {@inheritDoc} + * + * Auxiliary function to implement the same function with parameter + * type RegularTileShape. + */ public abstract boolean is_contained_in (IntBox p_other); /** * Auxiliary function to implement the same function with parameter diff --git a/geometry/planar/Shape.java b/src/main/java/geometry/planar/Shape.java similarity index 71% rename from geometry/planar/Shape.java rename to src/main/java/geometry/planar/Shape.java index 98d680b..910d254 100644 --- a/geometry/planar/Shape.java +++ b/src/main/java/geometry/planar/Shape.java @@ -25,71 +25,98 @@ * A Shape object is expected to be simply connected, that means, it may not contain holes. * * @author Alfons Wirtz + * @version $Id: $Id */ - public interface Shape extends Area { /** * Returns the length of the border of this shape. * If the shape is unbounded, Integer.MAX_VALUE is returned. + * + * @return a double. */ double circumference(); /** * Returns the content of the area of the shape. * If the shape is unbounded, Double.MAX_VALUE is returned. + * + * @return a double. */ double area(); /** * Returns the gravity point of this shape + * + * @return a {@link geometry.planar.FloatPoint} object. */ FloatPoint centre_of_gravity(); /** * Returns true, if p_point is not contained in the inside or the * boundary of the shape + * + * @param p_point a {@link geometry.planar.Point} object. + * @return a boolean. */ boolean is_outside(Point p_point); /** * Returns true, if p_point is contained in this shape, * but not on the border. + * + * @param p_point a {@link geometry.planar.Point} object. + * @return a boolean. */ boolean contains_inside(Point p_point); /** * Returns true, if p_point lies exact on the boundary of the shape + * + * @param p_point a {@link geometry.planar.Point} object. + * @return a boolean. */ boolean contains_on_border(Point p_point); /** * Returns the distance between p_point and its nearest point * on the shape. 0, if p_point is contained in this shape + * + * @param p_point a {@link geometry.planar.FloatPoint} object. + * @return a double. */ double distance(FloatPoint p_point); /** * Return a bounding TileShape of this shape. + * + * @return a {@link geometry.planar.TileShape} object. */ TileShape bounding_tile(); /** * Returns the bounding RegularTileShape with the fixed directions p_dirs + * + * @param p_dirs a {@link geometry.planar.ShapeBoundingDirections} object. + * @return a {@link geometry.planar.RegularTileShape} object. */ RegularTileShape bounding_shape(ShapeBoundingDirections p_dirs); /** * Returns the distance between p_point and its nearest point * on the border of the shape. + * + * @param p_point a {@link geometry.planar.FloatPoint} object. + * @return a double. */ - double border_distance(FloatPoint p_point); /** * Returns the smallest distance from the centre of gravity to the border * of the shape. + * + * @return a double. */ double smallest_radius(); @@ -98,11 +125,17 @@ public interface Shape extends Area * boundary by p_distance to the outside. * The result instsnce may be of a different class than this instance. * (For example an enlarged IntBox is an IntOctagon). + * + * @param p_offset a double. + * @return a {@link geometry.planar.Shape} object. */ Shape enlarge(double p_offset); /** * checks, if the this shape and p_other have an nonempty intersection. + * + * @param p_other a {@link geometry.planar.Shape} object. + * @return a boolean. */ boolean intersects(Shape p_other); @@ -111,27 +144,42 @@ public interface Shape extends Area * and returns a list of the remaining pieces of p_polyline. * Pieces completely contained in the border of this shape * are not returned. + * + * @param p_polyline a {@link geometry.planar.Polyline} object. + * @return an array of {@link geometry.planar.Polyline} objects. */ Polyline [] cutout(Polyline p_polyline); /** * Auxiliary function to implement the same function with parameter * type Shape. + * + * @param p_other a {@link geometry.planar.IntBox} object. + * @return a boolean. */ boolean intersects(IntBox p_other); /** * Auxiliary function to implement the same function with parameter * type Shape. + * + * @param p_other a {@link geometry.planar.IntOctagon} object. + * @return a boolean. */ boolean intersects(IntOctagon p_other); /** * Auxiliary function to implement the same function with parameter * type Shape. + * + * @param p_other a {@link geometry.planar.Simplex} object. + * @return a boolean. */ boolean intersects(Simplex p_other); /** * Auxiliary function to implement the same function with parameter * type Shape. + * + * @param p_other a {@link geometry.planar.Circle} object. + * @return a boolean. */ boolean intersects(Circle p_other); } diff --git a/geometry/planar/ShapeBoundingDirections.java b/src/main/java/geometry/planar/ShapeBoundingDirections.java similarity index 68% rename from geometry/planar/ShapeBoundingDirections.java rename to src/main/java/geometry/planar/ShapeBoundingDirections.java index b8777ee..65f3d19 100644 --- a/geometry/planar/ShapeBoundingDirections.java +++ b/src/main/java/geometry/planar/ShapeBoundingDirections.java @@ -1,65 +1,85 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - */ - -package geometry.planar; - -/** - * - * Describing the functionality for the fixed directions of a RegularTileShape. - * - * @author Alfons Wirtz - */ - -public interface ShapeBoundingDirections -{ - /** - * Retuns the count of the fixed directions. - */ - int count(); - - /** - * Calculates for an abitrary ConvexShape a surrounding RegularTileShape - * with this fixed directions. - * Is used in the implementation of the seach trees. - */ - RegularTileShape bounds(ConvexShape p_shape); - - /** - * Auxiliary function to implement the same function with parameter - * type ConvexShape. - */ - RegularTileShape bounds(IntBox p_box); - /** - * Auxiliary function to implement the same function with parameter - * type ConvexShape. - */ - RegularTileShape bounds(IntOctagon p_oct); - /** - * Auxiliary function to implement the same function with parameter - * type ConvexShape. - */ - RegularTileShape bounds(Simplex p_simplex); - /** - * Auxiliary function to implement the same function with parameter - * type ConvexShape. - */ - RegularTileShape bounds(Circle p_circle); - /** - * Auxiliary function to implement the same function with parameter - * type ConvexShape. - */ - RegularTileShape bounds(PolygonShape p_polygon); -} \ No newline at end of file +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + */ + +package geometry.planar; + +/** + * + * Describing the functionality for the fixed directions of a RegularTileShape. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public interface ShapeBoundingDirections +{ + /** + * Retuns the count of the fixed directions. + * + * @return a int. + */ + int count(); + + /** + * Calculates for an abitrary ConvexShape a surrounding RegularTileShape + * with this fixed directions. + * Is used in the implementation of the seach trees. + * + * @param p_shape a {@link geometry.planar.ConvexShape} object. + * @return a {@link geometry.planar.RegularTileShape} object. + */ + RegularTileShape bounds(ConvexShape p_shape); + + /** + * Auxiliary function to implement the same function with parameter + * type ConvexShape. + * + * @param p_box a {@link geometry.planar.IntBox} object. + * @return a {@link geometry.planar.RegularTileShape} object. + */ + RegularTileShape bounds(IntBox p_box); + /** + * Auxiliary function to implement the same function with parameter + * type ConvexShape. + * + * @param p_oct a {@link geometry.planar.IntOctagon} object. + * @return a {@link geometry.planar.RegularTileShape} object. + */ + RegularTileShape bounds(IntOctagon p_oct); + /** + * Auxiliary function to implement the same function with parameter + * type ConvexShape. + * + * @param p_simplex a {@link geometry.planar.Simplex} object. + * @return a {@link geometry.planar.RegularTileShape} object. + */ + RegularTileShape bounds(Simplex p_simplex); + /** + * Auxiliary function to implement the same function with parameter + * type ConvexShape. + * + * @param p_circle a {@link geometry.planar.Circle} object. + * @return a {@link geometry.planar.RegularTileShape} object. + */ + RegularTileShape bounds(Circle p_circle); + /** + * Auxiliary function to implement the same function with parameter + * type ConvexShape. + * + * @param p_polygon a {@link geometry.planar.PolygonShape} object. + * @return a {@link geometry.planar.RegularTileShape} object. + */ + RegularTileShape bounds(PolygonShape p_polygon); +} diff --git a/geometry/planar/Side.java b/src/main/java/geometry/planar/Side.java similarity index 88% rename from geometry/planar/Side.java rename to src/main/java/geometry/planar/Side.java index bbc7812..fd899f7 100644 --- a/geometry/planar/Side.java +++ b/src/main/java/geometry/planar/Side.java @@ -1,93 +1,99 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - */ - -package geometry.planar; - -/** - * - * Implementation of an enum class Side with the three values - * ON_THE_LEFT, ON_THE_RIGHT, COLLINEAR. - * - - * @author Alfons Wirtz - */ - -public class Side -{ - public static final Side ON_THE_LEFT = new Side ("on_the_left"); - public static final Side ON_THE_RIGHT = new Side ("on_the_right"); - public static final Side COLLINEAR = new Side ("collinear"); - - /** - * returns the string of this instance - */ - public String to_string () - { - return name; - } - - /** - * returns the opposite side of this side - */ - public final Side negate() - { - Side result; - if (this == ON_THE_LEFT) - { - result = ON_THE_RIGHT; - } - else if (this == ON_THE_RIGHT) - { - result = ON_THE_LEFT; - } - else - { - result = this; - } - return result; - } - - /** - * returns ON_THE_LEFT, if p_value < 0, - * ON_THE_RIGHT, if p_value > 0 - * and COLLINEAR, if p_value == 0 - */ - static final Side of(double p_value) - { - Side result; - if (p_value > 0) - { - result = Side.ON_THE_LEFT; - } - else if (p_value < 0) - { - result = Side.ON_THE_RIGHT; - } - else - { - result = Side.COLLINEAR; - } - return result; - } - - - private Side(String p_name) - { - name = p_name; - } - - private final String name; -} \ No newline at end of file +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + */ + +package geometry.planar; + +/** + * + * Implementation of an enum class Side with the three values + * ON_THE_LEFT, ON_THE_RIGHT, COLLINEAR. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class Side +{ + /** Constant ON_THE_LEFT */ + public static final Side ON_THE_LEFT = new Side ("on_the_left"); + /** Constant ON_THE_RIGHT */ + public static final Side ON_THE_RIGHT = new Side ("on_the_right"); + /** Constant COLLINEAR */ + public static final Side COLLINEAR = new Side ("collinear"); + + /** + * returns the string of this instance + * + * @return a {@link java.lang.String} object. + */ + public String to_string () + { + return name; + } + + /** + * returns the opposite side of this side + * + * @return a {@link geometry.planar.Side} object. + */ + public final Side negate() + { + Side result; + if (this == ON_THE_LEFT) + { + result = ON_THE_RIGHT; + } + else if (this == ON_THE_RIGHT) + { + result = ON_THE_LEFT; + } + else + { + result = this; + } + return result; + } + + /** + * returns ON_THE_LEFT, if p_value < 0, + * ON_THE_RIGHT, if p_value > 0 + * and COLLINEAR, if p_value == 0 + */ + static final Side of(double p_value) + { + Side result; + if (p_value > 0) + { + result = Side.ON_THE_LEFT; + } + else if (p_value < 0) + { + result = Side.ON_THE_RIGHT; + } + else + { + result = Side.COLLINEAR; + } + return result; + } + + + private Side(String p_name) + { + name = p_name; + } + + private final String name; +} diff --git a/geometry/planar/Simplex.java b/src/main/java/geometry/planar/Simplex.java similarity index 94% rename from geometry/planar/Simplex.java rename to src/main/java/geometry/planar/Simplex.java index 151b48f..b5bf6f4 100644 --- a/geometry/planar/Simplex.java +++ b/src/main/java/geometry/planar/Simplex.java @@ -1,1418 +1,1536 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - */ - -package geometry.planar; - -import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedList; - -/** - * - * Convex shape defined as intersection of half-planes. - * A half-plane is defined as the positive side of a directed line. - * - * @author Alfons Wirtz - */ - - -public class Simplex extends TileShape implements java.io.Serializable -{ - - /** - * Standard implementation for an empty Simplex. - */ - public static final Simplex EMPTY = new Simplex(new Line [0]); - - /** - * creates a Simplex as intersection of the halfplanes defined - * by an array of directed lines - */ - public static Simplex get_instance(Line[] p_line_arr) - { - if (p_line_arr.length <= 0) - { - return Simplex.EMPTY; - } - Line [] curr_arr = new Line[p_line_arr.length]; - System.arraycopy(p_line_arr, 0, curr_arr, 0, p_line_arr.length); - // sort the lines in ascending direction - java.util.Arrays.sort(curr_arr); - Simplex curr_simplex = new Simplex(curr_arr); - Simplex result = curr_simplex.remove_redundant_lines(); - return result; - } - - /** - * Return true, if this simplex is empty - */ - public boolean is_empty() - { - return (arr.length == 0); - } - - /** - * Converts the physical instance of this shape to a simpler physical instance, if possible. - * (For example a Simplex to an IntOctagon). - */ - public TileShape simplify() - { - TileShape result = this; - if (this.is_empty()) - { - result = Simplex.EMPTY; - } - else if (this.is_IntBox()) - { - result = this.bounding_box(); - } - else if (this.is_IntOctagon()) - { - result = this.to_IntOctagon(); - } - return result; - } - - /** - * Returns true, if the determinant of the direction of index - * p_no -1 and the direction of index p_no is > 0 - */ - public boolean corner_is_bounded(int p_no) - { - int no; - if (p_no < 0) - { - System.out.println("corner: p_no is < 0"); - no = 0; - } - else if (p_no >= arr.length) - { - System.out.println("corner: p_index must be less than arr.length - 1"); - no = arr.length - 1; - } - else - { - no = p_no; - } - if(arr.length == 1) - { - return false; - } - int prev_no; - if (no == 0) - { - prev_no = arr.length - 1; - } - else - { - prev_no = no - 1; - } - IntVector prev_dir = (IntVector)arr[prev_no].direction().get_vector(); - IntVector curr_dir = (IntVector)arr[no].direction().get_vector(); - return (prev_dir.determinant(curr_dir) > 0); - } - - - /** - * Returns true, if the shape of this simplex is contained in a - * sufficiently large box - */ - public boolean is_bounded() - { - if (arr.length == 0) - { - return true; - } - if (arr.length < 3) - { - return false; - } - for (int i = 0; i < arr.length; ++i) - { - if (!corner_is_bounded(i)) - { - return false; - } - } - return true; - } - - /** - * Returns the number of edge lines defining this simplex - */ - public int border_line_count() - { - return arr.length; - } - - /** - * Returns the intersection of the p_no -1-th with the p_no-th line of this simplex. - * If the simplex is not bounded at this corner, the - * coordinates of the result will be set to Integer.MAX_VALUE. - */ - public Point corner(int p_no) - { - int no; - if (p_no < 0) - { - System.out.println("Simplex.corner: p_no is < 0"); - no = 0; - } - else if (p_no >= arr.length) - { - System.out.println("Simplex.corner: p_no must be less than arr.length - 1"); - no = arr.length - 1; - } - else - { - no = p_no; - } - if (precalculated_corners == null) - // corner array is not yet allocated - { - precalculated_corners = new Point[arr.length]; - } - if (precalculated_corners [no] == null) - // corner is not yet calculated - { - Line prev; - if (no == 0) - { - prev = arr[arr.length - 1]; - } - else - { - prev = arr[no - 1]; - } - precalculated_corners[no] = arr[no].intersection(prev); - } - return precalculated_corners [no]; - } - - /** - * Returns an approximation of the intersection of the p_no -1-th with the - * p_no-th line of this simplex by a FloatPoint. - * If the simplex is not bounded at this corner, the - * coordinates of the result will be set to Integer.MAX_VALUE. - */ - public FloatPoint corner_approx(int p_no) - { - if (arr.length <= 0) - { - return null; - } - int no; - if (p_no < 0) - { - System.out.println("Simplex.corner_approx: p_no is < 0"); - no = 0; - } - else if (p_no >= arr.length) - { - System.out.println("Simplex.corner_approx: p_no must be less than arr.length - 1"); - no = arr.length - 1; - } - else - { - no = p_no; - } - if (precalculated_float_corners == null) - // corner array is not yet allocated - { - precalculated_float_corners = new FloatPoint[arr.length]; - } - if (precalculated_float_corners [no] == null) - // corner is not yet calculated - { - Line prev; - if (no == 0) - { - prev = arr[arr.length - 1]; - } - else - { - prev = arr[no - 1]; - } - precalculated_float_corners[no] = arr[no].intersection_approx(prev); - } - return precalculated_float_corners [no]; - } - - public FloatPoint[] corner_approx_arr() - { - if (precalculated_float_corners == null) - // corner array is not yet allocated - { - precalculated_float_corners = new FloatPoint[arr.length]; - } - for (int i = 0; i < precalculated_float_corners.length; ++i) - { - if (precalculated_float_corners [i] == null) - // corner is not yet calculated - { - Line prev; - if (i == 0) - { - prev = arr[arr.length - 1]; - } - else - { - prev = arr[i - 1]; - } - precalculated_float_corners[i] = arr[i].intersection_approx(prev); - } - } - return precalculated_float_corners; - } - - /** - * returns the p_no-th edge line of this simplex. - * The edge lines are sorted in ascending direction. - */ - public Line border_line(int p_no) - { - if (arr.length <= 0) - { - System.out.println("Simplex.edge_line : simplex is empty"); - return null; - } - int no; - if (p_no < 0) - { - System.out.println("Simplex.edge_line : p_no is < 0"); - no = 0; - } - else if (p_no >= arr.length) - { - System.out.println("Simplex.edge_line: p_no must be less than arr.length - 1"); - no = arr.length - 1; - } - else - { - no = p_no; - } - return arr[no]; - } - - /** - * Returns the dimension of this simplex. - * The result may be 2, 1, 0, or -1 (if the simplex is empty). - */ - public int dimension() - { - if (arr.length == 0) - { - return -1; - } - if (arr.length > 4) - { - return 2; - } - if (arr.length == 1) - { - // we have a half plane - return 2; - } - if (arr.length == 2) - { - if(arr[0].overlaps(arr[1])) - { - return 1; - } - return 2; - } - if (arr.length == 3) - { - if (arr[0].overlaps(arr[1]) || arr[0].overlaps(arr[2]) - || arr[1].overlaps(arr[2])) - { - // simplex is 1 dimensional and unbounded at one side - return 1; - } - Point intersection = arr[1].intersection(arr[2]); - Side side_of_line0 = arr[0].side_of(intersection); - if(side_of_line0 == Side.ON_THE_RIGHT) - { - return 2; - } - if (side_of_line0 == Side.ON_THE_LEFT) - { - System.out.println("empty Simplex not normalized"); - return -1; - } - // now the 3 lines intersect in the same point - return 0; - } - // now the simplex has 4 edge lines - // check if opposing lines are collinear - boolean collinear_0_2 = arr[0].overlaps(arr[2]); - boolean collinear_1_3 = arr[1].overlaps(arr[3]); - if (collinear_0_2 && collinear_1_3) - { - return 0; - } - if (collinear_0_2 || collinear_1_3) - { - return 1; - } - return 2; - } - - public double max_width() - { - if (!this.is_bounded()) - { - return Integer.MAX_VALUE; - } - double max_distance = Integer.MIN_VALUE; - double max_distance_2 = Integer.MIN_VALUE; - FloatPoint gravity_point = this.centre_of_gravity(); - - for (int i = 0; i < border_line_count(); ++i) - { - double curr_distance = Math.abs(arr[i].signed_distance(gravity_point)); - - if (curr_distance > max_distance) - { - max_distance_2 = max_distance; - max_distance = curr_distance; - } - else if (curr_distance > max_distance_2) - { - max_distance_2 = curr_distance; - } - } - return max_distance + max_distance_2; - } - - public double min_width() - { - if (!this.is_bounded()) - { - return Integer.MAX_VALUE; - } - double min_distance = Integer.MAX_VALUE; - double min_distance_2 = Integer.MAX_VALUE; - FloatPoint gravity_point = this.centre_of_gravity(); - - for (int i = 0; i < border_line_count(); ++i) - { - double curr_distance = Math.abs(arr[i].signed_distance(gravity_point)); - - if (curr_distance < min_distance) - { - min_distance_2 = min_distance; - min_distance = curr_distance; - } - else if (curr_distance < min_distance_2) - { - min_distance_2 = curr_distance; - } - } - return min_distance + min_distance_2; - } - - - /** - * checks if this simplex can be converted into an IntBox - */ - public boolean is_IntBox() - { - for (int i = 0; i < arr.length; ++i) - { - Line curr_line = arr[i]; - if (!(curr_line.a instanceof IntPoint && - curr_line.b instanceof IntPoint )) - { - return false; - } - if (!curr_line.is_orthogonal()) - { - return false; - } - if (!corner_is_bounded(i)) - { - return false; - } - } - return true; - } - - /** - * checks if this simplex can be converted into an IntOctagon - */ - public boolean is_IntOctagon() - { - for (int i = 0; i < arr.length; ++i) - { - Line curr_line = arr[i]; - if (!(curr_line.a instanceof IntPoint && - curr_line.b instanceof IntPoint )) - { - return false; - } - if (!curr_line.is_multiple_of_45_degree()) - { - return false; - } - if (!corner_is_bounded(i)) - { - return false; - } - } - return true; - } - - /** - * Converts this IntSimplex to an IntOctagon. - * Returns null, if that is not possible, because not all lines - * of this IntSimplex are 45 degree - */ - public IntOctagon to_IntOctagon() - { - // this function is at the moment only implemented for lines - // consisting of IntPoints. - // The general implementation is still missing. - if (!is_IntOctagon()) - { - return null; - } - if (is_empty()) - { - return IntOctagon.EMPTY; - } - - // initialise to biggest octagon values - - int rx = Limits.CRIT_INT; - int uy = Limits.CRIT_INT; - int lrx = Limits.CRIT_INT; - int urx = Limits.CRIT_INT; - int lx = -Limits.CRIT_INT; - int ly = -Limits.CRIT_INT; - int llx = -Limits.CRIT_INT; - int ulx = -Limits.CRIT_INT; - for (int i = 0; i < arr.length; ++i) - { - Line curr_line = arr[i]; - IntPoint a = (IntPoint) curr_line.a; - IntPoint b = (IntPoint) curr_line.b; - if (a.y == b.y) - { - if (b.x >= a.x) - { - // lower boundary line - ly = a.y; - } - if (b.x <= a.x) - { - // upper boundary line - uy = a.y; - } - } - if (a.x == b.x) - { - if (b.y >= a.y) - { - // right boundary line - rx = a.x; - } - if (b.y <= a.y) - { - // left boundary line - lx = a.x; - } - } - if (a.y < b.y) - { - if (a.x < b.x) - { - // lower right boundary line - lrx = a.x - a.y; - } - else if (a.x > b.x) - { - // upper right boundary line - urx = a.x + a.y; - } - } - else if (a.y > b.y) - { - if (a.x < b.x) - { - // lower left boundary line - llx = a.x + a.y; - } - else if (a.x > b.x) - { - // upper left boundary line - ulx = a.x - a.y; - } - } - } - IntOctagon result = new IntOctagon(lx, ly, rx, uy, ulx, lrx, llx, urx); - return result.normalize(); - } - - /** - * Returns the simplex, which results from translating - * the lines of this simplex by p_vector - */ - public Simplex translate_by(Vector p_vector) - { - if (p_vector.equals(Vector.ZERO)) - { - return this; - } - Line[] new_arr = new Line[arr.length]; - for( int i = 0; i < arr.length; ++i) - { - new_arr [i] = arr[i].translate_by(p_vector); - } - return new Simplex(new_arr); - } - - - /** - * Returns the smallest box with int coordinates containing - * all corners of this simplex. - * The coordinates of the result will be Integer.MAX_VALUE, - * if the simplex is not bounded - */ - public IntBox bounding_box() - { - if (arr.length == 0) - { - return IntBox.EMPTY; - } - if (precalculated_bounding_box == null) - { - double llx = Integer.MAX_VALUE; - double lly = Integer.MAX_VALUE; - double urx = Integer.MIN_VALUE; - double ury = Integer.MIN_VALUE; - for (int i = 0; i < arr.length; ++i) - { - FloatPoint curr = corner_approx(i); - llx = Math.min(llx, curr.x); - lly = Math.min(lly, curr.y); - urx = Math.max(urx, curr.x); - ury = Math.max(ury, curr.y); - } - IntPoint lower_left = new IntPoint((int)Math.floor(llx),(int)Math.floor(lly)); - IntPoint upper_right = new IntPoint((int)Math.ceil(urx),(int)Math.ceil(ury)); - precalculated_bounding_box = new IntBox(lower_left, upper_right); - } - return precalculated_bounding_box; - } - - /** - * Calculates a bounding octagon of the Simplex. - * Returns null, if the Simplex is not bounded. - */ - public IntOctagon bounding_octagon() - { - if (precalculated_bounding_octagon == null) - { - double lx = Integer.MAX_VALUE; - double ly = Integer.MAX_VALUE; - double rx = Integer.MIN_VALUE; - double uy = Integer.MIN_VALUE; - double ulx = Integer.MAX_VALUE; - double lrx = Integer.MIN_VALUE; - double llx = Integer.MAX_VALUE; - double urx = Integer.MIN_VALUE; - for (int i = 0; i < arr.length; ++i) - { - FloatPoint curr = corner_approx(i); - lx = Math.min(lx, curr.x); - ly = Math.min(ly, curr.y); - rx = Math.max(rx, curr.x); - uy = Math.max(uy, curr.y); - - double tmp = curr.x - curr.y; - ulx = Math.min(ulx, tmp); - lrx = Math.max(lrx, tmp); - - tmp = curr.x + curr.y; - llx = Math.min(llx, tmp); - urx = Math.max(urx, tmp); - } - if (Math.min(lx, ly) < -Limits.CRIT_INT - || Math.max(rx, uy) > Limits.CRIT_INT - || Math.min(ulx, llx) < -Limits.CRIT_INT - || Math.max(lrx, urx) > Limits.CRIT_INT) - // result is not bounded - { - return null; - } - precalculated_bounding_octagon = new - IntOctagon((int)Math.floor(lx), (int)Math.floor(ly), - (int)Math.ceil(rx), (int)Math.ceil(uy), - (int)Math.floor(ulx), (int)Math.ceil(lrx), - (int)Math.floor(llx), (int)Math.ceil(urx)); - } - return precalculated_bounding_octagon; - } - - public Simplex bounding_tile() - { - return this; - } - - public RegularTileShape bounding_shape(ShapeBoundingDirections p_dirs) - { - return p_dirs.bounds(this); - } - - - /** - * Returns the simplex offseted by p_with. - * If p_width > 0, the offset is to the outer, else to the inner. - */ - public Simplex offset(double p_width) - { - if (p_width == 0) - { - return this; - } - Line[] new_arr = new Line[arr.length]; - for (int i = 0; i < arr.length; ++i) - { - new_arr[i] = arr[i].translate(-p_width); - } - Simplex offset_simplex = new Simplex(new_arr); - if (p_width < 0) - { - offset_simplex = offset_simplex.remove_redundant_lines(); - } - return offset_simplex; - } - - /** - * Returns this simplex enlarged by p_offset. - * The result simplex is intersected with the - * by p_offset enlarged bounding octagon of this simplex - */ - public Simplex enlarge(double p_offset) - { - if (p_offset == 0) - { - return this; - } - Simplex offset_simplex = offset(p_offset); - IntOctagon bounding_oct = this.bounding_octagon(); - if (bounding_oct == null) - { - return Simplex.EMPTY; - } - IntOctagon offset_oct = bounding_oct.offset(p_offset); - return offset_simplex.intersection(offset_oct.to_Simplex()); - } - - - - /** - * Returns the number of the rightmost corner seen from p_from_point - * No other point of this simplex may be to the right - * of the line from p_from_point to the result corner. - */ - public int index_of_right_most_corner( Point p_from_point) - { - Point pole = p_from_point; - Point right_most_corner = corner(0); - int result = 0; - for (int i = 1; i < arr.length; ++i) - { - Point curr_corner = corner(i); - if (curr_corner.side_of(pole, right_most_corner) == Side.ON_THE_RIGHT) - { - right_most_corner = curr_corner; - result = i; - } - } - return result; - } - - /** - * Returns the intersection of p_box with this simplex - */ - public Simplex intersection(IntBox p_box) - { - return intersection(p_box.to_Simplex()); - } - - /** - * Returns the intersection of this simplex and p_other - */ - public Simplex intersection(Simplex p_other) - { - if (this.is_empty() || p_other.is_empty()) - { - return EMPTY; - } - Line[] new_arr = new Line[arr.length + p_other.arr.length]; - System.arraycopy(arr, 0, new_arr, 0, arr.length); - System.arraycopy(p_other.arr, 0, new_arr, arr.length, p_other.arr.length); - java.util.Arrays.sort(new_arr); - Simplex result = new Simplex( new_arr); - return result.remove_redundant_lines(); - } - - /** - * Returns the intersection of this simplex and the shape p_other - */ - public TileShape intersection(TileShape p_other) - { - TileShape result = p_other.intersection(this); - return result; - } - - - public boolean intersects(Shape p_other) - { - return p_other.intersects(this); - } - - public boolean intersects(Simplex p_other) - { - ConvexShape is = intersection(p_other); - return !is.is_empty(); - } - - /** - * if p_line is a borderline of this simplex the number of that - * edge is returned, otherwise -1 - */ - public int border_line_index(Line p_line) - { - for (int i = 0; i < arr.length; ++i) - { - if (p_line.equals(arr[i])) - { - return i; - } - } - return -1; - } - - /** - * Enlarges the simplex by removing the edge line with index p_no. - * The result simplex may get unbounded. - */ - public Simplex remove_border_line( int p_no) - { - if (p_no < 0 || p_no >= arr.length) - { - return this; - } - Line [] new_arr = new Line [this.arr.length - 1]; - System.arraycopy(this.arr, 0, new_arr, 0, p_no); - System.arraycopy(this.arr, p_no + 1, new_arr, p_no, new_arr.length - p_no); - return new Simplex(new_arr); - } - - /** - * Constructs a Simplex from the directed lines in p_line_arr. - * The simplex will not be normalized. - * To get a normalised simplex use TileShape.get_instance - */ - public Simplex(Line[] p_line_arr) - { - arr = p_line_arr; - } - - public Simplex to_Simplex() - { - return this; - } - - - Simplex intersection(IntOctagon p_other) - { - return intersection(p_other.to_Simplex()); - } - - public TileShape[] cutout(TileShape p_shape) - { - return p_shape.cutout_from(this); - } - - /** - * cuts this simplex out of p_outer_simplex. - * Divides the resulting shape into simplices along the minimal - * distance lines from the vertices of the inner simplex to the outer - * simplex; Returns the convex pieces constructed by this division. - */ - public Simplex[] cutout_from(Simplex p_outer_simplex) - { - if(this.dimension() < 2) - { - System.out.println("Simplex.cutout_from only implemented for 2-dim simplex"); - return null; - } - Simplex inner_simplex = this.intersection(p_outer_simplex); - if (inner_simplex.dimension() < 2) - { - // nothing to cutout from p_outer_simplex - Simplex[] result = new Simplex[1]; - result[0] = p_outer_simplex; - return result; - } - int inner_corner_count = inner_simplex.arr.length; - Line [][] division_line_arr = new Line[inner_corner_count][]; - for (int inner_corner_no = 0; inner_corner_no < inner_corner_count; ++inner_corner_no) - { - division_line_arr[inner_corner_no] = - inner_simplex.calc_division_lines(inner_corner_no, p_outer_simplex); - if (division_line_arr[inner_corner_no] == null) - { - System.out.println("Simplex.cutout_from: division line is null"); - Simplex[] result = new Simplex[1]; - result[0] = p_outer_simplex; - return result; - } - } - boolean check_cross_first_line = false; - Line prev_division_line = null; - Line first_division_line = division_line_arr[0][0]; - IntDirection first_direction = (IntDirection)first_division_line.direction(); - Collection result_list = new LinkedList(); - - for (int inner_corner_no = 0; inner_corner_no < inner_corner_count; ++inner_corner_no) - { - Line next_division_line; - if (inner_corner_no == inner_simplex.arr.length - 1) - next_division_line = division_line_arr[0][0]; - else - next_division_line = division_line_arr[inner_corner_no + 1][0]; - Line[] curr_division_lines = division_line_arr[inner_corner_no]; - if (curr_division_lines.length == 2) - { - // 2 division lines are nessesary (sharp corner). - // Construct an unbounded simplex from - // curr_division_lines[1] and curr_division_lines[0] - // and intersect it with the outer simplex - IntDirection curr_dir = (IntDirection)curr_division_lines[0].direction(); - boolean merge_prev_division_line = false; - boolean merge_first_division_line = false; - if (prev_division_line != null) - { - IntDirection prev_dir = (IntDirection)prev_division_line.direction(); - if (curr_dir.determinant(prev_dir) > 0) - - { - // the previous division line may intersect - // curr_division_lines[0] inside p_divide_simplex - merge_prev_division_line = true; - } - } - if (!check_cross_first_line) - { - check_cross_first_line = (inner_corner_no > 0 && - curr_dir.determinant(first_direction) > 0); - } - if (check_cross_first_line) - { - IntDirection curr_dir2 = (IntDirection)curr_division_lines[1].direction(); - if (curr_dir2.determinant(first_direction) < 0) - { - // The current piece has an intersection area with the first - // piece. - // Add a line to tmp_polyline to prevent this - merge_first_division_line = true; - } - } - int piece_line_count = 2; - if (merge_prev_division_line) - ++piece_line_count; - if (merge_first_division_line) - ++piece_line_count; - Line[] piece_lines = new Line[piece_line_count]; - piece_lines[0] = new Line(curr_division_lines[1].b, curr_division_lines[1].a); - piece_lines[1] = curr_division_lines[0]; - int curr_line_no = 1; - if (merge_prev_division_line) - { - ++curr_line_no; - piece_lines[curr_line_no] = prev_division_line; - } - if (merge_first_division_line) - { - ++curr_line_no; - piece_lines[curr_line_no] = - new Line(first_division_line.b, first_division_line.a); - } - Simplex curr_piece = new Simplex(piece_lines); - result_list.add(curr_piece.intersection(p_outer_simplex)); - } - // construct an unbounded simplex from next_division_line, - // inner_simplex.line [inner_corner_no] and the last current division line - // and intersect it with the outer simplex - boolean merge_next_division_line = !next_division_line.b.equals(next_division_line.a); - Line last_curr_division_line = curr_division_lines[curr_division_lines.length - 1]; - IntDirection last_curr_dir = (IntDirection)last_curr_division_line.direction(); - boolean merge_last_curr_division_line = - !last_curr_division_line.b.equals(last_curr_division_line.a); - boolean merge_prev_division_line = false; - boolean merge_first_division_line = false; - if (prev_division_line != null) - { - IntDirection prev_dir = (IntDirection)prev_division_line.direction(); - if (last_curr_dir.determinant(prev_dir) > 0) - - { - // the previous division line may intersect - // the last current division line inside p_divide_simplex - merge_prev_division_line = true; - } - } - if (!check_cross_first_line) - { - check_cross_first_line = inner_corner_no > 0 && - last_curr_dir.determinant(first_direction) > 0 && - last_curr_dir.get_vector().scalar_product(first_direction.get_vector()) < 0; - // scalar_product checked to ignore backcrossing at - // small inner_corner_no - } - if (check_cross_first_line) - { - IntDirection next_dir = (IntDirection)next_division_line.direction(); - if(next_dir.determinant(first_direction) < 0) - { - // The current piece has an intersection area with the first piece. - // Add a line to tmp_polyline to prevent this - merge_first_division_line = true; - } - } - int piece_line_count = 1; - if (merge_next_division_line) - ++piece_line_count; - if (merge_last_curr_division_line) - ++piece_line_count; - if (merge_prev_division_line) - ++piece_line_count; - if (merge_first_division_line) - ++piece_line_count; - Line[] piece_lines = new Line[piece_line_count]; - Line curr_line = inner_simplex.arr[inner_corner_no]; - piece_lines[0] = new Line(curr_line.b, curr_line.a); - int curr_line_no = 0; - if (merge_next_division_line) - { - ++curr_line_no; - piece_lines[curr_line_no] = new Line(next_division_line.b, next_division_line.a); - } - if (merge_last_curr_division_line) - { - ++curr_line_no; - piece_lines[curr_line_no] = last_curr_division_line; - } - if (merge_prev_division_line) - { - ++curr_line_no; - piece_lines[curr_line_no] = prev_division_line; - } - if (merge_first_division_line) - { - ++curr_line_no; - piece_lines[curr_line_no] = - new Line(first_division_line.b, first_division_line.a); - } - Simplex curr_piece = new Simplex(piece_lines); - result_list.add(curr_piece.intersection(p_outer_simplex)); - next_division_line = prev_division_line; - } - Simplex[] result = new Simplex[result_list.size()]; - Iterator it = result_list.iterator(); - for (int i = 0; i < result.length; ++i) - { - result[i] = it.next(); - } - return result; - } - - Simplex[] cutout_from(IntOctagon p_oct) - { - return cutout_from(p_oct.to_Simplex()); - } - - Simplex[] cutout_from(IntBox p_box) - { - return cutout_from(p_box.to_Simplex()); - } - - /** - * Removes lines, which are redundant in the definition of the - * shape of this simplex. - * Assumes that the lines of this simplex are sorted. - */ - Simplex remove_redundant_lines() - { - Line [] line_arr = new Line [arr.length]; - // copy the sorted lines of arr into line_arr while skipping - // multiple lines - int new_length = 1; - line_arr[0] = arr[0]; - Line prev = line_arr[0]; - for (int i = 1; i < arr.length; ++i) - { - if (!arr[i].fast_equals(prev)) - { - line_arr[new_length] = arr[i]; - prev = line_arr[new_length]; - ++new_length; - } - } - - Side [] intersection_sides = new Side [new_length]; - // precalculated array , on which side of this line the previous and the - // next line do intersect - - boolean try_again = new_length > 2; - int index_of_last_removed_line = new_length; - while(try_again) - { - try_again = false; - int prev_ind = new_length - 1; - int next_ind; - Line prev_line = line_arr[prev_ind]; - Line curr_line = line_arr[0]; - Line next_line; - for (int ind = 0; ind < new_length; ++ind) - { - if (ind == new_length - 1) - { - next_ind = 0; - } - else - { - next_ind = ind + 1; - } - next_line = line_arr[next_ind]; - - boolean remove_line = false; - IntDirection prev_dir = (IntDirection) prev_line.direction(); - IntDirection next_dir = (IntDirection) next_line.direction(); - double det = prev_dir.determinant(next_dir); - if (det != 0) // prev_line and next_line are not parallel - { - if (intersection_sides [ind] == null) - { - // intersection_sides [ind] not precalculated - intersection_sides [ind] = curr_line.side_of_intersection(prev_line, next_line); - } - if(det > 0 ) - // direction of next_line is bigger than direction of prev_line - { - // if the intersection of prev_line and next_line - // is on the left of curr_line, curr_line does not - // contribute to the shape of the simplex - remove_line = (intersection_sides[ind] != Side.ON_THE_LEFT); - } - else - // direction of next_line is smaller than direction of prev_line - { - - if (intersection_sides[ind] == Side.ON_THE_LEFT) - { - IntDirection curr_dir = (IntDirection) curr_line.direction(); - if (prev_dir.determinant(curr_dir) > 0) - // direction of curr_line is bigger than direction of prev_line - { - // the halfplane defined by curr_line does not intersect - // with the simplex defined by prev_line and nex_line, - // hence this simplex must be empty - new_length = 0; - try_again = false; - break; - } - } - } - } - else // prev_line and next_line are parallel - { - if (prev_line.side_of(next_line.a) == Side.ON_THE_LEFT) - // prev_line is to the left of next_line, - // the halfplanes defined by prev_line and next_line - // do not intersect - { - new_length = 0; - try_again = false; - break; - } - } - if (remove_line) - { - try_again = true; - --new_length; - for (int i = ind; i < new_length; ++i) - { - line_arr [i] = line_arr [i + 1]; - intersection_sides[i] = intersection_sides [i + 1]; - } - - if (new_length < 3) - { - try_again = false; - break; - } - // reset 3 precalculated intersection_sides - if (ind == 0) - { - prev_ind = new_length - 1; - } - intersection_sides [prev_ind] = null; - if (ind >= new_length) - { - next_ind = 0; - } - else - { - next_ind = ind; - } - intersection_sides [next_ind] = null; - --ind; - index_of_last_removed_line = ind; - } - else - { - prev_line = curr_line; - prev_ind = ind; - } - curr_line = next_line; - if( !try_again && ind >= index_of_last_removed_line) - // tried all lines without removing one - { - break; - } - } - } - - if (new_length == 2) - { - if (line_arr[0].is_parallel(line_arr[1])) - { - if(line_arr[0].direction().equals(line_arr[1].direction())) - // one of the two remaining lines is redundant - { - if (line_arr[1].side_of(line_arr[0].a) == Side.ON_THE_LEFT) - { - line_arr[0] = line_arr[1]; - } - --new_length; - } - else - // the two remaining lines have opposite direction - // the simplex may be empty - { - if (line_arr[1].side_of(line_arr[0].a) == Side.ON_THE_LEFT) - { - new_length = 0; - } - } - } - } - if (new_length == arr.length) - { - return this; // nothing removed - } - if (new_length == 0) - { - return Simplex.EMPTY; - } - Line [] result = new Line [new_length]; - System.arraycopy(line_arr, 0, result, 0, new_length); - return new Simplex(result); - } - - public boolean intersects(IntBox p_box) - { - return intersects(p_box.to_Simplex()); - } - - public boolean intersects(IntOctagon p_octagon) - { - return intersects(p_octagon.to_Simplex()); - } - - public boolean intersects(Circle p_circle) - { - return p_circle.intersects(this); - } - - /** - * For each corner of this inner simplex 1 or 2 perpendicular - * projections onto lines of the outer simplex are constructed, - * so that the resulting pieces after cutting out the inner simplex - * are convex. 2 projections may be nessesary at sharp angle corners. - * Used in in the method cutout_from with parametertype Simplex. - */ - private Line[] calc_division_lines(int p_inner_corner_no, Simplex p_outer_simplex) - { - Line curr_inner_line = this.arr[p_inner_corner_no]; - Line prev_inner_line; - if (p_inner_corner_no != 0) - prev_inner_line = this.arr[p_inner_corner_no - 1]; - else - prev_inner_line = this.arr[arr.length - 1]; - FloatPoint intersection = curr_inner_line.intersection_approx(prev_inner_line); - if (intersection.x >= Integer.MAX_VALUE) - { - System.out.println("Simplex.calc_division_lines: intersection expexted"); - return null; - } - IntPoint inner_corner = intersection.round(); - double c_tolerance = 0.0001; - boolean is_exact = - Math.abs(inner_corner.x - intersection.x) < c_tolerance - && Math.abs(inner_corner.y - intersection.y) < c_tolerance; - - if (!is_exact) - { - // it is assumed, that the corners of the original inner simplex are - // exact and the not exact corners come from the intersection of - // the inner simplex with the outer simplex. - // Because these corners lie on the border of the outer simplex, - // no division is nessesary - Line [] result = new Line[1]; - result[0] = prev_inner_line; - return result; - } - IntDirection first_projection_dir = Direction.NULL; - IntDirection second_projection_dir = Direction.NULL; - IntDirection prev_inner_dir = (IntDirection) prev_inner_line.direction().opposite(); - IntDirection next_inner_dir = (IntDirection) curr_inner_line.direction(); - int outer_line_no = 0; - - - // search the first outer line, so that - // the perpendicular projection of the inner corner onto this - // line is visible from inner_corner to the left of prev_inner_line. - - double min_distance = Integer.MAX_VALUE; - - for (int ind = 0; ind < p_outer_simplex.arr.length; ++ind) - { - Line outer_line = p_outer_simplex.arr[outer_line_no]; - IntDirection curr_projection_dir = - (IntDirection)inner_corner.perpendicular_direction(outer_line); - if (curr_projection_dir == Direction.NULL) - { - Line [] result = new Line[1]; - result[0] = new Line(inner_corner, inner_corner); - return result; - } - boolean projection_visible = prev_inner_dir.determinant(curr_projection_dir) >= 0; - if (projection_visible) - { - double curr_distance = Math.abs(outer_line.signed_distance(inner_corner.to_float())); - boolean second_division_necessary = - curr_projection_dir.determinant(next_inner_dir) < 0; - // may occor at a sharp angle - IntDirection curr_second_projection_dir = curr_projection_dir; - - if (second_division_necessary) - { - // search the first projection_dir between curr_projection_dir - // and next_inner_dir, that is visible from next_inner_line - boolean second_projection_visible = false; - int tmp_outer_line_no = outer_line_no; - while (!second_projection_visible) - { - if (tmp_outer_line_no == p_outer_simplex.arr.length - 1) - { - tmp_outer_line_no = 0; - } - else - { - ++tmp_outer_line_no; - } - curr_second_projection_dir = - (IntDirection)inner_corner.perpendicular_direction( - p_outer_simplex.arr[tmp_outer_line_no]); - - if (curr_second_projection_dir == Direction.NULL) - // inner corner is on outer_line - { - Line [] result = new Line[1]; - result[0] = new Line(inner_corner, inner_corner); - return result; - } - if (curr_projection_dir.determinant(curr_second_projection_dir) < 0) - { - // curr_second_projection_dir not found; - // the angle between curr_projection_dir and - // curr_second_projection_dir would be already bigger - // than 180 degree - curr_distance = Integer.MAX_VALUE; - break; - } - - second_projection_visible = - curr_second_projection_dir.determinant(next_inner_dir) >= 0; - } - curr_distance += - Math.abs(p_outer_simplex.arr[tmp_outer_line_no].signed_distance(inner_corner.to_float())); - } - if (curr_distance < min_distance) - { - min_distance = curr_distance; - first_projection_dir = curr_projection_dir; - second_projection_dir = curr_second_projection_dir; - } - } - if (outer_line_no == p_outer_simplex.arr.length - 1) - { - outer_line_no = 0; - } - else - { - ++outer_line_no; - - } - } - if (min_distance == Integer.MAX_VALUE) - { - System.out.println("Simplex.calc_division_lines: division not found"); - return null; - } - Line[] result; - if (first_projection_dir.equals(second_projection_dir)) - { - result = new Line[1]; - result[0] = new Line(inner_corner, first_projection_dir); - } - else - { - result = new Line[2]; - result[0] = new Line(inner_corner, first_projection_dir); - result[1] = new Line(inner_corner, second_projection_dir); - } - return result; - } - - private final Line[] arr; - - /** - * the following fields are for storing precalculated data - */ - transient private Point[] precalculated_corners = null; - transient private FloatPoint[] precalculated_float_corners = null; - transient private IntBox precalculated_bounding_box = null; - transient private IntOctagon precalculated_bounding_octagon = null; - -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + */ + +package geometry.planar; + +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; + +/** + * + * Convex shape defined as intersection of half-planes. + * A half-plane is defined as the positive side of a directed line. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class Simplex extends TileShape implements java.io.Serializable +{ + + /** + * Standard implementation for an empty Simplex. + */ + public static final Simplex EMPTY = new Simplex(new Line [0]); + + /** + * {@inheritDoc} + * + * creates a Simplex as intersection of the halfplanes defined + * by an array of directed lines + * + * @param p_line_arr an array of {@link geometry.planar.Line} objects. + * @return a {@link geometry.planar.Simplex} object. + */ + public static Simplex get_instance(Line[] p_line_arr) + { + if (p_line_arr.length <= 0) + { + return Simplex.EMPTY; + } + Line [] curr_arr = new Line[p_line_arr.length]; + System.arraycopy(p_line_arr, 0, curr_arr, 0, p_line_arr.length); + // sort the lines in ascending direction + java.util.Arrays.sort(curr_arr); + Simplex curr_simplex = new Simplex(curr_arr); + Simplex result = curr_simplex.remove_redundant_lines(); + return result; + } + + /** + * Return true, if this simplex is empty + * + * @return a boolean. + */ + public boolean is_empty() + { + return (arr.length == 0); + } + + /** + * Converts the physical instance of this shape to a simpler physical instance, if possible. + * (For example a Simplex to an IntOctagon). + * + * @return a {@link geometry.planar.TileShape} object. + */ + public TileShape simplify() + { + TileShape result = this; + if (this.is_empty()) + { + result = Simplex.EMPTY; + } + else if (this.is_IntBox()) + { + result = this.bounding_box(); + } + else if (this.is_IntOctagon()) + { + result = this.to_IntOctagon(); + } + return result; + } + + /** + * {@inheritDoc} + * + * Returns true, if the determinant of the direction of index + * p_no -1 and the direction of index {@code p_no is > 0} + */ + public boolean corner_is_bounded(int p_no) + { + int no; + if (p_no < 0) + { + System.out.println("corner: p_no is < 0"); + no = 0; + } + else if (p_no >= arr.length) + { + System.out.println("corner: p_index must be less than arr.length - 1"); + no = arr.length - 1; + } + else + { + no = p_no; + } + if(arr.length == 1) + { + return false; + } + int prev_no; + if (no == 0) + { + prev_no = arr.length - 1; + } + else + { + prev_no = no - 1; + } + IntVector prev_dir = (IntVector)arr[prev_no].direction().get_vector(); + IntVector curr_dir = (IntVector)arr[no].direction().get_vector(); + return (prev_dir.determinant(curr_dir) > 0); + } + + + /** + * Returns true, if the shape of this simplex is contained in a + * sufficiently large box + * + * @return a boolean. + */ + public boolean is_bounded() + { + if (arr.length == 0) + { + return true; + } + if (arr.length < 3) + { + return false; + } + for (int i = 0; i < arr.length; ++i) + { + if (!corner_is_bounded(i)) + { + return false; + } + } + return true; + } + + /** + * Returns the number of edge lines defining this simplex + * + * @return a int. + */ + public int border_line_count() + { + return arr.length; + } + + /** + * {@inheritDoc} + * + * Returns the intersection of the p_no -1-th with the p_no-th line of this simplex. + * If the simplex is not bounded at this corner, the + * coordinates of the result will be set to Integer.MAX_VALUE. + */ + public Point corner(int p_no) + { + int no; + if (p_no < 0) + { + System.out.println("Simplex.corner: p_no is < 0"); + no = 0; + } + else if (p_no >= arr.length) + { + System.out.println("Simplex.corner: p_no must be less than arr.length - 1"); + no = arr.length - 1; + } + else + { + no = p_no; + } + if (precalculated_corners == null) + // corner array is not yet allocated + { + precalculated_corners = new Point[arr.length]; + } + if (precalculated_corners [no] == null) + // corner is not yet calculated + { + Line prev; + if (no == 0) + { + prev = arr[arr.length - 1]; + } + else + { + prev = arr[no - 1]; + } + precalculated_corners[no] = arr[no].intersection(prev); + } + return precalculated_corners [no]; + } + + /** + * {@inheritDoc} + * + * Returns an approximation of the intersection of the p_no -1-th with the + * p_no-th line of this simplex by a FloatPoint. + * If the simplex is not bounded at this corner, the + * coordinates of the result will be set to Integer.MAX_VALUE. + */ + public FloatPoint corner_approx(int p_no) + { + if (arr.length <= 0) + { + return null; + } + int no; + if (p_no < 0) + { + System.out.println("Simplex.corner_approx: p_no is < 0"); + no = 0; + } + else if (p_no >= arr.length) + { + System.out.println("Simplex.corner_approx: p_no must be less than arr.length - 1"); + no = arr.length - 1; + } + else + { + no = p_no; + } + if (precalculated_float_corners == null) + // corner array is not yet allocated + { + precalculated_float_corners = new FloatPoint[arr.length]; + } + if (precalculated_float_corners [no] == null) + // corner is not yet calculated + { + Line prev; + if (no == 0) + { + prev = arr[arr.length - 1]; + } + else + { + prev = arr[no - 1]; + } + precalculated_float_corners[no] = arr[no].intersection_approx(prev); + } + return precalculated_float_corners [no]; + } + + /** + *

corner_approx_arr.

+ * + * @return an array of {@link geometry.planar.FloatPoint} objects. + */ + public FloatPoint[] corner_approx_arr() + { + if (precalculated_float_corners == null) + // corner array is not yet allocated + { + precalculated_float_corners = new FloatPoint[arr.length]; + } + for (int i = 0; i < precalculated_float_corners.length; ++i) + { + if (precalculated_float_corners [i] == null) + // corner is not yet calculated + { + Line prev; + if (i == 0) + { + prev = arr[arr.length - 1]; + } + else + { + prev = arr[i - 1]; + } + precalculated_float_corners[i] = arr[i].intersection_approx(prev); + } + } + return precalculated_float_corners; + } + + /** + * {@inheritDoc} + * + * returns the p_no-th edge line of this simplex. + * The edge lines are sorted in ascending direction. + */ + public Line border_line(int p_no) + { + if (arr.length <= 0) + { + System.out.println("Simplex.edge_line : simplex is empty"); + return null; + } + int no; + if (p_no < 0) + { + System.out.println("Simplex.edge_line : p_no is < 0"); + no = 0; + } + else if (p_no >= arr.length) + { + System.out.println("Simplex.edge_line: p_no must be less than arr.length - 1"); + no = arr.length - 1; + } + else + { + no = p_no; + } + return arr[no]; + } + + /** + * Returns the dimension of this simplex. + * The result may be 2, 1, 0, or -1 (if the simplex is empty). + * + * @return a int. + */ + public int dimension() + { + if (arr.length == 0) + { + return -1; + } + if (arr.length > 4) + { + return 2; + } + if (arr.length == 1) + { + // we have a half plane + return 2; + } + if (arr.length == 2) + { + if(arr[0].overlaps(arr[1])) + { + return 1; + } + return 2; + } + if (arr.length == 3) + { + if (arr[0].overlaps(arr[1]) || arr[0].overlaps(arr[2]) + || arr[1].overlaps(arr[2])) + { + // simplex is 1 dimensional and unbounded at one side + return 1; + } + Point intersection = arr[1].intersection(arr[2]); + Side side_of_line0 = arr[0].side_of(intersection); + if(side_of_line0 == Side.ON_THE_RIGHT) + { + return 2; + } + if (side_of_line0 == Side.ON_THE_LEFT) + { + System.out.println("empty Simplex not normalized"); + return -1; + } + // now the 3 lines intersect in the same point + return 0; + } + // now the simplex has 4 edge lines + // check if opposing lines are collinear + boolean collinear_0_2 = arr[0].overlaps(arr[2]); + boolean collinear_1_3 = arr[1].overlaps(arr[3]); + if (collinear_0_2 && collinear_1_3) + { + return 0; + } + if (collinear_0_2 || collinear_1_3) + { + return 1; + } + return 2; + } + + /** + *

max_width.

+ * + * @return a double. + */ + public double max_width() + { + if (!this.is_bounded()) + { + return Integer.MAX_VALUE; + } + double max_distance = Integer.MIN_VALUE; + double max_distance_2 = Integer.MIN_VALUE; + FloatPoint gravity_point = this.centre_of_gravity(); + + for (int i = 0; i < border_line_count(); ++i) + { + double curr_distance = Math.abs(arr[i].signed_distance(gravity_point)); + + if (curr_distance > max_distance) + { + max_distance_2 = max_distance; + max_distance = curr_distance; + } + else if (curr_distance > max_distance_2) + { + max_distance_2 = curr_distance; + } + } + return max_distance + max_distance_2; + } + + /** + *

min_width.

+ * + * @return a double. + */ + public double min_width() + { + if (!this.is_bounded()) + { + return Integer.MAX_VALUE; + } + double min_distance = Integer.MAX_VALUE; + double min_distance_2 = Integer.MAX_VALUE; + FloatPoint gravity_point = this.centre_of_gravity(); + + for (int i = 0; i < border_line_count(); ++i) + { + double curr_distance = Math.abs(arr[i].signed_distance(gravity_point)); + + if (curr_distance < min_distance) + { + min_distance_2 = min_distance; + min_distance = curr_distance; + } + else if (curr_distance < min_distance_2) + { + min_distance_2 = curr_distance; + } + } + return min_distance + min_distance_2; + } + + + /** + * checks if this simplex can be converted into an IntBox + * + * @return a boolean. + */ + public boolean is_IntBox() + { + for (int i = 0; i < arr.length; ++i) + { + Line curr_line = arr[i]; + if (!(curr_line.a instanceof IntPoint && + curr_line.b instanceof IntPoint )) + { + return false; + } + if (!curr_line.is_orthogonal()) + { + return false; + } + if (!corner_is_bounded(i)) + { + return false; + } + } + return true; + } + + /** + * checks if this simplex can be converted into an IntOctagon + * + * @return a boolean. + */ + public boolean is_IntOctagon() + { + for (int i = 0; i < arr.length; ++i) + { + Line curr_line = arr[i]; + if (!(curr_line.a instanceof IntPoint && + curr_line.b instanceof IntPoint )) + { + return false; + } + if (!curr_line.is_multiple_of_45_degree()) + { + return false; + } + if (!corner_is_bounded(i)) + { + return false; + } + } + return true; + } + + /** + * Converts this IntSimplex to an IntOctagon. + * Returns null, if that is not possible, because not all lines + * of this IntSimplex are 45 degree + * + * @return a {@link geometry.planar.IntOctagon} object. + */ + public IntOctagon to_IntOctagon() + { + // this function is at the moment only implemented for lines + // consisting of IntPoints. + // The general implementation is still missing. + if (!is_IntOctagon()) + { + return null; + } + if (is_empty()) + { + return IntOctagon.EMPTY; + } + + // initialise to biggest octagon values + + int rx = Limits.CRIT_INT; + int uy = Limits.CRIT_INT; + int lrx = Limits.CRIT_INT; + int urx = Limits.CRIT_INT; + int lx = -Limits.CRIT_INT; + int ly = -Limits.CRIT_INT; + int llx = -Limits.CRIT_INT; + int ulx = -Limits.CRIT_INT; + for (int i = 0; i < arr.length; ++i) + { + Line curr_line = arr[i]; + IntPoint a = (IntPoint) curr_line.a; + IntPoint b = (IntPoint) curr_line.b; + if (a.y == b.y) + { + if (b.x >= a.x) + { + // lower boundary line + ly = a.y; + } + if (b.x <= a.x) + { + // upper boundary line + uy = a.y; + } + } + if (a.x == b.x) + { + if (b.y >= a.y) + { + // right boundary line + rx = a.x; + } + if (b.y <= a.y) + { + // left boundary line + lx = a.x; + } + } + if (a.y < b.y) + { + if (a.x < b.x) + { + // lower right boundary line + lrx = a.x - a.y; + } + else if (a.x > b.x) + { + // upper right boundary line + urx = a.x + a.y; + } + } + else if (a.y > b.y) + { + if (a.x < b.x) + { + // lower left boundary line + llx = a.x + a.y; + } + else if (a.x > b.x) + { + // upper left boundary line + ulx = a.x - a.y; + } + } + } + IntOctagon result = new IntOctagon(lx, ly, rx, uy, ulx, lrx, llx, urx); + return result.normalize(); + } + + /** + * {@inheritDoc} + * + * Returns the simplex, which results from translating + * the lines of this simplex by p_vector + */ + public Simplex translate_by(Vector p_vector) + { + if (p_vector.equals(Vector.ZERO)) + { + return this; + } + Line[] new_arr = new Line[arr.length]; + for( int i = 0; i < arr.length; ++i) + { + new_arr [i] = arr[i].translate_by(p_vector); + } + return new Simplex(new_arr); + } + + + /** + * Returns the smallest box with int coordinates containing + * all corners of this simplex. + * The coordinates of the result will be Integer.MAX_VALUE, + * if the simplex is not bounded + * + * @return a {@link geometry.planar.IntBox} object. + */ + public IntBox bounding_box() + { + if (arr.length == 0) + { + return IntBox.EMPTY; + } + if (precalculated_bounding_box == null) + { + double llx = Integer.MAX_VALUE; + double lly = Integer.MAX_VALUE; + double urx = Integer.MIN_VALUE; + double ury = Integer.MIN_VALUE; + for (int i = 0; i < arr.length; ++i) + { + FloatPoint curr = corner_approx(i); + llx = Math.min(llx, curr.x); + lly = Math.min(lly, curr.y); + urx = Math.max(urx, curr.x); + ury = Math.max(ury, curr.y); + } + IntPoint lower_left = new IntPoint((int)Math.floor(llx),(int)Math.floor(lly)); + IntPoint upper_right = new IntPoint((int)Math.ceil(urx),(int)Math.ceil(ury)); + precalculated_bounding_box = new IntBox(lower_left, upper_right); + } + return precalculated_bounding_box; + } + + /** + * Calculates a bounding octagon of the Simplex. + * Returns null, if the Simplex is not bounded. + * + * @return a {@link geometry.planar.IntOctagon} object. + */ + public IntOctagon bounding_octagon() + { + if (precalculated_bounding_octagon == null) + { + double lx = Integer.MAX_VALUE; + double ly = Integer.MAX_VALUE; + double rx = Integer.MIN_VALUE; + double uy = Integer.MIN_VALUE; + double ulx = Integer.MAX_VALUE; + double lrx = Integer.MIN_VALUE; + double llx = Integer.MAX_VALUE; + double urx = Integer.MIN_VALUE; + for (int i = 0; i < arr.length; ++i) + { + FloatPoint curr = corner_approx(i); + lx = Math.min(lx, curr.x); + ly = Math.min(ly, curr.y); + rx = Math.max(rx, curr.x); + uy = Math.max(uy, curr.y); + + double tmp = curr.x - curr.y; + ulx = Math.min(ulx, tmp); + lrx = Math.max(lrx, tmp); + + tmp = curr.x + curr.y; + llx = Math.min(llx, tmp); + urx = Math.max(urx, tmp); + } + if (Math.min(lx, ly) < -Limits.CRIT_INT + || Math.max(rx, uy) > Limits.CRIT_INT + || Math.min(ulx, llx) < -Limits.CRIT_INT + || Math.max(lrx, urx) > Limits.CRIT_INT) + // result is not bounded + { + return null; + } + precalculated_bounding_octagon = new + IntOctagon((int)Math.floor(lx), (int)Math.floor(ly), + (int)Math.ceil(rx), (int)Math.ceil(uy), + (int)Math.floor(ulx), (int)Math.ceil(lrx), + (int)Math.floor(llx), (int)Math.ceil(urx)); + } + return precalculated_bounding_octagon; + } + + /** + *

bounding_tile.

+ * + * @return a {@link geometry.planar.Simplex} object. + */ + public Simplex bounding_tile() + { + return this; + } + + /** {@inheritDoc} */ + public RegularTileShape bounding_shape(ShapeBoundingDirections p_dirs) + { + return p_dirs.bounds(this); + } + + + /** + * {@inheritDoc} + * + * Returns the simplex offseted by p_with. + * {@code If p_width > 0, the offset is to the outer, else to the inner.} + */ + public Simplex offset(double p_width) + { + if (p_width == 0) + { + return this; + } + Line[] new_arr = new Line[arr.length]; + for (int i = 0; i < arr.length; ++i) + { + new_arr[i] = arr[i].translate(-p_width); + } + Simplex offset_simplex = new Simplex(new_arr); + if (p_width < 0) + { + offset_simplex = offset_simplex.remove_redundant_lines(); + } + return offset_simplex; + } + + /** + * {@inheritDoc} + * + * Returns this simplex enlarged by p_offset. + * The result simplex is intersected with the + * by p_offset enlarged bounding octagon of this simplex + */ + public Simplex enlarge(double p_offset) + { + if (p_offset == 0) + { + return this; + } + Simplex offset_simplex = offset(p_offset); + IntOctagon bounding_oct = this.bounding_octagon(); + if (bounding_oct == null) + { + return Simplex.EMPTY; + } + IntOctagon offset_oct = bounding_oct.offset(p_offset); + return offset_simplex.intersection(offset_oct.to_Simplex()); + } + + + + /** + * Returns the number of the rightmost corner seen from p_from_point + * No other point of this simplex may be to the right + * of the line from p_from_point to the result corner. + * + * @param p_from_point a {@link geometry.planar.Point} object. + * @return a int. + */ + public int index_of_right_most_corner( Point p_from_point) + { + Point pole = p_from_point; + Point right_most_corner = corner(0); + int result = 0; + for (int i = 1; i < arr.length; ++i) + { + Point curr_corner = corner(i); + if (curr_corner.side_of(pole, right_most_corner) == Side.ON_THE_RIGHT) + { + right_most_corner = curr_corner; + result = i; + } + } + return result; + } + + /** + * Returns the intersection of p_box with this simplex + * + * @param p_box a {@link geometry.planar.IntBox} object. + * @return a {@link geometry.planar.Simplex} object. + */ + public Simplex intersection(IntBox p_box) + { + return intersection(p_box.to_Simplex()); + } + + /** + * {@inheritDoc} + * + * Returns the intersection of this simplex and p_other + * + * @param p_other a {@link geometry.planar.Simplex} object. + * @return a {@link geometry.planar.Simplex} object. + */ + public Simplex intersection(Simplex p_other) + { + if (this.is_empty() || p_other.is_empty()) + { + return EMPTY; + } + Line[] new_arr = new Line[arr.length + p_other.arr.length]; + System.arraycopy(arr, 0, new_arr, 0, arr.length); + System.arraycopy(p_other.arr, 0, new_arr, arr.length, p_other.arr.length); + java.util.Arrays.sort(new_arr); + Simplex result = new Simplex( new_arr); + return result.remove_redundant_lines(); + } + + /** + * {@inheritDoc} + * + * Returns the intersection of this simplex and the shape p_other + */ + public TileShape intersection(TileShape p_other) + { + TileShape result = p_other.intersection(this); + return result; + } + + + /** + *

intersects.

+ * + * @param p_other a {@link geometry.planar.Shape} object. + * @return a boolean. + */ + public boolean intersects(Shape p_other) + { + return p_other.intersects(this); + } + + /** + *

intersects.

+ * + * @param p_other a {@link geometry.planar.Simplex} object. + * @return a boolean. + */ + public boolean intersects(Simplex p_other) + { + ConvexShape is = intersection(p_other); + return !is.is_empty(); + } + + /** + * {@inheritDoc} + * + * if p_line is a borderline of this simplex the number of that + * edge is returned, otherwise -1 + */ + public int border_line_index(Line p_line) + { + for (int i = 0; i < arr.length; ++i) + { + if (p_line.equals(arr[i])) + { + return i; + } + } + return -1; + } + + /** + * Enlarges the simplex by removing the edge line with index p_no. + * The result simplex may get unbounded. + * + * @param p_no a int. + * @return a {@link geometry.planar.Simplex} object. + */ + public Simplex remove_border_line( int p_no) + { + if (p_no < 0 || p_no >= arr.length) + { + return this; + } + Line [] new_arr = new Line [this.arr.length - 1]; + System.arraycopy(this.arr, 0, new_arr, 0, p_no); + System.arraycopy(this.arr, p_no + 1, new_arr, p_no, new_arr.length - p_no); + return new Simplex(new_arr); + } + + /** + * Constructs a Simplex from the directed lines in p_line_arr. + * The simplex will not be normalized. + * To get a normalised simplex use TileShape.get_instance + * + * @param p_line_arr an array of {@link geometry.planar.Line} objects. + */ + public Simplex(Line[] p_line_arr) + { + arr = p_line_arr; + } + + /** + *

to_Simplex.

+ * + * @return a {@link geometry.planar.Simplex} object. + */ + public Simplex to_Simplex() + { + return this; + } + + + Simplex intersection(IntOctagon p_other) + { + return intersection(p_other.to_Simplex()); + } + + /** + *

cutout.

+ * + * @param p_shape a {@link geometry.planar.TileShape} object. + * @return an array of {@link geometry.planar.TileShape} objects. + */ + public TileShape[] cutout(TileShape p_shape) + { + return p_shape.cutout_from(this); + } + + /** + * cuts this simplex out of p_outer_simplex. + * Divides the resulting shape into simplices along the minimal + * distance lines from the vertices of the inner simplex to the outer + * simplex; Returns the convex pieces constructed by this division. + * + * @param p_outer_simplex a {@link geometry.planar.Simplex} object. + * @return an array of {@link geometry.planar.Simplex} objects. + */ + public Simplex[] cutout_from(Simplex p_outer_simplex) + { + if(this.dimension() < 2) + { + System.out.println("Simplex.cutout_from only implemented for 2-dim simplex"); + return null; + } + Simplex inner_simplex = this.intersection(p_outer_simplex); + if (inner_simplex.dimension() < 2) + { + // nothing to cutout from p_outer_simplex + Simplex[] result = new Simplex[1]; + result[0] = p_outer_simplex; + return result; + } + int inner_corner_count = inner_simplex.arr.length; + Line [][] division_line_arr = new Line[inner_corner_count][]; + for (int inner_corner_no = 0; inner_corner_no < inner_corner_count; ++inner_corner_no) + { + division_line_arr[inner_corner_no] = + inner_simplex.calc_division_lines(inner_corner_no, p_outer_simplex); + if (division_line_arr[inner_corner_no] == null) + { + System.out.println("Simplex.cutout_from: division line is null"); + Simplex[] result = new Simplex[1]; + result[0] = p_outer_simplex; + return result; + } + } + boolean check_cross_first_line = false; + Line prev_division_line = null; + Line first_division_line = division_line_arr[0][0]; + IntDirection first_direction = (IntDirection)first_division_line.direction(); + Collection result_list = new LinkedList(); + + for (int inner_corner_no = 0; inner_corner_no < inner_corner_count; ++inner_corner_no) + { + Line next_division_line; + if (inner_corner_no == inner_simplex.arr.length - 1) + next_division_line = division_line_arr[0][0]; + else + next_division_line = division_line_arr[inner_corner_no + 1][0]; + Line[] curr_division_lines = division_line_arr[inner_corner_no]; + if (curr_division_lines.length == 2) + { + // 2 division lines are nessesary (sharp corner). + // Construct an unbounded simplex from + // curr_division_lines[1] and curr_division_lines[0] + // and intersect it with the outer simplex + IntDirection curr_dir = (IntDirection)curr_division_lines[0].direction(); + boolean merge_prev_division_line = false; + boolean merge_first_division_line = false; + if (prev_division_line != null) + { + IntDirection prev_dir = (IntDirection)prev_division_line.direction(); + if (curr_dir.determinant(prev_dir) > 0) + + { + // the previous division line may intersect + // curr_division_lines[0] inside p_divide_simplex + merge_prev_division_line = true; + } + } + if (!check_cross_first_line) + { + check_cross_first_line = (inner_corner_no > 0 && + curr_dir.determinant(first_direction) > 0); + } + if (check_cross_first_line) + { + IntDirection curr_dir2 = (IntDirection)curr_division_lines[1].direction(); + if (curr_dir2.determinant(first_direction) < 0) + { + // The current piece has an intersection area with the first + // piece. + // Add a line to tmp_polyline to prevent this + merge_first_division_line = true; + } + } + int piece_line_count = 2; + if (merge_prev_division_line) + ++piece_line_count; + if (merge_first_division_line) + ++piece_line_count; + Line[] piece_lines = new Line[piece_line_count]; + piece_lines[0] = new Line(curr_division_lines[1].b, curr_division_lines[1].a); + piece_lines[1] = curr_division_lines[0]; + int curr_line_no = 1; + if (merge_prev_division_line) + { + ++curr_line_no; + piece_lines[curr_line_no] = prev_division_line; + } + if (merge_first_division_line) + { + ++curr_line_no; + piece_lines[curr_line_no] = + new Line(first_division_line.b, first_division_line.a); + } + Simplex curr_piece = new Simplex(piece_lines); + result_list.add(curr_piece.intersection(p_outer_simplex)); + } + // construct an unbounded simplex from next_division_line, + // inner_simplex.line [inner_corner_no] and the last current division line + // and intersect it with the outer simplex + boolean merge_next_division_line = !next_division_line.b.equals(next_division_line.a); + Line last_curr_division_line = curr_division_lines[curr_division_lines.length - 1]; + IntDirection last_curr_dir = (IntDirection)last_curr_division_line.direction(); + boolean merge_last_curr_division_line = + !last_curr_division_line.b.equals(last_curr_division_line.a); + boolean merge_prev_division_line = false; + boolean merge_first_division_line = false; + if (prev_division_line != null) + { + IntDirection prev_dir = (IntDirection)prev_division_line.direction(); + if (last_curr_dir.determinant(prev_dir) > 0) + + { + // the previous division line may intersect + // the last current division line inside p_divide_simplex + merge_prev_division_line = true; + } + } + if (!check_cross_first_line) + { + check_cross_first_line = inner_corner_no > 0 && + last_curr_dir.determinant(first_direction) > 0 && + last_curr_dir.get_vector().scalar_product(first_direction.get_vector()) < 0; + // scalar_product checked to ignore backcrossing at + // small inner_corner_no + } + if (check_cross_first_line) + { + IntDirection next_dir = (IntDirection)next_division_line.direction(); + if(next_dir.determinant(first_direction) < 0) + { + // The current piece has an intersection area with the first piece. + // Add a line to tmp_polyline to prevent this + merge_first_division_line = true; + } + } + int piece_line_count = 1; + if (merge_next_division_line) + ++piece_line_count; + if (merge_last_curr_division_line) + ++piece_line_count; + if (merge_prev_division_line) + ++piece_line_count; + if (merge_first_division_line) + ++piece_line_count; + Line[] piece_lines = new Line[piece_line_count]; + Line curr_line = inner_simplex.arr[inner_corner_no]; + piece_lines[0] = new Line(curr_line.b, curr_line.a); + int curr_line_no = 0; + if (merge_next_division_line) + { + ++curr_line_no; + piece_lines[curr_line_no] = new Line(next_division_line.b, next_division_line.a); + } + if (merge_last_curr_division_line) + { + ++curr_line_no; + piece_lines[curr_line_no] = last_curr_division_line; + } + if (merge_prev_division_line) + { + ++curr_line_no; + piece_lines[curr_line_no] = prev_division_line; + } + if (merge_first_division_line) + { + ++curr_line_no; + piece_lines[curr_line_no] = + new Line(first_division_line.b, first_division_line.a); + } + Simplex curr_piece = new Simplex(piece_lines); + result_list.add(curr_piece.intersection(p_outer_simplex)); + next_division_line = prev_division_line; + } + Simplex[] result = new Simplex[result_list.size()]; + Iterator it = result_list.iterator(); + for (int i = 0; i < result.length; ++i) + { + result[i] = it.next(); + } + return result; + } + + Simplex[] cutout_from(IntOctagon p_oct) + { + return cutout_from(p_oct.to_Simplex()); + } + + Simplex[] cutout_from(IntBox p_box) + { + return cutout_from(p_box.to_Simplex()); + } + + /** + * Removes lines, which are redundant in the definition of the + * shape of this simplex. + * Assumes that the lines of this simplex are sorted. + */ + Simplex remove_redundant_lines() + { + Line [] line_arr = new Line [arr.length]; + // copy the sorted lines of arr into line_arr while skipping + // multiple lines + int new_length = 1; + line_arr[0] = arr[0]; + Line prev = line_arr[0]; + for (int i = 1; i < arr.length; ++i) + { + if (!arr[i].fast_equals(prev)) + { + line_arr[new_length] = arr[i]; + prev = line_arr[new_length]; + ++new_length; + } + } + + Side [] intersection_sides = new Side [new_length]; + // precalculated array , on which side of this line the previous and the + // next line do intersect + + boolean try_again = new_length > 2; + int index_of_last_removed_line = new_length; + while(try_again) + { + try_again = false; + int prev_ind = new_length - 1; + int next_ind; + Line prev_line = line_arr[prev_ind]; + Line curr_line = line_arr[0]; + Line next_line; + for (int ind = 0; ind < new_length; ++ind) + { + if (ind == new_length - 1) + { + next_ind = 0; + } + else + { + next_ind = ind + 1; + } + next_line = line_arr[next_ind]; + + boolean remove_line = false; + IntDirection prev_dir = (IntDirection) prev_line.direction(); + IntDirection next_dir = (IntDirection) next_line.direction(); + double det = prev_dir.determinant(next_dir); + if (det != 0) // prev_line and next_line are not parallel + { + if (intersection_sides [ind] == null) + { + // intersection_sides [ind] not precalculated + intersection_sides [ind] = curr_line.side_of_intersection(prev_line, next_line); + } + if(det > 0 ) + // direction of next_line is bigger than direction of prev_line + { + // if the intersection of prev_line and next_line + // is on the left of curr_line, curr_line does not + // contribute to the shape of the simplex + remove_line = (intersection_sides[ind] != Side.ON_THE_LEFT); + } + else + // direction of next_line is smaller than direction of prev_line + { + + if (intersection_sides[ind] == Side.ON_THE_LEFT) + { + IntDirection curr_dir = (IntDirection) curr_line.direction(); + if (prev_dir.determinant(curr_dir) > 0) + // direction of curr_line is bigger than direction of prev_line + { + // the halfplane defined by curr_line does not intersect + // with the simplex defined by prev_line and nex_line, + // hence this simplex must be empty + new_length = 0; + try_again = false; + break; + } + } + } + } + else // prev_line and next_line are parallel + { + if (prev_line.side_of(next_line.a) == Side.ON_THE_LEFT) + // prev_line is to the left of next_line, + // the halfplanes defined by prev_line and next_line + // do not intersect + { + new_length = 0; + try_again = false; + break; + } + } + if (remove_line) + { + try_again = true; + --new_length; + for (int i = ind; i < new_length; ++i) + { + line_arr [i] = line_arr [i + 1]; + intersection_sides[i] = intersection_sides [i + 1]; + } + + if (new_length < 3) + { + try_again = false; + break; + } + // reset 3 precalculated intersection_sides + if (ind == 0) + { + prev_ind = new_length - 1; + } + intersection_sides [prev_ind] = null; + if (ind >= new_length) + { + next_ind = 0; + } + else + { + next_ind = ind; + } + intersection_sides [next_ind] = null; + --ind; + index_of_last_removed_line = ind; + } + else + { + prev_line = curr_line; + prev_ind = ind; + } + curr_line = next_line; + if( !try_again && ind >= index_of_last_removed_line) + // tried all lines without removing one + { + break; + } + } + } + + if (new_length == 2) + { + if (line_arr[0].is_parallel(line_arr[1])) + { + if(line_arr[0].direction().equals(line_arr[1].direction())) + // one of the two remaining lines is redundant + { + if (line_arr[1].side_of(line_arr[0].a) == Side.ON_THE_LEFT) + { + line_arr[0] = line_arr[1]; + } + --new_length; + } + else + // the two remaining lines have opposite direction + // the simplex may be empty + { + if (line_arr[1].side_of(line_arr[0].a) == Side.ON_THE_LEFT) + { + new_length = 0; + } + } + } + } + if (new_length == arr.length) + { + return this; // nothing removed + } + if (new_length == 0) + { + return Simplex.EMPTY; + } + Line [] result = new Line [new_length]; + System.arraycopy(line_arr, 0, result, 0, new_length); + return new Simplex(result); + } + + /** + *

intersects.

+ * + * @param p_box a {@link geometry.planar.IntBox} object. + * @return a boolean. + */ + public boolean intersects(IntBox p_box) + { + return intersects(p_box.to_Simplex()); + } + + /** {@inheritDoc} */ + public boolean intersects(IntOctagon p_octagon) + { + return intersects(p_octagon.to_Simplex()); + } + + /** + *

intersects.

+ * + * @param p_circle a {@link geometry.planar.Circle} object. + * @return a boolean. + */ + public boolean intersects(Circle p_circle) + { + return p_circle.intersects(this); + } + + /** + * For each corner of this inner simplex 1 or 2 perpendicular + * projections onto lines of the outer simplex are constructed, + * so that the resulting pieces after cutting out the inner simplex + * are convex. 2 projections may be nessesary at sharp angle corners. + * Used in in the method cutout_from with parametertype Simplex. + */ + private Line[] calc_division_lines(int p_inner_corner_no, Simplex p_outer_simplex) + { + Line curr_inner_line = this.arr[p_inner_corner_no]; + Line prev_inner_line; + if (p_inner_corner_no != 0) + prev_inner_line = this.arr[p_inner_corner_no - 1]; + else + prev_inner_line = this.arr[arr.length - 1]; + FloatPoint intersection = curr_inner_line.intersection_approx(prev_inner_line); + if (intersection.x >= Integer.MAX_VALUE) + { + System.out.println("Simplex.calc_division_lines: intersection expexted"); + return null; + } + IntPoint inner_corner = intersection.round(); + double c_tolerance = 0.0001; + boolean is_exact = + Math.abs(inner_corner.x - intersection.x) < c_tolerance + && Math.abs(inner_corner.y - intersection.y) < c_tolerance; + + if (!is_exact) + { + // it is assumed, that the corners of the original inner simplex are + // exact and the not exact corners come from the intersection of + // the inner simplex with the outer simplex. + // Because these corners lie on the border of the outer simplex, + // no division is nessesary + Line [] result = new Line[1]; + result[0] = prev_inner_line; + return result; + } + IntDirection first_projection_dir = Direction.NULL; + IntDirection second_projection_dir = Direction.NULL; + IntDirection prev_inner_dir = (IntDirection) prev_inner_line.direction().opposite(); + IntDirection next_inner_dir = (IntDirection) curr_inner_line.direction(); + int outer_line_no = 0; + + + // search the first outer line, so that + // the perpendicular projection of the inner corner onto this + // line is visible from inner_corner to the left of prev_inner_line. + + double min_distance = Integer.MAX_VALUE; + + for (int ind = 0; ind < p_outer_simplex.arr.length; ++ind) + { + Line outer_line = p_outer_simplex.arr[outer_line_no]; + IntDirection curr_projection_dir = + (IntDirection)inner_corner.perpendicular_direction(outer_line); + if (curr_projection_dir == Direction.NULL) + { + Line [] result = new Line[1]; + result[0] = new Line(inner_corner, inner_corner); + return result; + } + boolean projection_visible = prev_inner_dir.determinant(curr_projection_dir) >= 0; + if (projection_visible) + { + double curr_distance = Math.abs(outer_line.signed_distance(inner_corner.to_float())); + boolean second_division_necessary = + curr_projection_dir.determinant(next_inner_dir) < 0; + // may occor at a sharp angle + IntDirection curr_second_projection_dir = curr_projection_dir; + + if (second_division_necessary) + { + // search the first projection_dir between curr_projection_dir + // and next_inner_dir, that is visible from next_inner_line + boolean second_projection_visible = false; + int tmp_outer_line_no = outer_line_no; + while (!second_projection_visible) + { + if (tmp_outer_line_no == p_outer_simplex.arr.length - 1) + { + tmp_outer_line_no = 0; + } + else + { + ++tmp_outer_line_no; + } + curr_second_projection_dir = + (IntDirection)inner_corner.perpendicular_direction( + p_outer_simplex.arr[tmp_outer_line_no]); + + if (curr_second_projection_dir == Direction.NULL) + // inner corner is on outer_line + { + Line [] result = new Line[1]; + result[0] = new Line(inner_corner, inner_corner); + return result; + } + if (curr_projection_dir.determinant(curr_second_projection_dir) < 0) + { + // curr_second_projection_dir not found; + // the angle between curr_projection_dir and + // curr_second_projection_dir would be already bigger + // than 180 degree + curr_distance = Integer.MAX_VALUE; + break; + } + + second_projection_visible = + curr_second_projection_dir.determinant(next_inner_dir) >= 0; + } + curr_distance += + Math.abs(p_outer_simplex.arr[tmp_outer_line_no].signed_distance(inner_corner.to_float())); + } + if (curr_distance < min_distance) + { + min_distance = curr_distance; + first_projection_dir = curr_projection_dir; + second_projection_dir = curr_second_projection_dir; + } + } + if (outer_line_no == p_outer_simplex.arr.length - 1) + { + outer_line_no = 0; + } + else + { + ++outer_line_no; + + } + } + if (min_distance == Integer.MAX_VALUE) + { + System.out.println("Simplex.calc_division_lines: division not found"); + return null; + } + Line[] result; + if (first_projection_dir.equals(second_projection_dir)) + { + result = new Line[1]; + result[0] = new Line(inner_corner, first_projection_dir); + } + else + { + result = new Line[2]; + result[0] = new Line(inner_corner, first_projection_dir); + result[1] = new Line(inner_corner, second_projection_dir); + } + return result; + } + + private final Line[] arr; + + /** + * the following fields are for storing precalculated data + */ + transient private Point[] precalculated_corners = null; + transient private FloatPoint[] precalculated_float_corners = null; + transient private IntBox precalculated_bounding_box = null; + transient private IntOctagon precalculated_bounding_octagon = null; + +} diff --git a/geometry/planar/TileShape.java b/src/main/java/geometry/planar/TileShape.java similarity index 90% rename from geometry/planar/TileShape.java rename to src/main/java/geometry/planar/TileShape.java index 4f25852..3779b65 100644 --- a/geometry/planar/TileShape.java +++ b/src/main/java/geometry/planar/TileShape.java @@ -1,1269 +1,1417 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - */ -package geometry.planar; - -import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedList; - -/** - * - * Abstract class defining functionality for convex shapes, whose - * borders consists of straight lines. - * - * @author Alfons Wirtz - */ -public abstract class TileShape extends PolylineShape implements ConvexShape, java.io.Serializable -{ - - /** - * creates a Simplex as intersection of the halfplanes defined - * by an array of directed lines - */ - public static TileShape get_instance(Line[] p_line_arr) - { - Simplex result = Simplex.get_instance(p_line_arr); - return result.simplify(); - } - - /** - * Creates a TileShape from a Point array, who forms the corners of the shape - * of a convex polygon. May work only for IntPoints. - */ - public static TileShape get_instance(Point[] p_convex_polygon) - { - Line[] line_arr = new Line[p_convex_polygon.length]; - for (int j = 0; j < line_arr.length - 1; ++j) - { - line_arr[j] = new Line(p_convex_polygon[j], p_convex_polygon[j + 1]); - } - line_arr[line_arr.length - 1] = - new Line(p_convex_polygon[line_arr.length - 1], p_convex_polygon[0]); - return get_instance(line_arr); - } - - /** - * creates a half_plane from a directed line - */ - public static TileShape get_instance(Line p_line) - { - Line[] lines = new Line[1]; - lines[0] = p_line; - return Simplex.get_instance(lines); - } - - /** - * Creates a normalized IntOctagon from the input values. - * For the meaning of the parameter shortcuts see class IntOctagon. - */ - public static IntOctagon get_instance(int p_lx, int p_ly, int p_rx, - int p_uy, int p_ulx, int p_lrx, - int p_llx, int p_urx) - { - IntOctagon oct = new IntOctagon(p_lx, p_ly, p_rx, p_uy, p_ulx, - p_lrx, p_llx, p_urx); - return oct.normalize(); - } - - /** - * creates a boxlike convex shape - */ - public static IntOctagon get_instance(int p_lower_left_x, - int p_lower_left_y, - int p_upper_right_x, - int p_upper_right_y) - { - IntBox box = new IntBox(p_lower_left_x, p_lower_left_y, - p_upper_right_x, p_upper_right_y); - return box.to_IntOctagon(); - } - - /** - * creates the smallest IntOctagon containing p_point - */ - public static IntBox get_instance(Point p_point) - { - return p_point.surrounding_box(); - } - - /** - * Tries to simplify the result shape to a simpler shape. - * Simplifying always in the intersection function may cause performance problems. - */ - public TileShape intersection_with_simplify(TileShape p_other) - { - TileShape result = this.intersection(p_other); - return result.simplify(); - } - - /** - * Converts the physical instance of this shape to a simpler physical instance, if possible. - */ - public abstract TileShape simplify(); - - /** - * checks if this TileShape is an IntBox or can be converted into an IntBox - */ - public abstract boolean is_IntBox(); - - /** - * checks if this TileShape is an IntOctagon or can be converted into an IntOctagon - */ - public abstract boolean is_IntOctagon(); - - /** - * Returns the intersection of this shape with p_other - */ - public abstract TileShape intersection(TileShape p_other); - - /** - * Returns the p_no-th edge line of this shape - * for p_no between 0 and edge_line_count() - 1. - * The edge lines are sorted in counterclock sense around - * the shape starting with the edge with the smallest direction. - */ - public abstract Line border_line(int p_no); - - /** - * if p_line is a borderline of this shape the number of that - * edge is returned, otherwise -1 - */ - public abstract int border_line_index(Line p_line); - - /** - * Converts the internal representation of this TieShape to a Simplex - */ - public abstract Simplex to_Simplex(); - - /** - * Returns the content of the area of the shape. - * If the shape is unbounded, Double.MAX_VALUE is returned. - */ - public double area() - { - if (!is_bounded()) - { - return Double.MAX_VALUE; - } - - if (dimension() < 2) - { - return 0; - } - // calculate half of the absolute value of - // x0 (y1 - yn-1) + x1 (y2 - y0) + x2 (y3 - y1) + ...+ xn-1( y0 - yn-2) - // where xi, yi are the coordinates of the i-th corner of this TileShape. - - double result = 0; - int corner_count = border_line_count(); - FloatPoint prev_corner = corner_approx(corner_count - 2); - FloatPoint curr_corner = corner_approx(corner_count - 1); - for (int i = 0; i < corner_count; ++i) - { - FloatPoint next_corner = corner_approx(i); - result += curr_corner.x * (next_corner.y - prev_corner.y); - prev_corner = curr_corner; - curr_corner = next_corner; - } - result = 0.5 * Math.abs(result); - return result; - } - - /** - * Returns true, if p_point is not contained in the inside or the - * edge of the shape - */ - public boolean is_outside(Point p_point) - { - int line_count = border_line_count(); - if (line_count == 0) - { - return true; - } - for (int i = 0; i < line_count; ++i) - { - if (border_line(i).side_of(p_point) == Side.ON_THE_LEFT) - { - return true; - } - } - return false; - } - - public boolean contains(Point p_point) - { - return !is_outside(p_point); - } - - /** - * Returns true, if p_point is contained in this shape, - * but not on an edge line - */ - public boolean contains_inside(Point p_point) - { - int line_count = border_line_count(); - if (line_count == 0) - { - return false; - } - for (int i = 0; i < line_count; ++i) - { - if (border_line(i).side_of(p_point) != Side.ON_THE_RIGHT) - { - return false; - } - } - return true; - } - - /** - * Returns true, if p_point is contained in this shape. - */ - public boolean contains(FloatPoint p_point) - { - return contains(p_point, 0); - } - - /** - * Returns true, if p_point is contained in this shape with tolerance p_tolerance. - * p_tolerance is used when determing, if a point is on the left side of a border line. - * It is used there in calculating a determinant and is not the distance of p_point to the border. - */ - public boolean contains(FloatPoint p_point, double p_tolerance) - { - int line_count = border_line_count(); - if (line_count == 0) - { - return false; - } - for (int i = 0; i < line_count; ++i) - { - if (border_line(i).side_of(p_point, p_tolerance) != Side.ON_THE_RIGHT) - { - return false; - } - } - return true; - } - - /** - * Returns Side.COLLINEAR if p_point is on the border of this shape with tolerance p_tolerence. - * p_tolerance is used when determing, if a point is on the right side of a border line. - * It is used there in calculating a determinant and is not the distance of p_point to the border. - * Otherwise the function returns Side.ON_THE_LEFT if p_point is outside of this shape, - * and Side.ON_THE_RIGTH if p_point is inside this shape. - */ - public Side side_of_border(FloatPoint p_point, double p_tolerance) - { - int line_count = border_line_count(); - if (line_count == 0) - { - return Side.COLLINEAR; - } - Side result = Side.ON_THE_RIGHT; // point is inside - for (int i = 0; i < line_count; ++i) - { - Side curr_side = border_line(i).side_of(p_point, p_tolerance); - if (curr_side == Side.ON_THE_LEFT) - { - return Side.ON_THE_LEFT; // point is outside - } - else if (curr_side == Side.COLLINEAR) - { - result = curr_side; - } - - } - return result; - } - - /** - * If p_point lies on the border of this shape, the number of the - * edge line segment containing p_point is returned, - * otherwise -1 is returned. - */ - public int contains_on_border_line_no(Point p_point) - { - int line_count = border_line_count(); - if (line_count == 0) - { - return -1; - } - int containing_line_no = -1; - for (int i = 0; i < line_count; ++i) - { - Side side_of = border_line(i).side_of(p_point); - if (side_of == Side.ON_THE_LEFT) - { - // p_point outside the convex shape - return -1; - } - if (side_of == Side.COLLINEAR) - { - containing_line_no = i; - } - } - return containing_line_no; - } - - /** - * Returns true, if p_point lies exact on the boundary of the shape - */ - public boolean contains_on_border(Point p_point) - { - return (contains_on_border_line_no(p_point) >= 0); - } - - /** - * Returns true, if this shape contains p_other completely. - * THere may be some numerical inaccurracy. - */ - public boolean contains_approx(TileShape p_other) - { - FloatPoint[] corners = p_other.corner_approx_arr(); - for (FloatPoint curr_corner : corners) - { - if (!this.contains(curr_corner)) - { - return false; - } - } - return true; - } - - /** - * Returns true, if this shape contains p_other completely. - */ - public boolean contains(TileShape p_other) - { - for (int i = 0; i < p_other.border_line_count(); ++i) - { - if (!this.contains(p_other.corner(i))) - { - return false; - } - } - return true; - } - - /** - * Returns the distance between p_point and its nearest point - * on the shape. 0, if p_point is contained in this shape - */ - public double distance(FloatPoint p_point) - { - FloatPoint nearest_point = nearest_point_approx(p_point); - return nearest_point.distance(p_point); - } - - /** - * Returns the distance between p_point and its nearest point - * on the edge of the shape. - */ - public double border_distance(FloatPoint p_point) - { - FloatPoint nearest_point = nearest_border_point_approx(p_point); - return nearest_point.distance(p_point); - } - - public double smallest_radius() - { - return border_distance(centre_of_gravity()); - } - - /** - * Returns the point in this shape, which has the smallest - * distance to p_from_point. p_from_point, if that point - * is contained in this shape - */ - public Point nearest_point(Point p_from_point) - { - if (!is_outside(p_from_point)) - { - return p_from_point; - } - return nearest_border_point(p_from_point); - } - - public FloatPoint nearest_point_approx(FloatPoint p_from_point) - { - if (this.contains(p_from_point)) - { - return p_from_point; - } - return nearest_border_point_approx(p_from_point); - } - - /** - * Returns a nearest point to p_from_point on the edge of the shape - */ - public Point nearest_border_point(Point p_from_point) - { - int line_count = border_line_count(); - if (line_count == 0) - { - return null; - } - FloatPoint from_point_f = p_from_point.to_float(); - if (line_count == 1) - { - return border_line(0).perpendicular_projection(p_from_point); - } - Point nearest_point = null; - double min_dist = Double.MAX_VALUE; - int min_dist_ind = 0; - - // calculate the distance to the nearest corner first - for (int i = 0; i < line_count; ++i) - { - FloatPoint curr_corner_f = corner_approx(i); - double curr_dist = curr_corner_f.distance_square(from_point_f); - if (curr_dist < min_dist) - { - min_dist = curr_dist; - min_dist_ind = i; - } - } - - nearest_point = corner(min_dist_ind); - - int prev_ind = line_count - 2; - int curr_ind = line_count - 1; - - for (int next_ind = 0; next_ind < line_count; ++next_ind) - { - Point projection = - border_line(curr_ind).perpendicular_projection(p_from_point); - if ((!corner_is_bounded(curr_ind) || border_line(prev_ind).side_of(projection) == Side.ON_THE_RIGHT) && (!corner_is_bounded(next_ind) || border_line(next_ind).side_of(projection) == Side.ON_THE_RIGHT)) - { - FloatPoint projection_f = projection.to_float(); - double curr_dist = projection_f.distance_square(from_point_f); - if (curr_dist < min_dist) - { - min_dist = curr_dist; - nearest_point = projection; - } - } - prev_ind = curr_ind; - curr_ind = next_ind; - } - return nearest_point; - } - - /** - * Returns an approximation of the nearest point - * to p_from_point on the border of the this shape - */ - public FloatPoint nearest_border_point_approx(FloatPoint p_from_point) - { - FloatPoint[] nearest_points = nearest_border_points_approx(p_from_point, 1); - if (nearest_points.length <= 0) - { - return null; - } - return nearest_points[0]; - } - - /** - * Returns an approximation of the p_count nearest points - * to p_from_point on the border of the this shape. - * The result points must be located on different border lines and are - * sorted in ascending order (the nearest point comes first). - */ - public FloatPoint[] nearest_border_points_approx(FloatPoint p_from_point, int p_count) - { - if (p_count <= 0) - { - return new FloatPoint[0]; - } - int line_count = border_line_count(); - int result_count = Math.min(p_count, line_count); - if (line_count == 0) - { - return new FloatPoint[0]; - } - if (line_count == 1) - { - FloatPoint[] result = new FloatPoint[1]; - result[0] = p_from_point.projection_approx(border_line(0)); - return result; - } - if (this.dimension() == 0) - { - FloatPoint[] result = new FloatPoint[1]; - result[0] = corner_approx(0); - return result; - } - FloatPoint[] nearest_points = new FloatPoint[result_count]; - double[] min_dists = new double[result_count]; - for (int i = 0; i < result_count; ++i) - { - min_dists[i] = Double.MAX_VALUE; - } - - // calculate the distances to the nearest corners first - for (int i = 0; i < line_count; ++i) - { - if (corner_is_bounded(i)) - { - FloatPoint curr_corner = corner_approx(i); - double curr_dist = curr_corner.distance_square(p_from_point); - for (int j = 0; j < result_count; ++j) - { - if (curr_dist < min_dists[j]) - { - for (int k = j + 1; k < result_count; ++k) - { - min_dists[k] = min_dists[k - 1]; - nearest_points[k] = nearest_points[k - 1]; - } - min_dists[j] = curr_dist; - nearest_points[j] = curr_corner; - break; - } - } - } - } - - int prev_ind = line_count - 2; - int curr_ind = line_count - 1; - - for (int next_ind = 0; next_ind < line_count; ++next_ind) - { - FloatPoint projection = p_from_point.projection_approx(border_line(curr_ind)); - if ((!corner_is_bounded(curr_ind) || border_line(prev_ind).side_of(projection) == Side.ON_THE_RIGHT) && (!corner_is_bounded(next_ind) || border_line(next_ind).side_of(projection) == Side.ON_THE_RIGHT)) - { - double curr_dist = projection.distance_square(p_from_point); - for (int j = 0; j < result_count; ++j) - { - if (curr_dist < min_dists[j]) - { - for (int k = j + 1; k < result_count; ++k) - { - min_dists[k] = min_dists[k - 1]; - nearest_points[k] = nearest_points[k - 1]; - } - min_dists[j] = curr_dist; - nearest_points[j] = projection; - break; - } - } - } - prev_ind = curr_ind; - curr_ind = next_ind; - } - return nearest_points; - } - - /** - * Returns the number of a nearest corner of the shape - * to p_from_point - */ - public int index_of_nearest_corner(Point p_from_point) - { - FloatPoint from_point_f = p_from_point.to_float(); - int result = 0; - int corner_count = border_line_count(); - double min_dist = Double.MIN_VALUE; - for (int i = 0; i < corner_count; ++i) - { - double curr_dist = corner_approx(i).distance(from_point_f); - if (curr_dist < min_dist) - { - min_dist = curr_dist; - result = i; - } - } - return result; - } - - /** - * Returns a line segment consisting of an approximations of the corners with - * index 0 and corner_count / 2. - */ - public FloatLine diagonal_corner_segment() - { - if (this.is_empty()) - { - return null; - } - FloatPoint first_corner = this.corner_approx(0); - FloatPoint last_corner = this.corner_approx(this.border_line_count() / 2); - return new FloatLine(first_corner, last_corner); - } - - /** - * Returns an approximation of the p_count nearest relative outside locations - * of p_shape in the direction of different border lines of this shape. - * These relative locations are sorted in ascending order (the shortest comes first). - */ - public FloatPoint[] nearest_relative_outside_locations(TileShape p_shape, int p_count) - { - int line_count = border_line_count(); - if (p_count <= 0 || line_count < 3 || !this.intersects(p_shape)) - { - return new FloatPoint[0]; - } - - int result_count = Math.min(p_count, line_count); - - FloatPoint[] translate_coors = new FloatPoint[result_count]; - double[] min_dists = new double[result_count]; - for (int i = 0; i < result_count; ++i) - { - min_dists[i] = Double.MAX_VALUE; - } - - int curr_ind = line_count - 1; - - int other_line_count = p_shape.border_line_count(); - - for (int next_ind = 0; next_ind < line_count; ++next_ind) - { - double curr_max_dist = 0; - FloatPoint curr_translate_coor = FloatPoint.ZERO; - for (int corner_no = 0; corner_no < other_line_count; ++corner_no) - { - FloatPoint curr_corner = p_shape.corner_approx(corner_no); - if (border_line(curr_ind).side_of(curr_corner) == Side.ON_THE_RIGHT) - { - FloatPoint projection = curr_corner.projection_approx(border_line(curr_ind)); - double curr_dist = projection.distance_square(curr_corner); - if (curr_dist > curr_max_dist) - { - curr_max_dist = curr_dist; - curr_translate_coor = projection.substract(curr_corner); - } - } - } - - for (int j = 0; j < result_count; ++j) - { - if (curr_max_dist < min_dists[j]) - { - for (int k = j + 1; k < result_count; ++k) - { - min_dists[k] = min_dists[k - 1]; - translate_coors[k] = translate_coors[k - 1]; - } - min_dists[j] = curr_max_dist; - translate_coors[j] = curr_translate_coor; - break; - } - } - curr_ind = next_ind; - } - return translate_coors; - } - - public ConvexShape shrink(double p_offset) - { - ConvexShape result = this.offset(-p_offset); - if (result.is_empty()) - { - IntBox centre_box = this.centre_of_gravity().bounding_box(); - result = this.intersection(centre_box); - } - return result; - } - - /** - * Returns the maximum of the edge widths of the shape. - * Only defined when the shape is bounded. - */ - public double length() - { - if (!this.is_bounded()) - { - return Integer.MAX_VALUE; - } - int dimension = this.dimension(); - if (dimension <= 0) - { - return 0; - } - if (dimension == 1) - { - return this.circumference() / 2; - } - // now the shape is 2-dimensional - double max_distance = -1; - double max_distance_2 = -1; - FloatPoint gravity_point = this.centre_of_gravity(); - for (int i = 0; i < border_line_count(); ++i) - { - double curr_distance = Math.abs(border_line(i).signed_distance(gravity_point)); - if (curr_distance > max_distance) - { - max_distance_2 = max_distance; - max_distance = curr_distance; - } - else if (curr_distance > max_distance_2) - { - max_distance_2 = curr_distance; - } - } - return max_distance + max_distance_2; - } - - /** - * Calculates, if this Shape and p_other habe a common border piece and returns - * an 2 dimensional array with the indices in this shape and p_other of the - * touching edge lines in this case. - * Otherwise an array of dimension 0 is returned. - * Used if the intersection shape is 1-dimensional. - */ - public int[] touching_sides(TileShape p_other) - { - // search the first edge line of p_other with reverse direction >= right - - int side_no_2 = -1; - Direction dir2 = null; - for (int i = 0; i < p_other.border_line_count(); ++i) - { - Direction curr_dir = p_other.border_line(i).direction(); - if (curr_dir.compareTo(Direction.LEFT) >= 0) - { - side_no_2 = i; - dir2 = curr_dir.opposite(); - break; - } - } - if (dir2 == null) - { - System.out.println("touching_side : dir2 not found"); - return new int[0]; - } - int side_no_1 = 0; - Direction dir1 = this.border_line(0).direction(); - final int max_ind = this.border_line_count() + p_other.border_line_count(); - - for (int i = 0; i < max_ind; ++i) - { - int compare = dir2.compareTo(dir1); - if (compare == 0) - { - if (this.border_line(side_no_1).is_equal_or_opposite(p_other.border_line(side_no_2))) - { - int[] result = new int[2]; - result[0] = side_no_1; - result[1] = side_no_2; - return result; - } - } - if (compare >= 0) // dir2 is bigger than dir1 - { - side_no_1 = (side_no_1 + 1) % this.border_line_count(); - dir1 = this.border_line(side_no_1).direction(); - } - else //dir1 is bigger than dir2 - { - side_no_2 = (side_no_2 + 1) % p_other.border_line_count(); - dir2 = p_other.border_line(side_no_2).direction().opposite(); - } - } - return new int[0]; - } - - /** - * Calculates the minimal distance of p_line to this shape, - * assuming, that p_line is on the left of this shape. - * Returns -1, if p_line is on the right of this shape or intersects - * with the interiour of this shape. - */ - public double distance_to_the_left(Line p_line) - { - double result = Integer.MAX_VALUE; - for (int i = 0; i < this.border_line_count(); ++i) - { - FloatPoint curr_corner = this.corner_approx(i); - Side line_side = p_line.side_of(curr_corner, 1); - if (line_side == Side.COLLINEAR) - { - line_side = p_line.side_of(this.corner(i)); - } - if (line_side == Side.ON_THE_RIGHT) - { - // curr_point would be outside the result shape - result = -1; - break; - } - result = Math.min(result, p_line.signed_distance(curr_corner)); - } - return result; - } - - /** - * Returns Side.COLLINEAR, if p_line intersects with the interiour of this shape, - * Side.ON_THE_LEFT, if this shape is completely on the left of p_line - * or Side.ON_THE_RIGHT, if this shape is completely on the right of p_line. - */ - public Side side_of(Line p_line) - { - boolean on_the_left = false; - boolean on_the_right = false; - for (int i = 0; i < this.border_line_count(); ++i) - { - Side curr_side = p_line.side_of(this.corner(i)); - if (curr_side == Side.ON_THE_LEFT) - { - on_the_right = true; - } - else if (curr_side == Side.ON_THE_RIGHT) - { - on_the_left = true; - } - if (on_the_left && on_the_right) - { - return Side.COLLINEAR; - } - } - Side result; - if (on_the_left) - { - result = Side.ON_THE_LEFT; - } - else - { - result = Side.ON_THE_RIGHT; - } - return result; - } - - public TileShape turn_90_degree(int p_factor, IntPoint p_pole) - { - Line[] new_lines = new Line[border_line_count()]; - for (int i = 0; i < new_lines.length; ++i) - { - new_lines[i] = this.border_line(i).turn_90_degree(p_factor, p_pole); - } - return get_instance(new_lines); - } - - public TileShape rotate_approx(double p_angle, FloatPoint p_pole) - { - if (p_angle == 0) - { - return this; - } - IntPoint[] new_corners = new IntPoint[border_line_count()]; - for (int i = 0; i < new_corners.length; ++i) - { - - new_corners[i] = this.corner_approx(i).rotate(p_angle, p_pole).round(); - } - Polygon corner_polygon = new Polygon(new_corners); - Point[] polygon_corners = corner_polygon.corner_array(); - TileShape result; - if (polygon_corners.length >= 3) - { - result = get_instance(polygon_corners); - } - else if (polygon_corners.length == 2) - { - Polyline curr_polyline = new Polyline(polygon_corners); - LineSegment curr_segment = new LineSegment(curr_polyline, 0); - result = curr_segment.to_simplex(); - } - else if (polygon_corners.length == 1) - { - result = get_instance(polygon_corners[0]); - } - else - { - result = Simplex.EMPTY; - } - return result; - } - - public TileShape mirror_vertical(IntPoint p_pole) - { - Line[] new_lines = new Line[border_line_count()]; - for (int i = 0; i < new_lines.length; ++i) - { - new_lines[i] = this.border_line(i).mirror_vertical(p_pole); - } - return get_instance(new_lines); - } - - public TileShape mirror_horizontal(IntPoint p_pole) - { - Line[] new_lines = new Line[border_line_count()]; - for (int i = 0; i < new_lines.length; ++i) - { - new_lines[i] = this.border_line(i).mirror_horizontal(p_pole); - } - return get_instance(new_lines); - } - - /** - * Calculates the border line of this shape intersecting the ray from p_from_point into the direction p_direction. - * p_from_point is assumed to be inside this shape, otherwise -1 is returned. - */ - public int intersecting_border_line_no(Point p_from_point, Direction p_direction) - { - if (!this.contains(p_from_point)) - { - return -1; - } - FloatPoint from_point = p_from_point.to_float(); - Line intersection_line = new Line(p_from_point, p_direction); - FloatPoint second_line_point = intersection_line.b.to_float(); - int result = -1; - double min_distance = Float.MAX_VALUE; - for (int i = 0; i < this.border_line_count(); ++i) - { - Line curr_border_line = this.border_line(i); - FloatPoint curr_intersection = curr_border_line.intersection_approx(intersection_line); - if (curr_intersection.x >= Integer.MAX_VALUE) - { - continue; // lines are parallel - } - double curr_distence = curr_intersection.distance_square(from_point); - if (curr_distence < min_distance) - { - boolean direction_ok = curr_border_line.side_of(second_line_point) == Side.ON_THE_LEFT || second_line_point.distance_square(curr_intersection) < curr_distence; - if (direction_ok) - { - result = i; - min_distance = curr_distence; - } - } - } - return result; - } - - /** - * Cuts p_shape out of this shape and divides the result into convex pieces - */ - public abstract TileShape[] cutout(TileShape p_shape); - - /** - * Returns an arry of tuples of integers. The length of the array is - * the number of points, where p_polyline enters or leaves the interiour - * of this shape. The first coordinate of the tuple is the number of - * the line segment of p_polyline, which enters the simplex and the - * second coordinate of the tuple is the number of the edge_line of the - * simplex, which is crossed there. - * That means that the entrance point is the intersection of this 2 lines. - */ - public int[][] entrance_points(Polyline p_polyline) - { - int[][] result = new int[2 * p_polyline.arr.length][2]; - int intersection_count = 0; - int prev_intersection_line_no = -1; - int prev_intersection_edge_no = -1; - for (int line_no = 1; line_no < p_polyline.arr.length - 1; ++line_no) - { - LineSegment curr_line_seg = new LineSegment(p_polyline, line_no); - int[] curr_intersections = curr_line_seg.border_intersections(this); - for (int i = 0; i < curr_intersections.length; ++i) - { - int edge_no = curr_intersections[i]; - if (line_no != prev_intersection_line_no || - edge_no != prev_intersection_edge_no) - { - result[intersection_count][0] = line_no; - result[intersection_count][1] = edge_no; - ++intersection_count; - prev_intersection_line_no = line_no; - prev_intersection_edge_no = edge_no; - } - } - } - int[][] normalized_result = new int[intersection_count][2]; - for (int j = 0; j < intersection_count; ++j) - { - for (int i = 0; i < 2; ++i) - { - normalized_result[j][i] = result[j][i]; - } - } - return normalized_result; - } - - /** - * Cuts out the parts of p_polyline in the interiour of this shape - * and returns a list of the remaining pieces of p_polyline. - * Pieces completely contained in the border of this shape - * are not returned. - */ - public Polyline[] cutout(Polyline p_polyline) - { - int[][] intersection_no = this.entrance_points(p_polyline); - Point first_corner = p_polyline.first_corner(); - boolean first_corner_is_inside = this.contains_inside(first_corner); - if (intersection_no.length == 0) - // no intersections - { - if (first_corner_is_inside) - // p_polyline is contained completely in this shape - { - return new Polyline[0]; - } - // p_polyline is completely outside - Polyline[] result = new Polyline[1]; - result[0] = p_polyline; - return result; - } - Collection pieces = new LinkedList(); - int curr_intersection_no = 0; - int[] curr_intersection_tuple = intersection_no[curr_intersection_no]; - Point first_intersection = - p_polyline.arr[curr_intersection_tuple[0]].intersection(this.border_line(curr_intersection_tuple[1])); - if (!first_corner_is_inside) - // calculate outside piece at start - { - if (!first_corner.equals(first_intersection)) - // otherwise skip 1 point outside polyline at the start - { - int curr_polyline_intersection_no = curr_intersection_tuple[0]; - Line[] curr_lines = new Line[curr_polyline_intersection_no + 2]; - System.arraycopy(p_polyline.arr, 0, curr_lines, 0, curr_polyline_intersection_no + 1); - // close the polyline piece with the intersected edge line. - curr_lines[curr_polyline_intersection_no + 1] = this.border_line(curr_intersection_tuple[1]); - Polyline curr_piece = new Polyline(curr_lines); - if (!curr_piece.is_empty()) - { - pieces.add(curr_piece); - } - } - ++curr_intersection_no; - } - while (curr_intersection_no < intersection_no.length - 1) - // calculate the next outside polyline piece - { - curr_intersection_tuple = intersection_no[curr_intersection_no]; - int[] next_intersection_tuple = intersection_no[curr_intersection_no + 1]; - int curr_intersection_no_of_polyline = curr_intersection_tuple[0]; - int next_intersection_no_of_polyline = next_intersection_tuple[0]; - // check that at least 1 corner of p_polyline with number between - // between curr_intersection_no_of_polyline and - // next_intersection_no_of_polyline - // is not contained in this shape. Otherwise the part of p_polyline - // between this intersections is completely contained in the border - // and can be ignored - boolean insert_piece = false; - for (int i = curr_intersection_no_of_polyline + 1; - i < next_intersection_no_of_polyline; ++i) - { - if (this.is_outside(p_polyline.corner(i))) - { - insert_piece = true; - break; - } - } - - if (insert_piece) - { - Line[] curr_lines = new Line[next_intersection_no_of_polyline - curr_intersection_no_of_polyline + 3]; - curr_lines[0] = this.border_line(curr_intersection_tuple[1]); - System.arraycopy(p_polyline.arr, curr_intersection_no_of_polyline, curr_lines, - 1, curr_lines.length - 2); - curr_lines[curr_lines.length - 1] = this.border_line(next_intersection_tuple[1]); - Polyline curr_piece = new Polyline(curr_lines); - if (!curr_piece.is_empty()) - { - pieces.add(curr_piece); - } - } - curr_intersection_no += 2; - } - if (curr_intersection_no <= intersection_no.length - 1) - // calculate outside piece at end - { - curr_intersection_tuple = intersection_no[curr_intersection_no]; - int curr_polyline_intersection_no = curr_intersection_tuple[0]; - Line[] curr_lines = new Line[p_polyline.arr.length - curr_polyline_intersection_no + 1]; - curr_lines[0] = this.border_line(curr_intersection_tuple[1]); - System.arraycopy(p_polyline.arr, curr_polyline_intersection_no, curr_lines, - 1, curr_lines.length - 1); - Polyline curr_piece = new Polyline(curr_lines); - if (!curr_piece.is_empty()) - { - pieces.add(curr_piece); - } - } - Polyline[] result = new Polyline[pieces.size()]; - Iterator it = pieces.iterator(); - for (int i = 0; i < result.length; ++i) - { - result[i] = it.next(); - } - return result; - } - - public TileShape[] split_to_convex() - { - TileShape[] result = new TileShape[1]; - result[0] = this; - return result; - } - - /** - * Divides this shape into sections with width and height at most p_max_section_width - * of about equal size. - */ - public TileShape[] divide_into_sections(double p_max_section_width) - { - if (this.is_empty()) - { - TileShape[] result = new TileShape[1]; - result[0] = this; - return result; - } - TileShape[] section_boxes = this.bounding_box().divide_into_sections(p_max_section_width); - Collection section_list = new LinkedList(); - for (int i = 0; i < section_boxes.length; ++i) - { - TileShape curr_section = this.intersection_with_simplify(section_boxes[i]); - if (curr_section.dimension() == 2) - { - section_list.add(curr_section); - } - } - TileShape[] result = new TileShape[section_list.size()]; - Iterator it = section_list.iterator(); - for (int i = 0; i < result.length; ++i) - { - result[i] = it.next(); - } - return result; - } - - /** - * Checks, if p_line_segment has a common point with the interiour of this shape. - */ - public boolean is_intersected_interiour_by(LineSegment p_line_segment) - { - FloatPoint float_start_point = p_line_segment.start_point_approx(); - FloatPoint float_end_point = p_line_segment.end_point_approx(); - - Side[] border_line_side_of_start_point_arr = new Side[this.border_line_count()]; - Side[] border_line_side_of_end_point_arr = new Side[border_line_side_of_start_point_arr.length]; - for (int i = 0; i < border_line_side_of_start_point_arr.length; ++i) - { - Line curr_border_line = this.border_line(i); - Side border_line_side_of_start_point = curr_border_line.side_of(float_start_point, 1); - if (border_line_side_of_start_point == Side.COLLINEAR) - { - border_line_side_of_start_point = curr_border_line.side_of(p_line_segment.start_point()); - } - Side border_line_side_of_end_point = curr_border_line.side_of(float_end_point, 1); - if (border_line_side_of_end_point == Side.COLLINEAR) - { - border_line_side_of_end_point = curr_border_line.side_of(p_line_segment.end_point()); - } - if (border_line_side_of_start_point != Side.ON_THE_RIGHT && border_line_side_of_end_point != Side.ON_THE_RIGHT) - { - // both endpoints are outside the border_line, - // no intersection possible - return false; - } - border_line_side_of_start_point_arr[i] = border_line_side_of_start_point; - border_line_side_of_end_point_arr[i] = border_line_side_of_end_point; - } - boolean start_point_is_inside = true; - for (int i = 0; i < border_line_side_of_start_point_arr.length; ++i) - { - if (border_line_side_of_start_point_arr[i] != Side.ON_THE_RIGHT) - { - start_point_is_inside = false; - break; - } - } - if (start_point_is_inside) - { - return true; - } - boolean end_point_is_inside = true; - for (int i = 0; i < border_line_side_of_end_point_arr.length; ++i) - { - if (border_line_side_of_end_point_arr[i] != Side.ON_THE_RIGHT) - { - end_point_is_inside = false; - break; - } - } - if (end_point_is_inside) - { - return true; - } - Line segment_line = p_line_segment.get_line(); - // Check, if this line segments intersect a border line of p_shape. - for (int i = 0; i < border_line_side_of_start_point_arr.length; ++i) - { - Side border_line_side_of_start_point = border_line_side_of_start_point_arr[i]; - Side border_line_side_of_end_point = border_line_side_of_end_point_arr[i]; - if (border_line_side_of_start_point != border_line_side_of_end_point) - { - if (border_line_side_of_start_point == Side.COLLINEAR && border_line_side_of_end_point == Side.ON_THE_LEFT || border_line_side_of_end_point == Side.COLLINEAR && border_line_side_of_start_point == Side.ON_THE_LEFT) - { - // the interiour of p_shape is not intersected. - continue; - } - Side prev_corner_side = segment_line.side_of(this.corner_approx(i), 1); - if (prev_corner_side == Side.COLLINEAR) - { - prev_corner_side = segment_line.side_of(this.corner(i)); - } - int next_corner_index; - if (i == border_line_side_of_start_point_arr.length - 1) - { - next_corner_index = 0; - } - else - { - next_corner_index = i + 1; - } - Side next_corner_side = segment_line.side_of(this.corner_approx(next_corner_index), 1); - if (next_corner_side == Side.COLLINEAR) - { - next_corner_side = segment_line.side_of(this.corner(next_corner_index)); - } - if (prev_corner_side == Side.ON_THE_LEFT && next_corner_side == Side.ON_THE_RIGHT || prev_corner_side == Side.ON_THE_RIGHT && next_corner_side == Side.ON_THE_LEFT) - { - // this line segment crosses a border line of p_shape - return true; - } - } - } - return false; - } - - // auxiliary functions needed because the virtual function mechanism does - // not work in parameter position - abstract TileShape intersection(Simplex p_other); - - abstract TileShape intersection(IntOctagon p_other); - - abstract TileShape intersection(IntBox p_other); - - /** - * Auxiliary function to implement the public function cutout(TileShape p_shape) - */ - abstract TileShape[] cutout_from(IntBox p_shape); - - /** - * Auxiliary function to implement the public function cutout(TileShape p_shape) - */ - abstract TileShape[] cutout_from(IntOctagon p_shape); - - /** - * Auxiliary function to implement the public function cutout(TileShape p_shape) - */ - abstract TileShape[] cutout_from(Simplex p_shape); -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + */ +package geometry.planar; + +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; + +/** + * + * Abstract class defining functionality for convex shapes, whose + * borders consists of straight lines. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public abstract class TileShape extends PolylineShape implements ConvexShape, java.io.Serializable +{ + + /** + * creates a Simplex as intersection of the halfplanes defined + * by an array of directed lines + * + * @param p_line_arr an array of {@link geometry.planar.Line} objects. + * @return a {@link geometry.planar.TileShape} object. + */ + public static TileShape get_instance(Line[] p_line_arr) + { + Simplex result = Simplex.get_instance(p_line_arr); + return result.simplify(); + } + + /** + * Creates a TileShape from a Point array, who forms the corners of the shape + * of a convex polygon. May work only for IntPoints. + * + * @param p_convex_polygon an array of {@link geometry.planar.Point} objects. + * @return a {@link geometry.planar.TileShape} object. + */ + public static TileShape get_instance(Point[] p_convex_polygon) + { + Line[] line_arr = new Line[p_convex_polygon.length]; + for (int j = 0; j < line_arr.length - 1; ++j) + { + line_arr[j] = new Line(p_convex_polygon[j], p_convex_polygon[j + 1]); + } + line_arr[line_arr.length - 1] = + new Line(p_convex_polygon[line_arr.length - 1], p_convex_polygon[0]); + return get_instance(line_arr); + } + + /** + * creates a half_plane from a directed line + * + * @param p_line a {@link geometry.planar.Line} object. + * @return a {@link geometry.planar.TileShape} object. + */ + public static TileShape get_instance(Line p_line) + { + Line[] lines = new Line[1]; + lines[0] = p_line; + return Simplex.get_instance(lines); + } + + /** + * Creates a normalized IntOctagon from the input values. + * For the meaning of the parameter shortcuts see class IntOctagon. + * + * @param p_lx a int. + * @param p_ly a int. + * @param p_rx a int. + * @param p_uy a int. + * @param p_ulx a int. + * @param p_lrx a int. + * @param p_llx a int. + * @param p_urx a int. + * @return a {@link geometry.planar.IntOctagon} object. + */ + public static IntOctagon get_instance(int p_lx, int p_ly, int p_rx, + int p_uy, int p_ulx, int p_lrx, + int p_llx, int p_urx) + { + IntOctagon oct = new IntOctagon(p_lx, p_ly, p_rx, p_uy, p_ulx, + p_lrx, p_llx, p_urx); + return oct.normalize(); + } + + /** + * creates a boxlike convex shape + * + * @param p_lower_left_x a int. + * @param p_lower_left_y a int. + * @param p_upper_right_x a int. + * @param p_upper_right_y a int. + * @return a {@link geometry.planar.IntOctagon} object. + */ + public static IntOctagon get_instance(int p_lower_left_x, + int p_lower_left_y, + int p_upper_right_x, + int p_upper_right_y) + { + IntBox box = new IntBox(p_lower_left_x, p_lower_left_y, + p_upper_right_x, p_upper_right_y); + return box.to_IntOctagon(); + } + + /** + * creates the smallest IntOctagon containing p_point + * + * @param p_point a {@link geometry.planar.Point} object. + * @return a {@link geometry.planar.IntBox} object. + */ + public static IntBox get_instance(Point p_point) + { + return p_point.surrounding_box(); + } + + /** + * Tries to simplify the result shape to a simpler shape. + * Simplifying always in the intersection function may cause performance problems. + * + * @param p_other a {@link geometry.planar.TileShape} object. + * @return a {@link geometry.planar.TileShape} object. + */ + public TileShape intersection_with_simplify(TileShape p_other) + { + TileShape result = this.intersection(p_other); + return result.simplify(); + } + + /** + * Converts the physical instance of this shape to a simpler physical instance, if possible. + * + * @return a {@link geometry.planar.TileShape} object. + */ + public abstract TileShape simplify(); + + /** + * checks if this TileShape is an IntBox or can be converted into an IntBox + * + * @return a boolean. + */ + public abstract boolean is_IntBox(); + + /** + * checks if this TileShape is an IntOctagon or can be converted into an IntOctagon + * + * @return a boolean. + */ + public abstract boolean is_IntOctagon(); + + /** + * Returns the intersection of this shape with p_other + * + * @param p_other a {@link geometry.planar.TileShape} object. + * @return a {@link geometry.planar.TileShape} object. + */ + public abstract TileShape intersection(TileShape p_other); + + /** + * {@inheritDoc} + * + * Returns the p_no-th edge line of this shape + * for p_no between 0 and edge_line_count() - 1. + * The edge lines are sorted in counterclock sense around + * the shape starting with the edge with the smallest direction. + */ + public abstract Line border_line(int p_no); + + /** + * if p_line is a borderline of this shape the number of that + * edge is returned, otherwise -1 + * + * @param p_line a {@link geometry.planar.Line} object. + * @return a int. + */ + public abstract int border_line_index(Line p_line); + + /** + * Converts the internal representation of this TieShape to a Simplex + * + * @return a {@link geometry.planar.Simplex} object. + */ + public abstract Simplex to_Simplex(); + + /** + * Returns the content of the area of the shape. + * If the shape is unbounded, Double.MAX_VALUE is returned. + * + * @return a double. + */ + public double area() + { + if (!is_bounded()) + { + return Double.MAX_VALUE; + } + + if (dimension() < 2) + { + return 0; + } + // calculate half of the absolute value of + // x0 (y1 - yn-1) + x1 (y2 - y0) + x2 (y3 - y1) + ...+ xn-1( y0 - yn-2) + // where xi, yi are the coordinates of the i-th corner of this TileShape. + + double result = 0; + int corner_count = border_line_count(); + FloatPoint prev_corner = corner_approx(corner_count - 2); + FloatPoint curr_corner = corner_approx(corner_count - 1); + for (int i = 0; i < corner_count; ++i) + { + FloatPoint next_corner = corner_approx(i); + result += curr_corner.x * (next_corner.y - prev_corner.y); + prev_corner = curr_corner; + curr_corner = next_corner; + } + result = 0.5 * Math.abs(result); + return result; + } + + /** + * {@inheritDoc} + * + * Returns true, if p_point is not contained in the inside or the + * edge of the shape + */ + public boolean is_outside(Point p_point) + { + int line_count = border_line_count(); + if (line_count == 0) + { + return true; + } + for (int i = 0; i < line_count; ++i) + { + if (border_line(i).side_of(p_point) == Side.ON_THE_LEFT) + { + return true; + } + } + return false; + } + + /** {@inheritDoc} */ + public boolean contains(Point p_point) + { + return !is_outside(p_point); + } + + /** + * {@inheritDoc} + * + * Returns true, if p_point is contained in this shape, + * but not on an edge line + */ + public boolean contains_inside(Point p_point) + { + int line_count = border_line_count(); + if (line_count == 0) + { + return false; + } + for (int i = 0; i < line_count; ++i) + { + if (border_line(i).side_of(p_point) != Side.ON_THE_RIGHT) + { + return false; + } + } + return true; + } + + /** + * Returns true, if p_point is contained in this shape. + * + * @param p_point a {@link geometry.planar.FloatPoint} object. + * @return a boolean. + */ + public boolean contains(FloatPoint p_point) + { + return contains(p_point, 0); + } + + /** + * Returns true, if p_point is contained in this shape with tolerance p_tolerance. + * p_tolerance is used when determing, if a point is on the left side of a border line. + * It is used there in calculating a determinant and is not the distance of p_point to the border. + * + * @param p_point a {@link geometry.planar.FloatPoint} object. + * @param p_tolerance a double. + * @return a boolean. + */ + public boolean contains(FloatPoint p_point, double p_tolerance) + { + int line_count = border_line_count(); + if (line_count == 0) + { + return false; + } + for (int i = 0; i < line_count; ++i) + { + if (border_line(i).side_of(p_point, p_tolerance) != Side.ON_THE_RIGHT) + { + return false; + } + } + return true; + } + + /** + * Returns Side.COLLINEAR if p_point is on the border of this shape with tolerance p_tolerence. + * p_tolerance is used when determing, if a point is on the right side of a border line. + * It is used there in calculating a determinant and is not the distance of p_point to the border. + * Otherwise the function returns Side.ON_THE_LEFT if p_point is outside of this shape, + * and Side.ON_THE_RIGTH if p_point is inside this shape. + * + * @param p_point a {@link geometry.planar.FloatPoint} object. + * @param p_tolerance a double. + * @return a {@link geometry.planar.Side} object. + */ + public Side side_of_border(FloatPoint p_point, double p_tolerance) + { + int line_count = border_line_count(); + if (line_count == 0) + { + return Side.COLLINEAR; + } + Side result = Side.ON_THE_RIGHT; // point is inside + for (int i = 0; i < line_count; ++i) + { + Side curr_side = border_line(i).side_of(p_point, p_tolerance); + if (curr_side == Side.ON_THE_LEFT) + { + return Side.ON_THE_LEFT; // point is outside + } + else if (curr_side == Side.COLLINEAR) + { + result = curr_side; + } + + } + return result; + } + + /** + * If p_point lies on the border of this shape, the number of the + * edge line segment containing p_point is returned, + * otherwise -1 is returned. + * + * @param p_point a {@link geometry.planar.Point} object. + * @return a int. + */ + public int contains_on_border_line_no(Point p_point) + { + int line_count = border_line_count(); + if (line_count == 0) + { + return -1; + } + int containing_line_no = -1; + for (int i = 0; i < line_count; ++i) + { + Side side_of = border_line(i).side_of(p_point); + if (side_of == Side.ON_THE_LEFT) + { + // p_point outside the convex shape + return -1; + } + if (side_of == Side.COLLINEAR) + { + containing_line_no = i; + } + } + return containing_line_no; + } + + /** + * {@inheritDoc} + * + * Returns true, if p_point lies exact on the boundary of the shape + */ + public boolean contains_on_border(Point p_point) + { + return (contains_on_border_line_no(p_point) >= 0); + } + + /** + * Returns true, if this shape contains p_other completely. + * THere may be some numerical inaccurracy. + * + * @param p_other a {@link geometry.planar.TileShape} object. + * @return a boolean. + */ + public boolean contains_approx(TileShape p_other) + { + FloatPoint[] corners = p_other.corner_approx_arr(); + for (FloatPoint curr_corner : corners) + { + if (!this.contains(curr_corner)) + { + return false; + } + } + return true; + } + + /** + * Returns true, if this shape contains p_other completely. + * + * @param p_other a {@link geometry.planar.TileShape} object. + * @return a boolean. + */ + public boolean contains(TileShape p_other) + { + for (int i = 0; i < p_other.border_line_count(); ++i) + { + if (!this.contains(p_other.corner(i))) + { + return false; + } + } + return true; + } + + /** + * {@inheritDoc} + * + * Returns the distance between p_point and its nearest point + * on the shape. 0, if p_point is contained in this shape + */ + public double distance(FloatPoint p_point) + { + FloatPoint nearest_point = nearest_point_approx(p_point); + return nearest_point.distance(p_point); + } + + /** + * {@inheritDoc} + * + * Returns the distance between p_point and its nearest point + * on the edge of the shape. + */ + public double border_distance(FloatPoint p_point) + { + FloatPoint nearest_point = nearest_border_point_approx(p_point); + return nearest_point.distance(p_point); + } + + /** + *

smallest_radius.

+ * + * @return a double. + */ + public double smallest_radius() + { + return border_distance(centre_of_gravity()); + } + + /** + * Returns the point in this shape, which has the smallest + * distance to p_from_point. p_from_point, if that point + * is contained in this shape + * + * @param p_from_point a {@link geometry.planar.Point} object. + * @return a {@link geometry.planar.Point} object. + */ + public Point nearest_point(Point p_from_point) + { + if (!is_outside(p_from_point)) + { + return p_from_point; + } + return nearest_border_point(p_from_point); + } + + /** {@inheritDoc} */ + public FloatPoint nearest_point_approx(FloatPoint p_from_point) + { + if (this.contains(p_from_point)) + { + return p_from_point; + } + return nearest_border_point_approx(p_from_point); + } + + /** + * Returns a nearest point to p_from_point on the edge of the shape + * + * @param p_from_point a {@link geometry.planar.Point} object. + * @return a {@link geometry.planar.Point} object. + */ + public Point nearest_border_point(Point p_from_point) + { + int line_count = border_line_count(); + if (line_count == 0) + { + return null; + } + FloatPoint from_point_f = p_from_point.to_float(); + if (line_count == 1) + { + return border_line(0).perpendicular_projection(p_from_point); + } + Point nearest_point = null; + double min_dist = Double.MAX_VALUE; + int min_dist_ind = 0; + + // calculate the distance to the nearest corner first + for (int i = 0; i < line_count; ++i) + { + FloatPoint curr_corner_f = corner_approx(i); + double curr_dist = curr_corner_f.distance_square(from_point_f); + if (curr_dist < min_dist) + { + min_dist = curr_dist; + min_dist_ind = i; + } + } + + nearest_point = corner(min_dist_ind); + + int prev_ind = line_count - 2; + int curr_ind = line_count - 1; + + for (int next_ind = 0; next_ind < line_count; ++next_ind) + { + Point projection = + border_line(curr_ind).perpendicular_projection(p_from_point); + if ((!corner_is_bounded(curr_ind) || border_line(prev_ind).side_of(projection) == Side.ON_THE_RIGHT) && (!corner_is_bounded(next_ind) || border_line(next_ind).side_of(projection) == Side.ON_THE_RIGHT)) + { + FloatPoint projection_f = projection.to_float(); + double curr_dist = projection_f.distance_square(from_point_f); + if (curr_dist < min_dist) + { + min_dist = curr_dist; + nearest_point = projection; + } + } + prev_ind = curr_ind; + curr_ind = next_ind; + } + return nearest_point; + } + + /** + * Returns an approximation of the nearest point + * to p_from_point on the border of the this shape + * + * @param p_from_point a {@link geometry.planar.FloatPoint} object. + * @return a {@link geometry.planar.FloatPoint} object. + */ + public FloatPoint nearest_border_point_approx(FloatPoint p_from_point) + { + FloatPoint[] nearest_points = nearest_border_points_approx(p_from_point, 1); + if (nearest_points.length <= 0) + { + return null; + } + return nearest_points[0]; + } + + /** + * Returns an approximation of the p_count nearest points + * to p_from_point on the border of the this shape. + * The result points must be located on different border lines and are + * sorted in ascending order (the nearest point comes first). + * + * @param p_from_point a {@link geometry.planar.FloatPoint} object. + * @param p_count a int. + * @return an array of {@link geometry.planar.FloatPoint} objects. + */ + public FloatPoint[] nearest_border_points_approx(FloatPoint p_from_point, int p_count) + { + if (p_count <= 0) + { + return new FloatPoint[0]; + } + int line_count = border_line_count(); + int result_count = Math.min(p_count, line_count); + if (line_count == 0) + { + return new FloatPoint[0]; + } + if (line_count == 1) + { + FloatPoint[] result = new FloatPoint[1]; + result[0] = p_from_point.projection_approx(border_line(0)); + return result; + } + if (this.dimension() == 0) + { + FloatPoint[] result = new FloatPoint[1]; + result[0] = corner_approx(0); + return result; + } + FloatPoint[] nearest_points = new FloatPoint[result_count]; + double[] min_dists = new double[result_count]; + for (int i = 0; i < result_count; ++i) + { + min_dists[i] = Double.MAX_VALUE; + } + + // calculate the distances to the nearest corners first + for (int i = 0; i < line_count; ++i) + { + if (corner_is_bounded(i)) + { + FloatPoint curr_corner = corner_approx(i); + double curr_dist = curr_corner.distance_square(p_from_point); + for (int j = 0; j < result_count; ++j) + { + if (curr_dist < min_dists[j]) + { + for (int k = j + 1; k < result_count; ++k) + { + min_dists[k] = min_dists[k - 1]; + nearest_points[k] = nearest_points[k - 1]; + } + min_dists[j] = curr_dist; + nearest_points[j] = curr_corner; + break; + } + } + } + } + + int prev_ind = line_count - 2; + int curr_ind = line_count - 1; + + for (int next_ind = 0; next_ind < line_count; ++next_ind) + { + FloatPoint projection = p_from_point.projection_approx(border_line(curr_ind)); + if ((!corner_is_bounded(curr_ind) || border_line(prev_ind).side_of(projection) == Side.ON_THE_RIGHT) && (!corner_is_bounded(next_ind) || border_line(next_ind).side_of(projection) == Side.ON_THE_RIGHT)) + { + double curr_dist = projection.distance_square(p_from_point); + for (int j = 0; j < result_count; ++j) + { + if (curr_dist < min_dists[j]) + { + for (int k = j + 1; k < result_count; ++k) + { + min_dists[k] = min_dists[k - 1]; + nearest_points[k] = nearest_points[k - 1]; + } + min_dists[j] = curr_dist; + nearest_points[j] = projection; + break; + } + } + } + prev_ind = curr_ind; + curr_ind = next_ind; + } + return nearest_points; + } + + /** + * Returns the number of a nearest corner of the shape + * to p_from_point + * + * @param p_from_point a {@link geometry.planar.Point} object. + * @return a int. + */ + public int index_of_nearest_corner(Point p_from_point) + { + FloatPoint from_point_f = p_from_point.to_float(); + int result = 0; + int corner_count = border_line_count(); + double min_dist = Double.MIN_VALUE; + for (int i = 0; i < corner_count; ++i) + { + double curr_dist = corner_approx(i).distance(from_point_f); + if (curr_dist < min_dist) + { + min_dist = curr_dist; + result = i; + } + } + return result; + } + + /** + * Returns a line segment consisting of an approximations of the corners with + * index 0 and corner_count / 2. + * + * @return a {@link geometry.planar.FloatLine} object. + */ + public FloatLine diagonal_corner_segment() + { + if (this.is_empty()) + { + return null; + } + FloatPoint first_corner = this.corner_approx(0); + FloatPoint last_corner = this.corner_approx(this.border_line_count() / 2); + return new FloatLine(first_corner, last_corner); + } + + /** + * Returns an approximation of the p_count nearest relative outside locations + * of p_shape in the direction of different border lines of this shape. + * These relative locations are sorted in ascending order (the shortest comes first). + * + * @param p_shape a {@link geometry.planar.TileShape} object. + * @param p_count a int. + * @return an array of {@link geometry.planar.FloatPoint} objects. + */ + public FloatPoint[] nearest_relative_outside_locations(TileShape p_shape, int p_count) + { + int line_count = border_line_count(); + if (p_count <= 0 || line_count < 3 || !this.intersects(p_shape)) + { + return new FloatPoint[0]; + } + + int result_count = Math.min(p_count, line_count); + + FloatPoint[] translate_coors = new FloatPoint[result_count]; + double[] min_dists = new double[result_count]; + for (int i = 0; i < result_count; ++i) + { + min_dists[i] = Double.MAX_VALUE; + } + + int curr_ind = line_count - 1; + + int other_line_count = p_shape.border_line_count(); + + for (int next_ind = 0; next_ind < line_count; ++next_ind) + { + double curr_max_dist = 0; + FloatPoint curr_translate_coor = FloatPoint.ZERO; + for (int corner_no = 0; corner_no < other_line_count; ++corner_no) + { + FloatPoint curr_corner = p_shape.corner_approx(corner_no); + if (border_line(curr_ind).side_of(curr_corner) == Side.ON_THE_RIGHT) + { + FloatPoint projection = curr_corner.projection_approx(border_line(curr_ind)); + double curr_dist = projection.distance_square(curr_corner); + if (curr_dist > curr_max_dist) + { + curr_max_dist = curr_dist; + curr_translate_coor = projection.substract(curr_corner); + } + } + } + + for (int j = 0; j < result_count; ++j) + { + if (curr_max_dist < min_dists[j]) + { + for (int k = j + 1; k < result_count; ++k) + { + min_dists[k] = min_dists[k - 1]; + translate_coors[k] = translate_coors[k - 1]; + } + min_dists[j] = curr_max_dist; + translate_coors[j] = curr_translate_coor; + break; + } + } + curr_ind = next_ind; + } + return translate_coors; + } + + /** {@inheritDoc} */ + public ConvexShape shrink(double p_offset) + { + ConvexShape result = this.offset(-p_offset); + if (result.is_empty()) + { + IntBox centre_box = this.centre_of_gravity().bounding_box(); + result = this.intersection(centre_box); + } + return result; + } + + /** + * Returns the maximum of the edge widths of the shape. + * Only defined when the shape is bounded. + * + * @return a double. + */ + public double length() + { + if (!this.is_bounded()) + { + return Integer.MAX_VALUE; + } + int dimension = this.dimension(); + if (dimension <= 0) + { + return 0; + } + if (dimension == 1) + { + return this.circumference() / 2; + } + // now the shape is 2-dimensional + double max_distance = -1; + double max_distance_2 = -1; + FloatPoint gravity_point = this.centre_of_gravity(); + for (int i = 0; i < border_line_count(); ++i) + { + double curr_distance = Math.abs(border_line(i).signed_distance(gravity_point)); + if (curr_distance > max_distance) + { + max_distance_2 = max_distance; + max_distance = curr_distance; + } + else if (curr_distance > max_distance_2) + { + max_distance_2 = curr_distance; + } + } + return max_distance + max_distance_2; + } + + /** + * Calculates, if this Shape and p_other habe a common border piece and returns + * an 2 dimensional array with the indices in this shape and p_other of the + * touching edge lines in this case. + * Otherwise an array of dimension 0 is returned. + * Used if the intersection shape is 1-dimensional. + * + * @param p_other a {@link geometry.planar.TileShape} object. + * @return an array of int. + */ + public int[] touching_sides(TileShape p_other) + { + // search the first edge line of p_other with reverse direction >= right + + int side_no_2 = -1; + Direction dir2 = null; + for (int i = 0; i < p_other.border_line_count(); ++i) + { + Direction curr_dir = p_other.border_line(i).direction(); + if (curr_dir.compareTo(Direction.LEFT) >= 0) + { + side_no_2 = i; + dir2 = curr_dir.opposite(); + break; + } + } + if (dir2 == null) + { + System.out.println("touching_side : dir2 not found"); + return new int[0]; + } + int side_no_1 = 0; + Direction dir1 = this.border_line(0).direction(); + final int max_ind = this.border_line_count() + p_other.border_line_count(); + + for (int i = 0; i < max_ind; ++i) + { + int compare = dir2.compareTo(dir1); + if (compare == 0) + { + if (this.border_line(side_no_1).is_equal_or_opposite(p_other.border_line(side_no_2))) + { + int[] result = new int[2]; + result[0] = side_no_1; + result[1] = side_no_2; + return result; + } + } + if (compare >= 0) // dir2 is bigger than dir1 + { + side_no_1 = (side_no_1 + 1) % this.border_line_count(); + dir1 = this.border_line(side_no_1).direction(); + } + else //dir1 is bigger than dir2 + { + side_no_2 = (side_no_2 + 1) % p_other.border_line_count(); + dir2 = p_other.border_line(side_no_2).direction().opposite(); + } + } + return new int[0]; + } + + /** + * Calculates the minimal distance of p_line to this shape, + * assuming, that p_line is on the left of this shape. + * Returns -1, if p_line is on the right of this shape or intersects + * with the interiour of this shape. + * + * @param p_line a {@link geometry.planar.Line} object. + * @return a double. + */ + public double distance_to_the_left(Line p_line) + { + double result = Integer.MAX_VALUE; + for (int i = 0; i < this.border_line_count(); ++i) + { + FloatPoint curr_corner = this.corner_approx(i); + Side line_side = p_line.side_of(curr_corner, 1); + if (line_side == Side.COLLINEAR) + { + line_side = p_line.side_of(this.corner(i)); + } + if (line_side == Side.ON_THE_RIGHT) + { + // curr_point would be outside the result shape + result = -1; + break; + } + result = Math.min(result, p_line.signed_distance(curr_corner)); + } + return result; + } + + /** + * Returns Side.COLLINEAR, if p_line intersects with the interiour of this shape, + * Side.ON_THE_LEFT, if this shape is completely on the left of p_line + * or Side.ON_THE_RIGHT, if this shape is completely on the right of p_line. + * + * @param p_line a {@link geometry.planar.Line} object. + * @return a {@link geometry.planar.Side} object. + */ + public Side side_of(Line p_line) + { + boolean on_the_left = false; + boolean on_the_right = false; + for (int i = 0; i < this.border_line_count(); ++i) + { + Side curr_side = p_line.side_of(this.corner(i)); + if (curr_side == Side.ON_THE_LEFT) + { + on_the_right = true; + } + else if (curr_side == Side.ON_THE_RIGHT) + { + on_the_left = true; + } + if (on_the_left && on_the_right) + { + return Side.COLLINEAR; + } + } + Side result; + if (on_the_left) + { + result = Side.ON_THE_LEFT; + } + else + { + result = Side.ON_THE_RIGHT; + } + return result; + } + + /** {@inheritDoc} */ + public TileShape turn_90_degree(int p_factor, IntPoint p_pole) + { + Line[] new_lines = new Line[border_line_count()]; + for (int i = 0; i < new_lines.length; ++i) + { + new_lines[i] = this.border_line(i).turn_90_degree(p_factor, p_pole); + } + return get_instance(new_lines); + } + + /** {@inheritDoc} */ + public TileShape rotate_approx(double p_angle, FloatPoint p_pole) + { + if (p_angle == 0) + { + return this; + } + IntPoint[] new_corners = new IntPoint[border_line_count()]; + for (int i = 0; i < new_corners.length; ++i) + { + + new_corners[i] = this.corner_approx(i).rotate(p_angle, p_pole).round(); + } + Polygon corner_polygon = new Polygon(new_corners); + Point[] polygon_corners = corner_polygon.corner_array(); + TileShape result; + if (polygon_corners.length >= 3) + { + result = get_instance(polygon_corners); + } + else if (polygon_corners.length == 2) + { + Polyline curr_polyline = new Polyline(polygon_corners); + LineSegment curr_segment = new LineSegment(curr_polyline, 0); + result = curr_segment.to_simplex(); + } + else if (polygon_corners.length == 1) + { + result = get_instance(polygon_corners[0]); + } + else + { + result = Simplex.EMPTY; + } + return result; + } + + /** {@inheritDoc} */ + public TileShape mirror_vertical(IntPoint p_pole) + { + Line[] new_lines = new Line[border_line_count()]; + for (int i = 0; i < new_lines.length; ++i) + { + new_lines[i] = this.border_line(i).mirror_vertical(p_pole); + } + return get_instance(new_lines); + } + + /** {@inheritDoc} */ + public TileShape mirror_horizontal(IntPoint p_pole) + { + Line[] new_lines = new Line[border_line_count()]; + for (int i = 0; i < new_lines.length; ++i) + { + new_lines[i] = this.border_line(i).mirror_horizontal(p_pole); + } + return get_instance(new_lines); + } + + /** + * Calculates the border line of this shape intersecting the ray from p_from_point into the direction p_direction. + * p_from_point is assumed to be inside this shape, otherwise -1 is returned. + * + * @param p_from_point a {@link geometry.planar.Point} object. + * @param p_direction a {@link geometry.planar.Direction} object. + * @return a int. + */ + public int intersecting_border_line_no(Point p_from_point, Direction p_direction) + { + if (!this.contains(p_from_point)) + { + return -1; + } + FloatPoint from_point = p_from_point.to_float(); + Line intersection_line = new Line(p_from_point, p_direction); + FloatPoint second_line_point = intersection_line.b.to_float(); + int result = -1; + double min_distance = Float.MAX_VALUE; + for (int i = 0; i < this.border_line_count(); ++i) + { + Line curr_border_line = this.border_line(i); + FloatPoint curr_intersection = curr_border_line.intersection_approx(intersection_line); + if (curr_intersection.x >= Integer.MAX_VALUE) + { + continue; // lines are parallel + } + double curr_distence = curr_intersection.distance_square(from_point); + if (curr_distence < min_distance) + { + boolean direction_ok = curr_border_line.side_of(second_line_point) == Side.ON_THE_LEFT || second_line_point.distance_square(curr_intersection) < curr_distence; + if (direction_ok) + { + result = i; + min_distance = curr_distence; + } + } + } + return result; + } + + /** + * Cuts p_shape out of this shape and divides the result into convex pieces + * + * @param p_shape a {@link geometry.planar.TileShape} object. + * @return an array of {@link geometry.planar.TileShape} objects. + */ + public abstract TileShape[] cutout(TileShape p_shape); + + /** + * Returns an arry of tuples of integers. The length of the array is + * the number of points, where p_polyline enters or leaves the interiour + * of this shape. The first coordinate of the tuple is the number of + * the line segment of p_polyline, which enters the simplex and the + * second coordinate of the tuple is the number of the edge_line of the + * simplex, which is crossed there. + * That means that the entrance point is the intersection of this 2 lines. + * + * @param p_polyline a {@link geometry.planar.Polyline} object. + * @return an array of int. + */ + public int[][] entrance_points(Polyline p_polyline) + { + int[][] result = new int[2 * p_polyline.arr.length][2]; + int intersection_count = 0; + int prev_intersection_line_no = -1; + int prev_intersection_edge_no = -1; + for (int line_no = 1; line_no < p_polyline.arr.length - 1; ++line_no) + { + LineSegment curr_line_seg = new LineSegment(p_polyline, line_no); + int[] curr_intersections = curr_line_seg.border_intersections(this); + for (int i = 0; i < curr_intersections.length; ++i) + { + int edge_no = curr_intersections[i]; + if (line_no != prev_intersection_line_no || + edge_no != prev_intersection_edge_no) + { + result[intersection_count][0] = line_no; + result[intersection_count][1] = edge_no; + ++intersection_count; + prev_intersection_line_no = line_no; + prev_intersection_edge_no = edge_no; + } + } + } + int[][] normalized_result = new int[intersection_count][2]; + for (int j = 0; j < intersection_count; ++j) + { + for (int i = 0; i < 2; ++i) + { + normalized_result[j][i] = result[j][i]; + } + } + return normalized_result; + } + + /** + * {@inheritDoc} + * + * Cuts out the parts of p_polyline in the interiour of this shape + * and returns a list of the remaining pieces of p_polyline. + * Pieces completely contained in the border of this shape + * are not returned. + */ + public Polyline[] cutout(Polyline p_polyline) + { + int[][] intersection_no = this.entrance_points(p_polyline); + Point first_corner = p_polyline.first_corner(); + boolean first_corner_is_inside = this.contains_inside(first_corner); + if (intersection_no.length == 0) + // no intersections + { + if (first_corner_is_inside) + // p_polyline is contained completely in this shape + { + return new Polyline[0]; + } + // p_polyline is completely outside + Polyline[] result = new Polyline[1]; + result[0] = p_polyline; + return result; + } + Collection pieces = new LinkedList(); + int curr_intersection_no = 0; + int[] curr_intersection_tuple = intersection_no[curr_intersection_no]; + Point first_intersection = + p_polyline.arr[curr_intersection_tuple[0]].intersection(this.border_line(curr_intersection_tuple[1])); + if (!first_corner_is_inside) + // calculate outside piece at start + { + if (!first_corner.equals(first_intersection)) + // otherwise skip 1 point outside polyline at the start + { + int curr_polyline_intersection_no = curr_intersection_tuple[0]; + Line[] curr_lines = new Line[curr_polyline_intersection_no + 2]; + System.arraycopy(p_polyline.arr, 0, curr_lines, 0, curr_polyline_intersection_no + 1); + // close the polyline piece with the intersected edge line. + curr_lines[curr_polyline_intersection_no + 1] = this.border_line(curr_intersection_tuple[1]); + Polyline curr_piece = new Polyline(curr_lines); + if (!curr_piece.is_empty()) + { + pieces.add(curr_piece); + } + } + ++curr_intersection_no; + } + while (curr_intersection_no < intersection_no.length - 1) + // calculate the next outside polyline piece + { + curr_intersection_tuple = intersection_no[curr_intersection_no]; + int[] next_intersection_tuple = intersection_no[curr_intersection_no + 1]; + int curr_intersection_no_of_polyline = curr_intersection_tuple[0]; + int next_intersection_no_of_polyline = next_intersection_tuple[0]; + // check that at least 1 corner of p_polyline with number between + // between curr_intersection_no_of_polyline and + // next_intersection_no_of_polyline + // is not contained in this shape. Otherwise the part of p_polyline + // between this intersections is completely contained in the border + // and can be ignored + boolean insert_piece = false; + for (int i = curr_intersection_no_of_polyline + 1; + i < next_intersection_no_of_polyline; ++i) + { + if (this.is_outside(p_polyline.corner(i))) + { + insert_piece = true; + break; + } + } + + if (insert_piece) + { + Line[] curr_lines = new Line[next_intersection_no_of_polyline - curr_intersection_no_of_polyline + 3]; + curr_lines[0] = this.border_line(curr_intersection_tuple[1]); + System.arraycopy(p_polyline.arr, curr_intersection_no_of_polyline, curr_lines, + 1, curr_lines.length - 2); + curr_lines[curr_lines.length - 1] = this.border_line(next_intersection_tuple[1]); + Polyline curr_piece = new Polyline(curr_lines); + if (!curr_piece.is_empty()) + { + pieces.add(curr_piece); + } + } + curr_intersection_no += 2; + } + if (curr_intersection_no <= intersection_no.length - 1) + // calculate outside piece at end + { + curr_intersection_tuple = intersection_no[curr_intersection_no]; + int curr_polyline_intersection_no = curr_intersection_tuple[0]; + Line[] curr_lines = new Line[p_polyline.arr.length - curr_polyline_intersection_no + 1]; + curr_lines[0] = this.border_line(curr_intersection_tuple[1]); + System.arraycopy(p_polyline.arr, curr_polyline_intersection_no, curr_lines, + 1, curr_lines.length - 1); + Polyline curr_piece = new Polyline(curr_lines); + if (!curr_piece.is_empty()) + { + pieces.add(curr_piece); + } + } + Polyline[] result = new Polyline[pieces.size()]; + Iterator it = pieces.iterator(); + for (int i = 0; i < result.length; ++i) + { + result[i] = it.next(); + } + return result; + } + + /** + *

split_to_convex.

+ * + * @return an array of {@link geometry.planar.TileShape} objects. + */ + public TileShape[] split_to_convex() + { + TileShape[] result = new TileShape[1]; + result[0] = this; + return result; + } + + /** + * Divides this shape into sections with width and height at most p_max_section_width + * of about equal size. + * + * @param p_max_section_width a double. + * @return an array of {@link geometry.planar.TileShape} objects. + */ + public TileShape[] divide_into_sections(double p_max_section_width) + { + if (this.is_empty()) + { + TileShape[] result = new TileShape[1]; + result[0] = this; + return result; + } + TileShape[] section_boxes = this.bounding_box().divide_into_sections(p_max_section_width); + Collection section_list = new LinkedList(); + for (int i = 0; i < section_boxes.length; ++i) + { + TileShape curr_section = this.intersection_with_simplify(section_boxes[i]); + if (curr_section.dimension() == 2) + { + section_list.add(curr_section); + } + } + TileShape[] result = new TileShape[section_list.size()]; + Iterator it = section_list.iterator(); + for (int i = 0; i < result.length; ++i) + { + result[i] = it.next(); + } + return result; + } + + /** + * Checks, if p_line_segment has a common point with the interiour of this shape. + * + * @param p_line_segment a {@link geometry.planar.LineSegment} object. + * @return a boolean. + */ + public boolean is_intersected_interiour_by(LineSegment p_line_segment) + { + FloatPoint float_start_point = p_line_segment.start_point_approx(); + FloatPoint float_end_point = p_line_segment.end_point_approx(); + + Side[] border_line_side_of_start_point_arr = new Side[this.border_line_count()]; + Side[] border_line_side_of_end_point_arr = new Side[border_line_side_of_start_point_arr.length]; + for (int i = 0; i < border_line_side_of_start_point_arr.length; ++i) + { + Line curr_border_line = this.border_line(i); + Side border_line_side_of_start_point = curr_border_line.side_of(float_start_point, 1); + if (border_line_side_of_start_point == Side.COLLINEAR) + { + border_line_side_of_start_point = curr_border_line.side_of(p_line_segment.start_point()); + } + Side border_line_side_of_end_point = curr_border_line.side_of(float_end_point, 1); + if (border_line_side_of_end_point == Side.COLLINEAR) + { + border_line_side_of_end_point = curr_border_line.side_of(p_line_segment.end_point()); + } + if (border_line_side_of_start_point != Side.ON_THE_RIGHT && border_line_side_of_end_point != Side.ON_THE_RIGHT) + { + // both endpoints are outside the border_line, + // no intersection possible + return false; + } + border_line_side_of_start_point_arr[i] = border_line_side_of_start_point; + border_line_side_of_end_point_arr[i] = border_line_side_of_end_point; + } + boolean start_point_is_inside = true; + for (int i = 0; i < border_line_side_of_start_point_arr.length; ++i) + { + if (border_line_side_of_start_point_arr[i] != Side.ON_THE_RIGHT) + { + start_point_is_inside = false; + break; + } + } + if (start_point_is_inside) + { + return true; + } + boolean end_point_is_inside = true; + for (int i = 0; i < border_line_side_of_end_point_arr.length; ++i) + { + if (border_line_side_of_end_point_arr[i] != Side.ON_THE_RIGHT) + { + end_point_is_inside = false; + break; + } + } + if (end_point_is_inside) + { + return true; + } + Line segment_line = p_line_segment.get_line(); + // Check, if this line segments intersect a border line of p_shape. + for (int i = 0; i < border_line_side_of_start_point_arr.length; ++i) + { + Side border_line_side_of_start_point = border_line_side_of_start_point_arr[i]; + Side border_line_side_of_end_point = border_line_side_of_end_point_arr[i]; + if (border_line_side_of_start_point != border_line_side_of_end_point) + { + if (border_line_side_of_start_point == Side.COLLINEAR && border_line_side_of_end_point == Side.ON_THE_LEFT || border_line_side_of_end_point == Side.COLLINEAR && border_line_side_of_start_point == Side.ON_THE_LEFT) + { + // the interiour of p_shape is not intersected. + continue; + } + Side prev_corner_side = segment_line.side_of(this.corner_approx(i), 1); + if (prev_corner_side == Side.COLLINEAR) + { + prev_corner_side = segment_line.side_of(this.corner(i)); + } + int next_corner_index; + if (i == border_line_side_of_start_point_arr.length - 1) + { + next_corner_index = 0; + } + else + { + next_corner_index = i + 1; + } + Side next_corner_side = segment_line.side_of(this.corner_approx(next_corner_index), 1); + if (next_corner_side == Side.COLLINEAR) + { + next_corner_side = segment_line.side_of(this.corner(next_corner_index)); + } + if (prev_corner_side == Side.ON_THE_LEFT && next_corner_side == Side.ON_THE_RIGHT || prev_corner_side == Side.ON_THE_RIGHT && next_corner_side == Side.ON_THE_LEFT) + { + // this line segment crosses a border line of p_shape + return true; + } + } + } + return false; + } + + // auxiliary functions needed because the virtual function mechanism does + // not work in parameter position + abstract TileShape intersection(Simplex p_other); + + abstract TileShape intersection(IntOctagon p_other); + + abstract TileShape intersection(IntBox p_other); + + /** + * Auxiliary function to implement the public function cutout(TileShape p_shape) + */ + abstract TileShape[] cutout_from(IntBox p_shape); + + /** + * Auxiliary function to implement the public function cutout(TileShape p_shape) + */ + abstract TileShape[] cutout_from(IntOctagon p_shape); + + /** + * Auxiliary function to implement the public function cutout(TileShape p_shape) + */ + abstract TileShape[] cutout_from(Simplex p_shape); +} diff --git a/geometry/planar/Vector.java b/src/main/java/geometry/planar/Vector.java similarity index 79% rename from geometry/planar/Vector.java rename to src/main/java/geometry/planar/Vector.java index 63bbc8f..fa34769 100644 --- a/geometry/planar/Vector.java +++ b/src/main/java/geometry/planar/Vector.java @@ -1,238 +1,292 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * Vector.java - * - * Created on 1. Februar 2003, 14:28 - */ - -package geometry.planar; - -import java.math.BigInteger; - -import datastructures.Signum; - -/** - * Abstract class describing functionality of Vectors. - * Vectors are used for translating Points in the plane. - * - * @author Alfons Wirtz - */ - -public abstract class Vector implements java.io.Serializable -{ - - /** - * returns true, if this vector is equal to the zero vector. - */ - public abstract boolean is_zero(); - - /** - * returns the Vector such that this plus this.negate() is zero - */ - public abstract Vector negate(); - - /** - * adds p_other to this vector - */ - public abstract Vector add( Vector p_other); - - /** - * Let L be the line from the Zero Vector to p_other. - * The function returns - * Side.ON_THE_LEFT, if this Vector is on the left of L - * Side.ON_THE_RIGHT, if this Vector is on the right of L - * and Side.COLLINEAR, if this Vector is collinear with L. - */ - public abstract Side side_of(Vector p_other); - - /** - * returns true, if the vector is horizontal or vertical - */ - public abstract boolean is_orthogonal(); - - /** - * returns true, if the vector is diagonal - */ - public abstract boolean is_diagonal(); - - /** - * Returns true, if the vector is orthogonal or diagonal - */ - public boolean is_multiple_of_45_degree() - { - return is_orthogonal() || is_diagonal(); - } - - /** - * The function returns - * Signum.POSITIVE, if the scalar product of this vector and p_other > 0, - * Signum.NEGATIVE, if the scalar product Vector is < 0, - * and Signum.ZERO, if the scalar product is equal 0. - */ - public abstract Signum projection(Vector p_other); - - /** - * Returns an approximation of the scalar product of this vector - * with p_other by a double. - */ - public abstract double scalar_product(Vector p_other); - - /** - * approximates the coordinates of this vector by float coordinates - */ - public abstract FloatPoint to_float(); - - /** - * Turns this vector by p_factor times 90 degree. - */ - public abstract Vector turn_90_degree(int p_factor); - - /** - * Mirrors this vector at the x axis. - */ - public abstract Vector mirror_at_x_axis(); - - /** - * Mirrors this vector at the y axis. - */ - public abstract Vector mirror_at_y_axis(); - - /** - * Standard implementation of the zero vector . - */ - public static final IntVector ZERO = new IntVector(0, 0); - - /** - * Creates a Vector (p_x, p_y) in the plane. - */ - public static Vector get_instance(int p_x, int p_y) - { - IntVector result = new IntVector(p_x, p_y); - if ( Math.abs(p_x) > Limits.CRIT_INT || - Math.abs(p_x) > Limits.CRIT_INT ) - { - return new RationalVector(result); - } - return result; - } - - /** - * Creates a 2-dimensinal Vector from the 3 input values. - * If p_z != 0 it correspondents to the Vector in the plane - * with rational number coordinates (p_x / p_z, p_y / p_z). - */ - public static Vector get_instance(BigInteger p_x, BigInteger p_y, - BigInteger p_z) - { - if (p_z.signum() < 0) - { - // the dominator z of a RationalVector is expected to be positive - p_x = p_x.negate(); - p_y = p_y.negate(); - p_z = p_z.negate(); - - } - if ((p_x.mod(p_z)).signum() == 0 && (p_x.mod(p_z)).signum() == 0) - { - // p_x and p_y can be divided by p_z - p_x = p_x.divide(p_z); - p_y = p_y.divide(p_z); - p_z = BigInteger.ONE; - } - if (p_z.equals(BigInteger.ONE)) - { - if ( (p_x.abs()).compareTo(Limits.CRIT_INT_BIG) <= 0 && - (p_y.abs()).compareTo(Limits.CRIT_INT_BIG) <= 0 ) - { - // the Point fits into an IntPoint - return new IntVector(p_x.intValue(), p_y.intValue()); - } - } - return new RationalVector(p_x, p_y, p_z); - } - - /** - * returns an approximation of the euclidian length of this vector - */ - public double length_approx() - { - return this.to_float().size(); - } - - - /** - * Returns an approximation of the cosinus of the angle - * between this vector and p_other by a double. - */ - public double cos_angle(Vector p_other) - { - double result = this.scalar_product(p_other); - result /= this.to_float().size() * p_other.to_float().size(); - return result; - } - - /** - * Returns an approximation of the signed angle between this vector and p_other. - */ - public double angle_approx(Vector p_other) - { - double result = Math.acos(cos_angle(p_other)); - if (this.side_of(p_other) == Side.ON_THE_LEFT) - { - result = - result; - } - return result; - } - - /** - * Returns an approximation of the signed angle between this vector and the x axis. - */ - public double angle_approx() - { - Vector other = new IntVector(1, 0); - return other.angle_approx(this); - } - - /** - * Returns an approximation vector of this vector with the same direction and - * length p_length. - */ - public abstract Vector change_length_approx(double p_lenght); - - abstract Direction to_normalized_direction(); - - - - // auxiliary functions needed because the virtual function mechanism - // does not work in parameter position - - abstract Vector add( IntVector p_other); - abstract Vector add( RationalVector p_other); - - abstract Point add_to(IntPoint p_point); - abstract Point add_to(RationalPoint p_point); - - abstract Side side_of(IntVector p_other); - abstract Side side_of(RationalVector p_other); - - abstract Signum projection(IntVector p_other); - abstract Signum projection(RationalVector p_other); - - abstract double scalar_product(IntVector p_other); - abstract double scalar_product(RationalVector p_other); - - -} \ No newline at end of file +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * Vector.java + * + * Created on 1. Februar 2003, 14:28 + */ + +package geometry.planar; + +import java.math.BigInteger; + +import datastructures.Signum; + +/** + * Abstract class describing functionality of Vectors. + * Vectors are used for translating Points in the plane. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public abstract class Vector implements java.io.Serializable +{ + + /** + * returns true, if this vector is equal to the zero vector. + * + * @return a boolean. + */ + public abstract boolean is_zero(); + + /** + * returns the Vector such that this plus this.negate() is zero + * + * @return a {@link geometry.planar.Vector} object. + */ + public abstract Vector negate(); + + /** + * adds p_other to this vector + * + * @param p_other a {@link geometry.planar.Vector} object. + * @return a {@link geometry.planar.Vector} object. + */ + public abstract Vector add( Vector p_other); + + /** + * Let L be the line from the Zero Vector to p_other. + * The function returns + * Side.ON_THE_LEFT, if this Vector is on the left of L + * Side.ON_THE_RIGHT, if this Vector is on the right of L + * and Side.COLLINEAR, if this Vector is collinear with L. + * + * @param p_other a {@link geometry.planar.Vector} object. + * @return a {@link geometry.planar.Side} object. + */ + public abstract Side side_of(Vector p_other); + + /** + * returns true, if the vector is horizontal or vertical + * + * @return a boolean. + */ + public abstract boolean is_orthogonal(); + + /** + * returns true, if the vector is diagonal + * + * @return a boolean. + */ + public abstract boolean is_diagonal(); + + /** + * Returns true, if the vector is orthogonal or diagonal + * + * @return a boolean. + */ + public boolean is_multiple_of_45_degree() + { + return is_orthogonal() || is_diagonal(); + } + + /** + * The function returns + * {@code + * Signum.POSITIVE, if the scalar product of this vector and p_other > 0, + * Signum.NEGATIVE, if the scalar product Vector is < 0, + * and Signum.ZERO, if the scalar product is equal 0.} + * + * @param p_other a {@link geometry.planar.Vector} object. + * @return a {@link datastructures.Signum} object. + */ + public abstract Signum projection(Vector p_other); + + /** + * Returns an approximation of the scalar product of this vector + * with p_other by a double. + * + * @param p_other a {@link geometry.planar.Vector} object. + * @return a double. + */ + public abstract double scalar_product(Vector p_other); + + /** + * approximates the coordinates of this vector by float coordinates + * + * @return a {@link geometry.planar.FloatPoint} object. + */ + public abstract FloatPoint to_float(); + + /** + * Turns this vector by p_factor times 90 degree. + * + * @param p_factor a int. + * @return a {@link geometry.planar.Vector} object. + */ + public abstract Vector turn_90_degree(int p_factor); + + /** + * Mirrors this vector at the x axis. + * + * @return a {@link geometry.planar.Vector} object. + */ + public abstract Vector mirror_at_x_axis(); + + /** + * Mirrors this vector at the y axis. + * + * @return a {@link geometry.planar.Vector} object. + */ + public abstract Vector mirror_at_y_axis(); + + /** + * Standard implementation of the zero vector . + */ + public static final IntVector ZERO = new IntVector(0, 0); + + /** + * Creates a Vector (p_x, p_y) in the plane. + * + * @param p_x a int. + * @param p_y a int. + * @return a {@link geometry.planar.Vector} object. + */ + public static Vector get_instance(int p_x, int p_y) + { + IntVector result = new IntVector(p_x, p_y); + if ( Math.abs(p_x) > Limits.CRIT_INT || + Math.abs(p_x) > Limits.CRIT_INT ) + { + return new RationalVector(result); + } + return result; + } + + /** + * Creates a 2-dimensinal Vector from the 3 input values. + * If p_z != 0 it correspondents to the Vector in the plane + * with rational number coordinates (p_x / p_z, p_y / p_z). + * + * @param p_x a {@link java.math.BigInteger} object. + * @param p_y a {@link java.math.BigInteger} object. + * @param p_z a {@link java.math.BigInteger} object. + * @return a {@link geometry.planar.Vector} object. + */ + public static Vector get_instance(BigInteger p_x, BigInteger p_y, + BigInteger p_z) + { + if (p_z.signum() < 0) + { + // the dominator z of a RationalVector is expected to be positive + p_x = p_x.negate(); + p_y = p_y.negate(); + p_z = p_z.negate(); + + } + if ((p_x.mod(p_z)).signum() == 0 && (p_x.mod(p_z)).signum() == 0) + { + // p_x and p_y can be divided by p_z + p_x = p_x.divide(p_z); + p_y = p_y.divide(p_z); + p_z = BigInteger.ONE; + } + if (p_z.equals(BigInteger.ONE)) + { + if ( (p_x.abs()).compareTo(Limits.CRIT_INT_BIG) <= 0 && + (p_y.abs()).compareTo(Limits.CRIT_INT_BIG) <= 0 ) + { + // the Point fits into an IntPoint + return new IntVector(p_x.intValue(), p_y.intValue()); + } + } + return new RationalVector(p_x, p_y, p_z); + } + + /** + * returns an approximation of the euclidian length of this vector + * + * @return a double. + */ + public double length_approx() + { + return this.to_float().size(); + } + + + /** + * Returns an approximation of the cosinus of the angle + * between this vector and p_other by a double. + * + * @param p_other a {@link geometry.planar.Vector} object. + * @return a double. + */ + public double cos_angle(Vector p_other) + { + double result = this.scalar_product(p_other); + result /= this.to_float().size() * p_other.to_float().size(); + return result; + } + + /** + * Returns an approximation of the signed angle between this vector and p_other. + * + * @param p_other a {@link geometry.planar.Vector} object. + * @return a double. + */ + public double angle_approx(Vector p_other) + { + double result = Math.acos(cos_angle(p_other)); + if (this.side_of(p_other) == Side.ON_THE_LEFT) + { + result = - result; + } + return result; + } + + /** + * Returns an approximation of the signed angle between this vector and the x axis. + * + * @return a double. + */ + public double angle_approx() + { + Vector other = new IntVector(1, 0); + return other.angle_approx(this); + } + + /** + * Returns an approximation vector of this vector with the same direction and + * length p_length. + * + * @param p_lenght a double. + * @return a {@link geometry.planar.Vector} object. + */ + public abstract Vector change_length_approx(double p_lenght); + + abstract Direction to_normalized_direction(); + + + + // auxiliary functions needed because the virtual function mechanism + // does not work in parameter position + + abstract Vector add( IntVector p_other); + abstract Vector add( RationalVector p_other); + + abstract Point add_to(IntPoint p_point); + abstract Point add_to(RationalPoint p_point); + + abstract Side side_of(IntVector p_other); + abstract Side side_of(RationalVector p_other); + + abstract Signum projection(IntVector p_other); + abstract Signum projection(RationalVector p_other); + + abstract double scalar_product(IntVector p_other); + abstract double scalar_product(RationalVector p_other); + + +} diff --git a/geometry/planar/package.html b/src/main/java/geometry/planar/package.html similarity index 100% rename from geometry/planar/package.html rename to src/main/java/geometry/planar/package.html diff --git a/src/main/java/gui/BoardFrame.java b/src/main/java/gui/BoardFrame.java new file mode 100644 index 0000000..4a5985e --- /dev/null +++ b/src/main/java/gui/BoardFrame.java @@ -0,0 +1,718 @@ +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + */ + +package gui; + +import interactive.ScreenMessages; + +import java.io.File; + +import datastructures.FileFilter; +import datastructures.IdNoGenerator; + +import board.TestLevel; +import board.BoardObservers; + +import designformats.specctra.DsnFile; + +/** + * + * Graphical frame of for interactive editing of a routing board. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class BoardFrame extends javax.swing.JFrame { + public enum Option { + FROM_START_MENU, SINGLE_FRAME, SESSION_FILE, WEBSTART, EXTENDED_TOOL_BAR + } + + /** + * Creates a new board frame with the input design file imbedded into a host cad + * software. + * + * @param p_design_file_path_name a {@link java.lang.String} object. + * @param p_observers a {@link board.BoardObservers} object. + * @param p_id_no_generator a {@link datastructures.IdNoGenerator} object. + * @param p_locale a {@link java.util.Locale} object. + * @return a {@link gui.BoardFrame} object. + */ + public static BoardFrame get_embedded_instance(String p_design_file_path_name, BoardObservers p_observers, + IdNoGenerator p_id_no_generator, java.util.Locale p_locale) { + final gui.DesignFile design_file = gui.DesignFile.get_instance(p_design_file_path_name); + if (design_file == null) { + WindowMessage.show("designfile not found"); + return null; + } + gui.BoardFrame board_frame = new gui.BoardFrame(design_file, gui.BoardFrame.Option.SINGLE_FRAME, + TestLevel.RELEASE_VERSION, p_observers, p_id_no_generator, p_locale, false); + + if (board_frame == null) { + WindowMessage.show("board_frame is null"); + return null; + } + java.io.InputStream input_stream = design_file.get_input_stream(); + boolean read_ok = board_frame.read(input_stream, true, null); + if (!read_ok) { + String error_message = "Unable to read design file with pathname " + p_design_file_path_name; + board_frame.setVisible(true); // to be able to display the status message + board_frame.screen_messages.set_status_message(error_message); + } + return board_frame; + } + + /** + * Creates new form BoardFrame. If p_option = FROM_START_MENU this frame is + * created from a start menu frame. If p_option = SINGLE_FRAME, this frame is + * created directly a single frame. If p_option = Option.IN_SAND_BOX, no + * security sensitive actions like for example choosing If p_option = + * Option.WEBSTART, the application has been started with Java Webstart. files + * are allowed, so that the frame can be used in an applet. Currently + * Option.EXTENDED_TOOL_BAR is used only if a new board is created by the + * application from scratch. If {@code p_test_level > RELEASE_VERSION}, + * functionality not yet ready for release is included. Also the warning output + * depends on p_test_level. + * + * @param p_design a {@link gui.DesignFile} object. + * @param p_option a {@link gui.BoardFrame.Option} object. + * @param p_test_level a {@link board.TestLevel} object. + * @param p_locale a {@link java.util.Locale} object. + * @param p_confirm_cancel a boolean. + */ + public BoardFrame(DesignFile p_design, Option p_option, TestLevel p_test_level, java.util.Locale p_locale, + boolean p_confirm_cancel) { + this(p_design, p_option, p_test_level, new board.BoardObserverAdaptor(), new board.ItemIdNoGenerator(), + p_locale, p_confirm_cancel); + } + + /** + * Creates new form BoardFrame. The parameters p_item_observers and + * p_item_id_no_generator are used for syncronizing purposes, if the frame is + * embedded into a host system, + */ + BoardFrame(DesignFile p_design, Option p_option, TestLevel p_test_level, BoardObservers p_observers, + datastructures.IdNoGenerator p_item_id_no_generator, java.util.Locale p_locale, boolean p_confirm_cancel) { + this.design_file = p_design; + this.is_web_start = (p_option == Option.WEBSTART); + this.test_level = p_test_level; + + this.confirm_cancel = p_confirm_cancel; + this.board_observers = p_observers; + this.item_id_no_generator = p_item_id_no_generator; + this.locale = p_locale; + this.resources = java.util.ResourceBundle.getBundle("gui.resources.BoardFrame", p_locale); + BoardMenuBar curr_menubar; + boolean session_file_option = (p_option == Option.SESSION_FILE); + boolean curr_help_system_used = true; + try { + curr_menubar = BoardMenuBar.get_instance(this, curr_help_system_used, session_file_option); + } catch (java.lang.NoClassDefFoundError e) { + // the system-file jh.jar may be missing + curr_help_system_used = false; + curr_menubar = BoardMenuBar.get_instance(this, false, session_file_option); + System.out.println("Online-Help deactivated because system file jh.jar is missing"); + } + this.menubar = curr_menubar; + this.help_system_used = curr_help_system_used; + setJMenuBar(this.menubar); + + this.toolbar_panel = new BoardToolbar(this); + this.add(this.toolbar_panel, java.awt.BorderLayout.NORTH); + + this.message_panel = new BoardPanelStatus(this.locale); + this.add(this.message_panel, java.awt.BorderLayout.SOUTH); + + this.select_toolbar = new BoardToolbarSelectedItem(this, p_option == Option.EXTENDED_TOOL_BAR); + + this.screen_messages = new ScreenMessages(this.message_panel.status_message, this.message_panel.add_message, + this.message_panel.current_layer, this.message_panel.mouse_position, this.locale); + + this.scroll_pane = new javax.swing.JScrollPane(); + this.scroll_pane.setPreferredSize(new java.awt.Dimension(1150, 800)); + this.scroll_pane.setVerifyInputWhenFocusTarget(false); + this.add(scroll_pane, java.awt.BorderLayout.CENTER); + + this.board_panel = new BoardPanel(screen_messages, this, this.is_web_start, p_locale); + this.scroll_pane.setViewportView(board_panel); + + this.setTitle(resources.getString("title")); + this.addWindowListener(new WindowStateListener()); + + this.pack(); + } + + /** + * Reads interactive actions from a logfile. + */ + void read_logfile(java.io.InputStream p_input_stream) { + board_panel.board_handling.read_logfile(p_input_stream); + } + + /** + * Reads an existing board design from file. If p_is_import, the design is read + * from a scpecctra dsn file. Returns false, if the file is invalid. + */ + boolean read(java.io.InputStream p_input_stream, boolean p_is_import, javax.swing.JTextField p_message_field) { + java.awt.Point viewport_position = null; + if (p_is_import) { + DsnFile.ReadResult read_result = board_panel.board_handling.import_design(p_input_stream, + this.board_observers, this.item_id_no_generator, this.test_level); + if (read_result != DsnFile.ReadResult.OK) { + if (p_message_field != null) { + if (read_result == DsnFile.ReadResult.OUTLINE_MISSING) { + p_message_field.setText(resources.getString("error_7")); + } else { + p_message_field.setText(resources.getString("error_6")); + } + } + return false; + } + viewport_position = new java.awt.Point(0, 0); + initialize_windows(); + } else { + java.io.ObjectInputStream object_stream = null; + try { + object_stream = new java.io.ObjectInputStream(p_input_stream); + } catch (java.io.IOException e) { + return false; + } + boolean read_ok = board_panel.board_handling.read_design(object_stream, this.test_level); + if (!read_ok) { + return false; + } + java.awt.Point frame_location; + java.awt.Rectangle frame_bounds; + try { + viewport_position = (java.awt.Point) object_stream.readObject(); + frame_location = (java.awt.Point) object_stream.readObject(); + frame_bounds = (java.awt.Rectangle) object_stream.readObject(); + } catch (Exception e) { + return false; + } + this.setLocation(frame_location); + this.setBounds(frame_bounds); + + allocate_permanent_subwindows(); + + for (int i = 0; i < this.permanent_subwindows.length; ++i) { + this.permanent_subwindows[i].read(object_stream); + } + } + try { + p_input_stream.close(); + } catch (java.io.IOException e) { + return false; + } + + java.awt.Dimension panel_size = board_panel.board_handling.graphics_context.get_panel_size(); + board_panel.setSize(panel_size); + board_panel.setPreferredSize(panel_size); + if (viewport_position != null) { + board_panel.set_viewport_position(viewport_position); + } + board_panel.create_popup_menus(); + board_panel.init_colors(); + board_panel.board_handling.create_ratsnest(); + this.hilight_selected_button(); + this.toolbar_panel.unit_factor_field.setValue(board_panel.board_handling.coordinate_transform.user_unit_factor); + this.toolbar_panel.unit_combo_box.setSelectedItem(board_panel.board_handling.coordinate_transform.user_unit); + this.setVisible(true); + if (p_is_import) { + // Read the default gui settings, if gui default file exists. + java.io.InputStream input_stream = null; + boolean defaults_file_found; + File defaults_file = new File(this.design_file.get_parent(), GUI_DEFAULTS_FILE_NAME); + defaults_file_found = true; + try { + input_stream = new java.io.FileInputStream(defaults_file); + } catch (java.io.FileNotFoundException e) { + defaults_file_found = false; + } + if (defaults_file_found) { + boolean read_ok = gui.GUIDefaultsFile.read(this, board_panel.board_handling, input_stream); + if (!read_ok) { + screen_messages.set_status_message(resources.getString("error_1")); + } + try { + input_stream.close(); + } catch (java.io.IOException e) { + return false; + } + } + this.zoom_all(); + } + return true; + } + + /** + * Saves the interactive settings and the design file to disk. Returns false, if + * the save failed. + */ + boolean save() { + if (this.design_file == null) { + return false; + } + java.io.OutputStream output_stream = null; + java.io.ObjectOutputStream object_stream = null; + try { + output_stream = new java.io.FileOutputStream(this.design_file.get_output_file()); + object_stream = new java.io.ObjectOutputStream(output_stream); + } catch (java.io.IOException e) { + screen_messages.set_status_message(resources.getString("error_2")); + return false; + } catch (java.security.AccessControlException e) { + screen_messages.set_status_message(resources.getString("error_3")); + return false; + } + boolean save_ok = board_panel.board_handling.save_design_file(object_stream); + if (!save_ok) { + return false; + } + try { + object_stream.writeObject(board_panel.get_viewport_position()); + object_stream.writeObject(this.getLocation()); + object_stream.writeObject(this.getBounds()); + } catch (java.io.IOException e) { + screen_messages.set_status_message(resources.getString("error_4")); + return false; + } + for (int i = 0; i < this.permanent_subwindows.length; ++i) { + this.permanent_subwindows[i].save(object_stream); + } + try { + object_stream.flush(); + output_stream.close(); + } catch (java.io.IOException e) { + screen_messages.set_status_message(resources.getString("error_5")); + return false; + } + return true; + } + + /** + * Sets contexts sensitive help for the input component, if the help system is + * used. + * + * @param p_component a {@link java.awt.Component} object. + * @param p_help_id a {@link java.lang.String} object. + */ + public void set_context_sensitive_help(java.awt.Component p_component, String p_help_id) { + if (this.help_system_used) { + java.awt.Component curr_component; + if (p_component instanceof javax.swing.JFrame) { + curr_component = ((javax.swing.JFrame) p_component).getRootPane(); + } else { + curr_component = p_component; + } + String help_id = "html_files." + p_help_id; + javax.help.CSH.setHelpIDString(curr_component, help_id); + if ((!this.is_web_start) && (help_set != null)) { + help_broker.enableHelpKey(curr_component, help_id, help_set); + } + } + } + + /** + * Sets the toolbar to the buttons of the selected item state. + */ + public void set_select_toolbar() { + getContentPane().remove(toolbar_panel); + getContentPane().add(select_toolbar, java.awt.BorderLayout.NORTH); + repaint(); + } + + /** + * Sets the toolbar buttons to the select. route and drag menu buttons of the + * main menu. + */ + public void set_menu_toolbar() { + getContentPane().remove(select_toolbar); + getContentPane().add(toolbar_panel, java.awt.BorderLayout.NORTH); + repaint(); + } + + /** + * Calculates the absolute location of the board frame in his outmost parent + * frame. + */ + java.awt.Point absolute_panel_location() { + int x = this.scroll_pane.getX(); + int y = this.scroll_pane.getY(); + java.awt.Container curr_parent = this.scroll_pane.getParent(); + while (curr_parent != null) { + x += curr_parent.getX(); + y += curr_parent.getY(); + curr_parent = curr_parent.getParent(); + } + return new java.awt.Point(x, y); + } + + /** + * Sets the displayed region to the whole board. + */ + public void zoom_all() { + board_panel.board_handling.adjust_design_bounds(); + java.awt.Rectangle display_rect = board_panel.get_viewport_bounds(); + java.awt.Rectangle design_bounds = board_panel.board_handling.graphics_context.get_design_bounds(); + double width_factor = display_rect.getWidth() / design_bounds.getWidth(); + double height_factor = display_rect.getHeight() / design_bounds.getHeight(); + double zoom_factor = Math.min(width_factor, height_factor); + java.awt.geom.Point2D zoom_center = board_panel.board_handling.graphics_context.get_design_center(); + board_panel.zoom(zoom_factor, zoom_center); + java.awt.geom.Point2D new_vieport_center = board_panel.board_handling.graphics_context.get_design_center(); + board_panel.set_viewport_center(new_vieport_center); + + } + + /** + * Actions to be taken when this frame vanishes. + */ + public void dispose() { + for (int i = 0; i < this.permanent_subwindows.length; ++i) { + if (this.permanent_subwindows[i] != null) { + this.permanent_subwindows[i].dispose(); + this.permanent_subwindows[i] = null; + } + } + for (BoardTemporarySubWindow curr_subwindow : this.temporary_subwindows) { + if (curr_subwindow != null) { + curr_subwindow.board_frame_disposed(); + } + } + if (board_panel.board_handling != null) { + board_panel.board_handling.dispose(); + board_panel.board_handling = null; + } + super.dispose(); + } + + private void allocate_permanent_subwindows() { + this.color_manager = new ColorManager(this); + this.permanent_subwindows[0] = this.color_manager; + this.object_visibility_window = WindowObjectVisibility.get_instance(this); + this.permanent_subwindows[1] = this.object_visibility_window; + this.layer_visibility_window = WindowLayerVisibility.get_instance(this); + this.permanent_subwindows[2] = this.layer_visibility_window; + this.display_misc_window = new WindowDisplayMisc(this); + this.permanent_subwindows[3] = this.display_misc_window; + this.snapshot_window = new WindowSnapshot(this); + this.permanent_subwindows[4] = this.snapshot_window; + this.route_parameter_window = new WindowRouteParameter(this); + this.permanent_subwindows[5] = this.route_parameter_window; + this.select_parameter_window = new WindowSelectParameter(this); + this.permanent_subwindows[6] = this.select_parameter_window; + this.clearance_matrix_window = new WindowClearanceMatrix(this); + this.permanent_subwindows[7] = this.clearance_matrix_window; + this.padstacks_window = new WindowPadstacks(this); + this.permanent_subwindows[8] = this.padstacks_window; + this.packages_window = new WindowPackages(this); + this.permanent_subwindows[9] = this.packages_window; + this.components_window = new WindowComponents(this); + this.permanent_subwindows[10] = this.components_window; + this.incompletes_window = new WindowIncompletes(this); + this.permanent_subwindows[11] = this.incompletes_window; + this.clearance_violations_window = new WindowClearanceViolations(this); + this.permanent_subwindows[12] = this.clearance_violations_window; + this.net_info_window = new WindowNets(this); + this.permanent_subwindows[13] = this.net_info_window; + this.via_window = new WindowVia(this); + this.permanent_subwindows[14] = this.via_window; + this.edit_vias_window = new WindowEditVias(this); + this.permanent_subwindows[15] = this.edit_vias_window; + this.edit_net_rules_window = new WindowNetClasses(this); + this.permanent_subwindows[16] = this.edit_net_rules_window; + this.assign_net_classes_window = new WindowAssignNetClass(this); + this.permanent_subwindows[17] = this.assign_net_classes_window; + this.length_violations_window = new WindowLengthViolations(this); + this.permanent_subwindows[18] = this.length_violations_window; + this.about_window = new WindowAbout(this.locale); + this.permanent_subwindows[19] = this.about_window; + this.move_parameter_window = new WindowMoveParameter(this); + this.permanent_subwindows[20] = this.move_parameter_window; + this.unconnected_route_window = new WindowUnconnectedRoute(this); + this.permanent_subwindows[21] = this.unconnected_route_window; + this.route_stubs_window = new WindowRouteStubs(this); + this.permanent_subwindows[22] = this.route_stubs_window; + this.autoroute_parameter_window = new WindowAutorouteParameter(this); + this.permanent_subwindows[23] = this.autoroute_parameter_window; + } + + /** + * Creates the additional frames of the board frame. + */ + private void initialize_windows() { + allocate_permanent_subwindows(); + + this.setLocation(120, 0); + + this.select_parameter_window.setLocation(0, 0); + this.select_parameter_window.setVisible(true); + + this.route_parameter_window.setLocation(0, 100); + this.autoroute_parameter_window.setLocation(0, 200); + this.move_parameter_window.setLocation(0, 50); + this.clearance_matrix_window.setLocation(0, 150); + this.via_window.setLocation(50, 150); + this.edit_vias_window.setLocation(100, 150); + this.edit_net_rules_window.setLocation(100, 200); + this.assign_net_classes_window.setLocation(100, 250); + this.padstacks_window.setLocation(100, 30); + this.packages_window.setLocation(200, 30); + this.components_window.setLocation(300, 30); + this.incompletes_window.setLocation(400, 30); + this.clearance_violations_window.setLocation(500, 30); + this.length_violations_window.setLocation(550, 30); + this.net_info_window.setLocation(350, 30); + this.unconnected_route_window.setLocation(650, 30); + this.route_stubs_window.setLocation(600, 30); + this.snapshot_window.setLocation(0, 250); + this.layer_visibility_window.setLocation(0, 450); + this.object_visibility_window.setLocation(0, 550); + this.display_misc_window.setLocation(0, 350); + this.color_manager.setLocation(0, 600); + this.about_window.setLocation(200, 200); + } + + /** + * Returns the currently used locale for the language dependent output. + * + * @return a {@link java.util.Locale} object. + */ + public java.util.Locale get_locale() { + return this.locale; + } + + /** + * Sets the background of the board panel + * + * @param p_color a {@link java.awt.Color} object. + */ + public void set_board_background(java.awt.Color p_color) { + this.board_panel.setBackground(p_color); + } + + /** + * Refreshs all displayed coordinates after the user unit has changed. + */ + public void refresh_windows() { + for (int i = 0; i < this.permanent_subwindows.length; ++i) { + if (permanent_subwindows[i] != null) { + permanent_subwindows[i].refresh(); + } + } + } + + /** + * Sets the selected button in the menu button button group + */ + public void hilight_selected_button() { + this.toolbar_panel.hilight_selected_button(); + } + + /** + * Restore the selected snapshot in the snapshot window. + */ + public void goto_selected_snapshot() { + if (this.snapshot_window != null) { + this.snapshot_window.goto_selected(); + } + } + + /** + * Selects the snapshot, which is previous to the current selected snapshot. + * Thecurent selected snapshot will be no more selected. + */ + public void select_previous_snapshot() { + if (this.snapshot_window != null) { + this.snapshot_window.select_previous_item(); + } + } + + /** + * Selects the snapshot, which is next to the current selected snapshot. + * Thecurent selected snapshot will be no more selected. + */ + public void select_next_snapshot() { + if (this.snapshot_window != null) { + this.snapshot_window.select_next_item(); + } + } + + /** + * Used for storing the subwindowfilters in a snapshot. + * + * @return a {@link gui.BoardFrame.SubwindowSelections} object. + */ + public SubwindowSelections get_snapshot_subwindow_selections() { + SubwindowSelections result = new SubwindowSelections(); + result.incompletes_selection = this.incompletes_window.get_snapshot_info(); + result.packages_selection = this.packages_window.get_snapshot_info(); + result.nets_selection = this.net_info_window.get_snapshot_info(); + result.components_selection = this.components_window.get_snapshot_info(); + result.padstacks_selection = this.padstacks_window.get_snapshot_info(); + return result; + } + + /** + * Used for restoring the subwindowfilters from a snapshot. + * + * @param p_filters a {@link gui.BoardFrame.SubwindowSelections} object. + */ + public void set_snapshot_subwindow_selections(SubwindowSelections p_filters) { + this.incompletes_window.set_snapshot_info(p_filters.incompletes_selection); + this.packages_window.set_snapshot_info(p_filters.packages_selection); + this.net_info_window.set_snapshot_info(p_filters.nets_selection); + this.components_window.set_snapshot_info(p_filters.components_selection); + this.padstacks_window.set_snapshot_info(p_filters.padstacks_selection); + } + + /** + * Repaints this board frame and all the subwindows of the board. + */ + public void repaint_all() { + this.repaint(); + for (int i = 0; i < permanent_subwindows.length; ++i) { + permanent_subwindows[i].repaint(); + } + } + + /** The scroll pane for the panel of the routing board. */ + final javax.swing.JScrollPane scroll_pane; + + /** The menubar of this frame */ + final BoardMenuBar menubar; + + /** The panel with the graphical representation of the board. */ + final BoardPanel board_panel; + + /** The panel with the toolbars */ + private final BoardToolbar toolbar_panel; + + /** The toolbar used in the selected item state. */ + private final javax.swing.JToolBar select_toolbar; + + /** The panel with the message line */ + private final BoardPanelStatus message_panel; + + final ScreenMessages screen_messages; + + private final TestLevel test_level; + + /** + * true, if the frame is created by an application running under Java Web Start + */ + final boolean is_web_start; + + private final boolean help_system_used; + static javax.help.HelpSet help_set = null; + static javax.help.HelpBroker help_broker = null; + + private final boolean confirm_cancel; + + private final java.util.ResourceBundle resources; + private java.util.Locale locale; + + private final BoardObservers board_observers; + private final datastructures.IdNoGenerator item_id_no_generator; + + WindowAbout about_window = null; + WindowRouteParameter route_parameter_window = null; + WindowAutorouteParameter autoroute_parameter_window = null; + WindowSelectParameter select_parameter_window = null; + WindowMoveParameter move_parameter_window = null; + WindowClearanceMatrix clearance_matrix_window = null; + WindowVia via_window = null; + WindowEditVias edit_vias_window = null; + WindowNetClasses edit_net_rules_window = null; + WindowAssignNetClass assign_net_classes_window = null; + WindowPadstacks padstacks_window = null; + WindowPackages packages_window = null; + WindowIncompletes incompletes_window = null; + WindowNets net_info_window = null; + WindowClearanceViolations clearance_violations_window = null; + WindowLengthViolations length_violations_window = null; + WindowUnconnectedRoute unconnected_route_window = null; + WindowRouteStubs route_stubs_window = null; + WindowComponents components_window = null; + WindowLayerVisibility layer_visibility_window = null; + WindowObjectVisibility object_visibility_window = null; + WindowDisplayMisc display_misc_window = null; + WindowSnapshot snapshot_window = null; + ColorManager color_manager = null; + + /** The windows above stored in an array */ + static final int SUBWINDOW_COUNT = 24; + BoardSavableSubWindow[] permanent_subwindows = new BoardSavableSubWindow[SUBWINDOW_COUNT]; + + java.util.Collection temporary_subwindows = new java.util.LinkedList(); + + DesignFile design_file = null; + + static final String[] log_file_extensions = { "log" }; + + static final String GUI_DEFAULTS_FILE_NAME = "gui_defaults.par"; + static final String GUI_DEFAULTS_FILE_BACKUP_NAME = "gui_defaults.par.bak"; + + static final FileFilter logfile_filter = new FileFilter(log_file_extensions); + + private class WindowStateListener extends java.awt.event.WindowAdapter { + public void windowClosing(java.awt.event.WindowEvent evt) { + setDefaultCloseOperation(DISPOSE_ON_CLOSE); + if (confirm_cancel) { + int option = javax.swing.JOptionPane.showConfirmDialog(null, resources.getString("confirm_cancel"), + null, javax.swing.JOptionPane.YES_NO_OPTION); + if (option == javax.swing.JOptionPane.NO_OPTION) { + setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); + } + } + } + + public void windowIconified(java.awt.event.WindowEvent evt) { + for (int i = 0; i < permanent_subwindows.length; ++i) { + permanent_subwindows[i].parent_iconified(); + } + for (BoardSubWindow curr_subwindow : temporary_subwindows) { + if (curr_subwindow != null) { + curr_subwindow.parent_iconified(); + } + } + } + + public void windowDeiconified(java.awt.event.WindowEvent evt) { + for (int i = 0; i < permanent_subwindows.length; ++i) { + if (permanent_subwindows[i] != null) { + permanent_subwindows[i].parent_deiconified(); + } + } + for (BoardSubWindow curr_subwindow : temporary_subwindows) { + if (curr_subwindow != null) { + curr_subwindow.parent_deiconified(); + } + } + } + } + + /** + * Used for storing the subwindow filters in a snapshot. + */ + public static class SubwindowSelections implements java.io.Serializable { + private WindowObjectListWithFilter.SnapshotInfo incompletes_selection; + private WindowObjectListWithFilter.SnapshotInfo packages_selection; + private WindowObjectListWithFilter.SnapshotInfo nets_selection; + private WindowObjectListWithFilter.SnapshotInfo components_selection; + private WindowObjectListWithFilter.SnapshotInfo padstacks_selection; + } +} diff --git a/gui/BoardMenuBar.java b/src/main/java/gui/BoardMenuBar.java similarity index 100% rename from gui/BoardMenuBar.java rename to src/main/java/gui/BoardMenuBar.java diff --git a/gui/BoardMenuDisplay.java b/src/main/java/gui/BoardMenuDisplay.java similarity index 94% rename from gui/BoardMenuDisplay.java rename to src/main/java/gui/BoardMenuDisplay.java index 24fa2f4..ae520df 100644 --- a/gui/BoardMenuDisplay.java +++ b/src/main/java/gui/BoardMenuDisplay.java @@ -24,10 +24,16 @@ * Creates the display menu of a board frame. * * @author Alfons Wirtz + * @version $Id: $Id */ public class BoardMenuDisplay extends javax.swing.JMenu { - /** Returns a new display menu for the board frame. */ + /** + * Returns a new display menu for the board frame. + * + * @param p_board_frame a {@link gui.BoardFrame} object. + * @return a {@link gui.BoardMenuDisplay} object. + */ public static BoardMenuDisplay get_instance(BoardFrame p_board_frame) { final BoardMenuDisplay display_menu = new BoardMenuDisplay(p_board_frame); diff --git a/src/main/java/gui/BoardMenuFile.java b/src/main/java/gui/BoardMenuFile.java new file mode 100644 index 0000000..7ed8112 --- /dev/null +++ b/src/main/java/gui/BoardMenuFile.java @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * BoardFileMenu.java + * + * Created on 11. Februar 2005, 11:26 + */ +package gui; + +/** + * Creates the file menu of a board frame. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class BoardMenuFile extends javax.swing.JMenu { + + /** + * Returns a new file menu for the board frame. + * + * @param p_board_frame a {@link gui.BoardFrame} object. + * @param p_session_file_option a boolean. + * @return a {@link gui.BoardMenuFile} object. + */ + public static BoardMenuFile get_instance(BoardFrame p_board_frame, boolean p_session_file_option) { + final BoardMenuFile file_menu = new BoardMenuFile(p_board_frame, p_session_file_option); + file_menu.setText(file_menu.resources.getString("file")); + + // Create the menu items. + + if (!p_session_file_option && !p_board_frame.is_web_start) { + javax.swing.JMenuItem save_item = new javax.swing.JMenuItem(); + save_item.setText(file_menu.resources.getString("save")); + save_item.setToolTipText(file_menu.resources.getString("save_tooltip")); + save_item.addActionListener(new java.awt.event.ActionListener() { + + public void actionPerformed(java.awt.event.ActionEvent evt) { + boolean save_ok = file_menu.board_frame.save(); + file_menu.board_frame.board_panel.board_handling.close_files(); + if (save_ok) { + file_menu.board_frame.screen_messages + .set_status_message(file_menu.resources.getString("save_message")); + } + } + }); + + file_menu.add(save_item); + } + + if (!p_board_frame.is_web_start) { + javax.swing.JMenuItem save_and_exit_item = new javax.swing.JMenuItem(); + save_and_exit_item.setText(file_menu.resources.getString("save_and_exit")); + save_and_exit_item.setToolTipText(file_menu.resources.getString("save_and_exit_tooltip")); + save_and_exit_item.addActionListener(new java.awt.event.ActionListener() { + + public void actionPerformed(java.awt.event.ActionEvent evt) { + if (file_menu.session_file_option) { + file_menu.board_frame.design_file.write_specctra_session_file(file_menu.board_frame); + } else { + file_menu.board_frame.save(); + } + file_menu.board_frame.dispose(); + } + }); + + file_menu.add(save_and_exit_item); + } + + javax.swing.JMenuItem cancel_and_exit_item = new javax.swing.JMenuItem(); + cancel_and_exit_item.setText(file_menu.resources.getString("cancel_and_exit")); + cancel_and_exit_item.setToolTipText(file_menu.resources.getString("cancel_and_exit_tooltip")); + cancel_and_exit_item.addActionListener(new java.awt.event.ActionListener() { + + public void actionPerformed(java.awt.event.ActionEvent evt) { + file_menu.board_frame.dispose(); + } + }); + + file_menu.add(cancel_and_exit_item); + + if (!file_menu.session_file_option) { + javax.swing.JMenuItem save_as_item = new javax.swing.JMenuItem(); + save_as_item.setText(file_menu.resources.getString("save_as")); + save_as_item.setToolTipText(file_menu.resources.getString("save_as_tooltip")); + save_as_item.addActionListener(new java.awt.event.ActionListener() { + + public void actionPerformed(java.awt.event.ActionEvent evt) { + file_menu.save_as_action(); + } + }); + + file_menu.add(save_as_item); + + if (!p_board_frame.is_web_start) { + javax.swing.JMenuItem write_logfile_item = new javax.swing.JMenuItem(); + write_logfile_item.setText(file_menu.resources.getString("generate_logfile")); + write_logfile_item.setToolTipText(file_menu.resources.getString("generate_logfile_tooltip")); + write_logfile_item.addActionListener(new java.awt.event.ActionListener() { + + public void actionPerformed(java.awt.event.ActionEvent evt) { + file_menu.write_logfile_action(); + } + }); + + file_menu.add(write_logfile_item); + + javax.swing.JMenuItem replay_logfile_item = new javax.swing.JMenuItem(); + replay_logfile_item.setText(file_menu.resources.getString("replay_logfile")); + replay_logfile_item.setToolTipText(file_menu.resources.getString("replay_logfile_tooltip")); + replay_logfile_item.addActionListener(new java.awt.event.ActionListener() { + + public void actionPerformed(java.awt.event.ActionEvent evt) { + file_menu.read_logfile_action(); + } + }); + + file_menu.add(replay_logfile_item); + } + } + + file_menu.add_save_settings_item(); + + return file_menu; + } + + /** + *

+ * add_design_dependent_items. + *

+ */ + public void add_design_dependent_items() { + if (this.session_file_option) { + return; + } + board.BasicBoard routing_board = this.board_frame.board_panel.board_handling.get_routing_board(); + boolean host_cad_is_eagle = routing_board.communication.host_cad_is_eagle(); + + javax.swing.JMenuItem write_session_file_item = new javax.swing.JMenuItem(); + write_session_file_item.setText(resources.getString("session_file")); + write_session_file_item.setToolTipText(resources.getString("session_file_tooltip")); + write_session_file_item.addActionListener(new java.awt.event.ActionListener() { + + public void actionPerformed(java.awt.event.ActionEvent evt) { + board_frame.design_file.write_specctra_session_file(board_frame); + } + }); + + if ((routing_board.get_test_level() != board.TestLevel.RELEASE_VERSION || !host_cad_is_eagle)) { + this.add(write_session_file_item); + } + + javax.swing.JMenuItem write_eagle_session_script_item = new javax.swing.JMenuItem(); + write_eagle_session_script_item.setText(resources.getString("eagle_script")); + write_eagle_session_script_item.setToolTipText(resources.getString("eagle_script_tooltip")); + write_eagle_session_script_item.addActionListener(new java.awt.event.ActionListener() { + + public void actionPerformed(java.awt.event.ActionEvent evt) { + board_frame.design_file.update_eagle(board_frame); + } + }); + + if (routing_board.get_test_level() != board.TestLevel.RELEASE_VERSION || host_cad_is_eagle) { + this.add(write_eagle_session_script_item); + } + } + + /** + * Adds a menu item for saving the current interactive settings as default. + */ + private void add_save_settings_item() { + javax.swing.JMenuItem save_settings_item = new javax.swing.JMenuItem(); + save_settings_item.setText(resources.getString("settings")); + save_settings_item.setToolTipText(resources.getString("settings_tooltip")); + save_settings_item.addActionListener(new java.awt.event.ActionListener() { + + public void actionPerformed(java.awt.event.ActionEvent evt) { + save_defaults_action(); + } + }); + add(save_settings_item); + } + + private void save_as_action() { + if (this.board_frame.design_file != null) { + this.board_frame.design_file.save_as_dialog(this, this.board_frame); + } + } + + private void write_logfile_action() { + javax.swing.JFileChooser file_chooser = new javax.swing.JFileChooser(); + java.io.File logfile_dir = board_frame.design_file.get_parent_file(); + file_chooser.setCurrentDirectory(logfile_dir); + file_chooser.setFileFilter(BoardFrame.logfile_filter); + file_chooser.showOpenDialog(this); + java.io.File filename = file_chooser.getSelectedFile(); + if (filename == null) { + board_frame.screen_messages.set_status_message(resources.getString("message_8")); + } else { + board_frame.screen_messages.set_status_message(resources.getString("message_9")); + board_frame.board_panel.board_handling.start_logfile(filename); + } + } + + private void read_logfile_action() { + javax.swing.JFileChooser file_chooser = new javax.swing.JFileChooser(); + java.io.File logfile_dir = board_frame.design_file.get_parent_file(); + file_chooser.setCurrentDirectory(logfile_dir); + file_chooser.setFileFilter(BoardFrame.logfile_filter); + file_chooser.showOpenDialog(this); + java.io.File filename = file_chooser.getSelectedFile(); + if (filename == null) { + board_frame.screen_messages.set_status_message(resources.getString("message_10")); + } else { + java.io.InputStream input_stream = null; + try { + input_stream = new java.io.FileInputStream(filename); + } catch (java.io.FileNotFoundException e) { + return; + } + board_frame.read_logfile(input_stream); + } + } + + private void save_defaults_action() { + java.io.OutputStream output_stream = null; + java.io.File defaults_file = new java.io.File(board_frame.design_file.get_parent(), + BoardFrame.GUI_DEFAULTS_FILE_NAME); + if (defaults_file.exists()) { + // Make a backup copy of the old defaulds file. + java.io.File defaults_file_backup = new java.io.File(board_frame.design_file.get_parent(), + BoardFrame.GUI_DEFAULTS_FILE_BACKUP_NAME); + if (defaults_file_backup.exists()) { + defaults_file_backup.delete(); + } + defaults_file.renameTo(defaults_file_backup); + } + try { + output_stream = new java.io.FileOutputStream(defaults_file); + } catch (Exception e) { + output_stream = null; + } + boolean write_ok; + if (output_stream == null) { + write_ok = false; + } else { + write_ok = gui.GUIDefaultsFile.write(board_frame, board_frame.board_panel.board_handling, output_stream); + } + if (write_ok) { + board_frame.screen_messages.set_status_message(resources.getString("message_17")); + } else { + board_frame.screen_messages.set_status_message(resources.getString("message_18")); + } + + } + + /** Creates a new instance of BoardFileMenu */ + private BoardMenuFile(BoardFrame p_board_frame, boolean p_session_file_option) { + session_file_option = p_session_file_option; + board_frame = p_board_frame; + resources = java.util.ResourceBundle.getBundle("gui.resources.BoardMenuFile", p_board_frame.get_locale()); + } + + private final BoardFrame board_frame; + private final boolean session_file_option; + private final java.util.ResourceBundle resources; +} diff --git a/gui/BoardMenuHelp.java b/src/main/java/gui/BoardMenuHelp.java similarity index 96% rename from gui/BoardMenuHelp.java rename to src/main/java/gui/BoardMenuHelp.java index b510707..a920daf 100644 --- a/gui/BoardMenuHelp.java +++ b/src/main/java/gui/BoardMenuHelp.java @@ -27,8 +27,10 @@ import java.net.URL; /** + *

BoardMenuHelp class.

* * @author Alfons Wirtz + * @version $Id: $Id */ public class BoardMenuHelp extends BoardMenuHelpReduced { @@ -36,6 +38,8 @@ public class BoardMenuHelp extends BoardMenuHelpReduced * Creates a new instance of BoardMenuHelp * Separated from BoardMenuHelpReduced to avoid ClassNotFound exception when the library * jh.jar is not found, which is only used in this extended class. + * + * @param p_board_frame a {@link gui.BoardFrame} object. */ public BoardMenuHelp(BoardFrame p_board_frame) { diff --git a/gui/BoardMenuHelpReduced.java b/src/main/java/gui/BoardMenuHelpReduced.java similarity index 93% rename from gui/BoardMenuHelpReduced.java rename to src/main/java/gui/BoardMenuHelpReduced.java index 9142739..a34f109 100644 --- a/gui/BoardMenuHelpReduced.java +++ b/src/main/java/gui/BoardMenuHelpReduced.java @@ -22,8 +22,10 @@ package gui; /** + *

BoardMenuHelpReduced class.

* * @author Alfons Wirtz + * @version $Id: $Id */ public class BoardMenuHelpReduced extends javax.swing.JMenu { @@ -31,6 +33,8 @@ public class BoardMenuHelpReduced extends javax.swing.JMenu * Creates a new instance of BoardMenuHelpReduced * Separated from BoardMenuHelp to avoid ClassNotFound exception when the library * jh.jar is not found, which is only used in the extended help menu. + * + * @param p_board_frame a {@link gui.BoardFrame} object. */ public BoardMenuHelpReduced(BoardFrame p_board_frame) { diff --git a/gui/BoardMenuInfo.java b/src/main/java/gui/BoardMenuInfo.java similarity index 95% rename from gui/BoardMenuInfo.java rename to src/main/java/gui/BoardMenuInfo.java index b6ae072..63c3bcd 100644 --- a/gui/BoardMenuInfo.java +++ b/src/main/java/gui/BoardMenuInfo.java @@ -21,12 +21,19 @@ package gui; /** + *

BoardMenuInfo class.

* * @author Alfons Wirtz + * @version $Id: $Id */ public class BoardMenuInfo extends javax.swing.JMenu { - /** Returns a new info menu for the board frame. */ + /** + * Returns a new info menu for the board frame. + * + * @param p_board_frame a {@link gui.BoardFrame} object. + * @return a {@link gui.BoardMenuInfo} object. + */ public static BoardMenuInfo get_instance(BoardFrame p_board_frame) { final BoardMenuInfo info_menu = new BoardMenuInfo(p_board_frame); diff --git a/gui/BoardMenuOther.java b/src/main/java/gui/BoardMenuOther.java similarity index 89% rename from gui/BoardMenuOther.java rename to src/main/java/gui/BoardMenuOther.java index 6d39832..bc866b8 100644 --- a/gui/BoardMenuOther.java +++ b/src/main/java/gui/BoardMenuOther.java @@ -22,12 +22,19 @@ package gui; /** + *

BoardMenuOther class.

* * @author Alfons Wirtz + * @version $Id: $Id */ public class BoardMenuOther extends javax.swing.JMenu { - /** Returns a new other menu for the board frame. */ + /** + * Returns a new other menu for the board frame. + * + * @param p_board_frame a {@link gui.BoardFrame} object. + * @return a {@link gui.BoardMenuOther} object. + */ public static BoardMenuOther get_instance(BoardFrame p_board_frame) { final BoardMenuOther other_menu = new BoardMenuOther(p_board_frame); diff --git a/gui/BoardMenuParameter.java b/src/main/java/gui/BoardMenuParameter.java similarity index 94% rename from gui/BoardMenuParameter.java rename to src/main/java/gui/BoardMenuParameter.java index c6b7245..15c4189 100644 --- a/gui/BoardMenuParameter.java +++ b/src/main/java/gui/BoardMenuParameter.java @@ -24,10 +24,16 @@ * Creates the parameter menu of a board frame. * * @author Alfons Wirtz + * @version $Id: $Id */ public class BoardMenuParameter extends javax.swing.JMenu { - /** Returns a new windows menu for the board frame. */ + /** + * Returns a new windows menu for the board frame. + * + * @param p_board_frame a {@link gui.BoardFrame} object. + * @return a {@link gui.BoardMenuParameter} object. + */ public static BoardMenuParameter get_instance(BoardFrame p_board_frame) { final BoardMenuParameter parameter_menu = new BoardMenuParameter(p_board_frame); diff --git a/gui/BoardMenuRules.java b/src/main/java/gui/BoardMenuRules.java similarity index 94% rename from gui/BoardMenuRules.java rename to src/main/java/gui/BoardMenuRules.java index 3b963a8..2f8f4f6 100644 --- a/gui/BoardMenuRules.java +++ b/src/main/java/gui/BoardMenuRules.java @@ -24,11 +24,17 @@ * Creates the rules menu of a board frame. * * @author Alfons Wirtz + * @version $Id: $Id */ public class BoardMenuRules extends javax.swing.JMenu { - /** Returns a new windows menu for the board frame. */ + /** + * Returns a new windows menu for the board frame. + * + * @param p_board_frame a {@link gui.BoardFrame} object. + * @return a {@link gui.BoardMenuRules} object. + */ public static BoardMenuRules get_instance(BoardFrame p_board_frame) { final BoardMenuRules rules_menu = new BoardMenuRules(p_board_frame); diff --git a/gui/BoardPanel.java b/src/main/java/gui/BoardPanel.java similarity index 92% rename from gui/BoardPanel.java rename to src/main/java/gui/BoardPanel.java index a036ce1..c6ee0e8 100644 --- a/gui/BoardPanel.java +++ b/src/main/java/gui/BoardPanel.java @@ -40,11 +40,19 @@ * Panel containing the graphical representation of a routing board. * * @author Alfons Wirtz + * @version $Id: $Id */ public class BoardPanel extends javax.swing.JPanel { - /** Creates a new BoardPanel in an Application */ + /** + * Creates a new BoardPanel in an Application + * + * @param p_screen_messages a {@link interactive.ScreenMessages} object. + * @param p_board_frame a {@link gui.BoardFrame} object. + * @param p_is_web_application a boolean. + * @param p_locale a {@link java.util.Locale} object. + */ public BoardPanel(ScreenMessages p_screen_messages, BoardFrame p_board_frame, boolean p_is_web_application, java.util.Locale p_locale) { @@ -133,6 +141,12 @@ void create_popup_menus() } + /** + *

zoom_with_mouse_wheel.

+ * + * @param p_point a java$awt$geom$Point2D object. + * @param p_wheel_rotation a int. + */ public void zoom_with_mouse_wheel(java.awt.geom.Point2D p_point, int p_wheel_rotation) { if (this.middle_drag_position != null || p_wheel_rotation == 0) @@ -215,6 +229,8 @@ else if (evt.getButton() == 3) } /** + * {@inheritDoc} + * * overwrites the paintComponent method to draw the routing board */ public void paintComponent(Graphics p_g) @@ -232,6 +248,8 @@ public void paintComponent(Graphics p_g) /** * Returns the position of the viewport + * + * @return a {@link java.awt.Point} object. */ public java.awt.Point get_viewport_position() { @@ -250,6 +268,8 @@ void set_viewport_position(java.awt.Point p_position) /** * zooms in at p_position + * + * @param p_position a java$awt$geom$Point2D object. */ public void zoom_in(java.awt.geom.Point2D p_position) { @@ -258,6 +278,8 @@ public void zoom_in(java.awt.geom.Point2D p_position) /** * zooms out at p_position + * + * @param p_position a java$awt$geom$Point2D object. */ public void zoom_out(java.awt.geom.Point2D p_position) { @@ -267,6 +289,9 @@ public void zoom_out(java.awt.geom.Point2D p_position) /** * zooms to frame + * + * @param p_position1 a java$awt$geom$Point2D object. + * @param p_position2 a java$awt$geom$Point2D object. */ public void zoom_frame(java.awt.geom.Point2D p_position1, java.awt.geom.Point2D p_position2) { @@ -287,6 +312,11 @@ public void zoom_frame(java.awt.geom.Point2D p_position1, java.awt.geom.Point2D set_viewport_center(changed_location); } + /** + *

center_display.

+ * + * @param p_new_center a java$awt$geom$Point2D object. + */ public void center_display(Point2D p_new_center) { java.awt.Point delta = set_viewport_center(p_new_center); @@ -301,6 +331,11 @@ public void center_display(Point2D p_new_center) } + /** + *

get_viewport_center.

+ * + * @return a java$awt$geom$Point2D object. + */ public java.awt.geom.Point2D get_viewport_center() { java.awt.Point pos = get_viewport_position(); @@ -312,6 +347,10 @@ public java.awt.geom.Point2D get_viewport_center() /** * zooms the content of the board by p_factor * Returns the change of the cursor location + * + * @param p_factor a double. + * @param p_location a java$awt$geom$Point2D object. + * @return a java$awt$geom$Point2D object. */ public java.awt.geom.Point2D zoom(double p_factor, java.awt.geom.Point2D p_location) { @@ -373,6 +412,8 @@ java.awt.Point set_viewport_center(java.awt.geom.Point2D p_point) /** * Selects the p_signal_layer_no-th layer in the select_parameter_window. + * + * @param p_signal_layer_no a int. */ public void set_selected_signal_layer(int p_signal_layer_no) { @@ -421,6 +462,11 @@ private void scroll_middle_mouse(java.awt.event.MouseEvent p_evt) set_viewport_position(p) ; } + /** + *

move_mouse.

+ * + * @param p_location a java$awt$geom$Point2D object. + */ public void move_mouse(Point2D p_location) { if (robot == null) @@ -438,6 +484,8 @@ public void move_mouse(Point2D p_location) * If p_value is true, the custom crosshair cursor will be used in display. * Otherwise the standard Cursor will be used. * Using the custom cursor may slow down the display performance a lot. + * + * @param p_value a boolean. */ public void set_custom_crosshair_cursor(boolean p_value) { @@ -457,6 +505,8 @@ public void set_custom_crosshair_cursor(boolean p_value) * If the result is true, the custom crosshair cursor will be used in display. * Otherwise the standard Cursor will be used. * Using the custom cursor may slow down the display performance a lot. + * + * @return a boolean. */ public boolean is_custom_cross_hair_cursor() { diff --git a/gui/BoardPanelStatus.java b/src/main/java/gui/BoardPanelStatus.java similarity index 100% rename from gui/BoardPanelStatus.java rename to src/main/java/gui/BoardPanelStatus.java diff --git a/gui/BoardSavableSubWindow.java b/src/main/java/gui/BoardSavableSubWindow.java similarity index 92% rename from gui/BoardSavableSubWindow.java rename to src/main/java/gui/BoardSavableSubWindow.java index fc32188..d8f8685 100644 --- a/gui/BoardSavableSubWindow.java +++ b/src/main/java/gui/BoardSavableSubWindow.java @@ -24,6 +24,7 @@ * Subwindow of the board frame, whose location and visibility can be saved and read from disc. * * @author Alfons Wirtz + * @version $Id: $Id */ public abstract class BoardSavableSubWindow extends BoardSubWindow { @@ -31,6 +32,9 @@ public abstract class BoardSavableSubWindow extends BoardSubWindow /** * Reads the data of this frame from disc. * Returns false, if the reading failed. + * + * @param p_object_stream a {@link java.io.ObjectInputStream} object. + * @return a boolean. */ public boolean read(java.io.ObjectInputStream p_object_stream) { @@ -50,6 +54,8 @@ public boolean read(java.io.ObjectInputStream p_object_stream) /** * Saves this frame to disk. + * + * @param p_object_stream a {@link java.io.ObjectOutputStream} object. */ public void save(java.io.ObjectOutputStream p_object_stream) { @@ -65,7 +71,7 @@ public void save(java.io.ObjectOutputStream p_object_stream) } } - /** + /** * Refreshs the displayed values in this window. * To be overwritten in derived classes. */ diff --git a/gui/BoardSubWindow.java b/src/main/java/gui/BoardSubWindow.java similarity index 90% rename from gui/BoardSubWindow.java rename to src/main/java/gui/BoardSubWindow.java index 54be86a..60c7546 100644 --- a/gui/BoardSubWindow.java +++ b/src/main/java/gui/BoardSubWindow.java @@ -25,16 +25,23 @@ * Subwindows of the board frame. * * @author Alfons Wirtz + * @version $Id: $Id */ public class BoardSubWindow extends javax.swing.JFrame { + /** + *

parent_iconified.

+ */ public void parent_iconified() { this.visible_before_iconifying = this.isVisible(); this.setVisible(false); } + /** + *

parent_deiconified.

+ */ public void parent_deiconified() { this.setVisible(this.visible_before_iconifying); diff --git a/gui/BoardTemporarySubWindow.java b/src/main/java/gui/BoardTemporarySubWindow.java similarity index 84% rename from gui/BoardTemporarySubWindow.java rename to src/main/java/gui/BoardTemporarySubWindow.java index 9a5bc27..06537e6 100644 --- a/gui/BoardTemporarySubWindow.java +++ b/src/main/java/gui/BoardTemporarySubWindow.java @@ -23,12 +23,18 @@ /** * Class for temporary subwindows of the boarrd frame + * * @author Alfons Wirtz + * @version $Id: $Id */ public class BoardTemporarySubWindow extends BoardSubWindow { - /** Creates a new instance of BoardTemporarySubWindow */ + /** + * Creates a new instance of BoardTemporarySubWindow + * + * @param p_board_frame a {@link gui.BoardFrame} object. + */ public BoardTemporarySubWindow(BoardFrame p_board_frame) { this.board_frame = p_board_frame; @@ -43,12 +49,17 @@ public void windowClosing(java.awt.event.WindowEvent evt) }); } - /** Used, when the board frame with all the subwindows is disposed. */ + /** + * Used, when the board frame with all the subwindows is disposed. + */ public void board_frame_disposed() { super.dispose(); } + /** + *

dispose.

+ */ public void dispose() { this.board_frame.temporary_subwindows.remove(this); diff --git a/gui/BoardToolbar.java b/src/main/java/gui/BoardToolbar.java similarity index 100% rename from gui/BoardToolbar.java rename to src/main/java/gui/BoardToolbar.java diff --git a/gui/BoardToolbarSelectedItem.java b/src/main/java/gui/BoardToolbarSelectedItem.java similarity index 100% rename from gui/BoardToolbarSelectedItem.java rename to src/main/java/gui/BoardToolbarSelectedItem.java diff --git a/gui/ColorManager.java b/src/main/java/gui/ColorManager.java similarity index 97% rename from gui/ColorManager.java rename to src/main/java/gui/ColorManager.java index 3c8546d..6ddfa75 100644 --- a/gui/ColorManager.java +++ b/src/main/java/gui/ColorManager.java @@ -48,11 +48,16 @@ * Window for changing the colors of board objects. * * @author Alfons Wirtz + * @version $Id: $Id */ public class ColorManager extends BoardSavableSubWindow { - /** Creates a new instance of ColorManager */ + /** + * Creates a new instance of ColorManager + * + * @param p_board_frame a {@link gui.BoardFrame} object. + */ public ColorManager(BoardFrame p_board_frame) { GraphicsContext graphics_context = p_board_frame.board_panel.board_handling.graphics_context; @@ -82,6 +87,8 @@ public ColorManager(BoardFrame p_board_frame) /** * Reassigns the table model variables because they may have changed in p_graphics_context. + * + * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object. */ public void set_table_models(GraphicsContext p_graphics_context) { diff --git a/gui/ComboBoxClearance.java b/src/main/java/gui/ComboBoxClearance.java similarity index 90% rename from gui/ComboBoxClearance.java rename to src/main/java/gui/ComboBoxClearance.java index 1c32058..3521e12 100644 --- a/gui/ComboBoxClearance.java +++ b/src/main/java/gui/ComboBoxClearance.java @@ -25,11 +25,16 @@ * A Combo Box with an item for each clearance class of the board.. * * @author alfons + * @version $Id: $Id */ public class ComboBoxClearance extends javax.swing.JComboBox { - /** Creates a new instance of ClearanceComboBox */ + /** + * Creates a new instance of ClearanceComboBox + * + * @param p_clearance_matrix a {@link rules.ClearanceMatrix} object. + */ public ComboBoxClearance(ClearanceMatrix p_clearance_matrix) { this.class_arr = new ClearanceClass [p_clearance_matrix.get_class_count()]; @@ -43,6 +48,8 @@ public ComboBoxClearance(ClearanceMatrix p_clearance_matrix) /** * Adjusts this combo box to p_new_clearance_matrix. + * + * @param p_new_clearance_matrix a {@link rules.ClearanceMatrix} object. */ public void adjust(ClearanceMatrix p_new_clearance_matrix) { @@ -58,6 +65,8 @@ public void adjust(ClearanceMatrix p_new_clearance_matrix) /** * Returns the index of the selected clearance class in the clearance matrix. + * + * @return a int. */ public int get_selected_class_index() { @@ -66,6 +75,8 @@ public int get_selected_class_index() /** * Returns the number of clearance classes in this combo box. + * + * @return a int. */ public int get_class_count() { diff --git a/gui/ComboBoxLayer.java b/src/main/java/gui/ComboBoxLayer.java similarity index 90% rename from gui/ComboBoxLayer.java rename to src/main/java/gui/ComboBoxLayer.java index 5af3a84..ab33d72 100644 --- a/gui/ComboBoxLayer.java +++ b/src/main/java/gui/ComboBoxLayer.java @@ -25,11 +25,17 @@ * A Combo Box with items for individuell board layers plus an additional item for all layers. * * @author Alfons Wirtz + * @version $Id: $Id */ public class ComboBoxLayer extends javax.swing.JComboBox { - /** Creates a new instance of LayerComboBox */ + /** + * Creates a new instance of LayerComboBox + * + * @param p_layer_structure a {@link board.LayerStructure} object. + * @param p_locale a {@link java.util.Locale} object. + */ public ComboBoxLayer(LayerStructure p_layer_structure, java.util.Locale p_locale) { java.util.ResourceBundle resources = @@ -59,6 +65,11 @@ public ComboBoxLayer(LayerStructure p_layer_structure, java.util.Locale p_locale this.setSelectedIndex(0); } + /** + *

get_selected_layer.

+ * + * @return a {@link gui.ComboBoxLayer.Layer} object. + */ public Layer get_selected_layer() { return (Layer) this.getSelectedItem(); diff --git a/gui/Cursor.java b/src/main/java/gui/Cursor.java similarity index 86% rename from gui/Cursor.java rename to src/main/java/gui/Cursor.java index be69aa2..afa73fe 100644 --- a/gui/Cursor.java +++ b/src/main/java/gui/Cursor.java @@ -1,101 +1,123 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * Cursor.java - * - * Created on 17. Maerz 2006, 06:52 - * - */ - -package gui; - -import java.awt.AlphaComposite; -import java.awt.BasicStroke; -import java.awt.Graphics; -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.RenderingHints; - -import java.awt.geom.GeneralPath; -import java.awt.geom.Point2D; -import java.awt.geom.Line2D; - - -/** - * - * @author Alfons Wirtz - */ -public abstract class Cursor -{ - - public static Cursor get_45_degree_cross_hair_cursor() - { - return new FortyfiveDegreeCrossHairCursor(); - } - - public abstract void draw(Graphics p_graphics); - - public void set_location(Point2D p_location) - { - this.x_coor = p_location.getX(); - this.y_coor = p_location.getY(); - location_initialized = true; - } - - protected static void init_graphics(Graphics2D p_graphics) - { - BasicStroke bs = new BasicStroke(0, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND); - p_graphics.setStroke(bs); - p_graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - p_graphics.setColor(Color.WHITE); - p_graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1)); - } - - double x_coor; - double y_coor; - - boolean location_initialized = false; - - private static final double MAX_COOR = 1000; - - private static Line2D VERTICAL_LINE = new Line2D.Double(0, -MAX_COOR, 0, MAX_COOR); - private static Line2D HORIZONTAL_LINE = new Line2D.Double(-MAX_COOR, 0, MAX_COOR, 0); - private static Line2D RIGHT_DIAGONAL_LINE = new Line2D.Double(-MAX_COOR, -MAX_COOR, MAX_COOR, MAX_COOR); - private static Line2D LEFT_DIAGONAL_LINE = new Line2D.Double(-MAX_COOR, MAX_COOR, MAX_COOR, -MAX_COOR); - - - private static class FortyfiveDegreeCrossHairCursor extends Cursor - { - - public void draw(Graphics p_graphics) - { - - if (!location_initialized) - { - return; - } - Graphics2D g2 = (Graphics2D)p_graphics; - init_graphics(g2); - GeneralPath draw_path = new GeneralPath(GeneralPath.WIND_EVEN_ODD); - draw_path.append(VERTICAL_LINE, false); - draw_path.append(HORIZONTAL_LINE, false); - draw_path.append(RIGHT_DIAGONAL_LINE, false); - draw_path.append(LEFT_DIAGONAL_LINE, false); - g2.translate(this.x_coor, this.y_coor); - g2.draw(draw_path); - } - } - -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * Cursor.java + * + * Created on 17. Maerz 2006, 06:52 + * + */ + +package gui; + +import java.awt.AlphaComposite; +import java.awt.BasicStroke; +import java.awt.Graphics; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.RenderingHints; + +import java.awt.geom.GeneralPath; +import java.awt.geom.Point2D; +import java.awt.geom.Line2D; + + +/** + *

Abstract Cursor class.

+ * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public abstract class Cursor +{ + + /** + *

get_45_degree_cross_hair_cursor.

+ * + * @return a {@link gui.Cursor} object. + */ + public static Cursor get_45_degree_cross_hair_cursor() + { + return new FortyfiveDegreeCrossHairCursor(); + } + + /** + *

draw.

+ * + * @param p_graphics a {@link java.awt.Graphics} object. + */ + public abstract void draw(Graphics p_graphics); + + /** + *

set_location.

+ * + * @param p_location a java$awt$geom$Point2D object. + */ + public void set_location(Point2D p_location) + { + this.x_coor = p_location.getX(); + this.y_coor = p_location.getY(); + location_initialized = true; + } + + /** + *

init_graphics.

+ * + * @param p_graphics a {@link java.awt.Graphics2D} object. + */ + protected static void init_graphics(Graphics2D p_graphics) + { + BasicStroke bs = new BasicStroke(0, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND); + p_graphics.setStroke(bs); + p_graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + p_graphics.setColor(Color.WHITE); + p_graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1)); + } + + double x_coor; + double y_coor; + + boolean location_initialized = false; + + private static final double MAX_COOR = 1000; + + private static Line2D VERTICAL_LINE = new Line2D.Double(0, -MAX_COOR, 0, MAX_COOR); + private static Line2D HORIZONTAL_LINE = new Line2D.Double(-MAX_COOR, 0, MAX_COOR, 0); + private static Line2D RIGHT_DIAGONAL_LINE = new Line2D.Double(-MAX_COOR, -MAX_COOR, MAX_COOR, MAX_COOR); + private static Line2D LEFT_DIAGONAL_LINE = new Line2D.Double(-MAX_COOR, MAX_COOR, MAX_COOR, -MAX_COOR); + + + private static class FortyfiveDegreeCrossHairCursor extends Cursor + { + + public void draw(Graphics p_graphics) + { + + if (!location_initialized) + { + return; + } + Graphics2D g2 = (Graphics2D)p_graphics; + init_graphics(g2); + GeneralPath draw_path = new GeneralPath(GeneralPath.WIND_EVEN_ODD); + draw_path.append(VERTICAL_LINE, false); + draw_path.append(HORIZONTAL_LINE, false); + draw_path.append(RIGHT_DIAGONAL_LINE, false); + draw_path.append(LEFT_DIAGONAL_LINE, false); + g2.translate(this.x_coor, this.y_coor); + g2.draw(draw_path); + } + } + +} diff --git a/src/main/java/gui/DesignFile.java b/src/main/java/gui/DesignFile.java new file mode 100644 index 0000000..8ae740e --- /dev/null +++ b/src/main/java/gui/DesignFile.java @@ -0,0 +1,393 @@ +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * DesignFile.java + * + * Created on 25. Oktober 2006, 07:48 + * + */ +package gui; + +import datastructures.FileFilter; + +/** + * File functionality with security restrictions used, when the application is + * opened with Java Webstart + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class DesignFile { + + /** Constant all_file_extensions="{bin, dsn}" */ + public static final String[] all_file_extensions = { "bin", "dsn" }; + /** Constant text_file_extensions="{dsn}" */ + public static final String[] text_file_extensions = { "dsn" }; + /** Constant binary_file_extension="bin" */ + public static final String binary_file_extension = "bin"; + + /** + *

+ * get_instance. + *

+ * + * @param p_design_file_name a {@link java.lang.String} object. + * @return a {@link gui.DesignFile} object. + */ + public static DesignFile get_instance(String p_design_file_name) { + if (p_design_file_name == null) { + return null; + } + DesignFile result = new DesignFile(new java.io.File(p_design_file_name), null); + return result; + } + + /** + * Shows a file chooser for opening a design file. If p_is_webstart there are + * security restrictions because the application was opened with java web start. + * + * @param p_design_dir_name a {@link java.lang.String} object. + * @return a {@link gui.DesignFile} object. + */ + public static DesignFile open_dialog(String p_design_dir_name) { + DesignFile result; + javax.swing.JFileChooser file_chooser = new javax.swing.JFileChooser(p_design_dir_name); + FileFilter file_filter = new FileFilter(all_file_extensions); + file_chooser.setFileFilter(file_filter); + file_chooser.showOpenDialog(null); + java.io.File curr_design_file = file_chooser.getSelectedFile(); + if (curr_design_file == null) { + return null; + } + result = new DesignFile(curr_design_file, file_chooser); + return result; + } + + /** + * Creates a new instance of DesignFile. If p_is_webstart, the application was + * opened with Java Web Start. + */ + private DesignFile(java.io.File p_design_file, + javax.swing.JFileChooser p_file_chooser) { + this.file_chooser = p_file_chooser; + this.input_file = p_design_file; + this.output_file = p_design_file; + if (p_design_file != null) { + String file_name = p_design_file.getName(); + String[] name_parts = file_name.split("\\."); + if (name_parts[name_parts.length - 1].compareToIgnoreCase(binary_file_extension) != 0) { + String binfile_name = name_parts[0] + "." + binary_file_extension; + this.output_file = new java.io.File(p_design_file.getParent(), binfile_name); + } + } + } + + /** + * Gets an InputStream from the file. Returns null, if the algorithm failed. + * + * @return a java$io$InputStream object. + */ + public java.io.InputStream get_input_stream() { + java.io.InputStream result; + if (this.input_file == null) { + return null; + } + try { + result = new java.io.FileInputStream(this.input_file); + } catch (Exception e) { + result = null; + } + return result; + } + + /** + * Gets the file name as a String. Returns null on failure. + * + * @return a {@link java.lang.String} object. + */ + public String get_name() { + + String result; + if (this.input_file != null) { + result = this.input_file.getName(); + } else { + result = null; + } + return result; + } + + /** + *

+ * save_as_dialog. + *

+ * + * @param p_parent a {@link java.awt.Component} object. + * @param p_board_frame a {@link gui.BoardFrame} object. + */ + public void save_as_dialog(java.awt.Component p_parent, BoardFrame p_board_frame) { + final java.util.ResourceBundle resources = java.util.ResourceBundle.getBundle("gui.resources.BoardMenuFile", + p_board_frame.get_locale()); + String[] file_name_parts = this.get_name().split("\\.", 2); + String design_name = file_name_parts[0]; + + if (this.file_chooser == null) { + String design_dir_name; + if (this.output_file == null) { + design_dir_name = null; + } else { + design_dir_name = this.output_file.getParent(); + } + this.file_chooser = new javax.swing.JFileChooser(design_dir_name); + FileFilter file_filter = new FileFilter(all_file_extensions); + this.file_chooser.setFileFilter(file_filter); + } + + this.file_chooser.showSaveDialog(p_parent); + java.io.File new_file = file_chooser.getSelectedFile(); + if (new_file == null) { + p_board_frame.screen_messages.set_status_message(resources.getString("message_1")); + return; + } + String new_file_name = new_file.getName(); + String[] new_name_parts = new_file_name.split("\\."); + String found_file_extension = new_name_parts[new_name_parts.length - 1]; + if (found_file_extension.compareToIgnoreCase(binary_file_extension) == 0) { + p_board_frame.screen_messages + .set_status_message(resources.getString("message_2") + " " + new_file.getName()); + this.output_file = new_file; + p_board_frame.save(); + } else { + if (found_file_extension.compareToIgnoreCase("dsn") != 0) { + p_board_frame.screen_messages.set_status_message(resources.getString("message_3")); + return; + } + java.io.OutputStream output_stream; + try { + output_stream = new java.io.FileOutputStream(new_file); + } catch (Exception e) { + output_stream = null; + } + if (p_board_frame.board_panel.board_handling.export_to_dsn_file(output_stream, design_name, false)) { + p_board_frame.screen_messages.set_status_message(resources.getString("message_4") + " " + new_file_name + + " " + resources.getString("message_5")); + } else { + p_board_frame.screen_messages.set_status_message(resources.getString("message_6") + " " + new_file_name + + " " + resources.getString("message_7")); + } + } + } + + /** + * Writes a Specctra Session File to update the design file in the host system. + * Returns false, if the write failed + * + * @param p_board_frame a {@link gui.BoardFrame} object. + * @return a boolean. + */ + public boolean write_specctra_session_file(BoardFrame p_board_frame) { + final java.util.ResourceBundle resources = java.util.ResourceBundle.getBundle("gui.resources.BoardMenuFile", + p_board_frame.get_locale()); + String design_file_name = this.get_name(); + String[] file_name_parts = design_file_name.split("\\.", 2); + String design_name = file_name_parts[0]; + String output_file_name = design_name + ".ses"; + java.io.File curr_output_file = new java.io.File(get_parent(), output_file_name); + java.io.OutputStream output_stream; + try { + output_stream = new java.io.FileOutputStream(curr_output_file); + } catch (Exception e) { + output_stream = null; + } + + if (p_board_frame.board_panel.board_handling.export_specctra_session_file(design_file_name, output_stream)) { + p_board_frame.screen_messages.set_status_message(resources.getString("message_11") + " " + output_file_name + + " " + resources.getString("message_12")); + } else { + p_board_frame.screen_messages.set_status_message(resources.getString("message_13") + " " + output_file_name + + " " + resources.getString("message_7")); + return false; + } + if (WindowMessage.confirm(resources.getString("confirm"))) { + return write_rules_file(design_name, p_board_frame.board_panel.board_handling); + } + return true; + } + + /** + * Saves the board rule to file, so that they can be reused later on. + */ + private boolean write_rules_file(String p_design_name, interactive.BoardHandling p_board_handling) { + String rules_file_name = p_design_name + RULES_FILE_EXTENSION; + java.io.OutputStream output_stream; + java.io.File rules_file = new java.io.File(this.get_parent(), rules_file_name); + try { + output_stream = new java.io.FileOutputStream(rules_file); + } catch (java.io.IOException e) { + System.out.println("unable to create rules file"); + return false; + } + designformats.specctra.RulesFile.write(p_board_handling, output_stream, p_design_name); + return true; + } + + /** + *

+ * read_rules_file. + *

+ * + * @param p_design_name a {@link java.lang.String} object. + * @param p_parent_name a {@link java.lang.String} object. + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_is_web_start a boolean. + * @param p_confirm_message a {@link java.lang.String} object. + * @return a boolean. + */ + public static boolean read_rules_file(String p_design_name, String p_parent_name, + interactive.BoardHandling p_board_handling, boolean p_is_web_start, String p_confirm_message) { + + boolean result = true; + String rule_file_name = p_design_name + ".rules"; + boolean dsn_file_generated_by_host = p_board_handling + .get_routing_board().communication.specctra_parser_info.dsn_file_generated_by_host; + try { + java.io.File rules_file = new java.io.File(p_parent_name, rule_file_name); + java.io.InputStream input_stream = new java.io.FileInputStream(rules_file); + if (input_stream != null && dsn_file_generated_by_host && WindowMessage.confirm(p_confirm_message)) { + result = designformats.specctra.RulesFile.read(input_stream, p_design_name, p_board_handling); + } else { + result = false; + } + try { + if (input_stream != null) { + input_stream.close(); + } + rules_file.delete(); + } catch (java.io.IOException e) { + result = false; + } + } catch (java.io.FileNotFoundException e) { + result = false; + } + return result; + } + + /** + *

+ * update_eagle. + *

+ * + * @param p_board_frame a {@link gui.BoardFrame} object. + */ + public void update_eagle(BoardFrame p_board_frame) { + final java.util.ResourceBundle resources = java.util.ResourceBundle.getBundle("gui.resources.BoardMenuFile", + p_board_frame.get_locale()); + String design_file_name = get_name(); + java.io.ByteArrayOutputStream session_output_stream = new java.io.ByteArrayOutputStream(); + if (!p_board_frame.board_panel.board_handling.export_specctra_session_file(design_file_name, + session_output_stream)) { + return; + } + java.io.InputStream input_stream = new java.io.ByteArrayInputStream(session_output_stream.toByteArray()); + + String[] file_name_parts = design_file_name.split("\\.", 2); + String design_name = file_name_parts[0]; + String output_file_name = design_name + ".scr"; + java.io.File curr_output_file = new java.io.File(get_parent(), output_file_name); + java.io.OutputStream output_stream; + try { + output_stream = new java.io.FileOutputStream(curr_output_file); + } catch (Exception e) { + output_stream = null; + } + + if (p_board_frame.board_panel.board_handling.export_eagle_session_file(input_stream, output_stream)) { + p_board_frame.screen_messages.set_status_message(resources.getString("message_14") + " " + output_file_name + + " " + resources.getString("message_15")); + } else { + p_board_frame.screen_messages.set_status_message(resources.getString("message_16") + " " + output_file_name + + " " + resources.getString("message_7")); + } + if (WindowMessage.confirm(resources.getString("confirm"))) { + write_rules_file(design_name, p_board_frame.board_panel.board_handling); + } + } + + + + /** + * Gets the binary file for saving or null, if the design file is not available + * because the application is run with Java Web Start. + * + * @return a {@link java.io.File} object. + */ + public java.io.File get_output_file() { + return this.output_file; + } + + /** + *

+ * get_input_file. + *

+ * + * @return a {@link java.io.File} object. + */ + public java.io.File get_input_file() { + return this.input_file; + } + + /** + *

+ * get_parent. + *

+ * + * @return a {@link java.lang.String} object. + */ + public String get_parent() { + if (input_file != null) { + return input_file.getParent(); + } + return null; + } + + /** + *

+ * get_parent_file. + *

+ * + * @return a {@link java.io.File} object. + */ + public java.io.File get_parent_file() { + if (input_file != null) { + return input_file.getParentFile(); + } + return null; + } + + /** + *

+ * is_created_from_text_file. + *

+ * + * @return a boolean. + */ + public boolean is_created_from_text_file() { + return this.input_file != this.output_file; + } + + private java.io.File output_file; + private final java.io.File input_file; + private javax.swing.JFileChooser file_chooser; + private static final String RULES_FILE_EXTENSION = ".rules"; +} diff --git a/gui/GUIDefaultsDescription.flex b/src/main/java/gui/GUIDefaultsDescription.flex similarity index 100% rename from gui/GUIDefaultsDescription.flex rename to src/main/java/gui/GUIDefaultsDescription.flex diff --git a/gui/GUIDefaultsFile.java b/src/main/java/gui/GUIDefaultsFile.java similarity index 99% rename from gui/GUIDefaultsFile.java rename to src/main/java/gui/GUIDefaultsFile.java index 2002b1a..a988d58 100644 --- a/gui/GUIDefaultsFile.java +++ b/src/main/java/gui/GUIDefaultsFile.java @@ -28,6 +28,7 @@ * Description of a text file, where the board independent interactive settings are stored. * * @author Alfons Wirtz + * @version $Id: $Id */ public class GUIDefaultsFile { @@ -54,6 +55,11 @@ enum Keyword /** * Writes the GUI setting of p_board_frame as default to p_file. * Returns false, if an error occured. + * + * @param p_board_frame a {@link gui.BoardFrame} object. + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_output_stream a {@link java.io.OutputStream} object. + * @return a boolean. */ public static boolean write(gui.BoardFrame p_board_frame, interactive.BoardHandling p_board_handling, java.io.OutputStream p_output_stream) @@ -91,6 +97,11 @@ public static boolean write(gui.BoardFrame p_board_frame, /** * Reads the GUI setting of p_board_frame from file. * Returns false, if an error occured while reading the file. + * + * @param p_board_frame a {@link gui.BoardFrame} object. + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_input_stream a {@link java.io.InputStream} object. + * @return a boolean. */ public static boolean read(gui.BoardFrame p_board_frame, interactive.BoardHandling p_board_handling, java.io.InputStream p_input_stream) diff --git a/gui/GUIDefaultsScanner.java b/src/main/java/gui/GUIDefaultsScanner.java similarity index 95% rename from gui/GUIDefaultsScanner.java rename to src/main/java/gui/GUIDefaultsScanner.java index ad7be03..95e82a1 100644 --- a/gui/GUIDefaultsScanner.java +++ b/src/main/java/gui/GUIDefaultsScanner.java @@ -1,1683 +1,1690 @@ -/* The following code was generated by JFlex 1.4 on 16.03.07 09:07 */ - -package gui; -@SuppressWarnings("all") - -/** - * This class is a scanner generated by - * JFlex 1.4 - * on 16.03.07 09:07 from the specification file - * C:/Dokumente und Einstellungen/alfons/Eigene Dateien/router/sources/gui/GUIDefaultsDescription.flex - */ -class GUIDefaultsScanner { - - /** This character denotes the end of file */ - public static final int YYEOF = -1; - - /** initial size of the lookahead buffer */ - private static final int ZZ_BUFFERSIZE = 16384; - - /** lexical states */ - public static final int YYINITIAL = 0; - - /** - * Translates characters to character classes - */ - private static final String ZZ_CMAP_PACKED = - "\11\0\1\3\1\2\1\0\1\3\1\1\22\0\1\3\2\0\1\6"+ - "\4\0\1\45\1\46\1\5\1\11\1\0\1\11\1\13\1\4\1\12"+ - "\11\10\7\0\1\16\1\23\1\33\1\35\1\14\1\37\1\24\1\42"+ - "\1\21\1\43\1\36\1\17\1\32\1\25\1\31\1\40\1\7\1\27"+ - "\1\22\1\26\1\30\1\20\1\44\1\41\1\34\1\7\4\0\1\15"+ - "\1\0\1\16\1\23\1\33\1\35\1\14\1\37\1\24\1\42\1\21"+ - "\1\43\1\36\1\17\1\32\1\25\1\31\1\40\1\7\1\27\1\22"+ - "\1\26\1\30\1\20\1\44\1\41\1\34\1\7\uff85\0"; - - /** - * Translates characters to character classes - */ - private static final char [] ZZ_CMAP = zzUnpackCMap(ZZ_CMAP_PACKED); - - /** - * Translates DFA states to action switch labels. - */ - private static final int [] ZZ_ACTION = zzUnpackAction(); - - private static final String ZZ_ACTION_PACKED_0 = - "\1\0\1\1\2\2\2\1\1\3\1\4\1\1\1\4"+ - "\25\3\1\5\1\6\4\0\1\7\30\3\1\10\23\3"+ - "\2\0\2\7\1\0\1\7\36\3\1\11\26\3\1\0"+ - "\7\3\1\12\17\3\1\13\30\3\1\14\57\3\1\15"+ - "\35\3\1\16\4\3\1\17\12\3\1\20\32\3\1\21"+ - "\24\3\1\22\1\3\1\23\12\3\1\24\1\25\10\3"+ - "\1\26\1\27\27\3\1\30\33\3\1\31\7\3\1\32"+ - "\10\3\1\33\1\34\33\3\1\35\15\3\1\36\7\3"+ - "\1\37\5\3\1\40\12\3\1\41\5\3\1\42\10\3"+ - "\1\43\5\3\1\44\3\3\1\45\4\3\1\46\2\3"+ - "\1\47\51\3\1\50\7\3\1\51\4\3\1\52\11\3"+ - "\1\53\1\3\1\54\22\3\1\55\1\56\1\3\1\57"+ - "\2\3\1\60\4\3\1\61\1\62\11\3\1\63\4\3"+ - "\1\64\14\3\1\65\3\3\1\66\2\3\1\67\1\70"+ - "\1\71\2\3\1\72\11\3\1\73\2\3\1\74\6\3"+ - "\1\75\4\3\1\76\10\3\1\77\1\3\1\100\3\3"+ - "\1\101\1\102\1\103\1\104\2\3\1\105\4\3\1\106"+ - "\7\3\1\107\1\110\6\3\1\111\25\3\1\112\5\3"+ - "\1\113\13\3\1\114\4\3\1\115\1\3\1\116\2\3"+ - "\1\117\1\3\1\120\1\121\1\3\1\122\2\3\1\123"+ - "\5\3\1\124"; - - private static int [] zzUnpackAction() { - int [] result = new int[796]; - int offset = 0; - offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result); - return result; - } - - private static int zzUnpackAction(String packed, int offset, int [] result) { - int i = 0; /* index in packed string */ - int j = offset; /* index in unpacked array */ - int l = packed.length(); - while (i < l) { - int count = packed.charAt(i++); - int value = packed.charAt(i++); - do result[j++] = value; while (--count > 0); - } - return j; - } - - - /** - * Translates a state to a row index in the transition table - */ - private static final int [] ZZ_ROWMAP = zzUnpackRowMap(); - - private static final String ZZ_ROWMAP_PACKED_0 = - "\0\0\0\47\0\116\0\47\0\165\0\234\0\303\0\352"+ - "\0\u0111\0\u0138\0\u015f\0\u0186\0\u01ad\0\u01d4\0\u01fb\0\u0222"+ - "\0\u0249\0\u0270\0\u0297\0\u02be\0\u02e5\0\u030c\0\u0333\0\u035a"+ - "\0\u0381\0\u03a8\0\u03cf\0\u03f6\0\u041d\0\u0444\0\u046b\0\47"+ - "\0\47\0\u0492\0\234\0\u04b9\0\u04e0\0\u0138\0\u0507\0\u052e"+ - "\0\u0555\0\u057c\0\u05a3\0\u05ca\0\u05f1\0\u0618\0\u063f\0\u0666"+ - "\0\u068d\0\u06b4\0\u06db\0\u0702\0\u0729\0\u0750\0\u0777\0\u079e"+ - "\0\u07c5\0\u07ec\0\u0813\0\u083a\0\u0861\0\u0888\0\303\0\u08af"+ - "\0\u08d6\0\u08fd\0\u0924\0\u094b\0\u0972\0\u0999\0\u09c0\0\u09e7"+ - "\0\u0a0e\0\u0a35\0\u0a5c\0\u0a83\0\u0aaa\0\u0ad1\0\u0af8\0\u0b1f"+ - "\0\u0b46\0\u0b6d\0\u0b94\0\u0bbb\0\u0be2\0\u0c09\0\u0c30\0\47"+ - "\0\u0c57\0\u0c7e\0\u0ca5\0\u0ccc\0\u0cf3\0\u0d1a\0\u0d41\0\u0d68"+ - "\0\u0d8f\0\u0db6\0\u0ddd\0\u0e04\0\u0e2b\0\u0e52\0\u0e79\0\u0ea0"+ - "\0\u0ec7\0\u0eee\0\u0f15\0\u0f3c\0\u0f63\0\u0f8a\0\u0fb1\0\u0fd8"+ - "\0\u0fff\0\u1026\0\u104d\0\u1074\0\u109b\0\u10c2\0\303\0\u10e9"+ - "\0\u1110\0\u1137\0\u115e\0\u1185\0\u11ac\0\u11d3\0\u11fa\0\u1221"+ - "\0\u1248\0\u126f\0\u1296\0\u12bd\0\u12e4\0\u130b\0\u1332\0\u1359"+ - "\0\u1380\0\u13a7\0\u13ce\0\u13f5\0\u141c\0\u1443\0\u146a\0\u1491"+ - "\0\u14b8\0\u14df\0\u1506\0\u152d\0\u1554\0\303\0\u157b\0\u15a2"+ - "\0\u15c9\0\u15f0\0\u1617\0\u163e\0\u1665\0\u168c\0\u16b3\0\u16da"+ - "\0\u1701\0\u1728\0\u174f\0\u1776\0\u179d\0\303\0\u17c4\0\u17eb"+ - "\0\u1812\0\u1839\0\u1860\0\u1887\0\u18ae\0\u18d5\0\u18fc\0\u1923"+ - "\0\u194a\0\u1971\0\u1998\0\u19bf\0\u19e6\0\u1a0d\0\u1a34\0\u1a5b"+ - "\0\u1a82\0\u1aa9\0\u1ad0\0\u1af7\0\u1b1e\0\u1b45\0\303\0\u1b6c"+ - "\0\u1b93\0\u1bba\0\u1be1\0\u1c08\0\u1c2f\0\u1c56\0\u1c7d\0\u1ca4"+ - "\0\u1ccb\0\u1cf2\0\u1d19\0\u1d40\0\u1d67\0\u1d8e\0\u1db5\0\u1ddc"+ - "\0\u1e03\0\u1e2a\0\u1e51\0\u1e78\0\u1e9f\0\u1ec6\0\u1eed\0\u1f14"+ - "\0\u1f3b\0\u1f62\0\u1f89\0\u1fb0\0\u1fd7\0\u1ffe\0\u2025\0\u204c"+ - "\0\u2073\0\u209a\0\u20c1\0\u20e8\0\u210f\0\u2136\0\u215d\0\u2184"+ - "\0\u21ab\0\u21d2\0\u21f9\0\u2220\0\u2247\0\u226e\0\u2295\0\u22bc"+ - "\0\u22e3\0\u230a\0\u2331\0\u2358\0\u237f\0\u23a6\0\u23cd\0\u23f4"+ - "\0\u241b\0\u2442\0\u2469\0\u2490\0\u24b7\0\u24de\0\u2505\0\u252c"+ - "\0\u2553\0\u257a\0\u25a1\0\u25c8\0\u25ef\0\u2616\0\u263d\0\u2664"+ - "\0\u268b\0\u26b2\0\u26d9\0\u2700\0\303\0\u2727\0\u274e\0\u2775"+ - "\0\u279c\0\303\0\u27c3\0\u27ea\0\u2811\0\u2838\0\u285f\0\u2886"+ - "\0\u28ad\0\u28d4\0\u28fb\0\u2922\0\303\0\u2949\0\u2970\0\u2997"+ - "\0\u29be\0\u29e5\0\u2a0c\0\u2a33\0\u2a5a\0\u2a81\0\u2aa8\0\u2acf"+ - "\0\u2af6\0\u2b1d\0\u2b44\0\u2b6b\0\u2b92\0\u2bb9\0\u2be0\0\u2c07"+ - "\0\u2c2e\0\u2c55\0\u2c7c\0\u2ca3\0\u2cca\0\u2cf1\0\u2d18\0\303"+ - "\0\u2d3f\0\u2d66\0\u2d8d\0\u2db4\0\u2ddb\0\u2e02\0\u2e29\0\u2e50"+ - "\0\u2e77\0\u2e9e\0\u2ec5\0\u2eec\0\u2f13\0\u2f3a\0\u2f61\0\u2f88"+ - "\0\u2faf\0\u2fd6\0\u2ffd\0\u3024\0\303\0\u304b\0\303\0\u3072"+ - "\0\u3099\0\u30c0\0\u30e7\0\u310e\0\u3135\0\u315c\0\u3183\0\u31aa"+ - "\0\u31d1\0\303\0\303\0\u31f8\0\u321f\0\u3246\0\u326d\0\u3294"+ - "\0\u32bb\0\u32e2\0\u3309\0\u3330\0\303\0\u3357\0\u337e\0\u33a5"+ - "\0\u33cc\0\u33f3\0\u341a\0\u3441\0\u3468\0\u348f\0\u34b6\0\u34dd"+ - "\0\u3504\0\u352b\0\u3552\0\u3579\0\u35a0\0\u35c7\0\u35ee\0\u3615"+ - "\0\u363c\0\u3663\0\u368a\0\u36b1\0\303\0\u36d8\0\u36ff\0\u3726"+ - "\0\u374d\0\u3774\0\u379b\0\u37c2\0\u37e9\0\u3810\0\u3837\0\u385e"+ - "\0\u3885\0\u38ac\0\u38d3\0\u38fa\0\u3921\0\u3948\0\u396f\0\u3996"+ - "\0\u39bd\0\u39e4\0\u3a0b\0\u3a32\0\u3a59\0\u3a80\0\u3aa7\0\u3ace"+ - "\0\303\0\u3af5\0\u3b1c\0\u3b43\0\u3b6a\0\u3b91\0\u3bb8\0\u3bdf"+ - "\0\303\0\u3c06\0\u3c2d\0\u3c54\0\u3c7b\0\u3ca2\0\u3cc9\0\u3cf0"+ - "\0\u3d17\0\303\0\303\0\u3d3e\0\u3d65\0\u3d8c\0\u3db3\0\u3dda"+ - "\0\u3e01\0\u3e28\0\u3e4f\0\u3e76\0\u3e9d\0\u3ec4\0\u3eeb\0\u3f12"+ - "\0\u3f39\0\u3f60\0\u3f87\0\u3fae\0\u3fd5\0\u3ffc\0\u4023\0\u404a"+ - "\0\u4071\0\u4098\0\u40bf\0\u40e6\0\u410d\0\u4134\0\303\0\u415b"+ - "\0\u4182\0\u41a9\0\u41d0\0\u41f7\0\u421e\0\u4245\0\u426c\0\u4293"+ - "\0\u42ba\0\u42e1\0\u4308\0\u432f\0\u4356\0\u437d\0\u43a4\0\u43cb"+ - "\0\u43f2\0\u4419\0\u4440\0\u4467\0\303\0\u448e\0\u44b5\0\u44dc"+ - "\0\u4503\0\u452a\0\303\0\u4551\0\u4578\0\u459f\0\u45c6\0\u45ed"+ - "\0\u4614\0\u463b\0\u4662\0\u4689\0\u46b0\0\303\0\u46d7\0\u46fe"+ - "\0\u4725\0\u474c\0\u4773\0\303\0\u479a\0\u47c1\0\u47e8\0\u480f"+ - "\0\u4836\0\u485d\0\u4884\0\u48ab\0\303\0\u48d2\0\u48f9\0\u4920"+ - "\0\u4947\0\u496e\0\303\0\u4995\0\u49bc\0\u49e3\0\u4a0a\0\u4a31"+ - "\0\u4a58\0\u4a7f\0\u4aa6\0\303\0\u4acd\0\u4af4\0\303\0\u4b1b"+ - "\0\u4b42\0\u4b69\0\u4b90\0\u4bb7\0\u4bde\0\u4c05\0\u4c2c\0\u4c53"+ - "\0\u4c7a\0\u4ca1\0\u4cc8\0\u4cef\0\u4d16\0\u4d3d\0\u4d64\0\u4d8b"+ - "\0\u4db2\0\u4dd9\0\u4e00\0\u4e27\0\u4e4e\0\u4e75\0\u4e9c\0\u4ec3"+ - "\0\u4eea\0\u4f11\0\u4f38\0\u4f5f\0\u4f86\0\u4fad\0\u4fd4\0\u4ffb"+ - "\0\u5022\0\u5049\0\u5070\0\u5097\0\u50be\0\u50e5\0\u510c\0\u5133"+ - "\0\303\0\u515a\0\u5181\0\u51a8\0\u51cf\0\u51f6\0\u521d\0\u5244"+ - "\0\303\0\u526b\0\u5292\0\u52b9\0\u52e0\0\303\0\u5307\0\u532e"+ - "\0\u5355\0\u537c\0\u53a3\0\u53ca\0\u53f1\0\u5418\0\u543f\0\303"+ - "\0\u5466\0\303\0\u548d\0\u54b4\0\u54db\0\u5502\0\u5529\0\u5550"+ - "\0\u5577\0\u559e\0\u55c5\0\u55ec\0\u5613\0\u563a\0\u5661\0\u5688"+ - "\0\u56af\0\u56d6\0\u56fd\0\u5724\0\303\0\303\0\u574b\0\303"+ - "\0\u5772\0\u5799\0\303\0\u57c0\0\u57e7\0\u580e\0\u5835\0\303"+ - "\0\303\0\u585c\0\u5883\0\u58aa\0\u58d1\0\u58f8\0\u591f\0\u5946"+ - "\0\u596d\0\u5994\0\303\0\u59bb\0\u59e2\0\u5a09\0\u5a30\0\303"+ - "\0\u5a57\0\u5a7e\0\u5aa5\0\u5acc\0\u5af3\0\u5b1a\0\u5b41\0\u5b68"+ - "\0\u5b8f\0\u5bb6\0\u5bdd\0\u5c04\0\303\0\u5c2b\0\u5c52\0\u5c79"+ - "\0\303\0\u5ca0\0\u5cc7\0\303\0\303\0\303\0\u5cee\0\u5d15"+ - "\0\303\0\u5d3c\0\u5d63\0\u5d8a\0\u5db1\0\u5dd8\0\u5dff\0\u5e26"+ - "\0\u5e4d\0\u5e74\0\303\0\u5e9b\0\u5ec2\0\303\0\u5ee9\0\u5f10"+ - "\0\u5f37\0\u5f5e\0\u5f85\0\u5fac\0\303\0\u5fd3\0\u5ffa\0\u6021"+ - "\0\u6048\0\303\0\u606f\0\u6096\0\u60bd\0\u60e4\0\u610b\0\u6132"+ - "\0\u6159\0\u6180\0\303\0\u61a7\0\303\0\u61ce\0\u61f5\0\u621c"+ - "\0\303\0\303\0\303\0\303\0\u6243\0\u626a\0\303\0\u6291"+ - "\0\u62b8\0\u62df\0\u6306\0\303\0\u632d\0\u6354\0\u637b\0\u63a2"+ - "\0\u63c9\0\u63f0\0\u6417\0\303\0\303\0\u643e\0\u6465\0\u648c"+ - "\0\u64b3\0\u64da\0\u6501\0\303\0\u6528\0\u654f\0\u6576\0\u659d"+ - "\0\u65c4\0\u65eb\0\u6612\0\u6639\0\u6660\0\u6687\0\u66ae\0\u66d5"+ - "\0\u66fc\0\u6723\0\u674a\0\u6771\0\u6798\0\u67bf\0\u67e6\0\u680d"+ - "\0\u6834\0\303\0\u685b\0\u6882\0\u68a9\0\u68d0\0\u68f7\0\303"+ - "\0\u691e\0\u6945\0\u696c\0\u6993\0\u69ba\0\u69e1\0\u6a08\0\u6a2f"+ - "\0\u6a56\0\u6a7d\0\u6aa4\0\303\0\u6acb\0\u6af2\0\u6b19\0\u6b40"+ - "\0\303\0\u6b67\0\303\0\u6b8e\0\u6bb5\0\303\0\u6bdc\0\303"+ - "\0\303\0\u6c03\0\303\0\u6c2a\0\u6c51\0\303\0\u6c78\0\u6c9f"+ - "\0\u6cc6\0\u6ced\0\u6d14\0\303"; - - private static int [] zzUnpackRowMap() { - int [] result = new int[796]; - int offset = 0; - offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result); - return result; - } - - private static int zzUnpackRowMap(String packed, int offset, int [] result) { - int i = 0; /* index in packed string */ - int j = offset; /* index in unpacked array */ - int l = packed.length(); - while (i < l) { - int high = packed.charAt(i++) << 16; - result[j++] = high | packed.charAt(i++); - } - return j; - } - - /** - * The transition table of the DFA - */ - private static final int [] ZZ_TRANS = zzUnpackTrans(); - - private static final String ZZ_TRANS_PACKED_0 = - "\1\2\1\3\2\4\1\5\1\2\1\6\1\7\1\10"+ - "\1\11\1\12\1\2\1\13\1\7\1\14\1\15\1\16"+ - "\1\17\1\20\1\21\1\22\1\23\1\24\1\25\1\26"+ - "\1\27\1\30\1\31\1\7\1\32\1\33\1\34\1\35"+ - "\1\7\1\36\1\7\1\37\1\40\1\41\51\0\1\4"+ - "\51\0\1\42\41\0\1\43\1\3\1\4\44\43\7\0"+ - "\2\7\1\0\1\7\1\0\31\7\12\0\1\10\1\0"+ - "\1\10\1\44\1\45\42\0\1\10\1\0\1\12\44\0"+ - "\1\46\1\0\1\46\1\44\1\45\41\0\2\7\1\0"+ - "\1\7\1\0\21\7\1\47\7\7\11\0\2\7\1\0"+ - "\1\7\1\0\3\7\1\50\2\7\1\51\5\7\1\52"+ - "\14\7\11\0\2\7\1\0\1\7\1\0\1\53\1\7"+ - "\1\54\26\7\11\0\2\7\1\0\1\7\1\0\5\7"+ - "\1\55\23\7\11\0\2\7\1\0\1\7\1\0\10\7"+ - "\1\56\1\57\17\7\11\0\2\7\1\0\1\7\1\0"+ - "\1\60\10\7\1\61\1\62\13\7\1\63\2\7\11\0"+ - "\2\7\1\0\1\7\1\0\2\7\1\64\12\7\1\65"+ - "\13\7\11\0\2\7\1\0\1\7\1\0\14\7\1\66"+ - "\14\7\11\0\2\7\1\0\1\7\1\0\1\67\4\7"+ - "\1\70\7\7\1\71\13\7\11\0\2\7\1\0\1\7"+ - "\1\0\13\7\1\72\15\7\11\0\2\7\1\0\1\7"+ - "\1\0\14\7\1\73\1\74\13\7\11\0\2\7\1\0"+ - "\1\7\1\0\11\7\1\75\17\7\11\0\2\7\1\0"+ - "\1\7\1\0\7\7\1\76\1\7\1\77\2\7\1\100"+ - "\6\7\1\101\5\7\11\0\2\7\1\0\1\7\1\0"+ - "\2\7\1\102\12\7\1\103\13\7\11\0\2\7\1\0"+ - "\1\7\1\0\3\7\1\104\10\7\1\105\1\106\13\7"+ - "\11\0\2\7\1\0\1\7\1\0\1\107\4\7\1\110"+ - "\5\7\1\111\4\7\1\112\10\7\11\0\2\7\1\0"+ - "\1\7\1\0\1\113\30\7\11\0\2\7\1\0\1\7"+ - "\1\0\5\7\1\114\7\7\1\115\13\7\11\0\2\7"+ - "\1\0\1\7\1\0\2\7\1\116\2\7\1\117\6\7"+ - "\1\120\14\7\11\0\2\7\1\0\1\7\1\0\5\7"+ - "\1\121\23\7\11\0\2\7\1\0\1\7\1\0\5\7"+ - "\1\122\23\7\2\0\5\123\1\124\41\123\10\0\1\125"+ - "\1\0\1\125\44\0\1\126\1\127\1\130\43\0\2\7"+ - "\1\0\1\7\1\0\5\7\1\131\23\7\11\0\2\7"+ - "\1\0\1\7\1\0\3\7\1\132\25\7\11\0\2\7"+ - "\1\0\1\7\1\0\6\7\1\133\22\7\11\0\2\7"+ - "\1\0\1\7\1\0\12\7\1\134\16\7\11\0\2\7"+ - "\1\0\1\7\1\0\11\7\1\135\17\7\11\0\2\7"+ - "\1\0\1\7\1\0\20\7\1\136\10\7\11\0\2\7"+ - "\1\0\1\7\1\0\2\7\1\137\3\7\1\140\6\7"+ - "\1\141\13\7\11\0\2\7\1\0\1\7\1\0\11\7"+ - "\1\142\17\7\11\0\2\7\1\0\1\7\1\0\12\7"+ - "\1\143\4\7\1\144\11\7\11\0\2\7\1\0\1\7"+ - "\1\0\3\7\1\145\25\7\11\0\2\7\1\0\1\7"+ - "\1\0\2\7\1\146\26\7\11\0\2\7\1\0\1\7"+ - "\1\0\5\7\1\147\23\7\11\0\2\7\1\0\1\7"+ - "\1\0\15\7\1\150\13\7\11\0\2\7\1\0\1\7"+ - "\1\0\17\7\1\151\11\7\11\0\2\7\1\0\1\7"+ - "\1\0\2\7\1\152\11\7\1\153\14\7\11\0\2\7"+ - "\1\0\1\7\1\0\5\7\1\154\23\7\11\0\2\7"+ - "\1\0\1\7\1\0\12\7\1\155\16\7\11\0\2\7"+ - "\1\0\1\7\1\0\11\7\1\156\17\7\11\0\2\7"+ - "\1\0\1\7\1\0\11\7\1\157\1\160\16\7\11\0"+ - "\2\7\1\0\1\7\1\0\2\7\1\161\26\7\11\0"+ - "\2\7\1\0\1\7\1\0\3\7\1\162\25\7\11\0"+ - "\2\7\1\0\1\7\1\0\14\7\1\163\14\7\11\0"+ - "\2\7\1\0\1\7\1\0\23\7\1\164\5\7\11\0"+ - "\2\7\1\0\1\7\1\0\27\7\1\165\1\7\11\0"+ - "\2\7\1\0\1\7\1\0\12\7\1\166\16\7\11\0"+ - "\2\7\1\0\1\7\1\0\23\7\1\167\5\7\11\0"+ - "\2\7\1\0\1\7\1\0\11\7\1\170\17\7\11\0"+ - "\2\7\1\0\1\7\1\0\4\7\1\171\24\7\11\0"+ - "\2\7\1\0\1\7\1\0\1\172\30\7\11\0\2\7"+ - "\1\0\1\7\1\0\13\7\1\173\15\7\11\0\2\7"+ - "\1\0\1\7\1\0\3\7\1\174\5\7\1\175\4\7"+ - "\1\176\12\7\11\0\2\7\1\0\1\7\1\0\6\7"+ - "\1\177\22\7\11\0\2\7\1\0\1\7\1\0\6\7"+ - "\1\200\22\7\11\0\2\7\1\0\1\7\1\0\2\7"+ - "\1\201\26\7\11\0\2\7\1\0\1\7\1\0\11\7"+ - "\1\202\17\7\11\0\2\7\1\0\1\7\1\0\1\203"+ - "\30\7\11\0\2\7\1\0\1\7\1\0\25\7\1\204"+ - "\3\7\11\0\2\7\1\0\1\7\1\0\13\7\1\205"+ - "\15\7\11\0\2\7\1\0\1\7\1\0\13\7\1\206"+ - "\3\7\1\207\1\7\1\210\7\7\11\0\2\7\1\0"+ - "\1\7\1\0\11\7\1\211\17\7\11\0\2\7\1\0"+ - "\1\7\1\0\3\7\1\212\2\7\1\213\22\7\11\0"+ - "\2\7\1\0\1\7\1\0\3\7\1\214\25\7\11\0"+ - "\2\7\1\0\1\7\1\0\11\7\1\215\17\7\2\0"+ - "\5\123\1\216\41\123\4\0\1\4\1\124\51\0\1\125"+ - "\1\0\1\125\1\0\1\45\42\0\1\126\1\0\1\126"+ - "\44\0\1\126\1\0\1\130\43\0\2\7\1\0\1\7"+ - "\1\0\12\7\1\217\16\7\11\0\2\7\1\0\1\7"+ - "\1\0\1\7\1\220\27\7\11\0\2\7\1\0\1\7"+ - "\1\0\5\7\1\221\23\7\11\0\2\7\1\0\1\7"+ - "\1\0\15\7\1\222\13\7\11\0\2\7\1\0\1\7"+ - "\1\0\10\7\1\223\20\7\11\0\2\7\1\0\1\7"+ - "\1\0\1\224\30\7\11\0\2\7\1\0\1\7\1\0"+ - "\1\7\1\225\4\7\1\226\22\7\11\0\2\7\1\0"+ - "\1\7\1\0\5\7\1\227\23\7\11\0\2\7\1\0"+ - "\1\7\1\0\3\7\1\230\25\7\11\0\2\7\1\0"+ - "\1\7\1\0\15\7\1\231\13\7\11\0\2\7\1\0"+ - "\1\7\1\0\1\232\30\7\11\0\2\7\1\0\1\7"+ - "\1\0\15\7\1\233\13\7\11\0\2\7\1\0\1\7"+ - "\1\0\1\234\30\7\11\0\2\7\1\0\1\7\1\0"+ - "\24\7\1\235\4\7\11\0\2\7\1\0\1\7\1\0"+ - "\12\7\1\236\16\7\11\0\2\7\1\0\1\7\1\0"+ - "\4\7\1\237\24\7\11\0\2\7\1\0\1\7\1\0"+ - "\22\7\1\240\6\7\11\0\2\7\1\0\1\7\1\0"+ - "\13\7\1\241\15\7\11\0\2\7\1\0\1\7\1\0"+ - "\11\7\1\242\17\7\11\0\2\7\1\0\1\7\1\0"+ - "\1\7\1\243\27\7\11\0\2\7\1\0\1\7\1\0"+ - "\1\7\1\244\27\7\11\0\2\7\1\0\1\7\1\0"+ - "\1\245\30\7\11\0\2\7\1\0\1\7\1\0\1\246"+ - "\30\7\11\0\2\7\1\0\1\7\1\0\1\7\1\247"+ - "\27\7\11\0\2\7\1\0\1\7\1\0\17\7\1\250"+ - "\11\7\11\0\2\7\1\0\1\7\1\0\1\251\30\7"+ - "\11\0\2\7\1\0\1\7\1\0\12\7\1\252\16\7"+ - "\11\0\2\7\1\0\1\7\1\0\5\7\1\253\23\7"+ - "\11\0\2\7\1\0\1\7\1\0\1\254\30\7\11\0"+ - "\2\7\1\0\1\7\1\0\3\7\1\255\25\7\11\0"+ - "\2\7\1\0\1\7\1\0\14\7\1\256\14\7\11\0"+ - "\2\7\1\0\1\7\1\0\1\257\30\7\11\0\2\7"+ - "\1\0\1\7\1\0\2\7\1\260\26\7\11\0\2\7"+ - "\1\0\1\7\1\0\13\7\1\261\15\7\11\0\2\7"+ - "\1\0\1\7\1\0\15\7\1\262\13\7\11\0\2\7"+ - "\1\0\1\7\1\0\21\7\1\263\7\7\11\0\2\7"+ - "\1\0\1\7\1\0\24\7\1\264\4\7\11\0\2\7"+ - "\1\0\1\7\1\0\1\265\30\7\11\0\2\7\1\0"+ - "\1\7\1\0\24\7\1\266\4\7\11\0\2\7\1\0"+ - "\1\7\1\0\10\7\1\267\20\7\11\0\2\7\1\0"+ - "\1\7\1\0\2\7\1\270\26\7\11\0\2\7\1\0"+ - "\1\7\1\0\24\7\1\271\4\7\11\0\2\7\1\0"+ - "\1\7\1\0\1\272\30\7\11\0\2\7\1\0\1\7"+ - "\1\0\12\7\1\273\16\7\11\0\2\7\1\0\1\7"+ - "\1\0\2\7\1\274\26\7\11\0\2\7\1\0\1\7"+ - "\1\0\22\7\1\275\6\7\11\0\2\7\1\0\1\7"+ - "\1\0\6\7\1\276\22\7\11\0\2\7\1\0\1\7"+ - "\1\0\6\7\1\277\22\7\11\0\2\7\1\0\1\7"+ - "\1\0\3\7\1\300\25\7\11\0\2\7\1\0\1\7"+ - "\1\0\26\7\1\301\2\7\11\0\2\7\1\0\1\7"+ - "\1\0\5\7\1\302\23\7\11\0\2\7\1\0\1\7"+ - "\1\0\21\7\1\303\7\7\2\0\4\123\1\4\1\216"+ - "\41\123\7\0\2\7\1\0\1\7\1\0\1\7\1\304"+ - "\27\7\11\0\2\7\1\0\1\7\1\0\4\7\1\305"+ - "\24\7\11\0\2\7\1\0\1\7\1\0\10\7\1\306"+ - "\20\7\11\0\2\7\1\0\1\7\1\0\16\7\1\307"+ - "\12\7\11\0\2\7\1\0\1\7\1\0\12\7\1\310"+ - "\16\7\11\0\2\7\1\0\1\7\1\0\13\7\1\311"+ - "\15\7\11\0\2\7\1\0\1\7\1\0\6\7\1\312"+ - "\4\7\1\313\6\7\1\314\6\7\11\0\2\7\1\0"+ - "\1\7\1\0\7\7\1\315\21\7\11\0\2\7\1\0"+ - "\1\7\1\0\2\7\1\316\26\7\11\0\2\7\1\0"+ - "\1\7\1\0\13\7\1\317\15\7\11\0\2\7\1\0"+ - "\1\7\1\0\13\7\1\320\15\7\11\0\2\7\1\0"+ - "\1\7\1\0\16\7\1\321\12\7\11\0\2\7\1\0"+ - "\1\7\1\0\17\7\1\322\11\7\11\0\2\7\1\0"+ - "\1\7\1\0\6\7\1\323\22\7\11\0\2\7\1\0"+ - "\1\7\1\0\17\7\1\324\11\7\11\0\2\7\1\0"+ - "\1\7\1\0\1\325\30\7\11\0\2\7\1\0\1\7"+ - "\1\0\10\7\1\326\20\7\11\0\2\7\1\0\1\7"+ - "\1\0\21\7\1\327\7\7\11\0\2\7\1\0\1\7"+ - "\1\0\21\7\1\330\7\7\11\0\2\7\1\0\1\7"+ - "\1\0\21\7\1\331\7\7\11\0\2\7\1\0\1\7"+ - "\1\0\5\7\1\332\23\7\11\0\2\7\1\0\1\7"+ - "\1\0\12\7\1\333\16\7\11\0\2\7\1\0\1\7"+ - "\1\0\4\7\1\334\24\7\11\0\2\7\1\0\1\7"+ - "\1\0\1\335\30\7\11\0\2\7\1\0\1\7\1\0"+ - "\1\7\1\336\27\7\11\0\2\7\1\0\1\7\1\0"+ - "\1\337\30\7\11\0\2\7\1\0\1\7\1\0\25\7"+ - "\1\340\3\7\11\0\2\7\1\0\1\7\1\0\17\7"+ - "\1\341\11\7\11\0\2\7\1\0\1\7\1\0\5\7"+ - "\1\342\23\7\11\0\2\7\1\0\1\7\1\0\2\7"+ - "\1\343\26\7\11\0\2\7\1\0\1\7\1\0\1\7"+ - "\1\344\27\7\11\0\2\7\1\0\1\7\1\0\13\7"+ - "\1\345\15\7\11\0\2\7\1\0\1\7\1\0\1\346"+ - "\30\7\11\0\2\7\1\0\1\7\1\0\13\7\1\347"+ - "\15\7\11\0\2\7\1\0\1\7\1\0\14\7\1\350"+ - "\14\7\11\0\2\7\1\0\1\7\1\0\15\7\1\351"+ - "\13\7\11\0\2\7\1\0\1\7\1\0\3\7\1\352"+ - "\25\7\11\0\2\7\1\0\1\7\1\0\3\7\1\353"+ - "\25\7\11\0\2\7\1\0\1\7\1\0\1\7\1\354"+ - "\27\7\11\0\2\7\1\0\1\7\1\0\16\7\1\355"+ - "\12\7\11\0\2\7\1\0\1\7\1\0\15\7\1\356"+ - "\13\7\11\0\2\7\1\0\1\7\1\0\21\7\1\357"+ - "\7\7\11\0\2\7\1\0\1\7\1\0\20\7\1\360"+ - "\10\7\11\0\2\7\1\0\1\7\1\0\16\7\1\361"+ - "\12\7\11\0\2\7\1\0\1\7\1\0\2\7\1\362"+ - "\26\7\11\0\2\7\1\0\1\7\1\0\12\7\1\363"+ - "\16\7\11\0\2\7\1\0\1\7\1\0\1\7\1\364"+ - "\27\7\11\0\2\7\1\0\1\7\1\0\1\7\1\365"+ - "\27\7\11\0\2\7\1\0\1\7\1\0\10\7\1\366"+ - "\20\7\11\0\2\7\1\0\1\7\1\0\15\7\1\367"+ - "\13\7\11\0\2\7\1\0\1\7\1\0\4\7\1\370"+ - "\4\7\1\371\17\7\11\0\2\7\1\0\1\7\1\0"+ - "\5\7\1\372\23\7\11\0\2\7\1\0\1\7\1\0"+ - "\11\7\1\373\17\7\11\0\2\7\1\0\1\7\1\0"+ - "\2\7\1\374\26\7\11\0\2\7\1\0\1\7\1\0"+ - "\26\7\1\375\2\7\11\0\2\7\1\0\1\7\1\0"+ - "\1\7\1\376\27\7\11\0\2\7\1\0\1\7\1\0"+ - "\11\7\1\377\17\7\11\0\2\7\1\0\1\7\1\0"+ - "\14\7\1\u0100\14\7\11\0\2\7\1\0\1\7\1\0"+ - "\1\u0101\30\7\11\0\2\7\1\0\1\7\1\0\3\7"+ - "\1\u0102\25\7\11\0\2\7\1\0\1\7\1\0\12\7"+ - "\1\u0103\16\7\11\0\2\7\1\0\1\7\1\0\1\u0104"+ - "\30\7\11\0\2\7\1\0\1\7\1\0\2\7\1\u0105"+ - "\26\7\11\0\2\7\1\0\1\7\1\0\24\7\1\u0106"+ - "\4\7\11\0\2\7\1\0\1\7\1\0\12\7\1\u0107"+ - "\16\7\11\0\2\7\1\0\1\7\1\0\26\7\1\u0108"+ - "\2\7\11\0\2\7\1\0\1\7\1\0\26\7\1\u0109"+ - "\2\7\11\0\2\7\1\0\1\7\1\0\1\7\1\u010a"+ - "\27\7\11\0\2\7\1\0\1\7\1\0\13\7\1\u010b"+ - "\15\7\11\0\2\7\1\0\1\7\1\0\1\7\1\u010c"+ - "\27\7\11\0\2\7\1\0\1\7\1\0\6\7\1\u010d"+ - "\22\7\11\0\2\7\1\0\1\7\1\0\1\u010e\30\7"+ - "\11\0\2\7\1\0\1\7\1\0\11\7\1\u010f\17\7"+ - "\11\0\2\7\1\0\1\7\1\0\20\7\1\u0110\10\7"+ - "\11\0\2\7\1\0\1\7\1\0\5\7\1\u0111\23\7"+ - "\11\0\2\7\1\0\1\7\1\0\6\7\1\u0112\22\7"+ - "\11\0\2\7\1\0\1\7\1\0\6\7\1\u0113\22\7"+ - "\11\0\2\7\1\0\1\7\1\0\1\7\1\u0114\27\7"+ - "\11\0\2\7\1\0\1\7\1\0\1\u0115\30\7\11\0"+ - "\2\7\1\0\1\7\1\0\12\7\1\u0116\16\7\11\0"+ - "\2\7\1\0\1\7\1\0\11\7\1\u0117\17\7\11\0"+ - "\2\7\1\0\1\7\1\0\3\7\1\u0118\25\7\11\0"+ - "\2\7\1\0\1\7\1\0\24\7\1\u0119\4\7\11\0"+ - "\2\7\1\0\1\7\1\0\2\7\1\u011a\26\7\11\0"+ - "\2\7\1\0\1\7\1\0\11\7\1\u011b\17\7\11\0"+ - "\2\7\1\0\1\7\1\0\1\7\1\u011c\4\7\1\u011d"+ - "\22\7\11\0\2\7\1\0\1\7\1\0\17\7\1\u011e"+ - "\11\7\11\0\2\7\1\0\1\7\1\0\11\7\1\u011f"+ - "\17\7\11\0\2\7\1\0\1\7\1\0\1\u0120\30\7"+ - "\11\0\2\7\1\0\1\7\1\0\2\7\1\u0121\26\7"+ - "\11\0\2\7\1\0\1\7\1\0\17\7\1\u0122\11\7"+ - "\11\0\2\7\1\0\1\7\1\0\5\7\1\u0123\23\7"+ - "\11\0\2\7\1\0\1\7\1\0\14\7\1\u0124\14\7"+ - "\11\0\2\7\1\0\1\7\1\0\1\7\1\u0125\27\7"+ - "\11\0\2\7\1\0\1\7\1\0\23\7\1\u0126\5\7"+ - "\11\0\2\7\1\0\1\7\1\0\1\u0127\30\7\11\0"+ - "\2\7\1\0\1\7\1\0\10\7\1\u0128\20\7\11\0"+ - "\2\7\1\0\1\7\1\0\2\7\1\u0129\26\7\11\0"+ - "\2\7\1\0\1\7\1\0\12\7\1\u012a\16\7\11\0"+ - "\2\7\1\0\1\7\1\0\2\7\1\u012b\26\7\11\0"+ - "\2\7\1\0\1\7\1\0\26\7\1\u012c\2\7\11\0"+ - "\2\7\1\0\1\7\1\0\30\7\1\u012d\11\0\2\7"+ - "\1\0\1\7\1\0\5\7\1\u012e\23\7\11\0\2\7"+ - "\1\0\1\7\1\0\1\u012f\30\7\11\0\2\7\1\0"+ - "\1\7\1\0\6\7\1\u0130\22\7\11\0\2\7\1\0"+ - "\1\7\1\0\1\7\1\u0131\27\7\11\0\2\7\1\0"+ - "\1\7\1\0\12\7\1\u0132\16\7\11\0\2\7\1\0"+ - "\1\7\1\0\1\7\1\u0133\27\7\11\0\2\7\1\0"+ - "\1\7\1\0\4\7\1\u0134\24\7\11\0\2\7\1\0"+ - "\1\7\1\0\2\7\1\u0135\26\7\11\0\2\7\1\0"+ - "\1\7\1\0\3\7\1\u0136\25\7\11\0\2\7\1\0"+ - "\1\7\1\0\1\u0137\30\7\11\0\2\7\1\0\1\7"+ - "\1\0\1\u0138\30\7\11\0\2\7\1\0\1\7\1\0"+ - "\5\7\1\u0139\23\7\11\0\2\7\1\0\1\7\1\0"+ - "\1\7\1\u013a\27\7\11\0\2\7\1\0\1\7\1\0"+ - "\17\7\1\u013b\11\7\11\0\2\7\1\0\1\7\1\0"+ - "\3\7\1\u013c\25\7\11\0\2\7\1\0\1\7\1\0"+ - "\1\7\1\u013d\1\u013e\2\7\1\u013f\23\7\11\0\2\7"+ - "\1\0\1\7\1\0\15\7\1\u0140\13\7\11\0\2\7"+ - "\1\0\1\7\1\0\5\7\1\u0141\23\7\11\0\2\7"+ - "\1\0\1\7\1\0\1\u0142\30\7\11\0\2\7\1\0"+ - "\1\7\1\0\15\7\1\u0143\13\7\11\0\2\7\1\0"+ - "\1\7\1\0\23\7\1\u0144\5\7\11\0\2\7\1\0"+ - "\1\7\1\0\23\7\1\u0145\5\7\11\0\2\7\1\0"+ - "\1\7\1\0\23\7\1\u0146\5\7\11\0\2\7\1\0"+ - "\1\7\1\0\1\7\1\u0147\27\7\11\0\2\7\1\0"+ - "\1\7\1\0\6\7\1\u0148\22\7\11\0\2\7\1\0"+ - "\1\7\1\0\1\u0149\30\7\11\0\2\7\1\0\1\7"+ - "\1\0\16\7\1\u014a\2\7\1\u014b\2\7\1\u014c\4\7"+ - "\11\0\2\7\1\0\1\7\1\0\21\7\1\u014d\7\7"+ - "\11\0\2\7\1\0\1\7\1\0\1\7\1\u014e\27\7"+ - "\11\0\2\7\1\0\1\7\1\0\1\u014f\30\7\11\0"+ - "\2\7\1\0\1\7\1\0\1\7\1\u0150\27\7\11\0"+ - "\2\7\1\0\1\7\1\0\2\7\1\u0151\26\7\11\0"+ - "\2\7\1\0\1\7\1\0\11\7\1\u0152\17\7\11\0"+ - "\2\7\1\0\1\7\1\0\12\7\1\u0153\16\7\11\0"+ - "\2\7\1\0\1\7\1\0\16\7\1\u0154\12\7\11\0"+ - "\2\7\1\0\1\7\1\0\12\7\1\u0155\16\7\11\0"+ - "\2\7\1\0\1\7\1\0\1\u0156\30\7\11\0\2\7"+ - "\1\0\1\7\1\0\17\7\1\u0157\11\7\11\0\2\7"+ - "\1\0\1\7\1\0\20\7\1\u0158\10\7\11\0\2\7"+ - "\1\0\1\7\1\0\15\7\1\u0159\13\7\11\0\2\7"+ - "\1\0\1\7\1\0\17\7\1\u015a\11\7\11\0\2\7"+ - "\1\0\1\7\1\0\12\7\1\u015b\16\7\11\0\2\7"+ - "\1\0\1\7\1\0\4\7\1\u015c\5\7\1\u015d\16\7"+ - "\11\0\2\7\1\0\1\7\1\0\5\7\1\u015e\23\7"+ - "\11\0\2\7\1\0\1\7\1\0\12\7\1\u015f\16\7"+ - "\11\0\2\7\1\0\1\7\1\0\1\u0160\30\7\11\0"+ - "\2\7\1\0\1\7\1\0\17\7\1\u0161\11\7\11\0"+ - "\2\7\1\0\1\7\1\0\5\7\1\u0162\23\7\11\0"+ - "\2\7\1\0\1\7\1\0\11\7\1\u0163\17\7\11\0"+ - "\2\7\1\0\1\7\1\0\12\7\1\u0164\16\7\11\0"+ - "\2\7\1\0\1\7\1\0\6\7\1\u0165\22\7\11\0"+ - "\2\7\1\0\1\7\1\0\2\7\1\u0166\26\7\11\0"+ - "\2\7\1\0\1\7\1\0\12\7\1\u0167\16\7\11\0"+ - "\2\7\1\0\1\7\1\0\5\7\1\u0168\23\7\11\0"+ - "\2\7\1\0\1\7\1\0\11\7\1\u0169\17\7\11\0"+ - "\2\7\1\0\1\7\1\0\5\7\1\u016a\23\7\11\0"+ - "\2\7\1\0\1\7\1\0\16\7\1\u016b\12\7\11\0"+ - "\2\7\1\0\1\7\1\0\5\7\1\u016c\23\7\11\0"+ - "\2\7\1\0\1\7\1\0\24\7\1\u016d\4\7\11\0"+ - "\2\7\1\0\1\7\1\0\1\u016e\30\7\11\0\2\7"+ - "\1\0\1\7\1\0\24\7\1\u016f\4\7\11\0\2\7"+ - "\1\0\1\7\1\0\15\7\1\u0170\13\7\11\0\2\7"+ - "\1\0\1\7\1\0\17\7\1\u0171\11\7\11\0\2\7"+ - "\1\0\1\7\1\0\12\7\1\u0172\16\7\11\0\2\7"+ - "\1\0\1\7\1\0\1\u0173\30\7\11\0\2\7\1\0"+ - "\1\7\1\0\24\7\1\u0174\4\7\11\0\2\7\1\0"+ - "\1\7\1\0\7\7\1\u0175\21\7\11\0\2\7\1\0"+ - "\1\7\1\0\15\7\1\u0176\13\7\11\0\2\7\1\0"+ - "\1\7\1\0\12\7\1\u0177\16\7\11\0\2\7\1\0"+ - "\1\7\1\0\11\7\1\u0178\17\7\11\0\2\7\1\0"+ - "\1\7\1\0\11\7\1\u0179\17\7\11\0\2\7\1\0"+ - "\1\7\1\0\14\7\1\u017a\14\7\11\0\2\7\1\0"+ - "\1\7\1\0\13\7\1\u017b\15\7\11\0\2\7\1\0"+ - "\1\7\1\0\2\7\1\u017c\26\7\11\0\2\7\1\0"+ - "\1\7\1\0\15\7\1\u017d\13\7\11\0\2\7\1\0"+ - "\1\7\1\0\21\7\1\u017e\7\7\11\0\2\7\1\0"+ - "\1\7\1\0\5\7\1\u017f\23\7\11\0\2\7\1\0"+ - "\1\7\1\0\3\7\1\u0180\25\7\11\0\2\7\1\0"+ - "\1\7\1\0\15\7\1\u0181\13\7\11\0\2\7\1\0"+ - "\1\7\1\0\1\u0182\30\7\11\0\2\7\1\0\1\7"+ - "\1\0\2\7\1\u0183\26\7\11\0\2\7\1\0\1\7"+ - "\1\0\4\7\1\u0184\12\7\1\u0185\11\7\11\0\2\7"+ - "\1\0\1\7\1\0\13\7\1\u0186\15\7\11\0\2\7"+ - "\1\0\1\7\1\0\13\7\1\u0187\15\7\11\0\2\7"+ - "\1\0\1\7\1\0\17\7\1\u0188\11\7\11\0\2\7"+ - "\1\0\1\7\1\0\1\7\1\u0189\27\7\11\0\2\7"+ - "\1\0\1\7\1\0\2\7\1\u018a\26\7\11\0\2\7"+ - "\1\0\1\7\1\0\5\7\1\u018b\23\7\11\0\2\7"+ - "\1\0\1\7\1\0\11\7\1\u018c\17\7\11\0\2\7"+ - "\1\0\1\7\1\0\12\7\1\u018d\16\7\11\0\2\7"+ - "\1\0\1\7\1\0\1\7\1\u018e\27\7\11\0\2\7"+ - "\1\0\1\7\1\0\16\7\1\u018f\12\7\11\0\2\7"+ - "\1\0\1\7\1\0\5\7\1\u0190\23\7\11\0\2\7"+ - "\1\0\1\7\1\0\13\7\1\u0191\15\7\11\0\2\7"+ - "\1\0\1\7\1\0\4\7\1\u0192\24\7\11\0\2\7"+ - "\1\0\1\7\1\0\1\u0193\30\7\11\0\2\7\1\0"+ - "\1\7\1\0\1\7\1\u0194\27\7\11\0\2\7\1\0"+ - "\1\7\1\0\22\7\1\u0195\6\7\11\0\2\7\1\0"+ - "\1\7\1\0\10\7\1\u0196\20\7\11\0\2\7\1\0"+ - "\1\7\1\0\21\7\1\u0197\7\7\11\0\2\7\1\0"+ - "\1\7\1\0\1\7\1\u0198\27\7\11\0\2\7\1\0"+ - "\1\7\1\0\6\7\1\u0199\22\7\11\0\2\7\1\0"+ - "\1\7\1\0\1\7\1\u019a\27\7\11\0\2\7\1\0"+ - "\1\7\1\0\7\7\1\u019b\21\7\11\0\2\7\1\0"+ - "\1\7\1\0\1\u019c\30\7\11\0\2\7\1\0\1\7"+ - "\1\0\17\7\1\u019d\11\7\11\0\2\7\1\0\1\7"+ - "\1\0\2\7\1\u019e\26\7\11\0\2\7\1\0\1\7"+ - "\1\0\6\7\1\u019f\22\7\11\0\2\7\1\0\1\7"+ - "\1\0\1\7\1\u01a0\27\7\11\0\2\7\1\0\1\7"+ - "\1\0\6\7\1\u01a1\22\7\11\0\2\7\1\0\1\7"+ - "\1\0\15\7\1\u01a2\13\7\11\0\2\7\1\0\1\7"+ - "\1\0\11\7\1\u01a3\17\7\11\0\2\7\1\0\1\7"+ - "\1\0\15\7\1\u01a4\13\7\11\0\2\7\1\0\1\7"+ - "\1\0\5\7\1\u01a5\23\7\11\0\2\7\1\0\1\7"+ - "\1\0\12\7\1\u01a6\16\7\11\0\2\7\1\0\1\7"+ - "\1\0\2\7\1\u01a7\26\7\11\0\2\7\1\0\1\7"+ - "\1\0\3\7\1\u01a8\25\7\11\0\2\7\1\0\1\7"+ - "\1\0\11\7\1\u01a9\17\7\11\0\2\7\1\0\1\7"+ - "\1\0\6\7\1\u01aa\22\7\11\0\2\7\1\0\1\7"+ - "\1\0\10\7\1\u01ab\20\7\11\0\2\7\1\0\1\7"+ - "\1\0\2\7\1\u01ac\26\7\11\0\2\7\1\0\1\7"+ - "\1\0\11\7\1\u01ad\17\7\11\0\2\7\1\0\1\7"+ - "\1\0\2\7\1\u01ae\26\7\11\0\2\7\1\0\1\7"+ - "\1\0\14\7\1\u01af\14\7\11\0\2\7\1\0\1\7"+ - "\1\0\1\u01b0\30\7\11\0\2\7\1\0\1\7\1\0"+ - "\7\7\1\u01b1\21\7\11\0\2\7\1\0\1\7\1\0"+ - "\1\u01b2\30\7\11\0\2\7\1\0\1\7\1\0\21\7"+ - "\1\u01b3\7\7\11\0\2\7\1\0\1\7\1\0\12\7"+ - "\1\u01b4\16\7\11\0\2\7\1\0\1\7\1\0\13\7"+ - "\1\u01b5\15\7\11\0\2\7\1\0\1\7\1\0\5\7"+ - "\1\u01b6\23\7\11\0\2\7\1\0\1\7\1\0\15\7"+ - "\1\u01b7\13\7\11\0\2\7\1\0\1\7\1\0\14\7"+ - "\1\u01b8\14\7\11\0\2\7\1\0\1\7\1\0\2\7"+ - "\1\u01b9\26\7\11\0\2\7\1\0\1\7\1\0\1\u01ba"+ - "\30\7\11\0\2\7\1\0\1\7\1\0\3\7\1\u01bb"+ - "\11\7\1\u01bc\13\7\11\0\2\7\1\0\1\7\1\0"+ - "\11\7\1\u01bd\17\7\11\0\2\7\1\0\1\7\1\0"+ - "\15\7\1\u01be\13\7\11\0\2\7\1\0\1\7\1\0"+ - "\12\7\1\u01bf\16\7\11\0\2\7\1\0\1\7\1\0"+ - "\1\u01c0\30\7\11\0\2\7\1\0\1\7\1\0\13\7"+ - "\1\u01c1\2\7\1\u01c2\12\7\11\0\2\7\1\0\1\7"+ - "\1\0\24\7\1\u01c3\4\7\11\0\2\7\1\0\1\7"+ - "\1\0\2\7\1\u01c4\26\7\11\0\2\7\1\0\1\7"+ - "\1\0\2\7\1\u01c5\26\7\11\0\2\7\1\0\1\7"+ - "\1\0\1\u01c6\30\7\11\0\2\7\1\0\1\7\1\0"+ - "\13\7\1\u01c7\15\7\11\0\2\7\1\0\1\7\1\0"+ - "\5\7\1\u01c8\23\7\11\0\2\7\1\0\1\7\1\0"+ - "\1\7\1\u01c9\27\7\11\0\2\7\1\0\1\7\1\0"+ - "\26\7\1\u01ca\2\7\11\0\2\7\1\0\1\7\1\0"+ - "\1\7\1\u01cb\27\7\11\0\2\7\1\0\1\7\1\0"+ - "\13\7\1\u01cc\15\7\11\0\2\7\1\0\1\7\1\0"+ - "\13\7\1\u01cd\15\7\11\0\2\7\1\0\1\7\1\0"+ - "\3\7\1\u01ce\25\7\11\0\2\7\1\0\1\7\1\0"+ - "\12\7\1\u01cf\16\7\11\0\2\7\1\0\1\7\1\0"+ - "\1\7\1\u01d0\27\7\11\0\2\7\1\0\1\7\1\0"+ - "\12\7\1\u01d1\16\7\11\0\2\7\1\0\1\7\1\0"+ - "\5\7\1\u01d2\23\7\11\0\2\7\1\0\1\7\1\0"+ - "\12\7\1\u01d3\16\7\11\0\2\7\1\0\1\7\1\0"+ - "\14\7\1\u01d4\14\7\11\0\2\7\1\0\1\7\1\0"+ - "\6\7\1\u01d5\22\7\11\0\2\7\1\0\1\7\1\0"+ - "\11\7\1\u01d6\17\7\11\0\2\7\1\0\1\7\1\0"+ - "\4\7\1\u01d7\24\7\11\0\2\7\1\0\1\7\1\0"+ - "\1\u01d8\30\7\11\0\2\7\1\0\1\7\1\0\13\7"+ - "\1\u01d9\15\7\11\0\2\7\1\0\1\7\1\0\1\u01da"+ - "\30\7\11\0\2\7\1\0\1\7\1\0\1\7\1\u01db"+ - "\27\7\11\0\2\7\1\0\1\7\1\0\7\7\1\u01dc"+ - "\21\7\11\0\2\7\1\0\1\7\1\0\21\7\1\u01dd"+ - "\7\7\11\0\2\7\1\0\1\7\1\0\16\7\1\u01de"+ - "\12\7\11\0\2\7\1\0\1\7\1\0\3\7\1\u01df"+ - "\25\7\11\0\2\7\1\0\1\7\1\0\10\7\1\u01e0"+ - "\20\7\11\0\2\7\1\0\1\7\1\0\3\7\1\u01e1"+ - "\25\7\11\0\2\7\1\0\1\7\1\0\17\7\1\u01e2"+ - "\11\7\11\0\2\7\1\0\1\7\1\0\1\u01e3\30\7"+ - "\11\0\2\7\1\0\1\7\1\0\2\7\1\u01e4\26\7"+ - "\11\0\2\7\1\0\1\7\1\0\2\7\1\u01e5\26\7"+ - "\11\0\2\7\1\0\1\7\1\0\6\7\1\u01e6\22\7"+ - "\11\0\2\7\1\0\1\7\1\0\3\7\1\u01e7\25\7"+ - "\11\0\2\7\1\0\1\7\1\0\3\7\1\u01e8\25\7"+ - "\11\0\2\7\1\0\1\7\1\0\16\7\1\u01e9\12\7"+ - "\11\0\2\7\1\0\1\7\1\0\1\7\1\u01ea\27\7"+ - "\11\0\2\7\1\0\1\7\1\0\2\7\1\u01eb\26\7"+ - "\11\0\2\7\1\0\1\7\1\0\11\7\1\u01ec\17\7"+ - "\11\0\2\7\1\0\1\7\1\0\2\7\1\u01ed\26\7"+ - "\11\0\2\7\1\0\1\7\1\0\11\7\1\u01ee\17\7"+ - "\11\0\2\7\1\0\1\7\1\0\1\7\1\u01ef\27\7"+ - "\11\0\2\7\1\0\1\7\1\0\21\7\1\u01f0\7\7"+ - "\11\0\2\7\1\0\1\7\1\0\1\u01f1\30\7\11\0"+ - "\2\7\1\0\1\7\1\0\5\7\1\u01f2\23\7\11\0"+ - "\2\7\1\0\1\7\1\0\15\7\1\u01f3\13\7\11\0"+ - "\2\7\1\0\1\7\1\0\6\7\1\u01f4\22\7\11\0"+ - "\2\7\1\0\1\7\1\0\17\7\1\u01f5\11\7\11\0"+ - "\2\7\1\0\1\7\1\0\1\7\1\u01f6\27\7\11\0"+ - "\2\7\1\0\1\7\1\0\11\7\1\u01f7\17\7\11\0"+ - "\2\7\1\0\1\7\1\0\5\7\1\u01f8\23\7\11\0"+ - "\2\7\1\0\1\7\1\0\12\7\1\u01f9\16\7\11\0"+ - "\2\7\1\0\1\7\1\0\6\7\1\u01fa\22\7\11\0"+ - "\2\7\1\0\1\7\1\0\15\7\1\u01fb\13\7\11\0"+ - "\2\7\1\0\1\7\1\0\14\7\1\u01fc\14\7\11\0"+ - "\2\7\1\0\1\7\1\0\1\u01fd\30\7\11\0\2\7"+ - "\1\0\1\7\1\0\1\7\1\u01fe\27\7\11\0\2\7"+ - "\1\0\1\7\1\0\3\7\1\u01ff\25\7\11\0\2\7"+ - "\1\0\1\7\1\0\17\7\1\u0200\11\7\11\0\2\7"+ - "\1\0\1\7\1\0\7\7\1\u0201\21\7\11\0\2\7"+ - "\1\0\1\7\1\0\15\7\1\u0202\13\7\11\0\2\7"+ - "\1\0\1\7\1\0\12\7\1\u0203\16\7\11\0\2\7"+ - "\1\0\1\7\1\0\1\7\1\u0204\27\7\11\0\2\7"+ - "\1\0\1\7\1\0\21\7\1\u0205\7\7\11\0\2\7"+ - "\1\0\1\7\1\0\1\u0206\30\7\11\0\2\7\1\0"+ - "\1\7\1\0\6\7\1\u0207\22\7\11\0\2\7\1\0"+ - "\1\7\1\0\2\7\1\u0208\26\7\11\0\2\7\1\0"+ - "\1\7\1\0\1\7\1\u0209\27\7\11\0\2\7\1\0"+ - "\1\7\1\0\3\7\1\u020a\25\7\11\0\2\7\1\0"+ - "\1\7\1\0\3\7\1\u020b\25\7\11\0\2\7\1\0"+ - "\1\7\1\0\1\u020c\30\7\11\0\2\7\1\0\1\7"+ - "\1\0\12\7\1\u020d\16\7\11\0\2\7\1\0\1\7"+ - "\1\0\13\7\1\u020e\15\7\11\0\2\7\1\0\1\7"+ - "\1\0\1\u020f\30\7\11\0\2\7\1\0\1\7\1\0"+ - "\12\7\1\u0210\16\7\11\0\2\7\1\0\1\7\1\0"+ - "\5\7\1\u0211\23\7\11\0\2\7\1\0\1\7\1\0"+ - "\16\7\1\u0212\12\7\11\0\2\7\1\0\1\7\1\0"+ - "\5\7\1\u0213\23\7\11\0\2\7\1\0\1\7\1\0"+ - "\15\7\1\u0214\13\7\11\0\2\7\1\0\1\7\1\0"+ - "\1\u0215\30\7\11\0\2\7\1\0\1\7\1\0\1\u0216"+ - "\30\7\11\0\2\7\1\0\1\7\1\0\16\7\1\u0217"+ - "\1\u0218\11\7\11\0\2\7\1\0\1\7\1\0\20\7"+ - "\1\u0219\10\7\11\0\2\7\1\0\1\7\1\0\3\7"+ - "\1\u021a\25\7\11\0\2\7\1\0\1\7\1\0\10\7"+ - "\1\u021b\20\7\11\0\2\7\1\0\1\7\1\0\5\7"+ - "\1\u021c\1\7\1\u021d\1\u021e\12\7\1\u021f\5\7\11\0"+ - "\2\7\1\0\1\7\1\0\1\7\1\u0220\27\7\11\0"+ - "\2\7\1\0\1\7\1\0\10\7\1\u0221\20\7\11\0"+ - "\2\7\1\0\1\7\1\0\6\7\1\u0222\22\7\11\0"+ - "\2\7\1\0\1\7\1\0\11\7\1\u0223\17\7\11\0"+ - "\2\7\1\0\1\7\1\0\1\u0224\30\7\11\0\2\7"+ - "\1\0\1\7\1\0\21\7\1\u0225\7\7\11\0\2\7"+ - "\1\0\1\7\1\0\23\7\1\u0226\5\7\11\0\2\7"+ - "\1\0\1\7\1\0\11\7\1\u0227\17\7\11\0\2\7"+ - "\1\0\1\7\1\0\1\7\1\u0228\27\7\11\0\2\7"+ - "\1\0\1\7\1\0\26\7\1\u0229\2\7\11\0\2\7"+ - "\1\0\1\7\1\0\14\7\1\u022a\14\7\11\0\2\7"+ - "\1\0\1\7\1\0\3\7\1\u022b\25\7\11\0\2\7"+ - "\1\0\1\7\1\0\13\7\1\u022c\15\7\11\0\2\7"+ - "\1\0\1\7\1\0\2\7\1\u022d\26\7\11\0\2\7"+ - "\1\0\1\7\1\0\26\7\1\u022e\2\7\11\0\2\7"+ - "\1\0\1\7\1\0\5\7\1\u022f\23\7\11\0\2\7"+ - "\1\0\1\7\1\0\1\7\1\u0230\27\7\11\0\2\7"+ - "\1\0\1\7\1\0\5\7\1\u0231\23\7\11\0\2\7"+ - "\1\0\1\7\1\0\14\7\1\u0232\14\7\11\0\2\7"+ - "\1\0\1\7\1\0\1\7\1\u0233\27\7\11\0\2\7"+ - "\1\0\1\7\1\0\1\7\1\u0234\27\7\11\0\2\7"+ - "\1\0\1\7\1\0\16\7\1\u0235\12\7\11\0\2\7"+ - "\1\0\1\7\1\0\5\7\1\u0236\23\7\11\0\2\7"+ - "\1\0\1\7\1\0\2\7\1\u0237\26\7\11\0\2\7"+ - "\1\0\1\7\1\0\1\u0238\30\7\11\0\2\7\1\0"+ - "\1\7\1\0\6\7\1\u0239\22\7\11\0\2\7\1\0"+ - "\1\7\1\0\1\u023a\30\7\11\0\2\7\1\0\1\7"+ - "\1\0\5\7\1\u023b\23\7\11\0\2\7\1\0\1\7"+ - "\1\0\3\7\1\u023c\25\7\11\0\2\7\1\0\1\7"+ - "\1\0\1\u023d\30\7\11\0\2\7\1\0\1\7\1\0"+ - "\7\7\1\u023e\21\7\11\0\2\7\1\0\1\7\1\0"+ - "\13\7\1\u023f\15\7\11\0\2\7\1\0\1\7\1\0"+ - "\1\7\1\u0240\4\7\1\u0241\22\7\11\0\2\7\1\0"+ - "\1\7\1\0\12\7\1\u0242\16\7\11\0\2\7\1\0"+ - "\1\7\1\0\2\7\1\u0243\26\7\11\0\2\7\1\0"+ - "\1\7\1\0\15\7\1\u0244\13\7\11\0\2\7\1\0"+ - "\1\7\1\0\1\u0245\30\7\11\0\2\7\1\0\1\7"+ - "\1\0\20\7\1\u0246\10\7\11\0\2\7\1\0\1\7"+ - "\1\0\1\u0247\30\7\11\0\2\7\1\0\1\7\1\0"+ - "\11\7\1\u0248\17\7\11\0\2\7\1\0\1\7\1\0"+ - "\2\7\1\u0249\26\7\11\0\2\7\1\0\1\7\1\0"+ - "\13\7\1\u024a\15\7\11\0\2\7\1\0\1\7\1\0"+ - "\13\7\1\u024b\15\7\11\0\2\7\1\0\1\7\1\0"+ - "\6\7\1\u024c\22\7\11\0\2\7\1\0\1\7\1\0"+ - "\5\7\1\u024d\23\7\11\0\2\7\1\0\1\7\1\0"+ - "\17\7\1\u024e\11\7\11\0\2\7\1\0\1\7\1\0"+ - "\1\u024f\30\7\11\0\2\7\1\0\1\7\1\0\6\7"+ - "\1\u0250\22\7\11\0\2\7\1\0\1\7\1\0\1\u0251"+ - "\30\7\11\0\2\7\1\0\1\7\1\0\15\7\1\u0252"+ - "\13\7\11\0\2\7\1\0\1\7\1\0\23\7\1\u0253"+ - "\5\7\11\0\2\7\1\0\1\7\1\0\2\7\1\u0254"+ - "\10\7\1\u0255\15\7\11\0\2\7\1\0\1\7\1\0"+ - "\15\7\1\u0256\13\7\11\0\2\7\1\0\1\7\1\0"+ - "\12\7\1\u0257\16\7\11\0\2\7\1\0\1\7\1\0"+ - "\1\u0258\30\7\11\0\2\7\1\0\1\7\1\0\14\7"+ - "\1\u0259\14\7\11\0\2\7\1\0\1\7\1\0\20\7"+ - "\1\u025a\10\7\11\0\2\7\1\0\1\7\1\0\5\7"+ - "\1\u025b\23\7\11\0\2\7\1\0\1\7\1\0\3\7"+ - "\1\u025c\25\7\11\0\2\7\1\0\1\7\1\0\6\7"+ - "\1\u025d\22\7\11\0\2\7\1\0\1\7\1\0\11\7"+ - "\1\u025e\17\7\11\0\2\7\1\0\1\7\1\0\17\7"+ - "\1\u025f\11\7\11\0\2\7\1\0\1\7\1\0\6\7"+ - "\1\u0260\22\7\11\0\2\7\1\0\1\7\1\0\5\7"+ - "\1\u0261\23\7\11\0\2\7\1\0\1\7\1\0\1\u0262"+ - "\30\7\11\0\2\7\1\0\1\7\1\0\12\7\1\u0263"+ - "\16\7\11\0\2\7\1\0\1\7\1\0\20\7\1\u0264"+ - "\10\7\11\0\2\7\1\0\1\7\1\0\21\7\1\u0265"+ - "\7\7\11\0\2\7\1\0\1\7\1\0\1\u0266\30\7"+ - "\11\0\2\7\1\0\1\7\1\0\15\7\1\u0267\13\7"+ - "\11\0\2\7\1\0\1\7\1\0\6\7\1\u0268\22\7"+ - "\11\0\2\7\1\0\1\7\1\0\12\7\1\u0269\16\7"+ - "\11\0\2\7\1\0\1\7\1\0\5\7\1\u026a\23\7"+ - "\11\0\2\7\1\0\1\7\1\0\6\7\1\u026b\22\7"+ - "\11\0\2\7\1\0\1\7\1\0\6\7\1\u026c\22\7"+ - "\11\0\2\7\1\0\1\7\1\0\1\u026d\30\7\11\0"+ - "\2\7\1\0\1\7\1\0\12\7\1\u026e\16\7\11\0"+ - "\2\7\1\0\1\7\1\0\16\7\1\u026f\12\7\11\0"+ - "\2\7\1\0\1\7\1\0\13\7\1\u0270\15\7\11\0"+ - "\2\7\1\0\1\7\1\0\13\7\1\u0271\15\7\11\0"+ - "\2\7\1\0\1\7\1\0\23\7\1\u0272\5\7\11\0"+ - "\2\7\1\0\1\7\1\0\17\7\1\u0273\11\7\11\0"+ - "\2\7\1\0\1\7\1\0\5\7\1\u0274\23\7\11\0"+ - "\2\7\1\0\1\7\1\0\15\7\1\u0275\13\7\11\0"+ - "\2\7\1\0\1\7\1\0\11\7\1\u0276\17\7\11\0"+ - "\2\7\1\0\1\7\1\0\15\7\1\u0277\13\7\11\0"+ - "\2\7\1\0\1\7\1\0\1\u0278\30\7\11\0\2\7"+ - "\1\0\1\7\1\0\11\7\1\u0279\17\7\11\0\2\7"+ - "\1\0\1\7\1\0\10\7\1\u027a\20\7\11\0\2\7"+ - "\1\0\1\7\1\0\15\7\1\u027b\13\7\11\0\2\7"+ - "\1\0\1\7\1\0\17\7\1\u027c\11\7\11\0\2\7"+ - "\1\0\1\7\1\0\1\u027d\30\7\11\0\2\7\1\0"+ - "\1\7\1\0\4\7\1\u027e\24\7\11\0\2\7\1\0"+ - "\1\7\1\0\5\7\1\u027f\23\7\11\0\2\7\1\0"+ - "\1\7\1\0\6\7\1\u0280\22\7\11\0\2\7\1\0"+ - "\1\7\1\0\3\7\1\u0281\25\7\11\0\2\7\1\0"+ - "\1\7\1\0\1\u0282\30\7\11\0\2\7\1\0\1\7"+ - "\1\0\11\7\1\u0283\17\7\11\0\2\7\1\0\1\7"+ - "\1\0\5\7\1\u0284\23\7\11\0\2\7\1\0\1\7"+ - "\1\0\16\7\1\u0285\12\7\11\0\2\7\1\0\1\7"+ - "\1\0\23\7\1\u0286\5\7\11\0\2\7\1\0\1\7"+ - "\1\0\12\7\1\u0287\16\7\11\0\2\7\1\0\1\7"+ - "\1\0\12\7\1\u0288\16\7\11\0\2\7\1\0\1\7"+ - "\1\0\11\7\1\u0289\17\7\11\0\2\7\1\0\1\7"+ - "\1\0\12\7\1\u028a\16\7\11\0\2\7\1\0\1\7"+ - "\1\0\1\u028b\30\7\11\0\2\7\1\0\1\7\1\0"+ - "\1\u028c\30\7\11\0\2\7\1\0\1\7\1\0\11\7"+ - "\1\u028d\17\7\11\0\2\7\1\0\1\7\1\0\1\u028e"+ - "\30\7\11\0\2\7\1\0\1\7\1\0\3\7\1\u028f"+ - "\25\7\11\0\2\7\1\0\1\7\1\0\1\u0290\30\7"+ - "\11\0\2\7\1\0\1\7\1\0\13\7\1\u0291\15\7"+ - "\11\0\2\7\1\0\1\7\1\0\13\7\1\u0292\15\7"+ - "\11\0\2\7\1\0\1\7\1\0\24\7\1\u0293\4\7"+ - "\11\0\2\7\1\0\1\7\1\0\15\7\1\u0294\13\7"+ - "\11\0\2\7\1\0\1\7\1\0\22\7\1\u0295\6\7"+ - "\11\0\2\7\1\0\1\7\1\0\21\7\1\u0296\7\7"+ - "\11\0\2\7\1\0\1\7\1\0\11\7\1\u0297\17\7"+ - "\11\0\2\7\1\0\1\7\1\0\2\7\1\u0298\26\7"+ - "\11\0\2\7\1\0\1\7\1\0\11\7\1\u0299\17\7"+ - "\11\0\2\7\1\0\1\7\1\0\3\7\1\u029a\25\7"+ - "\11\0\2\7\1\0\1\7\1\0\12\7\1\u029b\16\7"+ - "\11\0\2\7\1\0\1\7\1\0\13\7\1\u029c\15\7"+ - "\11\0\2\7\1\0\1\7\1\0\17\7\1\u029d\11\7"+ - "\11\0\2\7\1\0\1\7\1\0\10\7\1\u029e\20\7"+ - "\11\0\2\7\1\0\1\7\1\0\1\u029f\30\7\11\0"+ - "\2\7\1\0\1\7\1\0\11\7\1\u02a0\17\7\11\0"+ - "\2\7\1\0\1\7\1\0\1\u02a1\30\7\11\0\2\7"+ - "\1\0\1\7\1\0\13\7\1\u02a2\15\7\11\0\2\7"+ - "\1\0\1\7\1\0\10\7\1\u02a3\20\7\11\0\2\7"+ - "\1\0\1\7\1\0\12\7\1\u02a4\16\7\11\0\2\7"+ - "\1\0\1\7\1\0\21\7\1\u02a5\7\7\11\0\2\7"+ - "\1\0\1\7\1\0\15\7\1\u02a6\13\7\11\0\2\7"+ - "\1\0\1\7\1\0\5\7\1\u02a7\23\7\11\0\2\7"+ - "\1\0\1\7\1\0\2\7\1\u02a8\26\7\11\0\2\7"+ - "\1\0\1\7\1\0\23\7\1\u02a9\5\7\11\0\2\7"+ - "\1\0\1\7\1\0\1\u02aa\30\7\11\0\2\7\1\0"+ - "\1\7\1\0\16\7\1\u02ab\12\7\11\0\2\7\1\0"+ - "\1\7\1\0\13\7\1\u02ac\15\7\11\0\2\7\1\0"+ - "\1\7\1\0\13\7\1\u02ad\15\7\11\0\2\7\1\0"+ - "\1\7\1\0\5\7\1\u02ae\23\7\11\0\2\7\1\0"+ - "\1\7\1\0\12\7\1\u02af\16\7\11\0\2\7\1\0"+ - "\1\7\1\0\5\7\1\u02b0\23\7\11\0\2\7\1\0"+ - "\1\7\1\0\1\u02b1\30\7\11\0\2\7\1\0\1\7"+ - "\1\0\12\7\1\u02b2\16\7\11\0\2\7\1\0\1\7"+ - "\1\0\24\7\1\u02b3\4\7\11\0\2\7\1\0\1\7"+ - "\1\0\3\7\1\u02b4\25\7\11\0\2\7\1\0\1\7"+ - "\1\0\6\7\1\u02b5\22\7\11\0\2\7\1\0\1\7"+ - "\1\0\1\u02b6\30\7\11\0\2\7\1\0\1\7\1\0"+ - "\14\7\1\u02b7\14\7\11\0\2\7\1\0\1\7\1\0"+ - "\5\7\1\u02b8\23\7\11\0\2\7\1\0\1\7\1\0"+ - "\1\7\1\u02b9\27\7\11\0\2\7\1\0\1\7\1\0"+ - "\10\7\1\u02ba\20\7\11\0\2\7\1\0\1\7\1\0"+ - "\6\7\1\u02bb\22\7\11\0\2\7\1\0\1\7\1\0"+ - "\1\7\1\u02bc\27\7\11\0\2\7\1\0\1\7\1\0"+ - "\20\7\1\u02bd\10\7\11\0\2\7\1\0\1\7\1\0"+ - "\1\7\1\u02be\27\7\11\0\2\7\1\0\1\7\1\0"+ - "\15\7\1\u02bf\13\7\11\0\2\7\1\0\1\7\1\0"+ - "\12\7\1\u02c0\16\7\11\0\2\7\1\0\1\7\1\0"+ - "\15\7\1\u02c1\13\7\11\0\2\7\1\0\1\7\1\0"+ - "\13\7\1\u02c2\15\7\11\0\2\7\1\0\1\7\1\0"+ - "\6\7\1\u02c3\22\7\11\0\2\7\1\0\1\7\1\0"+ - "\6\7\1\u02c4\22\7\11\0\2\7\1\0\1\7\1\0"+ - "\12\7\1\u02c5\16\7\11\0\2\7\1\0\1\7\1\0"+ - "\12\7\1\u02c6\16\7\11\0\2\7\1\0\1\7\1\0"+ - "\25\7\1\u02c7\3\7\11\0\2\7\1\0\1\7\1\0"+ - "\11\7\1\u02c8\17\7\11\0\2\7\1\0\1\7\1\0"+ - "\6\7\1\u02c9\22\7\11\0\2\7\1\0\1\7\1\0"+ - "\2\7\1\u02ca\26\7\11\0\2\7\1\0\1\7\1\0"+ - "\1\7\1\u02cb\27\7\11\0\2\7\1\0\1\7\1\0"+ - "\1\u02cc\30\7\11\0\2\7\1\0\1\7\1\0\13\7"+ - "\1\u02cd\15\7\11\0\2\7\1\0\1\7\1\0\15\7"+ - "\1\u02ce\13\7\11\0\2\7\1\0\1\7\1\0\1\u02cf"+ - "\30\7\11\0\2\7\1\0\1\7\1\0\1\7\1\u02d0"+ - "\27\7\11\0\2\7\1\0\1\7\1\0\21\7\1\u02d1"+ - "\7\7\11\0\2\7\1\0\1\7\1\0\17\7\1\u02d2"+ - "\11\7\11\0\2\7\1\0\1\7\1\0\11\7\1\u02d3"+ - "\17\7\11\0\2\7\1\0\1\7\1\0\1\u02d4\30\7"+ - "\11\0\2\7\1\0\1\7\1\0\20\7\1\u02d5\10\7"+ - "\11\0\2\7\1\0\1\7\1\0\5\7\1\u02d6\23\7"+ - "\11\0\2\7\1\0\1\7\1\0\6\7\1\u02d7\22\7"+ - "\11\0\2\7\1\0\1\7\1\0\26\7\1\u02d8\2\7"+ - "\11\0\2\7\1\0\1\7\1\0\11\7\1\u02d9\17\7"+ - "\11\0\2\7\1\0\1\7\1\0\1\u02da\30\7\11\0"+ - "\2\7\1\0\1\7\1\0\2\7\1\u02db\26\7\11\0"+ - "\2\7\1\0\1\7\1\0\11\7\1\u02dc\17\7\11\0"+ - "\2\7\1\0\1\7\1\0\11\7\1\u02dd\17\7\11\0"+ - "\2\7\1\0\1\7\1\0\15\7\1\u02de\13\7\11\0"+ - "\2\7\1\0\1\7\1\0\5\7\1\u02df\23\7\11\0"+ - "\2\7\1\0\1\7\1\0\1\u02e0\30\7\11\0\2\7"+ - "\1\0\1\7\1\0\1\7\1\u02e1\27\7\11\0\2\7"+ - "\1\0\1\7\1\0\11\7\1\u02e2\17\7\11\0\2\7"+ - "\1\0\1\7\1\0\2\7\1\u02e3\26\7\11\0\2\7"+ - "\1\0\1\7\1\0\15\7\1\u02e4\13\7\11\0\2\7"+ - "\1\0\1\7\1\0\5\7\1\u02e5\23\7\11\0\2\7"+ - "\1\0\1\7\1\0\11\7\1\u02e6\17\7\11\0\2\7"+ - "\1\0\1\7\1\0\17\7\1\u02e7\11\7\11\0\2\7"+ - "\1\0\1\7\1\0\2\7\1\u02e8\26\7\11\0\2\7"+ - "\1\0\1\7\1\0\7\7\1\u02e9\21\7\11\0\2\7"+ - "\1\0\1\7\1\0\16\7\1\u02ea\12\7\11\0\2\7"+ - "\1\0\1\7\1\0\11\7\1\u02eb\17\7\11\0\2\7"+ - "\1\0\1\7\1\0\2\7\1\u02ec\26\7\11\0\2\7"+ - "\1\0\1\7\1\0\10\7\1\u02ed\20\7\11\0\2\7"+ - "\1\0\1\7\1\0\12\7\1\u02ee\16\7\11\0\2\7"+ - "\1\0\1\7\1\0\12\7\1\u02ef\16\7\11\0\2\7"+ - "\1\0\1\7\1\0\15\7\1\u02f0\13\7\11\0\2\7"+ - "\1\0\1\7\1\0\2\7\1\u02f1\26\7\11\0\2\7"+ - "\1\0\1\7\1\0\20\7\1\u02f2\10\7\11\0\2\7"+ - "\1\0\1\7\1\0\7\7\1\u02f3\21\7\11\0\2\7"+ - "\1\0\1\7\1\0\6\7\1\u02f4\22\7\11\0\2\7"+ - "\1\0\1\7\1\0\16\7\1\u02f5\12\7\11\0\2\7"+ - "\1\0\1\7\1\0\12\7\1\u02f6\16\7\11\0\2\7"+ - "\1\0\1\7\1\0\13\7\1\u02f7\15\7\11\0\2\7"+ - "\1\0\1\7\1\0\6\7\1\u02f8\22\7\11\0\2\7"+ - "\1\0\1\7\1\0\5\7\1\u02f9\23\7\11\0\2\7"+ - "\1\0\1\7\1\0\1\7\1\u02fa\27\7\11\0\2\7"+ - "\1\0\1\7\1\0\14\7\1\u02fb\14\7\11\0\2\7"+ - "\1\0\1\7\1\0\7\7\1\u02fc\21\7\11\0\2\7"+ - "\1\0\1\7\1\0\3\7\1\u02fd\25\7\11\0\2\7"+ - "\1\0\1\7\1\0\12\7\1\u02fe\16\7\11\0\2\7"+ - "\1\0\1\7\1\0\5\7\1\u02ff\23\7\11\0\2\7"+ - "\1\0\1\7\1\0\1\u0300\30\7\11\0\2\7\1\0"+ - "\1\7\1\0\1\u0301\30\7\11\0\2\7\1\0\1\7"+ - "\1\0\15\7\1\u0302\13\7\11\0\2\7\1\0\1\7"+ - "\1\0\2\7\1\u0303\26\7\11\0\2\7\1\0\1\7"+ - "\1\0\6\7\1\u0304\22\7\11\0\2\7\1\0\1\7"+ - "\1\0\3\7\1\u0305\25\7\11\0\2\7\1\0\1\7"+ - "\1\0\1\u0306\30\7\11\0\2\7\1\0\1\7\1\0"+ - "\2\7\1\u0307\26\7\11\0\2\7\1\0\1\7\1\0"+ - "\11\7\1\u0308\17\7\11\0\2\7\1\0\1\7\1\0"+ - "\13\7\1\u0309\15\7\11\0\2\7\1\0\1\7\1\0"+ - "\2\7\1\u030a\26\7\11\0\2\7\1\0\1\7\1\0"+ - "\11\7\1\u030b\17\7\11\0\2\7\1\0\1\7\1\0"+ - "\12\7\1\u030c\16\7\11\0\2\7\1\0\1\7\1\0"+ - "\1\u030d\30\7\11\0\2\7\1\0\1\7\1\0\21\7"+ - "\1\u030e\7\7\11\0\2\7\1\0\1\7\1\0\17\7"+ - "\1\u030f\11\7\11\0\2\7\1\0\1\7\1\0\10\7"+ - "\1\u0310\20\7\11\0\2\7\1\0\1\7\1\0\6\7"+ - "\1\u0311\22\7\11\0\2\7\1\0\1\7\1\0\12\7"+ - "\1\u0312\16\7\11\0\2\7\1\0\1\7\1\0\21\7"+ - "\1\u0313\7\7\11\0\2\7\1\0\1\7\1\0\3\7"+ - "\1\u0314\25\7\11\0\2\7\1\0\1\7\1\0\13\7"+ - "\1\u0315\15\7\11\0\2\7\1\0\1\7\1\0\1\u0316"+ - "\30\7\11\0\2\7\1\0\1\7\1\0\5\7\1\u0317"+ - "\23\7\11\0\2\7\1\0\1\7\1\0\7\7\1\u0318"+ - "\21\7\11\0\2\7\1\0\1\7\1\0\14\7\1\u0319"+ - "\14\7\11\0\2\7\1\0\1\7\1\0\12\7\1\u031a"+ - "\16\7\11\0\2\7\1\0\1\7\1\0\1\u031b\30\7"+ - "\11\0\2\7\1\0\1\7\1\0\6\7\1\u031c\22\7"+ - "\2\0"; - - private static int [] zzUnpackTrans() { - int [] result = new int[27963]; - int offset = 0; - offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result); - return result; - } - - private static int zzUnpackTrans(String packed, int offset, int [] result) { - int i = 0; /* index in packed string */ - int j = offset; /* index in unpacked array */ - int l = packed.length(); - while (i < l) { - int count = packed.charAt(i++); - int value = packed.charAt(i++); - value--; - do result[j++] = value; while (--count > 0); - } - return j; - } - - - /* error codes */ - private static final int ZZ_UNKNOWN_ERROR = 0; - private static final int ZZ_NO_MATCH = 1; - private static final int ZZ_PUSHBACK_2BIG = 2; - - /* error messages for the codes above */ - private static final String ZZ_ERROR_MSG[] = { - "Unkown internal scanner error", - "Error: could not match input", - "Error: pushback value was too large" - }; - - /** - * ZZ_ATTRIBUTE[aState] contains the attributes of state aState - */ - private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute(); - - private static final String ZZ_ATTRIBUTE_PACKED_0 = - "\1\0\1\11\1\1\1\11\33\1\2\11\4\0\55\1"+ - "\2\0\2\1\1\0\1\11\65\1\1\0\u028e\1"; - - private static int [] zzUnpackAttribute() { - int [] result = new int[796]; - int offset = 0; - offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result); - return result; - } - - private static int zzUnpackAttribute(String packed, int offset, int [] result) { - int i = 0; /* index in packed string */ - int j = offset; /* index in unpacked array */ - int l = packed.length(); - while (i < l) { - int count = packed.charAt(i++); - int value = packed.charAt(i++); - do result[j++] = value; while (--count > 0); - } - return j; - } - - /** the input device */ - private java.io.Reader zzReader; - - /** the current state of the DFA */ - private int zzState; - - /** the current lexical state */ - private int zzLexicalState = YYINITIAL; - - /** this buffer contains the current text to be matched and is - the source of the yytext() string */ - private char zzBuffer[] = new char[ZZ_BUFFERSIZE]; - - /** the textposition at the last accepting state */ - private int zzMarkedPos; - - /** the textposition at the last state to be included in yytext */ - private int zzPushbackPos; - - /** the current text position in the buffer */ - private int zzCurrentPos; - - /** startRead marks the beginning of the yytext() string in the buffer */ - private int zzStartRead; - - /** endRead marks the last character in the buffer, that has been read - from input */ - private int zzEndRead; - - /** number of newlines encountered up to the start of the matched text */ - private int yyline; - - /** the number of characters up to the start of the matched text */ - private int yychar; - - /** - * the number of characters from the last newline up to the start of the - * matched text - */ - private int yycolumn; - - /** - * zzAtBOL == true <=> the scanner is currently at the beginning of a line - */ - private boolean zzAtBOL = true; - - /** zzAtEOF == true <=> the scanner is at the EOF */ - private boolean zzAtEOF; - - - /** - * Creates a new scanner - * There is also a java.io.InputStream version of this constructor. - * - * @param in the java.io.Reader to read input from. - */ - GUIDefaultsScanner(java.io.Reader in) { - this.zzReader = in; - } - - /** - * Creates a new scanner. - * There is also java.io.Reader version of this constructor. - * - * @param in the java.io.Inputstream to read input from. - */ - GUIDefaultsScanner(java.io.InputStream in) { - this(new java.io.InputStreamReader(in)); - } - - /** - * Unpacks the compressed character translation table. - * - * @param packed the packed character translation table - * @return the unpacked character translation table - */ - private static char [] zzUnpackCMap(String packed) { - char [] map = new char[0x10000]; - int i = 0; /* index in packed string */ - int j = 0; /* index in unpacked array */ - while (i < 156) { - int count = packed.charAt(i++); - char value = packed.charAt(i++); - do map[j++] = value; while (--count > 0); - } - return map; - } - - - /** - * Refills the input buffer. - * - * @return false, iff there was new input. - * - * @exception java.io.IOException if any I/O-Error occurs - */ - private boolean zzRefill() throws java.io.IOException { - - /* first: make room (if you can) */ - if (zzStartRead > 0) { - System.arraycopy(zzBuffer, zzStartRead, - zzBuffer, 0, - zzEndRead-zzStartRead); - - /* translate stored positions */ - zzEndRead-= zzStartRead; - zzCurrentPos-= zzStartRead; - zzMarkedPos-= zzStartRead; - zzPushbackPos-= zzStartRead; - zzStartRead = 0; - } - - /* is the buffer big enough? */ - if (zzCurrentPos >= zzBuffer.length) { - /* if not: blow it up */ - char newBuffer[] = new char[zzCurrentPos*2]; - System.arraycopy(zzBuffer, 0, newBuffer, 0, zzBuffer.length); - zzBuffer = newBuffer; - } - - /* finally: fill the buffer with new input */ - int numRead = zzReader.read(zzBuffer, zzEndRead, - zzBuffer.length-zzEndRead); - - if (numRead < 0) { - return true; - } - else { - zzEndRead+= numRead; - return false; - } - } - - - /** - * Closes the input stream. - */ - public final void yyclose() throws java.io.IOException { - zzAtEOF = true; /* indicate end of file */ - zzEndRead = zzStartRead; /* invalidate buffer */ - - if (zzReader != null) - zzReader.close(); - } - - - /** - * Resets the scanner to read from a new input stream. - * Does not close the old reader. - * - * All internal variables are reset, the old input stream - * cannot be reused (internal buffer is discarded and lost). - * Lexical state is set to ZZ_INITIAL. - * - * @param reader the new input stream - */ - public final void yyreset(java.io.Reader reader) { - zzReader = reader; - zzAtBOL = true; - zzAtEOF = false; - zzEndRead = zzStartRead = 0; - zzCurrentPos = zzMarkedPos = zzPushbackPos = 0; - yyline = yychar = yycolumn = 0; - zzLexicalState = YYINITIAL; - } - - - /** - * Returns the current lexical state. - */ - public final int yystate() { - return zzLexicalState; - } - - - /** - * Enters a new lexical state - * - * @param newState the new lexical state - */ - public final void yybegin(int newState) { - zzLexicalState = newState; - } - - - /** - * Returns the text matched by the current regular expression. - */ - public final String yytext() { - return new String( zzBuffer, zzStartRead, zzMarkedPos-zzStartRead ); - } - - - /** - * Returns the character at position pos from the - * matched text. - * - * It is equivalent to yytext().charAt(pos), but faster - * - * @param pos the position of the character to fetch. - * A value from 0 to yylength()-1. - * - * @return the character at position pos - */ - public final char yycharat(int pos) { - return zzBuffer[zzStartRead+pos]; - } - - - /** - * Returns the length of the matched text region. - */ - public final int yylength() { - return zzMarkedPos-zzStartRead; - } - - - /** - * Reports an error that occured while scanning. - * - * In a wellformed scanner (no or only correct usage of - * yypushback(int) and a match-all fallback rule) this method - * will only be called with things that "Can't Possibly Happen". - * If this method is called, something is seriously wrong - * (e.g. a JFlex bug producing a faulty scanner etc.). - * - * Usual syntax/scanner level error handling should be done - * in error fallback rules. - * - * @param errorCode the code of the errormessage to display - */ - private void zzScanError(int errorCode) { - String message; - try { - message = ZZ_ERROR_MSG[errorCode]; - } - catch (ArrayIndexOutOfBoundsException e) { - message = ZZ_ERROR_MSG[ZZ_UNKNOWN_ERROR]; - } - - throw new Error(message); - } - - - /** - * Pushes the specified amount of characters back into the input stream. - * - * They will be read again by then next call of the scanning method - * - * @param number the number of characters to be read again. - * This number must not be greater than yylength()! - */ - public void yypushback(int number) { - if ( number > yylength() ) - zzScanError(ZZ_PUSHBACK_2BIG); - - zzMarkedPos -= number; - } - - - /** - * Resumes scanning until the next regular expression is matched, - * the end of input is encountered or an I/O-Error occurs. - * - * @return the next token - * @exception java.io.IOException if any I/O-Error occurs - */ - public Object next_token() throws java.io.IOException { - int zzInput; - int zzAction; - - // cached fields: - int zzCurrentPosL; - int zzMarkedPosL; - int zzEndReadL = zzEndRead; - char [] zzBufferL = zzBuffer; - char [] zzCMapL = ZZ_CMAP; - - int [] zzTransL = ZZ_TRANS; - int [] zzRowMapL = ZZ_ROWMAP; - int [] zzAttrL = ZZ_ATTRIBUTE; - - while (true) { - zzMarkedPosL = zzMarkedPos; - - zzAction = -1; - - zzCurrentPosL = zzCurrentPos = zzStartRead = zzMarkedPosL; - - zzState = zzLexicalState; - - - zzForAction: { - while (true) { - - if (zzCurrentPosL < zzEndReadL) - zzInput = zzBufferL[zzCurrentPosL++]; - else if (zzAtEOF) { - zzInput = YYEOF; - break zzForAction; - } - else { - // store back cached positions - zzCurrentPos = zzCurrentPosL; - zzMarkedPos = zzMarkedPosL; - boolean eof = zzRefill(); - // get translated positions and possibly new buffer - zzCurrentPosL = zzCurrentPos; - zzMarkedPosL = zzMarkedPos; - zzBufferL = zzBuffer; - zzEndReadL = zzEndRead; - if (eof) { - zzInput = YYEOF; - break zzForAction; - } - else { - zzInput = zzBufferL[zzCurrentPosL++]; - } - } - int zzNext = zzTransL[ zzRowMapL[zzState] + zzCMapL[zzInput] ]; - if (zzNext == -1) break zzForAction; - zzState = zzNext; - - int zzAttributes = zzAttrL[zzState]; - if ( (zzAttributes & 1) == 1 ) { - zzAction = zzState; - zzMarkedPosL = zzCurrentPosL; - if ( (zzAttributes & 8) == 8 ) break zzForAction; - } - - } - } - - // store back cached position - zzMarkedPos = zzMarkedPosL; - - switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) { - case 11: - { return GUIDefaultsFile.Keyword.NONE; - } - case 85: break; - case 52: - { return GUIDefaultsFile.Keyword.EDIT_NET_RULES; - } - case 86: break; - case 44: - { return GUIDefaultsFile.Keyword.PACKAGE_INFO; - } - case 87: break; - case 34: - { return GUIDefaultsFile.Keyword.FIXED_VIAS; - } - case 88: break; - case 60: - { return GUIDefaultsFile.Keyword.VIOLATIONS_INFO; - } - case 89: break; - case 70: - { return GUIDefaultsFile.Keyword.FORTYFIVE_DEGREE; - } - case 90: break; - case 54: - { return GUIDefaultsFile.Keyword.MOVE_PARAMETER; - } - case 91: break; - case 76: - { return GUIDefaultsFile.Keyword.DISPLAY_MISCELLANIOUS; - } - case 92: break; - case 53: - { return GUIDefaultsFile.Keyword.RULE_SELECTION; - } - case 93: break; - case 41: - { return GUIDefaultsFile.Keyword.MANUAL_RULES; - } - case 94: break; - case 17: - { return GUIDefaultsFile.Keyword.VISIBLE; - } - case 95: break; - case 12: - { return GUIDefaultsFile.Keyword.PINS; - } - case 96: break; - case 56: - { return GUIDefaultsFile.Keyword.COMPONENT_BACK; - } - case 97: break; - case 40: - { return GUIDefaultsFile.Keyword.GUI_DEFAULTS; - } - case 98: break; - case 15: - { return GUIDefaultsFile.Keyword.TRACES; - } - case 99: break; - case 73: - { return GUIDefaultsFile.Keyword.PULL_TIGHT_REGION; - } - case 100: break; - case 26: - { return GUIDefaultsFile.Keyword.VIA_RULES; - } - case 101: break; - case 77: - { return GUIDefaultsFile.Keyword.VIA_SNAP_TO_SMD_CENTER; - } - case 102: break; - case 38: - { return GUIDefaultsFile.Keyword.BOARD_FRAME; - } - case 103: break; - case 61: - { return GUIDefaultsFile.Keyword.ROUTE_PARAMETER; - } - case 104: break; - case 29: - { return GUIDefaultsFile.Keyword.PARAMETER; - } - case 105: break; - case 33: - { return GUIDefaultsFile.Keyword.CONDUCTION; - } - case 106: break; - case 48: - { return GUIDefaultsFile.Keyword.OBJECT_COLORS; - } - case 107: break; - case 28: - { return GUIDefaultsFile.Keyword.STITCHING; - } - case 108: break; - case 66: - { return GUIDefaultsFile.Keyword.SELECT_PARAMETER; - } - case 109: break; - case 72: - { return GUIDefaultsFile.Keyword.OBJECT_VISIBILITY; - } - case 110: break; - case 74: - { return GUIDefaultsFile.Keyword.PULL_TIGHT_ACCURACY; - } - case 111: break; - case 58: - { return GUIDefaultsFile.Keyword.DISPLAY_REGION; - } - case 112: break; - case 71: - { return GUIDefaultsFile.Keyword.INTERACTIVE_STATE; - } - case 113: break; - case 39: - { return GUIDefaultsFile.Keyword.NOT_VISIBLE; - } - case 114: break; - case 20: - { return GUIDefaultsFile.Keyword.DYNAMIC; - } - case 115: break; - case 84: - { return GUIDefaultsFile.Keyword.DESELECTED_SNAPSHOT_ATTRIBUTES; - } - case 116: break; - case 31: - { return GUIDefaultsFile.Keyword.BACKGROUND; - } - case 117: break; - case 64: - { return GUIDefaultsFile.Keyword.LAYER_VISIBILITY; - } - case 118: break; - case 43: - { return GUIDefaultsFile.Keyword.FIXED_TRACES; - } - case 119: break; - case 51: - { return GUIDefaultsFile.Keyword.PADSTACK_INFO; - } - case 120: break; - case 22: - { return GUIDefaultsFile.Keyword.HILIGHT; - } - case 121: break; - case 14: - { return GUIDefaultsFile.Keyword.BOUNDS; - } - case 122: break; - case 82: - { return GUIDefaultsFile.Keyword.DRAG_COMPONENTS_ENABLED; - } - case 123: break; - case 75: - { return GUIDefaultsFile.Keyword.MANUAL_RULE_SETTINGS; - } - case 124: break; - case 10: - { return GUIDefaultsFile.Keyword.VIAS; - } - case 125: break; - case 3: - { return yytext(); - } - case 126: break; - case 55: - { return GUIDefaultsFile.Keyword.COMPONENT_INFO; - } - case 127: break; - case 32: - { return GUIDefaultsFile.Keyword.ROUTE_MODE; - } - case 128: break; - case 50: - { return GUIDefaultsFile.Keyword.COLOR_MANAGER; - } - case 129: break; - case 30: - { return GUIDefaultsFile.Keyword.VIOLATIONS; - } - case 130: break; - case 67: - { return GUIDefaultsFile.Keyword.SELECTABLE_ITEMS; - } - case 131: break; - case 19: - { return GUIDefaultsFile.Keyword.OUTLINE; - } - case 132: break; - case 42: - { return GUIDefaultsFile.Keyword.CURRENT_ONLY; - } - case 133: break; - case 9: - { return GUIDefaultsFile.Keyword.OFF; - } - case 134: break; - case 45: - { return GUIDefaultsFile.Keyword.SHOVE_ENABLED; - } - case 135: break; - case 63: - { return GUIDefaultsFile.Keyword.ASSIGN_NET_RULES; - } - case 136: break; - case 25: - { return GUIDefaultsFile.Keyword.EDIT_VIAS; - } - case 137: break; - case 81: - { return GUIDefaultsFile.Keyword.IGNORE_CONDUCTION_AREAS; - } - case 138: break; - case 5: - { return GUIDefaultsFile.Keyword.OPEN_BRACKET; - } - case 139: break; - case 36: - { return GUIDefaultsFile.Keyword.VIA_KEEPOUT; - } - case 140: break; - case 8: - { return GUIDefaultsFile.Keyword.ON; - } - case 141: break; - case 16: - { return GUIDefaultsFile.Keyword.COLORS; - } - case 142: break; - case 68: - { return GUIDefaultsFile.Keyword.SELECTION_LAYERS; - } - case 143: break; - case 46: - { return GUIDefaultsFile.Keyword.NINETY_DEGREE; - } - case 144: break; - case 23: - { return GUIDefaultsFile.Keyword.WINDOWS; - } - case 145: break; - case 57: - { return GUIDefaultsFile.Keyword.COMPONENT_GRID; - } - case 146: break; - case 7: - { return new Double(yytext()); - } - case 147: break; - case 69: - { return GUIDefaultsFile.Keyword.CLEARANCE_MATRIX; - } - case 148: break; - case 65: - { return GUIDefaultsFile.Keyword.INCOMPLETES_INFO; - } - case 149: break; - case 62: - { return GUIDefaultsFile.Keyword.COMPONENT_FRONT; - } - case 150: break; - case 18: - { return GUIDefaultsFile.Keyword.UNFIXED; - } - case 151: break; - case 59: - { return GUIDefaultsFile.Keyword.LENGTH_MATCHING; - } - case 152: break; - case 80: - { return GUIDefaultsFile.Keyword.AUTOMATIC_LAYER_DIMMING; - } - case 153: break; - case 79: - { return GUIDefaultsFile.Keyword.PUSH_AND_SHOVE_ENABLED; - } - case 154: break; - case 24: - { return GUIDefaultsFile.Keyword.NET_INFO; - } - case 155: break; - case 78: - { return GUIDefaultsFile.Keyword.CLEARANCE_COMPENSATION; - } - case 156: break; - case 47: - { return GUIDefaultsFile.Keyword.ROUTE_DETAILS; - } - case 157: break; - case 2: - { /* ignore */ - } - case 158: break; - case 83: - { return GUIDefaultsFile.Keyword.HILIGHT_ROUTING_OBSTACLE; - } - case 159: break; - case 35: - { return GUIDefaultsFile.Keyword.ALL_VISIBLE; - } - case 160: break; - case 6: - { return GUIDefaultsFile.Keyword.CLOSED_BRACKET; - } - case 161: break; - case 1: - { throw new Error("Illegal character <"+ - yytext()+">"); - } - case 162: break; - case 37: - { return GUIDefaultsFile.Keyword.INCOMPLETES; - } - case 163: break; - case 49: - { return GUIDefaultsFile.Keyword.CURRENT_LAYER; - } - case 164: break; - case 21: - { return GUIDefaultsFile.Keyword.KEEPOUT; - } - case 165: break; - case 4: - { return new Integer(yytext()); - } - case 166: break; - case 13: - { return GUIDefaultsFile.Keyword.FIXED; - } - case 167: break; - case 27: - { return GUIDefaultsFile.Keyword.SNAPSHOTS; - } - case 168: break; - default: - if (zzInput == YYEOF && zzStartRead == zzCurrentPos) { - zzAtEOF = true; - return null; - } - else { - zzScanError(ZZ_NO_MATCH); - } - } - } - } - - -} +/* The following code was generated by JFlex 1.4 on 16.03.07 09:07 */ + +package gui; +@SuppressWarnings("all") + +/** + * This class is a scanner generated by + * JFlex 1.4 + * on 16.03.07 09:07 from the specification file + * C:/Dokumente und Einstellungen/alfons/Eigene Dateien/router/sources/gui/GUIDefaultsDescription.flex + */ +class GUIDefaultsScanner { + + /** This character denotes the end of file */ + public static final int YYEOF = -1; + + /** initial size of the lookahead buffer */ + private static final int ZZ_BUFFERSIZE = 16384; + + /** lexical states */ + public static final int YYINITIAL = 0; + + /** + * Translates characters to character classes + */ + private static final String ZZ_CMAP_PACKED = + "\11\0\1\3\1\2\1\0\1\3\1\1\22\0\1\3\2\0\1\6"+ + "\4\0\1\45\1\46\1\5\1\11\1\0\1\11\1\13\1\4\1\12"+ + "\11\10\7\0\1\16\1\23\1\33\1\35\1\14\1\37\1\24\1\42"+ + "\1\21\1\43\1\36\1\17\1\32\1\25\1\31\1\40\1\7\1\27"+ + "\1\22\1\26\1\30\1\20\1\44\1\41\1\34\1\7\4\0\1\15"+ + "\1\0\1\16\1\23\1\33\1\35\1\14\1\37\1\24\1\42\1\21"+ + "\1\43\1\36\1\17\1\32\1\25\1\31\1\40\1\7\1\27\1\22"+ + "\1\26\1\30\1\20\1\44\1\41\1\34\1\7\uff85\0"; + + /** + * Translates characters to character classes + */ + private static final char [] ZZ_CMAP = zzUnpackCMap(ZZ_CMAP_PACKED); + + /** + * Translates DFA states to action switch labels. + */ + private static final int [] ZZ_ACTION = zzUnpackAction(); + + private static final String ZZ_ACTION_PACKED_0 = + "\1\0\1\1\2\2\2\1\1\3\1\4\1\1\1\4"+ + "\25\3\1\5\1\6\4\0\1\7\30\3\1\10\23\3"+ + "\2\0\2\7\1\0\1\7\36\3\1\11\26\3\1\0"+ + "\7\3\1\12\17\3\1\13\30\3\1\14\57\3\1\15"+ + "\35\3\1\16\4\3\1\17\12\3\1\20\32\3\1\21"+ + "\24\3\1\22\1\3\1\23\12\3\1\24\1\25\10\3"+ + "\1\26\1\27\27\3\1\30\33\3\1\31\7\3\1\32"+ + "\10\3\1\33\1\34\33\3\1\35\15\3\1\36\7\3"+ + "\1\37\5\3\1\40\12\3\1\41\5\3\1\42\10\3"+ + "\1\43\5\3\1\44\3\3\1\45\4\3\1\46\2\3"+ + "\1\47\51\3\1\50\7\3\1\51\4\3\1\52\11\3"+ + "\1\53\1\3\1\54\22\3\1\55\1\56\1\3\1\57"+ + "\2\3\1\60\4\3\1\61\1\62\11\3\1\63\4\3"+ + "\1\64\14\3\1\65\3\3\1\66\2\3\1\67\1\70"+ + "\1\71\2\3\1\72\11\3\1\73\2\3\1\74\6\3"+ + "\1\75\4\3\1\76\10\3\1\77\1\3\1\100\3\3"+ + "\1\101\1\102\1\103\1\104\2\3\1\105\4\3\1\106"+ + "\7\3\1\107\1\110\6\3\1\111\25\3\1\112\5\3"+ + "\1\113\13\3\1\114\4\3\1\115\1\3\1\116\2\3"+ + "\1\117\1\3\1\120\1\121\1\3\1\122\2\3\1\123"+ + "\5\3\1\124"; + + private static int [] zzUnpackAction() { + int [] result = new int[796]; + int offset = 0; + offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackAction(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int count = packed.charAt(i++); + int value = packed.charAt(i++); + do result[j++] = value; while (--count > 0); + } + return j; + } + + + /** + * Translates a state to a row index in the transition table + */ + private static final int [] ZZ_ROWMAP = zzUnpackRowMap(); + + private static final String ZZ_ROWMAP_PACKED_0 = + "\0\0\0\47\0\116\0\47\0\165\0\234\0\303\0\352"+ + "\0\u0111\0\u0138\0\u015f\0\u0186\0\u01ad\0\u01d4\0\u01fb\0\u0222"+ + "\0\u0249\0\u0270\0\u0297\0\u02be\0\u02e5\0\u030c\0\u0333\0\u035a"+ + "\0\u0381\0\u03a8\0\u03cf\0\u03f6\0\u041d\0\u0444\0\u046b\0\47"+ + "\0\47\0\u0492\0\234\0\u04b9\0\u04e0\0\u0138\0\u0507\0\u052e"+ + "\0\u0555\0\u057c\0\u05a3\0\u05ca\0\u05f1\0\u0618\0\u063f\0\u0666"+ + "\0\u068d\0\u06b4\0\u06db\0\u0702\0\u0729\0\u0750\0\u0777\0\u079e"+ + "\0\u07c5\0\u07ec\0\u0813\0\u083a\0\u0861\0\u0888\0\303\0\u08af"+ + "\0\u08d6\0\u08fd\0\u0924\0\u094b\0\u0972\0\u0999\0\u09c0\0\u09e7"+ + "\0\u0a0e\0\u0a35\0\u0a5c\0\u0a83\0\u0aaa\0\u0ad1\0\u0af8\0\u0b1f"+ + "\0\u0b46\0\u0b6d\0\u0b94\0\u0bbb\0\u0be2\0\u0c09\0\u0c30\0\47"+ + "\0\u0c57\0\u0c7e\0\u0ca5\0\u0ccc\0\u0cf3\0\u0d1a\0\u0d41\0\u0d68"+ + "\0\u0d8f\0\u0db6\0\u0ddd\0\u0e04\0\u0e2b\0\u0e52\0\u0e79\0\u0ea0"+ + "\0\u0ec7\0\u0eee\0\u0f15\0\u0f3c\0\u0f63\0\u0f8a\0\u0fb1\0\u0fd8"+ + "\0\u0fff\0\u1026\0\u104d\0\u1074\0\u109b\0\u10c2\0\303\0\u10e9"+ + "\0\u1110\0\u1137\0\u115e\0\u1185\0\u11ac\0\u11d3\0\u11fa\0\u1221"+ + "\0\u1248\0\u126f\0\u1296\0\u12bd\0\u12e4\0\u130b\0\u1332\0\u1359"+ + "\0\u1380\0\u13a7\0\u13ce\0\u13f5\0\u141c\0\u1443\0\u146a\0\u1491"+ + "\0\u14b8\0\u14df\0\u1506\0\u152d\0\u1554\0\303\0\u157b\0\u15a2"+ + "\0\u15c9\0\u15f0\0\u1617\0\u163e\0\u1665\0\u168c\0\u16b3\0\u16da"+ + "\0\u1701\0\u1728\0\u174f\0\u1776\0\u179d\0\303\0\u17c4\0\u17eb"+ + "\0\u1812\0\u1839\0\u1860\0\u1887\0\u18ae\0\u18d5\0\u18fc\0\u1923"+ + "\0\u194a\0\u1971\0\u1998\0\u19bf\0\u19e6\0\u1a0d\0\u1a34\0\u1a5b"+ + "\0\u1a82\0\u1aa9\0\u1ad0\0\u1af7\0\u1b1e\0\u1b45\0\303\0\u1b6c"+ + "\0\u1b93\0\u1bba\0\u1be1\0\u1c08\0\u1c2f\0\u1c56\0\u1c7d\0\u1ca4"+ + "\0\u1ccb\0\u1cf2\0\u1d19\0\u1d40\0\u1d67\0\u1d8e\0\u1db5\0\u1ddc"+ + "\0\u1e03\0\u1e2a\0\u1e51\0\u1e78\0\u1e9f\0\u1ec6\0\u1eed\0\u1f14"+ + "\0\u1f3b\0\u1f62\0\u1f89\0\u1fb0\0\u1fd7\0\u1ffe\0\u2025\0\u204c"+ + "\0\u2073\0\u209a\0\u20c1\0\u20e8\0\u210f\0\u2136\0\u215d\0\u2184"+ + "\0\u21ab\0\u21d2\0\u21f9\0\u2220\0\u2247\0\u226e\0\u2295\0\u22bc"+ + "\0\u22e3\0\u230a\0\u2331\0\u2358\0\u237f\0\u23a6\0\u23cd\0\u23f4"+ + "\0\u241b\0\u2442\0\u2469\0\u2490\0\u24b7\0\u24de\0\u2505\0\u252c"+ + "\0\u2553\0\u257a\0\u25a1\0\u25c8\0\u25ef\0\u2616\0\u263d\0\u2664"+ + "\0\u268b\0\u26b2\0\u26d9\0\u2700\0\303\0\u2727\0\u274e\0\u2775"+ + "\0\u279c\0\303\0\u27c3\0\u27ea\0\u2811\0\u2838\0\u285f\0\u2886"+ + "\0\u28ad\0\u28d4\0\u28fb\0\u2922\0\303\0\u2949\0\u2970\0\u2997"+ + "\0\u29be\0\u29e5\0\u2a0c\0\u2a33\0\u2a5a\0\u2a81\0\u2aa8\0\u2acf"+ + "\0\u2af6\0\u2b1d\0\u2b44\0\u2b6b\0\u2b92\0\u2bb9\0\u2be0\0\u2c07"+ + "\0\u2c2e\0\u2c55\0\u2c7c\0\u2ca3\0\u2cca\0\u2cf1\0\u2d18\0\303"+ + "\0\u2d3f\0\u2d66\0\u2d8d\0\u2db4\0\u2ddb\0\u2e02\0\u2e29\0\u2e50"+ + "\0\u2e77\0\u2e9e\0\u2ec5\0\u2eec\0\u2f13\0\u2f3a\0\u2f61\0\u2f88"+ + "\0\u2faf\0\u2fd6\0\u2ffd\0\u3024\0\303\0\u304b\0\303\0\u3072"+ + "\0\u3099\0\u30c0\0\u30e7\0\u310e\0\u3135\0\u315c\0\u3183\0\u31aa"+ + "\0\u31d1\0\303\0\303\0\u31f8\0\u321f\0\u3246\0\u326d\0\u3294"+ + "\0\u32bb\0\u32e2\0\u3309\0\u3330\0\303\0\u3357\0\u337e\0\u33a5"+ + "\0\u33cc\0\u33f3\0\u341a\0\u3441\0\u3468\0\u348f\0\u34b6\0\u34dd"+ + "\0\u3504\0\u352b\0\u3552\0\u3579\0\u35a0\0\u35c7\0\u35ee\0\u3615"+ + "\0\u363c\0\u3663\0\u368a\0\u36b1\0\303\0\u36d8\0\u36ff\0\u3726"+ + "\0\u374d\0\u3774\0\u379b\0\u37c2\0\u37e9\0\u3810\0\u3837\0\u385e"+ + "\0\u3885\0\u38ac\0\u38d3\0\u38fa\0\u3921\0\u3948\0\u396f\0\u3996"+ + "\0\u39bd\0\u39e4\0\u3a0b\0\u3a32\0\u3a59\0\u3a80\0\u3aa7\0\u3ace"+ + "\0\303\0\u3af5\0\u3b1c\0\u3b43\0\u3b6a\0\u3b91\0\u3bb8\0\u3bdf"+ + "\0\303\0\u3c06\0\u3c2d\0\u3c54\0\u3c7b\0\u3ca2\0\u3cc9\0\u3cf0"+ + "\0\u3d17\0\303\0\303\0\u3d3e\0\u3d65\0\u3d8c\0\u3db3\0\u3dda"+ + "\0\u3e01\0\u3e28\0\u3e4f\0\u3e76\0\u3e9d\0\u3ec4\0\u3eeb\0\u3f12"+ + "\0\u3f39\0\u3f60\0\u3f87\0\u3fae\0\u3fd5\0\u3ffc\0\u4023\0\u404a"+ + "\0\u4071\0\u4098\0\u40bf\0\u40e6\0\u410d\0\u4134\0\303\0\u415b"+ + "\0\u4182\0\u41a9\0\u41d0\0\u41f7\0\u421e\0\u4245\0\u426c\0\u4293"+ + "\0\u42ba\0\u42e1\0\u4308\0\u432f\0\u4356\0\u437d\0\u43a4\0\u43cb"+ + "\0\u43f2\0\u4419\0\u4440\0\u4467\0\303\0\u448e\0\u44b5\0\u44dc"+ + "\0\u4503\0\u452a\0\303\0\u4551\0\u4578\0\u459f\0\u45c6\0\u45ed"+ + "\0\u4614\0\u463b\0\u4662\0\u4689\0\u46b0\0\303\0\u46d7\0\u46fe"+ + "\0\u4725\0\u474c\0\u4773\0\303\0\u479a\0\u47c1\0\u47e8\0\u480f"+ + "\0\u4836\0\u485d\0\u4884\0\u48ab\0\303\0\u48d2\0\u48f9\0\u4920"+ + "\0\u4947\0\u496e\0\303\0\u4995\0\u49bc\0\u49e3\0\u4a0a\0\u4a31"+ + "\0\u4a58\0\u4a7f\0\u4aa6\0\303\0\u4acd\0\u4af4\0\303\0\u4b1b"+ + "\0\u4b42\0\u4b69\0\u4b90\0\u4bb7\0\u4bde\0\u4c05\0\u4c2c\0\u4c53"+ + "\0\u4c7a\0\u4ca1\0\u4cc8\0\u4cef\0\u4d16\0\u4d3d\0\u4d64\0\u4d8b"+ + "\0\u4db2\0\u4dd9\0\u4e00\0\u4e27\0\u4e4e\0\u4e75\0\u4e9c\0\u4ec3"+ + "\0\u4eea\0\u4f11\0\u4f38\0\u4f5f\0\u4f86\0\u4fad\0\u4fd4\0\u4ffb"+ + "\0\u5022\0\u5049\0\u5070\0\u5097\0\u50be\0\u50e5\0\u510c\0\u5133"+ + "\0\303\0\u515a\0\u5181\0\u51a8\0\u51cf\0\u51f6\0\u521d\0\u5244"+ + "\0\303\0\u526b\0\u5292\0\u52b9\0\u52e0\0\303\0\u5307\0\u532e"+ + "\0\u5355\0\u537c\0\u53a3\0\u53ca\0\u53f1\0\u5418\0\u543f\0\303"+ + "\0\u5466\0\303\0\u548d\0\u54b4\0\u54db\0\u5502\0\u5529\0\u5550"+ + "\0\u5577\0\u559e\0\u55c5\0\u55ec\0\u5613\0\u563a\0\u5661\0\u5688"+ + "\0\u56af\0\u56d6\0\u56fd\0\u5724\0\303\0\303\0\u574b\0\303"+ + "\0\u5772\0\u5799\0\303\0\u57c0\0\u57e7\0\u580e\0\u5835\0\303"+ + "\0\303\0\u585c\0\u5883\0\u58aa\0\u58d1\0\u58f8\0\u591f\0\u5946"+ + "\0\u596d\0\u5994\0\303\0\u59bb\0\u59e2\0\u5a09\0\u5a30\0\303"+ + "\0\u5a57\0\u5a7e\0\u5aa5\0\u5acc\0\u5af3\0\u5b1a\0\u5b41\0\u5b68"+ + "\0\u5b8f\0\u5bb6\0\u5bdd\0\u5c04\0\303\0\u5c2b\0\u5c52\0\u5c79"+ + "\0\303\0\u5ca0\0\u5cc7\0\303\0\303\0\303\0\u5cee\0\u5d15"+ + "\0\303\0\u5d3c\0\u5d63\0\u5d8a\0\u5db1\0\u5dd8\0\u5dff\0\u5e26"+ + "\0\u5e4d\0\u5e74\0\303\0\u5e9b\0\u5ec2\0\303\0\u5ee9\0\u5f10"+ + "\0\u5f37\0\u5f5e\0\u5f85\0\u5fac\0\303\0\u5fd3\0\u5ffa\0\u6021"+ + "\0\u6048\0\303\0\u606f\0\u6096\0\u60bd\0\u60e4\0\u610b\0\u6132"+ + "\0\u6159\0\u6180\0\303\0\u61a7\0\303\0\u61ce\0\u61f5\0\u621c"+ + "\0\303\0\303\0\303\0\303\0\u6243\0\u626a\0\303\0\u6291"+ + "\0\u62b8\0\u62df\0\u6306\0\303\0\u632d\0\u6354\0\u637b\0\u63a2"+ + "\0\u63c9\0\u63f0\0\u6417\0\303\0\303\0\u643e\0\u6465\0\u648c"+ + "\0\u64b3\0\u64da\0\u6501\0\303\0\u6528\0\u654f\0\u6576\0\u659d"+ + "\0\u65c4\0\u65eb\0\u6612\0\u6639\0\u6660\0\u6687\0\u66ae\0\u66d5"+ + "\0\u66fc\0\u6723\0\u674a\0\u6771\0\u6798\0\u67bf\0\u67e6\0\u680d"+ + "\0\u6834\0\303\0\u685b\0\u6882\0\u68a9\0\u68d0\0\u68f7\0\303"+ + "\0\u691e\0\u6945\0\u696c\0\u6993\0\u69ba\0\u69e1\0\u6a08\0\u6a2f"+ + "\0\u6a56\0\u6a7d\0\u6aa4\0\303\0\u6acb\0\u6af2\0\u6b19\0\u6b40"+ + "\0\303\0\u6b67\0\303\0\u6b8e\0\u6bb5\0\303\0\u6bdc\0\303"+ + "\0\303\0\u6c03\0\303\0\u6c2a\0\u6c51\0\303\0\u6c78\0\u6c9f"+ + "\0\u6cc6\0\u6ced\0\u6d14\0\303"; + + private static int [] zzUnpackRowMap() { + int [] result = new int[796]; + int offset = 0; + offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackRowMap(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int high = packed.charAt(i++) << 16; + result[j++] = high | packed.charAt(i++); + } + return j; + } + + /** + * The transition table of the DFA + */ + private static final int [] ZZ_TRANS = zzUnpackTrans(); + + private static final String ZZ_TRANS_PACKED_0 = + "\1\2\1\3\2\4\1\5\1\2\1\6\1\7\1\10"+ + "\1\11\1\12\1\2\1\13\1\7\1\14\1\15\1\16"+ + "\1\17\1\20\1\21\1\22\1\23\1\24\1\25\1\26"+ + "\1\27\1\30\1\31\1\7\1\32\1\33\1\34\1\35"+ + "\1\7\1\36\1\7\1\37\1\40\1\41\51\0\1\4"+ + "\51\0\1\42\41\0\1\43\1\3\1\4\44\43\7\0"+ + "\2\7\1\0\1\7\1\0\31\7\12\0\1\10\1\0"+ + "\1\10\1\44\1\45\42\0\1\10\1\0\1\12\44\0"+ + "\1\46\1\0\1\46\1\44\1\45\41\0\2\7\1\0"+ + "\1\7\1\0\21\7\1\47\7\7\11\0\2\7\1\0"+ + "\1\7\1\0\3\7\1\50\2\7\1\51\5\7\1\52"+ + "\14\7\11\0\2\7\1\0\1\7\1\0\1\53\1\7"+ + "\1\54\26\7\11\0\2\7\1\0\1\7\1\0\5\7"+ + "\1\55\23\7\11\0\2\7\1\0\1\7\1\0\10\7"+ + "\1\56\1\57\17\7\11\0\2\7\1\0\1\7\1\0"+ + "\1\60\10\7\1\61\1\62\13\7\1\63\2\7\11\0"+ + "\2\7\1\0\1\7\1\0\2\7\1\64\12\7\1\65"+ + "\13\7\11\0\2\7\1\0\1\7\1\0\14\7\1\66"+ + "\14\7\11\0\2\7\1\0\1\7\1\0\1\67\4\7"+ + "\1\70\7\7\1\71\13\7\11\0\2\7\1\0\1\7"+ + "\1\0\13\7\1\72\15\7\11\0\2\7\1\0\1\7"+ + "\1\0\14\7\1\73\1\74\13\7\11\0\2\7\1\0"+ + "\1\7\1\0\11\7\1\75\17\7\11\0\2\7\1\0"+ + "\1\7\1\0\7\7\1\76\1\7\1\77\2\7\1\100"+ + "\6\7\1\101\5\7\11\0\2\7\1\0\1\7\1\0"+ + "\2\7\1\102\12\7\1\103\13\7\11\0\2\7\1\0"+ + "\1\7\1\0\3\7\1\104\10\7\1\105\1\106\13\7"+ + "\11\0\2\7\1\0\1\7\1\0\1\107\4\7\1\110"+ + "\5\7\1\111\4\7\1\112\10\7\11\0\2\7\1\0"+ + "\1\7\1\0\1\113\30\7\11\0\2\7\1\0\1\7"+ + "\1\0\5\7\1\114\7\7\1\115\13\7\11\0\2\7"+ + "\1\0\1\7\1\0\2\7\1\116\2\7\1\117\6\7"+ + "\1\120\14\7\11\0\2\7\1\0\1\7\1\0\5\7"+ + "\1\121\23\7\11\0\2\7\1\0\1\7\1\0\5\7"+ + "\1\122\23\7\2\0\5\123\1\124\41\123\10\0\1\125"+ + "\1\0\1\125\44\0\1\126\1\127\1\130\43\0\2\7"+ + "\1\0\1\7\1\0\5\7\1\131\23\7\11\0\2\7"+ + "\1\0\1\7\1\0\3\7\1\132\25\7\11\0\2\7"+ + "\1\0\1\7\1\0\6\7\1\133\22\7\11\0\2\7"+ + "\1\0\1\7\1\0\12\7\1\134\16\7\11\0\2\7"+ + "\1\0\1\7\1\0\11\7\1\135\17\7\11\0\2\7"+ + "\1\0\1\7\1\0\20\7\1\136\10\7\11\0\2\7"+ + "\1\0\1\7\1\0\2\7\1\137\3\7\1\140\6\7"+ + "\1\141\13\7\11\0\2\7\1\0\1\7\1\0\11\7"+ + "\1\142\17\7\11\0\2\7\1\0\1\7\1\0\12\7"+ + "\1\143\4\7\1\144\11\7\11\0\2\7\1\0\1\7"+ + "\1\0\3\7\1\145\25\7\11\0\2\7\1\0\1\7"+ + "\1\0\2\7\1\146\26\7\11\0\2\7\1\0\1\7"+ + "\1\0\5\7\1\147\23\7\11\0\2\7\1\0\1\7"+ + "\1\0\15\7\1\150\13\7\11\0\2\7\1\0\1\7"+ + "\1\0\17\7\1\151\11\7\11\0\2\7\1\0\1\7"+ + "\1\0\2\7\1\152\11\7\1\153\14\7\11\0\2\7"+ + "\1\0\1\7\1\0\5\7\1\154\23\7\11\0\2\7"+ + "\1\0\1\7\1\0\12\7\1\155\16\7\11\0\2\7"+ + "\1\0\1\7\1\0\11\7\1\156\17\7\11\0\2\7"+ + "\1\0\1\7\1\0\11\7\1\157\1\160\16\7\11\0"+ + "\2\7\1\0\1\7\1\0\2\7\1\161\26\7\11\0"+ + "\2\7\1\0\1\7\1\0\3\7\1\162\25\7\11\0"+ + "\2\7\1\0\1\7\1\0\14\7\1\163\14\7\11\0"+ + "\2\7\1\0\1\7\1\0\23\7\1\164\5\7\11\0"+ + "\2\7\1\0\1\7\1\0\27\7\1\165\1\7\11\0"+ + "\2\7\1\0\1\7\1\0\12\7\1\166\16\7\11\0"+ + "\2\7\1\0\1\7\1\0\23\7\1\167\5\7\11\0"+ + "\2\7\1\0\1\7\1\0\11\7\1\170\17\7\11\0"+ + "\2\7\1\0\1\7\1\0\4\7\1\171\24\7\11\0"+ + "\2\7\1\0\1\7\1\0\1\172\30\7\11\0\2\7"+ + "\1\0\1\7\1\0\13\7\1\173\15\7\11\0\2\7"+ + "\1\0\1\7\1\0\3\7\1\174\5\7\1\175\4\7"+ + "\1\176\12\7\11\0\2\7\1\0\1\7\1\0\6\7"+ + "\1\177\22\7\11\0\2\7\1\0\1\7\1\0\6\7"+ + "\1\200\22\7\11\0\2\7\1\0\1\7\1\0\2\7"+ + "\1\201\26\7\11\0\2\7\1\0\1\7\1\0\11\7"+ + "\1\202\17\7\11\0\2\7\1\0\1\7\1\0\1\203"+ + "\30\7\11\0\2\7\1\0\1\7\1\0\25\7\1\204"+ + "\3\7\11\0\2\7\1\0\1\7\1\0\13\7\1\205"+ + "\15\7\11\0\2\7\1\0\1\7\1\0\13\7\1\206"+ + "\3\7\1\207\1\7\1\210\7\7\11\0\2\7\1\0"+ + "\1\7\1\0\11\7\1\211\17\7\11\0\2\7\1\0"+ + "\1\7\1\0\3\7\1\212\2\7\1\213\22\7\11\0"+ + "\2\7\1\0\1\7\1\0\3\7\1\214\25\7\11\0"+ + "\2\7\1\0\1\7\1\0\11\7\1\215\17\7\2\0"+ + "\5\123\1\216\41\123\4\0\1\4\1\124\51\0\1\125"+ + "\1\0\1\125\1\0\1\45\42\0\1\126\1\0\1\126"+ + "\44\0\1\126\1\0\1\130\43\0\2\7\1\0\1\7"+ + "\1\0\12\7\1\217\16\7\11\0\2\7\1\0\1\7"+ + "\1\0\1\7\1\220\27\7\11\0\2\7\1\0\1\7"+ + "\1\0\5\7\1\221\23\7\11\0\2\7\1\0\1\7"+ + "\1\0\15\7\1\222\13\7\11\0\2\7\1\0\1\7"+ + "\1\0\10\7\1\223\20\7\11\0\2\7\1\0\1\7"+ + "\1\0\1\224\30\7\11\0\2\7\1\0\1\7\1\0"+ + "\1\7\1\225\4\7\1\226\22\7\11\0\2\7\1\0"+ + "\1\7\1\0\5\7\1\227\23\7\11\0\2\7\1\0"+ + "\1\7\1\0\3\7\1\230\25\7\11\0\2\7\1\0"+ + "\1\7\1\0\15\7\1\231\13\7\11\0\2\7\1\0"+ + "\1\7\1\0\1\232\30\7\11\0\2\7\1\0\1\7"+ + "\1\0\15\7\1\233\13\7\11\0\2\7\1\0\1\7"+ + "\1\0\1\234\30\7\11\0\2\7\1\0\1\7\1\0"+ + "\24\7\1\235\4\7\11\0\2\7\1\0\1\7\1\0"+ + "\12\7\1\236\16\7\11\0\2\7\1\0\1\7\1\0"+ + "\4\7\1\237\24\7\11\0\2\7\1\0\1\7\1\0"+ + "\22\7\1\240\6\7\11\0\2\7\1\0\1\7\1\0"+ + "\13\7\1\241\15\7\11\0\2\7\1\0\1\7\1\0"+ + "\11\7\1\242\17\7\11\0\2\7\1\0\1\7\1\0"+ + "\1\7\1\243\27\7\11\0\2\7\1\0\1\7\1\0"+ + "\1\7\1\244\27\7\11\0\2\7\1\0\1\7\1\0"+ + "\1\245\30\7\11\0\2\7\1\0\1\7\1\0\1\246"+ + "\30\7\11\0\2\7\1\0\1\7\1\0\1\7\1\247"+ + "\27\7\11\0\2\7\1\0\1\7\1\0\17\7\1\250"+ + "\11\7\11\0\2\7\1\0\1\7\1\0\1\251\30\7"+ + "\11\0\2\7\1\0\1\7\1\0\12\7\1\252\16\7"+ + "\11\0\2\7\1\0\1\7\1\0\5\7\1\253\23\7"+ + "\11\0\2\7\1\0\1\7\1\0\1\254\30\7\11\0"+ + "\2\7\1\0\1\7\1\0\3\7\1\255\25\7\11\0"+ + "\2\7\1\0\1\7\1\0\14\7\1\256\14\7\11\0"+ + "\2\7\1\0\1\7\1\0\1\257\30\7\11\0\2\7"+ + "\1\0\1\7\1\0\2\7\1\260\26\7\11\0\2\7"+ + "\1\0\1\7\1\0\13\7\1\261\15\7\11\0\2\7"+ + "\1\0\1\7\1\0\15\7\1\262\13\7\11\0\2\7"+ + "\1\0\1\7\1\0\21\7\1\263\7\7\11\0\2\7"+ + "\1\0\1\7\1\0\24\7\1\264\4\7\11\0\2\7"+ + "\1\0\1\7\1\0\1\265\30\7\11\0\2\7\1\0"+ + "\1\7\1\0\24\7\1\266\4\7\11\0\2\7\1\0"+ + "\1\7\1\0\10\7\1\267\20\7\11\0\2\7\1\0"+ + "\1\7\1\0\2\7\1\270\26\7\11\0\2\7\1\0"+ + "\1\7\1\0\24\7\1\271\4\7\11\0\2\7\1\0"+ + "\1\7\1\0\1\272\30\7\11\0\2\7\1\0\1\7"+ + "\1\0\12\7\1\273\16\7\11\0\2\7\1\0\1\7"+ + "\1\0\2\7\1\274\26\7\11\0\2\7\1\0\1\7"+ + "\1\0\22\7\1\275\6\7\11\0\2\7\1\0\1\7"+ + "\1\0\6\7\1\276\22\7\11\0\2\7\1\0\1\7"+ + "\1\0\6\7\1\277\22\7\11\0\2\7\1\0\1\7"+ + "\1\0\3\7\1\300\25\7\11\0\2\7\1\0\1\7"+ + "\1\0\26\7\1\301\2\7\11\0\2\7\1\0\1\7"+ + "\1\0\5\7\1\302\23\7\11\0\2\7\1\0\1\7"+ + "\1\0\21\7\1\303\7\7\2\0\4\123\1\4\1\216"+ + "\41\123\7\0\2\7\1\0\1\7\1\0\1\7\1\304"+ + "\27\7\11\0\2\7\1\0\1\7\1\0\4\7\1\305"+ + "\24\7\11\0\2\7\1\0\1\7\1\0\10\7\1\306"+ + "\20\7\11\0\2\7\1\0\1\7\1\0\16\7\1\307"+ + "\12\7\11\0\2\7\1\0\1\7\1\0\12\7\1\310"+ + "\16\7\11\0\2\7\1\0\1\7\1\0\13\7\1\311"+ + "\15\7\11\0\2\7\1\0\1\7\1\0\6\7\1\312"+ + "\4\7\1\313\6\7\1\314\6\7\11\0\2\7\1\0"+ + "\1\7\1\0\7\7\1\315\21\7\11\0\2\7\1\0"+ + "\1\7\1\0\2\7\1\316\26\7\11\0\2\7\1\0"+ + "\1\7\1\0\13\7\1\317\15\7\11\0\2\7\1\0"+ + "\1\7\1\0\13\7\1\320\15\7\11\0\2\7\1\0"+ + "\1\7\1\0\16\7\1\321\12\7\11\0\2\7\1\0"+ + "\1\7\1\0\17\7\1\322\11\7\11\0\2\7\1\0"+ + "\1\7\1\0\6\7\1\323\22\7\11\0\2\7\1\0"+ + "\1\7\1\0\17\7\1\324\11\7\11\0\2\7\1\0"+ + "\1\7\1\0\1\325\30\7\11\0\2\7\1\0\1\7"+ + "\1\0\10\7\1\326\20\7\11\0\2\7\1\0\1\7"+ + "\1\0\21\7\1\327\7\7\11\0\2\7\1\0\1\7"+ + "\1\0\21\7\1\330\7\7\11\0\2\7\1\0\1\7"+ + "\1\0\21\7\1\331\7\7\11\0\2\7\1\0\1\7"+ + "\1\0\5\7\1\332\23\7\11\0\2\7\1\0\1\7"+ + "\1\0\12\7\1\333\16\7\11\0\2\7\1\0\1\7"+ + "\1\0\4\7\1\334\24\7\11\0\2\7\1\0\1\7"+ + "\1\0\1\335\30\7\11\0\2\7\1\0\1\7\1\0"+ + "\1\7\1\336\27\7\11\0\2\7\1\0\1\7\1\0"+ + "\1\337\30\7\11\0\2\7\1\0\1\7\1\0\25\7"+ + "\1\340\3\7\11\0\2\7\1\0\1\7\1\0\17\7"+ + "\1\341\11\7\11\0\2\7\1\0\1\7\1\0\5\7"+ + "\1\342\23\7\11\0\2\7\1\0\1\7\1\0\2\7"+ + "\1\343\26\7\11\0\2\7\1\0\1\7\1\0\1\7"+ + "\1\344\27\7\11\0\2\7\1\0\1\7\1\0\13\7"+ + "\1\345\15\7\11\0\2\7\1\0\1\7\1\0\1\346"+ + "\30\7\11\0\2\7\1\0\1\7\1\0\13\7\1\347"+ + "\15\7\11\0\2\7\1\0\1\7\1\0\14\7\1\350"+ + "\14\7\11\0\2\7\1\0\1\7\1\0\15\7\1\351"+ + "\13\7\11\0\2\7\1\0\1\7\1\0\3\7\1\352"+ + "\25\7\11\0\2\7\1\0\1\7\1\0\3\7\1\353"+ + "\25\7\11\0\2\7\1\0\1\7\1\0\1\7\1\354"+ + "\27\7\11\0\2\7\1\0\1\7\1\0\16\7\1\355"+ + "\12\7\11\0\2\7\1\0\1\7\1\0\15\7\1\356"+ + "\13\7\11\0\2\7\1\0\1\7\1\0\21\7\1\357"+ + "\7\7\11\0\2\7\1\0\1\7\1\0\20\7\1\360"+ + "\10\7\11\0\2\7\1\0\1\7\1\0\16\7\1\361"+ + "\12\7\11\0\2\7\1\0\1\7\1\0\2\7\1\362"+ + "\26\7\11\0\2\7\1\0\1\7\1\0\12\7\1\363"+ + "\16\7\11\0\2\7\1\0\1\7\1\0\1\7\1\364"+ + "\27\7\11\0\2\7\1\0\1\7\1\0\1\7\1\365"+ + "\27\7\11\0\2\7\1\0\1\7\1\0\10\7\1\366"+ + "\20\7\11\0\2\7\1\0\1\7\1\0\15\7\1\367"+ + "\13\7\11\0\2\7\1\0\1\7\1\0\4\7\1\370"+ + "\4\7\1\371\17\7\11\0\2\7\1\0\1\7\1\0"+ + "\5\7\1\372\23\7\11\0\2\7\1\0\1\7\1\0"+ + "\11\7\1\373\17\7\11\0\2\7\1\0\1\7\1\0"+ + "\2\7\1\374\26\7\11\0\2\7\1\0\1\7\1\0"+ + "\26\7\1\375\2\7\11\0\2\7\1\0\1\7\1\0"+ + "\1\7\1\376\27\7\11\0\2\7\1\0\1\7\1\0"+ + "\11\7\1\377\17\7\11\0\2\7\1\0\1\7\1\0"+ + "\14\7\1\u0100\14\7\11\0\2\7\1\0\1\7\1\0"+ + "\1\u0101\30\7\11\0\2\7\1\0\1\7\1\0\3\7"+ + "\1\u0102\25\7\11\0\2\7\1\0\1\7\1\0\12\7"+ + "\1\u0103\16\7\11\0\2\7\1\0\1\7\1\0\1\u0104"+ + "\30\7\11\0\2\7\1\0\1\7\1\0\2\7\1\u0105"+ + "\26\7\11\0\2\7\1\0\1\7\1\0\24\7\1\u0106"+ + "\4\7\11\0\2\7\1\0\1\7\1\0\12\7\1\u0107"+ + "\16\7\11\0\2\7\1\0\1\7\1\0\26\7\1\u0108"+ + "\2\7\11\0\2\7\1\0\1\7\1\0\26\7\1\u0109"+ + "\2\7\11\0\2\7\1\0\1\7\1\0\1\7\1\u010a"+ + "\27\7\11\0\2\7\1\0\1\7\1\0\13\7\1\u010b"+ + "\15\7\11\0\2\7\1\0\1\7\1\0\1\7\1\u010c"+ + "\27\7\11\0\2\7\1\0\1\7\1\0\6\7\1\u010d"+ + "\22\7\11\0\2\7\1\0\1\7\1\0\1\u010e\30\7"+ + "\11\0\2\7\1\0\1\7\1\0\11\7\1\u010f\17\7"+ + "\11\0\2\7\1\0\1\7\1\0\20\7\1\u0110\10\7"+ + "\11\0\2\7\1\0\1\7\1\0\5\7\1\u0111\23\7"+ + "\11\0\2\7\1\0\1\7\1\0\6\7\1\u0112\22\7"+ + "\11\0\2\7\1\0\1\7\1\0\6\7\1\u0113\22\7"+ + "\11\0\2\7\1\0\1\7\1\0\1\7\1\u0114\27\7"+ + "\11\0\2\7\1\0\1\7\1\0\1\u0115\30\7\11\0"+ + "\2\7\1\0\1\7\1\0\12\7\1\u0116\16\7\11\0"+ + "\2\7\1\0\1\7\1\0\11\7\1\u0117\17\7\11\0"+ + "\2\7\1\0\1\7\1\0\3\7\1\u0118\25\7\11\0"+ + "\2\7\1\0\1\7\1\0\24\7\1\u0119\4\7\11\0"+ + "\2\7\1\0\1\7\1\0\2\7\1\u011a\26\7\11\0"+ + "\2\7\1\0\1\7\1\0\11\7\1\u011b\17\7\11\0"+ + "\2\7\1\0\1\7\1\0\1\7\1\u011c\4\7\1\u011d"+ + "\22\7\11\0\2\7\1\0\1\7\1\0\17\7\1\u011e"+ + "\11\7\11\0\2\7\1\0\1\7\1\0\11\7\1\u011f"+ + "\17\7\11\0\2\7\1\0\1\7\1\0\1\u0120\30\7"+ + "\11\0\2\7\1\0\1\7\1\0\2\7\1\u0121\26\7"+ + "\11\0\2\7\1\0\1\7\1\0\17\7\1\u0122\11\7"+ + "\11\0\2\7\1\0\1\7\1\0\5\7\1\u0123\23\7"+ + "\11\0\2\7\1\0\1\7\1\0\14\7\1\u0124\14\7"+ + "\11\0\2\7\1\0\1\7\1\0\1\7\1\u0125\27\7"+ + "\11\0\2\7\1\0\1\7\1\0\23\7\1\u0126\5\7"+ + "\11\0\2\7\1\0\1\7\1\0\1\u0127\30\7\11\0"+ + "\2\7\1\0\1\7\1\0\10\7\1\u0128\20\7\11\0"+ + "\2\7\1\0\1\7\1\0\2\7\1\u0129\26\7\11\0"+ + "\2\7\1\0\1\7\1\0\12\7\1\u012a\16\7\11\0"+ + "\2\7\1\0\1\7\1\0\2\7\1\u012b\26\7\11\0"+ + "\2\7\1\0\1\7\1\0\26\7\1\u012c\2\7\11\0"+ + "\2\7\1\0\1\7\1\0\30\7\1\u012d\11\0\2\7"+ + "\1\0\1\7\1\0\5\7\1\u012e\23\7\11\0\2\7"+ + "\1\0\1\7\1\0\1\u012f\30\7\11\0\2\7\1\0"+ + "\1\7\1\0\6\7\1\u0130\22\7\11\0\2\7\1\0"+ + "\1\7\1\0\1\7\1\u0131\27\7\11\0\2\7\1\0"+ + "\1\7\1\0\12\7\1\u0132\16\7\11\0\2\7\1\0"+ + "\1\7\1\0\1\7\1\u0133\27\7\11\0\2\7\1\0"+ + "\1\7\1\0\4\7\1\u0134\24\7\11\0\2\7\1\0"+ + "\1\7\1\0\2\7\1\u0135\26\7\11\0\2\7\1\0"+ + "\1\7\1\0\3\7\1\u0136\25\7\11\0\2\7\1\0"+ + "\1\7\1\0\1\u0137\30\7\11\0\2\7\1\0\1\7"+ + "\1\0\1\u0138\30\7\11\0\2\7\1\0\1\7\1\0"+ + "\5\7\1\u0139\23\7\11\0\2\7\1\0\1\7\1\0"+ + "\1\7\1\u013a\27\7\11\0\2\7\1\0\1\7\1\0"+ + "\17\7\1\u013b\11\7\11\0\2\7\1\0\1\7\1\0"+ + "\3\7\1\u013c\25\7\11\0\2\7\1\0\1\7\1\0"+ + "\1\7\1\u013d\1\u013e\2\7\1\u013f\23\7\11\0\2\7"+ + "\1\0\1\7\1\0\15\7\1\u0140\13\7\11\0\2\7"+ + "\1\0\1\7\1\0\5\7\1\u0141\23\7\11\0\2\7"+ + "\1\0\1\7\1\0\1\u0142\30\7\11\0\2\7\1\0"+ + "\1\7\1\0\15\7\1\u0143\13\7\11\0\2\7\1\0"+ + "\1\7\1\0\23\7\1\u0144\5\7\11\0\2\7\1\0"+ + "\1\7\1\0\23\7\1\u0145\5\7\11\0\2\7\1\0"+ + "\1\7\1\0\23\7\1\u0146\5\7\11\0\2\7\1\0"+ + "\1\7\1\0\1\7\1\u0147\27\7\11\0\2\7\1\0"+ + "\1\7\1\0\6\7\1\u0148\22\7\11\0\2\7\1\0"+ + "\1\7\1\0\1\u0149\30\7\11\0\2\7\1\0\1\7"+ + "\1\0\16\7\1\u014a\2\7\1\u014b\2\7\1\u014c\4\7"+ + "\11\0\2\7\1\0\1\7\1\0\21\7\1\u014d\7\7"+ + "\11\0\2\7\1\0\1\7\1\0\1\7\1\u014e\27\7"+ + "\11\0\2\7\1\0\1\7\1\0\1\u014f\30\7\11\0"+ + "\2\7\1\0\1\7\1\0\1\7\1\u0150\27\7\11\0"+ + "\2\7\1\0\1\7\1\0\2\7\1\u0151\26\7\11\0"+ + "\2\7\1\0\1\7\1\0\11\7\1\u0152\17\7\11\0"+ + "\2\7\1\0\1\7\1\0\12\7\1\u0153\16\7\11\0"+ + "\2\7\1\0\1\7\1\0\16\7\1\u0154\12\7\11\0"+ + "\2\7\1\0\1\7\1\0\12\7\1\u0155\16\7\11\0"+ + "\2\7\1\0\1\7\1\0\1\u0156\30\7\11\0\2\7"+ + "\1\0\1\7\1\0\17\7\1\u0157\11\7\11\0\2\7"+ + "\1\0\1\7\1\0\20\7\1\u0158\10\7\11\0\2\7"+ + "\1\0\1\7\1\0\15\7\1\u0159\13\7\11\0\2\7"+ + "\1\0\1\7\1\0\17\7\1\u015a\11\7\11\0\2\7"+ + "\1\0\1\7\1\0\12\7\1\u015b\16\7\11\0\2\7"+ + "\1\0\1\7\1\0\4\7\1\u015c\5\7\1\u015d\16\7"+ + "\11\0\2\7\1\0\1\7\1\0\5\7\1\u015e\23\7"+ + "\11\0\2\7\1\0\1\7\1\0\12\7\1\u015f\16\7"+ + "\11\0\2\7\1\0\1\7\1\0\1\u0160\30\7\11\0"+ + "\2\7\1\0\1\7\1\0\17\7\1\u0161\11\7\11\0"+ + "\2\7\1\0\1\7\1\0\5\7\1\u0162\23\7\11\0"+ + "\2\7\1\0\1\7\1\0\11\7\1\u0163\17\7\11\0"+ + "\2\7\1\0\1\7\1\0\12\7\1\u0164\16\7\11\0"+ + "\2\7\1\0\1\7\1\0\6\7\1\u0165\22\7\11\0"+ + "\2\7\1\0\1\7\1\0\2\7\1\u0166\26\7\11\0"+ + "\2\7\1\0\1\7\1\0\12\7\1\u0167\16\7\11\0"+ + "\2\7\1\0\1\7\1\0\5\7\1\u0168\23\7\11\0"+ + "\2\7\1\0\1\7\1\0\11\7\1\u0169\17\7\11\0"+ + "\2\7\1\0\1\7\1\0\5\7\1\u016a\23\7\11\0"+ + "\2\7\1\0\1\7\1\0\16\7\1\u016b\12\7\11\0"+ + "\2\7\1\0\1\7\1\0\5\7\1\u016c\23\7\11\0"+ + "\2\7\1\0\1\7\1\0\24\7\1\u016d\4\7\11\0"+ + "\2\7\1\0\1\7\1\0\1\u016e\30\7\11\0\2\7"+ + "\1\0\1\7\1\0\24\7\1\u016f\4\7\11\0\2\7"+ + "\1\0\1\7\1\0\15\7\1\u0170\13\7\11\0\2\7"+ + "\1\0\1\7\1\0\17\7\1\u0171\11\7\11\0\2\7"+ + "\1\0\1\7\1\0\12\7\1\u0172\16\7\11\0\2\7"+ + "\1\0\1\7\1\0\1\u0173\30\7\11\0\2\7\1\0"+ + "\1\7\1\0\24\7\1\u0174\4\7\11\0\2\7\1\0"+ + "\1\7\1\0\7\7\1\u0175\21\7\11\0\2\7\1\0"+ + "\1\7\1\0\15\7\1\u0176\13\7\11\0\2\7\1\0"+ + "\1\7\1\0\12\7\1\u0177\16\7\11\0\2\7\1\0"+ + "\1\7\1\0\11\7\1\u0178\17\7\11\0\2\7\1\0"+ + "\1\7\1\0\11\7\1\u0179\17\7\11\0\2\7\1\0"+ + "\1\7\1\0\14\7\1\u017a\14\7\11\0\2\7\1\0"+ + "\1\7\1\0\13\7\1\u017b\15\7\11\0\2\7\1\0"+ + "\1\7\1\0\2\7\1\u017c\26\7\11\0\2\7\1\0"+ + "\1\7\1\0\15\7\1\u017d\13\7\11\0\2\7\1\0"+ + "\1\7\1\0\21\7\1\u017e\7\7\11\0\2\7\1\0"+ + "\1\7\1\0\5\7\1\u017f\23\7\11\0\2\7\1\0"+ + "\1\7\1\0\3\7\1\u0180\25\7\11\0\2\7\1\0"+ + "\1\7\1\0\15\7\1\u0181\13\7\11\0\2\7\1\0"+ + "\1\7\1\0\1\u0182\30\7\11\0\2\7\1\0\1\7"+ + "\1\0\2\7\1\u0183\26\7\11\0\2\7\1\0\1\7"+ + "\1\0\4\7\1\u0184\12\7\1\u0185\11\7\11\0\2\7"+ + "\1\0\1\7\1\0\13\7\1\u0186\15\7\11\0\2\7"+ + "\1\0\1\7\1\0\13\7\1\u0187\15\7\11\0\2\7"+ + "\1\0\1\7\1\0\17\7\1\u0188\11\7\11\0\2\7"+ + "\1\0\1\7\1\0\1\7\1\u0189\27\7\11\0\2\7"+ + "\1\0\1\7\1\0\2\7\1\u018a\26\7\11\0\2\7"+ + "\1\0\1\7\1\0\5\7\1\u018b\23\7\11\0\2\7"+ + "\1\0\1\7\1\0\11\7\1\u018c\17\7\11\0\2\7"+ + "\1\0\1\7\1\0\12\7\1\u018d\16\7\11\0\2\7"+ + "\1\0\1\7\1\0\1\7\1\u018e\27\7\11\0\2\7"+ + "\1\0\1\7\1\0\16\7\1\u018f\12\7\11\0\2\7"+ + "\1\0\1\7\1\0\5\7\1\u0190\23\7\11\0\2\7"+ + "\1\0\1\7\1\0\13\7\1\u0191\15\7\11\0\2\7"+ + "\1\0\1\7\1\0\4\7\1\u0192\24\7\11\0\2\7"+ + "\1\0\1\7\1\0\1\u0193\30\7\11\0\2\7\1\0"+ + "\1\7\1\0\1\7\1\u0194\27\7\11\0\2\7\1\0"+ + "\1\7\1\0\22\7\1\u0195\6\7\11\0\2\7\1\0"+ + "\1\7\1\0\10\7\1\u0196\20\7\11\0\2\7\1\0"+ + "\1\7\1\0\21\7\1\u0197\7\7\11\0\2\7\1\0"+ + "\1\7\1\0\1\7\1\u0198\27\7\11\0\2\7\1\0"+ + "\1\7\1\0\6\7\1\u0199\22\7\11\0\2\7\1\0"+ + "\1\7\1\0\1\7\1\u019a\27\7\11\0\2\7\1\0"+ + "\1\7\1\0\7\7\1\u019b\21\7\11\0\2\7\1\0"+ + "\1\7\1\0\1\u019c\30\7\11\0\2\7\1\0\1\7"+ + "\1\0\17\7\1\u019d\11\7\11\0\2\7\1\0\1\7"+ + "\1\0\2\7\1\u019e\26\7\11\0\2\7\1\0\1\7"+ + "\1\0\6\7\1\u019f\22\7\11\0\2\7\1\0\1\7"+ + "\1\0\1\7\1\u01a0\27\7\11\0\2\7\1\0\1\7"+ + "\1\0\6\7\1\u01a1\22\7\11\0\2\7\1\0\1\7"+ + "\1\0\15\7\1\u01a2\13\7\11\0\2\7\1\0\1\7"+ + "\1\0\11\7\1\u01a3\17\7\11\0\2\7\1\0\1\7"+ + "\1\0\15\7\1\u01a4\13\7\11\0\2\7\1\0\1\7"+ + "\1\0\5\7\1\u01a5\23\7\11\0\2\7\1\0\1\7"+ + "\1\0\12\7\1\u01a6\16\7\11\0\2\7\1\0\1\7"+ + "\1\0\2\7\1\u01a7\26\7\11\0\2\7\1\0\1\7"+ + "\1\0\3\7\1\u01a8\25\7\11\0\2\7\1\0\1\7"+ + "\1\0\11\7\1\u01a9\17\7\11\0\2\7\1\0\1\7"+ + "\1\0\6\7\1\u01aa\22\7\11\0\2\7\1\0\1\7"+ + "\1\0\10\7\1\u01ab\20\7\11\0\2\7\1\0\1\7"+ + "\1\0\2\7\1\u01ac\26\7\11\0\2\7\1\0\1\7"+ + "\1\0\11\7\1\u01ad\17\7\11\0\2\7\1\0\1\7"+ + "\1\0\2\7\1\u01ae\26\7\11\0\2\7\1\0\1\7"+ + "\1\0\14\7\1\u01af\14\7\11\0\2\7\1\0\1\7"+ + "\1\0\1\u01b0\30\7\11\0\2\7\1\0\1\7\1\0"+ + "\7\7\1\u01b1\21\7\11\0\2\7\1\0\1\7\1\0"+ + "\1\u01b2\30\7\11\0\2\7\1\0\1\7\1\0\21\7"+ + "\1\u01b3\7\7\11\0\2\7\1\0\1\7\1\0\12\7"+ + "\1\u01b4\16\7\11\0\2\7\1\0\1\7\1\0\13\7"+ + "\1\u01b5\15\7\11\0\2\7\1\0\1\7\1\0\5\7"+ + "\1\u01b6\23\7\11\0\2\7\1\0\1\7\1\0\15\7"+ + "\1\u01b7\13\7\11\0\2\7\1\0\1\7\1\0\14\7"+ + "\1\u01b8\14\7\11\0\2\7\1\0\1\7\1\0\2\7"+ + "\1\u01b9\26\7\11\0\2\7\1\0\1\7\1\0\1\u01ba"+ + "\30\7\11\0\2\7\1\0\1\7\1\0\3\7\1\u01bb"+ + "\11\7\1\u01bc\13\7\11\0\2\7\1\0\1\7\1\0"+ + "\11\7\1\u01bd\17\7\11\0\2\7\1\0\1\7\1\0"+ + "\15\7\1\u01be\13\7\11\0\2\7\1\0\1\7\1\0"+ + "\12\7\1\u01bf\16\7\11\0\2\7\1\0\1\7\1\0"+ + "\1\u01c0\30\7\11\0\2\7\1\0\1\7\1\0\13\7"+ + "\1\u01c1\2\7\1\u01c2\12\7\11\0\2\7\1\0\1\7"+ + "\1\0\24\7\1\u01c3\4\7\11\0\2\7\1\0\1\7"+ + "\1\0\2\7\1\u01c4\26\7\11\0\2\7\1\0\1\7"+ + "\1\0\2\7\1\u01c5\26\7\11\0\2\7\1\0\1\7"+ + "\1\0\1\u01c6\30\7\11\0\2\7\1\0\1\7\1\0"+ + "\13\7\1\u01c7\15\7\11\0\2\7\1\0\1\7\1\0"+ + "\5\7\1\u01c8\23\7\11\0\2\7\1\0\1\7\1\0"+ + "\1\7\1\u01c9\27\7\11\0\2\7\1\0\1\7\1\0"+ + "\26\7\1\u01ca\2\7\11\0\2\7\1\0\1\7\1\0"+ + "\1\7\1\u01cb\27\7\11\0\2\7\1\0\1\7\1\0"+ + "\13\7\1\u01cc\15\7\11\0\2\7\1\0\1\7\1\0"+ + "\13\7\1\u01cd\15\7\11\0\2\7\1\0\1\7\1\0"+ + "\3\7\1\u01ce\25\7\11\0\2\7\1\0\1\7\1\0"+ + "\12\7\1\u01cf\16\7\11\0\2\7\1\0\1\7\1\0"+ + "\1\7\1\u01d0\27\7\11\0\2\7\1\0\1\7\1\0"+ + "\12\7\1\u01d1\16\7\11\0\2\7\1\0\1\7\1\0"+ + "\5\7\1\u01d2\23\7\11\0\2\7\1\0\1\7\1\0"+ + "\12\7\1\u01d3\16\7\11\0\2\7\1\0\1\7\1\0"+ + "\14\7\1\u01d4\14\7\11\0\2\7\1\0\1\7\1\0"+ + "\6\7\1\u01d5\22\7\11\0\2\7\1\0\1\7\1\0"+ + "\11\7\1\u01d6\17\7\11\0\2\7\1\0\1\7\1\0"+ + "\4\7\1\u01d7\24\7\11\0\2\7\1\0\1\7\1\0"+ + "\1\u01d8\30\7\11\0\2\7\1\0\1\7\1\0\13\7"+ + "\1\u01d9\15\7\11\0\2\7\1\0\1\7\1\0\1\u01da"+ + "\30\7\11\0\2\7\1\0\1\7\1\0\1\7\1\u01db"+ + "\27\7\11\0\2\7\1\0\1\7\1\0\7\7\1\u01dc"+ + "\21\7\11\0\2\7\1\0\1\7\1\0\21\7\1\u01dd"+ + "\7\7\11\0\2\7\1\0\1\7\1\0\16\7\1\u01de"+ + "\12\7\11\0\2\7\1\0\1\7\1\0\3\7\1\u01df"+ + "\25\7\11\0\2\7\1\0\1\7\1\0\10\7\1\u01e0"+ + "\20\7\11\0\2\7\1\0\1\7\1\0\3\7\1\u01e1"+ + "\25\7\11\0\2\7\1\0\1\7\1\0\17\7\1\u01e2"+ + "\11\7\11\0\2\7\1\0\1\7\1\0\1\u01e3\30\7"+ + "\11\0\2\7\1\0\1\7\1\0\2\7\1\u01e4\26\7"+ + "\11\0\2\7\1\0\1\7\1\0\2\7\1\u01e5\26\7"+ + "\11\0\2\7\1\0\1\7\1\0\6\7\1\u01e6\22\7"+ + "\11\0\2\7\1\0\1\7\1\0\3\7\1\u01e7\25\7"+ + "\11\0\2\7\1\0\1\7\1\0\3\7\1\u01e8\25\7"+ + "\11\0\2\7\1\0\1\7\1\0\16\7\1\u01e9\12\7"+ + "\11\0\2\7\1\0\1\7\1\0\1\7\1\u01ea\27\7"+ + "\11\0\2\7\1\0\1\7\1\0\2\7\1\u01eb\26\7"+ + "\11\0\2\7\1\0\1\7\1\0\11\7\1\u01ec\17\7"+ + "\11\0\2\7\1\0\1\7\1\0\2\7\1\u01ed\26\7"+ + "\11\0\2\7\1\0\1\7\1\0\11\7\1\u01ee\17\7"+ + "\11\0\2\7\1\0\1\7\1\0\1\7\1\u01ef\27\7"+ + "\11\0\2\7\1\0\1\7\1\0\21\7\1\u01f0\7\7"+ + "\11\0\2\7\1\0\1\7\1\0\1\u01f1\30\7\11\0"+ + "\2\7\1\0\1\7\1\0\5\7\1\u01f2\23\7\11\0"+ + "\2\7\1\0\1\7\1\0\15\7\1\u01f3\13\7\11\0"+ + "\2\7\1\0\1\7\1\0\6\7\1\u01f4\22\7\11\0"+ + "\2\7\1\0\1\7\1\0\17\7\1\u01f5\11\7\11\0"+ + "\2\7\1\0\1\7\1\0\1\7\1\u01f6\27\7\11\0"+ + "\2\7\1\0\1\7\1\0\11\7\1\u01f7\17\7\11\0"+ + "\2\7\1\0\1\7\1\0\5\7\1\u01f8\23\7\11\0"+ + "\2\7\1\0\1\7\1\0\12\7\1\u01f9\16\7\11\0"+ + "\2\7\1\0\1\7\1\0\6\7\1\u01fa\22\7\11\0"+ + "\2\7\1\0\1\7\1\0\15\7\1\u01fb\13\7\11\0"+ + "\2\7\1\0\1\7\1\0\14\7\1\u01fc\14\7\11\0"+ + "\2\7\1\0\1\7\1\0\1\u01fd\30\7\11\0\2\7"+ + "\1\0\1\7\1\0\1\7\1\u01fe\27\7\11\0\2\7"+ + "\1\0\1\7\1\0\3\7\1\u01ff\25\7\11\0\2\7"+ + "\1\0\1\7\1\0\17\7\1\u0200\11\7\11\0\2\7"+ + "\1\0\1\7\1\0\7\7\1\u0201\21\7\11\0\2\7"+ + "\1\0\1\7\1\0\15\7\1\u0202\13\7\11\0\2\7"+ + "\1\0\1\7\1\0\12\7\1\u0203\16\7\11\0\2\7"+ + "\1\0\1\7\1\0\1\7\1\u0204\27\7\11\0\2\7"+ + "\1\0\1\7\1\0\21\7\1\u0205\7\7\11\0\2\7"+ + "\1\0\1\7\1\0\1\u0206\30\7\11\0\2\7\1\0"+ + "\1\7\1\0\6\7\1\u0207\22\7\11\0\2\7\1\0"+ + "\1\7\1\0\2\7\1\u0208\26\7\11\0\2\7\1\0"+ + "\1\7\1\0\1\7\1\u0209\27\7\11\0\2\7\1\0"+ + "\1\7\1\0\3\7\1\u020a\25\7\11\0\2\7\1\0"+ + "\1\7\1\0\3\7\1\u020b\25\7\11\0\2\7\1\0"+ + "\1\7\1\0\1\u020c\30\7\11\0\2\7\1\0\1\7"+ + "\1\0\12\7\1\u020d\16\7\11\0\2\7\1\0\1\7"+ + "\1\0\13\7\1\u020e\15\7\11\0\2\7\1\0\1\7"+ + "\1\0\1\u020f\30\7\11\0\2\7\1\0\1\7\1\0"+ + "\12\7\1\u0210\16\7\11\0\2\7\1\0\1\7\1\0"+ + "\5\7\1\u0211\23\7\11\0\2\7\1\0\1\7\1\0"+ + "\16\7\1\u0212\12\7\11\0\2\7\1\0\1\7\1\0"+ + "\5\7\1\u0213\23\7\11\0\2\7\1\0\1\7\1\0"+ + "\15\7\1\u0214\13\7\11\0\2\7\1\0\1\7\1\0"+ + "\1\u0215\30\7\11\0\2\7\1\0\1\7\1\0\1\u0216"+ + "\30\7\11\0\2\7\1\0\1\7\1\0\16\7\1\u0217"+ + "\1\u0218\11\7\11\0\2\7\1\0\1\7\1\0\20\7"+ + "\1\u0219\10\7\11\0\2\7\1\0\1\7\1\0\3\7"+ + "\1\u021a\25\7\11\0\2\7\1\0\1\7\1\0\10\7"+ + "\1\u021b\20\7\11\0\2\7\1\0\1\7\1\0\5\7"+ + "\1\u021c\1\7\1\u021d\1\u021e\12\7\1\u021f\5\7\11\0"+ + "\2\7\1\0\1\7\1\0\1\7\1\u0220\27\7\11\0"+ + "\2\7\1\0\1\7\1\0\10\7\1\u0221\20\7\11\0"+ + "\2\7\1\0\1\7\1\0\6\7\1\u0222\22\7\11\0"+ + "\2\7\1\0\1\7\1\0\11\7\1\u0223\17\7\11\0"+ + "\2\7\1\0\1\7\1\0\1\u0224\30\7\11\0\2\7"+ + "\1\0\1\7\1\0\21\7\1\u0225\7\7\11\0\2\7"+ + "\1\0\1\7\1\0\23\7\1\u0226\5\7\11\0\2\7"+ + "\1\0\1\7\1\0\11\7\1\u0227\17\7\11\0\2\7"+ + "\1\0\1\7\1\0\1\7\1\u0228\27\7\11\0\2\7"+ + "\1\0\1\7\1\0\26\7\1\u0229\2\7\11\0\2\7"+ + "\1\0\1\7\1\0\14\7\1\u022a\14\7\11\0\2\7"+ + "\1\0\1\7\1\0\3\7\1\u022b\25\7\11\0\2\7"+ + "\1\0\1\7\1\0\13\7\1\u022c\15\7\11\0\2\7"+ + "\1\0\1\7\1\0\2\7\1\u022d\26\7\11\0\2\7"+ + "\1\0\1\7\1\0\26\7\1\u022e\2\7\11\0\2\7"+ + "\1\0\1\7\1\0\5\7\1\u022f\23\7\11\0\2\7"+ + "\1\0\1\7\1\0\1\7\1\u0230\27\7\11\0\2\7"+ + "\1\0\1\7\1\0\5\7\1\u0231\23\7\11\0\2\7"+ + "\1\0\1\7\1\0\14\7\1\u0232\14\7\11\0\2\7"+ + "\1\0\1\7\1\0\1\7\1\u0233\27\7\11\0\2\7"+ + "\1\0\1\7\1\0\1\7\1\u0234\27\7\11\0\2\7"+ + "\1\0\1\7\1\0\16\7\1\u0235\12\7\11\0\2\7"+ + "\1\0\1\7\1\0\5\7\1\u0236\23\7\11\0\2\7"+ + "\1\0\1\7\1\0\2\7\1\u0237\26\7\11\0\2\7"+ + "\1\0\1\7\1\0\1\u0238\30\7\11\0\2\7\1\0"+ + "\1\7\1\0\6\7\1\u0239\22\7\11\0\2\7\1\0"+ + "\1\7\1\0\1\u023a\30\7\11\0\2\7\1\0\1\7"+ + "\1\0\5\7\1\u023b\23\7\11\0\2\7\1\0\1\7"+ + "\1\0\3\7\1\u023c\25\7\11\0\2\7\1\0\1\7"+ + "\1\0\1\u023d\30\7\11\0\2\7\1\0\1\7\1\0"+ + "\7\7\1\u023e\21\7\11\0\2\7\1\0\1\7\1\0"+ + "\13\7\1\u023f\15\7\11\0\2\7\1\0\1\7\1\0"+ + "\1\7\1\u0240\4\7\1\u0241\22\7\11\0\2\7\1\0"+ + "\1\7\1\0\12\7\1\u0242\16\7\11\0\2\7\1\0"+ + "\1\7\1\0\2\7\1\u0243\26\7\11\0\2\7\1\0"+ + "\1\7\1\0\15\7\1\u0244\13\7\11\0\2\7\1\0"+ + "\1\7\1\0\1\u0245\30\7\11\0\2\7\1\0\1\7"+ + "\1\0\20\7\1\u0246\10\7\11\0\2\7\1\0\1\7"+ + "\1\0\1\u0247\30\7\11\0\2\7\1\0\1\7\1\0"+ + "\11\7\1\u0248\17\7\11\0\2\7\1\0\1\7\1\0"+ + "\2\7\1\u0249\26\7\11\0\2\7\1\0\1\7\1\0"+ + "\13\7\1\u024a\15\7\11\0\2\7\1\0\1\7\1\0"+ + "\13\7\1\u024b\15\7\11\0\2\7\1\0\1\7\1\0"+ + "\6\7\1\u024c\22\7\11\0\2\7\1\0\1\7\1\0"+ + "\5\7\1\u024d\23\7\11\0\2\7\1\0\1\7\1\0"+ + "\17\7\1\u024e\11\7\11\0\2\7\1\0\1\7\1\0"+ + "\1\u024f\30\7\11\0\2\7\1\0\1\7\1\0\6\7"+ + "\1\u0250\22\7\11\0\2\7\1\0\1\7\1\0\1\u0251"+ + "\30\7\11\0\2\7\1\0\1\7\1\0\15\7\1\u0252"+ + "\13\7\11\0\2\7\1\0\1\7\1\0\23\7\1\u0253"+ + "\5\7\11\0\2\7\1\0\1\7\1\0\2\7\1\u0254"+ + "\10\7\1\u0255\15\7\11\0\2\7\1\0\1\7\1\0"+ + "\15\7\1\u0256\13\7\11\0\2\7\1\0\1\7\1\0"+ + "\12\7\1\u0257\16\7\11\0\2\7\1\0\1\7\1\0"+ + "\1\u0258\30\7\11\0\2\7\1\0\1\7\1\0\14\7"+ + "\1\u0259\14\7\11\0\2\7\1\0\1\7\1\0\20\7"+ + "\1\u025a\10\7\11\0\2\7\1\0\1\7\1\0\5\7"+ + "\1\u025b\23\7\11\0\2\7\1\0\1\7\1\0\3\7"+ + "\1\u025c\25\7\11\0\2\7\1\0\1\7\1\0\6\7"+ + "\1\u025d\22\7\11\0\2\7\1\0\1\7\1\0\11\7"+ + "\1\u025e\17\7\11\0\2\7\1\0\1\7\1\0\17\7"+ + "\1\u025f\11\7\11\0\2\7\1\0\1\7\1\0\6\7"+ + "\1\u0260\22\7\11\0\2\7\1\0\1\7\1\0\5\7"+ + "\1\u0261\23\7\11\0\2\7\1\0\1\7\1\0\1\u0262"+ + "\30\7\11\0\2\7\1\0\1\7\1\0\12\7\1\u0263"+ + "\16\7\11\0\2\7\1\0\1\7\1\0\20\7\1\u0264"+ + "\10\7\11\0\2\7\1\0\1\7\1\0\21\7\1\u0265"+ + "\7\7\11\0\2\7\1\0\1\7\1\0\1\u0266\30\7"+ + "\11\0\2\7\1\0\1\7\1\0\15\7\1\u0267\13\7"+ + "\11\0\2\7\1\0\1\7\1\0\6\7\1\u0268\22\7"+ + "\11\0\2\7\1\0\1\7\1\0\12\7\1\u0269\16\7"+ + "\11\0\2\7\1\0\1\7\1\0\5\7\1\u026a\23\7"+ + "\11\0\2\7\1\0\1\7\1\0\6\7\1\u026b\22\7"+ + "\11\0\2\7\1\0\1\7\1\0\6\7\1\u026c\22\7"+ + "\11\0\2\7\1\0\1\7\1\0\1\u026d\30\7\11\0"+ + "\2\7\1\0\1\7\1\0\12\7\1\u026e\16\7\11\0"+ + "\2\7\1\0\1\7\1\0\16\7\1\u026f\12\7\11\0"+ + "\2\7\1\0\1\7\1\0\13\7\1\u0270\15\7\11\0"+ + "\2\7\1\0\1\7\1\0\13\7\1\u0271\15\7\11\0"+ + "\2\7\1\0\1\7\1\0\23\7\1\u0272\5\7\11\0"+ + "\2\7\1\0\1\7\1\0\17\7\1\u0273\11\7\11\0"+ + "\2\7\1\0\1\7\1\0\5\7\1\u0274\23\7\11\0"+ + "\2\7\1\0\1\7\1\0\15\7\1\u0275\13\7\11\0"+ + "\2\7\1\0\1\7\1\0\11\7\1\u0276\17\7\11\0"+ + "\2\7\1\0\1\7\1\0\15\7\1\u0277\13\7\11\0"+ + "\2\7\1\0\1\7\1\0\1\u0278\30\7\11\0\2\7"+ + "\1\0\1\7\1\0\11\7\1\u0279\17\7\11\0\2\7"+ + "\1\0\1\7\1\0\10\7\1\u027a\20\7\11\0\2\7"+ + "\1\0\1\7\1\0\15\7\1\u027b\13\7\11\0\2\7"+ + "\1\0\1\7\1\0\17\7\1\u027c\11\7\11\0\2\7"+ + "\1\0\1\7\1\0\1\u027d\30\7\11\0\2\7\1\0"+ + "\1\7\1\0\4\7\1\u027e\24\7\11\0\2\7\1\0"+ + "\1\7\1\0\5\7\1\u027f\23\7\11\0\2\7\1\0"+ + "\1\7\1\0\6\7\1\u0280\22\7\11\0\2\7\1\0"+ + "\1\7\1\0\3\7\1\u0281\25\7\11\0\2\7\1\0"+ + "\1\7\1\0\1\u0282\30\7\11\0\2\7\1\0\1\7"+ + "\1\0\11\7\1\u0283\17\7\11\0\2\7\1\0\1\7"+ + "\1\0\5\7\1\u0284\23\7\11\0\2\7\1\0\1\7"+ + "\1\0\16\7\1\u0285\12\7\11\0\2\7\1\0\1\7"+ + "\1\0\23\7\1\u0286\5\7\11\0\2\7\1\0\1\7"+ + "\1\0\12\7\1\u0287\16\7\11\0\2\7\1\0\1\7"+ + "\1\0\12\7\1\u0288\16\7\11\0\2\7\1\0\1\7"+ + "\1\0\11\7\1\u0289\17\7\11\0\2\7\1\0\1\7"+ + "\1\0\12\7\1\u028a\16\7\11\0\2\7\1\0\1\7"+ + "\1\0\1\u028b\30\7\11\0\2\7\1\0\1\7\1\0"+ + "\1\u028c\30\7\11\0\2\7\1\0\1\7\1\0\11\7"+ + "\1\u028d\17\7\11\0\2\7\1\0\1\7\1\0\1\u028e"+ + "\30\7\11\0\2\7\1\0\1\7\1\0\3\7\1\u028f"+ + "\25\7\11\0\2\7\1\0\1\7\1\0\1\u0290\30\7"+ + "\11\0\2\7\1\0\1\7\1\0\13\7\1\u0291\15\7"+ + "\11\0\2\7\1\0\1\7\1\0\13\7\1\u0292\15\7"+ + "\11\0\2\7\1\0\1\7\1\0\24\7\1\u0293\4\7"+ + "\11\0\2\7\1\0\1\7\1\0\15\7\1\u0294\13\7"+ + "\11\0\2\7\1\0\1\7\1\0\22\7\1\u0295\6\7"+ + "\11\0\2\7\1\0\1\7\1\0\21\7\1\u0296\7\7"+ + "\11\0\2\7\1\0\1\7\1\0\11\7\1\u0297\17\7"+ + "\11\0\2\7\1\0\1\7\1\0\2\7\1\u0298\26\7"+ + "\11\0\2\7\1\0\1\7\1\0\11\7\1\u0299\17\7"+ + "\11\0\2\7\1\0\1\7\1\0\3\7\1\u029a\25\7"+ + "\11\0\2\7\1\0\1\7\1\0\12\7\1\u029b\16\7"+ + "\11\0\2\7\1\0\1\7\1\0\13\7\1\u029c\15\7"+ + "\11\0\2\7\1\0\1\7\1\0\17\7\1\u029d\11\7"+ + "\11\0\2\7\1\0\1\7\1\0\10\7\1\u029e\20\7"+ + "\11\0\2\7\1\0\1\7\1\0\1\u029f\30\7\11\0"+ + "\2\7\1\0\1\7\1\0\11\7\1\u02a0\17\7\11\0"+ + "\2\7\1\0\1\7\1\0\1\u02a1\30\7\11\0\2\7"+ + "\1\0\1\7\1\0\13\7\1\u02a2\15\7\11\0\2\7"+ + "\1\0\1\7\1\0\10\7\1\u02a3\20\7\11\0\2\7"+ + "\1\0\1\7\1\0\12\7\1\u02a4\16\7\11\0\2\7"+ + "\1\0\1\7\1\0\21\7\1\u02a5\7\7\11\0\2\7"+ + "\1\0\1\7\1\0\15\7\1\u02a6\13\7\11\0\2\7"+ + "\1\0\1\7\1\0\5\7\1\u02a7\23\7\11\0\2\7"+ + "\1\0\1\7\1\0\2\7\1\u02a8\26\7\11\0\2\7"+ + "\1\0\1\7\1\0\23\7\1\u02a9\5\7\11\0\2\7"+ + "\1\0\1\7\1\0\1\u02aa\30\7\11\0\2\7\1\0"+ + "\1\7\1\0\16\7\1\u02ab\12\7\11\0\2\7\1\0"+ + "\1\7\1\0\13\7\1\u02ac\15\7\11\0\2\7\1\0"+ + "\1\7\1\0\13\7\1\u02ad\15\7\11\0\2\7\1\0"+ + "\1\7\1\0\5\7\1\u02ae\23\7\11\0\2\7\1\0"+ + "\1\7\1\0\12\7\1\u02af\16\7\11\0\2\7\1\0"+ + "\1\7\1\0\5\7\1\u02b0\23\7\11\0\2\7\1\0"+ + "\1\7\1\0\1\u02b1\30\7\11\0\2\7\1\0\1\7"+ + "\1\0\12\7\1\u02b2\16\7\11\0\2\7\1\0\1\7"+ + "\1\0\24\7\1\u02b3\4\7\11\0\2\7\1\0\1\7"+ + "\1\0\3\7\1\u02b4\25\7\11\0\2\7\1\0\1\7"+ + "\1\0\6\7\1\u02b5\22\7\11\0\2\7\1\0\1\7"+ + "\1\0\1\u02b6\30\7\11\0\2\7\1\0\1\7\1\0"+ + "\14\7\1\u02b7\14\7\11\0\2\7\1\0\1\7\1\0"+ + "\5\7\1\u02b8\23\7\11\0\2\7\1\0\1\7\1\0"+ + "\1\7\1\u02b9\27\7\11\0\2\7\1\0\1\7\1\0"+ + "\10\7\1\u02ba\20\7\11\0\2\7\1\0\1\7\1\0"+ + "\6\7\1\u02bb\22\7\11\0\2\7\1\0\1\7\1\0"+ + "\1\7\1\u02bc\27\7\11\0\2\7\1\0\1\7\1\0"+ + "\20\7\1\u02bd\10\7\11\0\2\7\1\0\1\7\1\0"+ + "\1\7\1\u02be\27\7\11\0\2\7\1\0\1\7\1\0"+ + "\15\7\1\u02bf\13\7\11\0\2\7\1\0\1\7\1\0"+ + "\12\7\1\u02c0\16\7\11\0\2\7\1\0\1\7\1\0"+ + "\15\7\1\u02c1\13\7\11\0\2\7\1\0\1\7\1\0"+ + "\13\7\1\u02c2\15\7\11\0\2\7\1\0\1\7\1\0"+ + "\6\7\1\u02c3\22\7\11\0\2\7\1\0\1\7\1\0"+ + "\6\7\1\u02c4\22\7\11\0\2\7\1\0\1\7\1\0"+ + "\12\7\1\u02c5\16\7\11\0\2\7\1\0\1\7\1\0"+ + "\12\7\1\u02c6\16\7\11\0\2\7\1\0\1\7\1\0"+ + "\25\7\1\u02c7\3\7\11\0\2\7\1\0\1\7\1\0"+ + "\11\7\1\u02c8\17\7\11\0\2\7\1\0\1\7\1\0"+ + "\6\7\1\u02c9\22\7\11\0\2\7\1\0\1\7\1\0"+ + "\2\7\1\u02ca\26\7\11\0\2\7\1\0\1\7\1\0"+ + "\1\7\1\u02cb\27\7\11\0\2\7\1\0\1\7\1\0"+ + "\1\u02cc\30\7\11\0\2\7\1\0\1\7\1\0\13\7"+ + "\1\u02cd\15\7\11\0\2\7\1\0\1\7\1\0\15\7"+ + "\1\u02ce\13\7\11\0\2\7\1\0\1\7\1\0\1\u02cf"+ + "\30\7\11\0\2\7\1\0\1\7\1\0\1\7\1\u02d0"+ + "\27\7\11\0\2\7\1\0\1\7\1\0\21\7\1\u02d1"+ + "\7\7\11\0\2\7\1\0\1\7\1\0\17\7\1\u02d2"+ + "\11\7\11\0\2\7\1\0\1\7\1\0\11\7\1\u02d3"+ + "\17\7\11\0\2\7\1\0\1\7\1\0\1\u02d4\30\7"+ + "\11\0\2\7\1\0\1\7\1\0\20\7\1\u02d5\10\7"+ + "\11\0\2\7\1\0\1\7\1\0\5\7\1\u02d6\23\7"+ + "\11\0\2\7\1\0\1\7\1\0\6\7\1\u02d7\22\7"+ + "\11\0\2\7\1\0\1\7\1\0\26\7\1\u02d8\2\7"+ + "\11\0\2\7\1\0\1\7\1\0\11\7\1\u02d9\17\7"+ + "\11\0\2\7\1\0\1\7\1\0\1\u02da\30\7\11\0"+ + "\2\7\1\0\1\7\1\0\2\7\1\u02db\26\7\11\0"+ + "\2\7\1\0\1\7\1\0\11\7\1\u02dc\17\7\11\0"+ + "\2\7\1\0\1\7\1\0\11\7\1\u02dd\17\7\11\0"+ + "\2\7\1\0\1\7\1\0\15\7\1\u02de\13\7\11\0"+ + "\2\7\1\0\1\7\1\0\5\7\1\u02df\23\7\11\0"+ + "\2\7\1\0\1\7\1\0\1\u02e0\30\7\11\0\2\7"+ + "\1\0\1\7\1\0\1\7\1\u02e1\27\7\11\0\2\7"+ + "\1\0\1\7\1\0\11\7\1\u02e2\17\7\11\0\2\7"+ + "\1\0\1\7\1\0\2\7\1\u02e3\26\7\11\0\2\7"+ + "\1\0\1\7\1\0\15\7\1\u02e4\13\7\11\0\2\7"+ + "\1\0\1\7\1\0\5\7\1\u02e5\23\7\11\0\2\7"+ + "\1\0\1\7\1\0\11\7\1\u02e6\17\7\11\0\2\7"+ + "\1\0\1\7\1\0\17\7\1\u02e7\11\7\11\0\2\7"+ + "\1\0\1\7\1\0\2\7\1\u02e8\26\7\11\0\2\7"+ + "\1\0\1\7\1\0\7\7\1\u02e9\21\7\11\0\2\7"+ + "\1\0\1\7\1\0\16\7\1\u02ea\12\7\11\0\2\7"+ + "\1\0\1\7\1\0\11\7\1\u02eb\17\7\11\0\2\7"+ + "\1\0\1\7\1\0\2\7\1\u02ec\26\7\11\0\2\7"+ + "\1\0\1\7\1\0\10\7\1\u02ed\20\7\11\0\2\7"+ + "\1\0\1\7\1\0\12\7\1\u02ee\16\7\11\0\2\7"+ + "\1\0\1\7\1\0\12\7\1\u02ef\16\7\11\0\2\7"+ + "\1\0\1\7\1\0\15\7\1\u02f0\13\7\11\0\2\7"+ + "\1\0\1\7\1\0\2\7\1\u02f1\26\7\11\0\2\7"+ + "\1\0\1\7\1\0\20\7\1\u02f2\10\7\11\0\2\7"+ + "\1\0\1\7\1\0\7\7\1\u02f3\21\7\11\0\2\7"+ + "\1\0\1\7\1\0\6\7\1\u02f4\22\7\11\0\2\7"+ + "\1\0\1\7\1\0\16\7\1\u02f5\12\7\11\0\2\7"+ + "\1\0\1\7\1\0\12\7\1\u02f6\16\7\11\0\2\7"+ + "\1\0\1\7\1\0\13\7\1\u02f7\15\7\11\0\2\7"+ + "\1\0\1\7\1\0\6\7\1\u02f8\22\7\11\0\2\7"+ + "\1\0\1\7\1\0\5\7\1\u02f9\23\7\11\0\2\7"+ + "\1\0\1\7\1\0\1\7\1\u02fa\27\7\11\0\2\7"+ + "\1\0\1\7\1\0\14\7\1\u02fb\14\7\11\0\2\7"+ + "\1\0\1\7\1\0\7\7\1\u02fc\21\7\11\0\2\7"+ + "\1\0\1\7\1\0\3\7\1\u02fd\25\7\11\0\2\7"+ + "\1\0\1\7\1\0\12\7\1\u02fe\16\7\11\0\2\7"+ + "\1\0\1\7\1\0\5\7\1\u02ff\23\7\11\0\2\7"+ + "\1\0\1\7\1\0\1\u0300\30\7\11\0\2\7\1\0"+ + "\1\7\1\0\1\u0301\30\7\11\0\2\7\1\0\1\7"+ + "\1\0\15\7\1\u0302\13\7\11\0\2\7\1\0\1\7"+ + "\1\0\2\7\1\u0303\26\7\11\0\2\7\1\0\1\7"+ + "\1\0\6\7\1\u0304\22\7\11\0\2\7\1\0\1\7"+ + "\1\0\3\7\1\u0305\25\7\11\0\2\7\1\0\1\7"+ + "\1\0\1\u0306\30\7\11\0\2\7\1\0\1\7\1\0"+ + "\2\7\1\u0307\26\7\11\0\2\7\1\0\1\7\1\0"+ + "\11\7\1\u0308\17\7\11\0\2\7\1\0\1\7\1\0"+ + "\13\7\1\u0309\15\7\11\0\2\7\1\0\1\7\1\0"+ + "\2\7\1\u030a\26\7\11\0\2\7\1\0\1\7\1\0"+ + "\11\7\1\u030b\17\7\11\0\2\7\1\0\1\7\1\0"+ + "\12\7\1\u030c\16\7\11\0\2\7\1\0\1\7\1\0"+ + "\1\u030d\30\7\11\0\2\7\1\0\1\7\1\0\21\7"+ + "\1\u030e\7\7\11\0\2\7\1\0\1\7\1\0\17\7"+ + "\1\u030f\11\7\11\0\2\7\1\0\1\7\1\0\10\7"+ + "\1\u0310\20\7\11\0\2\7\1\0\1\7\1\0\6\7"+ + "\1\u0311\22\7\11\0\2\7\1\0\1\7\1\0\12\7"+ + "\1\u0312\16\7\11\0\2\7\1\0\1\7\1\0\21\7"+ + "\1\u0313\7\7\11\0\2\7\1\0\1\7\1\0\3\7"+ + "\1\u0314\25\7\11\0\2\7\1\0\1\7\1\0\13\7"+ + "\1\u0315\15\7\11\0\2\7\1\0\1\7\1\0\1\u0316"+ + "\30\7\11\0\2\7\1\0\1\7\1\0\5\7\1\u0317"+ + "\23\7\11\0\2\7\1\0\1\7\1\0\7\7\1\u0318"+ + "\21\7\11\0\2\7\1\0\1\7\1\0\14\7\1\u0319"+ + "\14\7\11\0\2\7\1\0\1\7\1\0\12\7\1\u031a"+ + "\16\7\11\0\2\7\1\0\1\7\1\0\1\u031b\30\7"+ + "\11\0\2\7\1\0\1\7\1\0\6\7\1\u031c\22\7"+ + "\2\0"; + + private static int [] zzUnpackTrans() { + int [] result = new int[27963]; + int offset = 0; + offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackTrans(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int count = packed.charAt(i++); + int value = packed.charAt(i++); + value--; + do result[j++] = value; while (--count > 0); + } + return j; + } + + + /* error codes */ + private static final int ZZ_UNKNOWN_ERROR = 0; + private static final int ZZ_NO_MATCH = 1; + private static final int ZZ_PUSHBACK_2BIG = 2; + + /* error messages for the codes above */ + private static final String ZZ_ERROR_MSG[] = { + "Unkown internal scanner error", + "Error: could not match input", + "Error: pushback value was too large" + }; + + /** + * ZZ_ATTRIBUTE[aState] contains the attributes of state aState + */ + private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute(); + + private static final String ZZ_ATTRIBUTE_PACKED_0 = + "\1\0\1\11\1\1\1\11\33\1\2\11\4\0\55\1"+ + "\2\0\2\1\1\0\1\11\65\1\1\0\u028e\1"; + + private static int [] zzUnpackAttribute() { + int [] result = new int[796]; + int offset = 0; + offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackAttribute(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int count = packed.charAt(i++); + int value = packed.charAt(i++); + do result[j++] = value; while (--count > 0); + } + return j; + } + + /** the input device */ + private java.io.Reader zzReader; + + /** the current state of the DFA */ + private int zzState; + + /** the current lexical state */ + private int zzLexicalState = YYINITIAL; + + /** this buffer contains the current text to be matched and is + the source of the yytext() string */ + private char zzBuffer[] = new char[ZZ_BUFFERSIZE]; + + /** the textposition at the last accepting state */ + private int zzMarkedPos; + + /** the textposition at the last state to be included in yytext */ + private int zzPushbackPos; + + /** the current text position in the buffer */ + private int zzCurrentPos; + + /** startRead marks the beginning of the yytext() string in the buffer */ + private int zzStartRead; + + /** endRead marks the last character in the buffer, that has been read + from input */ + private int zzEndRead; + + /** number of newlines encountered up to the start of the matched text */ + private int yyline; + + /** the number of characters up to the start of the matched text */ + private int yychar; + + /** + * the number of characters from the last newline up to the start of the + * matched text + */ + private int yycolumn; + + /** + * zzAtBOL == true <=> the scanner is currently at the beginning of a line + */ + private boolean zzAtBOL = true; + + /** zzAtEOF == true <=> the scanner is at the EOF */ + private boolean zzAtEOF; + + + /** + * Creates a new scanner + * There is also a java.io.InputStream version of this constructor. + * + * @param in the java.io.Reader to read input from. + */ + GUIDefaultsScanner(java.io.Reader in) { + this.zzReader = in; + } + + /** + * Creates a new scanner. + * There is also java.io.Reader version of this constructor. + * + * @param in the java.io.Inputstream to read input from. + */ + GUIDefaultsScanner(java.io.InputStream in) { + this(new java.io.InputStreamReader(in)); + } + + /** + * Unpacks the compressed character translation table. + * + * @param packed the packed character translation table + * @return the unpacked character translation table + */ + private static char [] zzUnpackCMap(String packed) { + char [] map = new char[0x10000]; + int i = 0; /* index in packed string */ + int j = 0; /* index in unpacked array */ + while (i < 156) { + int count = packed.charAt(i++); + char value = packed.charAt(i++); + do map[j++] = value; while (--count > 0); + } + return map; + } + + + /** + * Refills the input buffer. + * + * @return false, iff there was new input. + * + * @exception java.io.IOException if any I/O-Error occurs + */ + private boolean zzRefill() throws java.io.IOException { + /* first: make room (if you can) */ + if (zzStartRead > 0) { + System.arraycopy(zzBuffer, zzStartRead, + zzBuffer, 0, + zzEndRead-zzStartRead); + + /* translate stored positions */ + zzEndRead-= zzStartRead; + zzCurrentPos-= zzStartRead; + zzMarkedPos-= zzStartRead; + zzPushbackPos-= zzStartRead; + zzStartRead = 0; + } + + /* is the buffer big enough? */ + if (zzCurrentPos >= zzBuffer.length) { + /* if not: blow it up */ + char newBuffer[] = new char[zzCurrentPos*2]; + System.arraycopy(zzBuffer, 0, newBuffer, 0, zzBuffer.length); + zzBuffer = newBuffer; + } + + /* finally: fill the buffer with new input */ + int numRead = zzReader.read(zzBuffer, zzEndRead, + zzBuffer.length-zzEndRead); + + if (numRead < 0) { + return true; + } + else { + zzEndRead+= numRead; + return false; + } + } + + + /** + * Closes the input stream. + * + * @throws java.io.IOException if any. + */ + public final void yyclose() throws java.io.IOException { + zzAtEOF = true; /* indicate end of file */ + zzEndRead = zzStartRead; /* invalidate buffer */ + + if (zzReader != null) + zzReader.close(); + } + + + /** + * Resets the scanner to read from a new input stream. + * Does not close the old reader. + * + * All internal variables are reset, the old input stream + * cannot be reused (internal buffer is discarded and lost). + * Lexical state is set to ZZ_INITIAL. + * + * @param reader the new input stream + */ + public final void yyreset(java.io.Reader reader) { + zzReader = reader; + zzAtBOL = true; + zzAtEOF = false; + zzEndRead = zzStartRead = 0; + zzCurrentPos = zzMarkedPos = zzPushbackPos = 0; + yyline = yychar = yycolumn = 0; + zzLexicalState = YYINITIAL; + } + + + /** + * Returns the current lexical state. + * + * @return a int. + */ + public final int yystate() { + return zzLexicalState; + } + + + /** + * Enters a new lexical state + * + * @param newState the new lexical state + */ + public final void yybegin(int newState) { + zzLexicalState = newState; + } + + + /** + * Returns the text matched by the current regular expression. + * + * @return a {@link java.lang.String} object. + */ + public final String yytext() { + return new String( zzBuffer, zzStartRead, zzMarkedPos-zzStartRead ); + } + + + /** + * Returns the character at position pos from the + * matched text. + * + * It is equivalent to yytext().charAt(pos), but faster + * + * @param pos the position of the character to fetch. + * A value from 0 to yylength()-1. + * @return the character at position pos + */ + public final char yycharat(int pos) { + return zzBuffer[zzStartRead+pos]; + } + + + /** + * Returns the length of the matched text region. + * + * @return a int. + */ + public final int yylength() { + return zzMarkedPos-zzStartRead; + } + + + /** + * Reports an error that occured while scanning. + * + * In a wellformed scanner (no or only correct usage of + * yypushback(int) and a match-all fallback rule) this method + * will only be called with things that "Can't Possibly Happen". + * If this method is called, something is seriously wrong + * (e.g. a JFlex bug producing a faulty scanner etc.). + * + * Usual syntax/scanner level error handling should be done + * in error fallback rules. + * + * @param errorCode the code of the errormessage to display + */ + private void zzScanError(int errorCode) { + String message; + try { + message = ZZ_ERROR_MSG[errorCode]; + } + catch (ArrayIndexOutOfBoundsException e) { + message = ZZ_ERROR_MSG[ZZ_UNKNOWN_ERROR]; + } + + throw new Error(message); + } + + + /** + * Pushes the specified amount of characters back into the input stream. + * + * They will be read again by then next call of the scanning method + * + * @param number the number of characters to be read again. + * This number must not be greater than yylength()! + */ + public void yypushback(int number) { + if ( number > yylength() ) + zzScanError(ZZ_PUSHBACK_2BIG); + + zzMarkedPos -= number; + } + + + /** + * Resumes scanning until the next regular expression is matched, + * the end of input is encountered or an I/O-Error occurs. + * + * @return the next token + * @exception java.io.IOException if any I/O-Error occurs + * @throws java.io.IOException if any. + */ + public Object next_token() throws java.io.IOException { + int zzInput; + int zzAction; + + // cached fields: + int zzCurrentPosL; + int zzMarkedPosL; + int zzEndReadL = zzEndRead; + char [] zzBufferL = zzBuffer; + char [] zzCMapL = ZZ_CMAP; + + int [] zzTransL = ZZ_TRANS; + int [] zzRowMapL = ZZ_ROWMAP; + int [] zzAttrL = ZZ_ATTRIBUTE; + + while (true) { + zzMarkedPosL = zzMarkedPos; + + zzAction = -1; + + zzCurrentPosL = zzCurrentPos = zzStartRead = zzMarkedPosL; + + zzState = zzLexicalState; + + + zzForAction: { + while (true) { + + if (zzCurrentPosL < zzEndReadL) + zzInput = zzBufferL[zzCurrentPosL++]; + else if (zzAtEOF) { + zzInput = YYEOF; + break zzForAction; + } + else { + // store back cached positions + zzCurrentPos = zzCurrentPosL; + zzMarkedPos = zzMarkedPosL; + boolean eof = zzRefill(); + // get translated positions and possibly new buffer + zzCurrentPosL = zzCurrentPos; + zzMarkedPosL = zzMarkedPos; + zzBufferL = zzBuffer; + zzEndReadL = zzEndRead; + if (eof) { + zzInput = YYEOF; + break zzForAction; + } + else { + zzInput = zzBufferL[zzCurrentPosL++]; + } + } + int zzNext = zzTransL[ zzRowMapL[zzState] + zzCMapL[zzInput] ]; + if (zzNext == -1) break zzForAction; + zzState = zzNext; + + int zzAttributes = zzAttrL[zzState]; + if ( (zzAttributes & 1) == 1 ) { + zzAction = zzState; + zzMarkedPosL = zzCurrentPosL; + if ( (zzAttributes & 8) == 8 ) break zzForAction; + } + + } + } + + // store back cached position + zzMarkedPos = zzMarkedPosL; + + switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) { + case 11: + { return GUIDefaultsFile.Keyword.NONE; + } + case 85: break; + case 52: + { return GUIDefaultsFile.Keyword.EDIT_NET_RULES; + } + case 86: break; + case 44: + { return GUIDefaultsFile.Keyword.PACKAGE_INFO; + } + case 87: break; + case 34: + { return GUIDefaultsFile.Keyword.FIXED_VIAS; + } + case 88: break; + case 60: + { return GUIDefaultsFile.Keyword.VIOLATIONS_INFO; + } + case 89: break; + case 70: + { return GUIDefaultsFile.Keyword.FORTYFIVE_DEGREE; + } + case 90: break; + case 54: + { return GUIDefaultsFile.Keyword.MOVE_PARAMETER; + } + case 91: break; + case 76: + { return GUIDefaultsFile.Keyword.DISPLAY_MISCELLANIOUS; + } + case 92: break; + case 53: + { return GUIDefaultsFile.Keyword.RULE_SELECTION; + } + case 93: break; + case 41: + { return GUIDefaultsFile.Keyword.MANUAL_RULES; + } + case 94: break; + case 17: + { return GUIDefaultsFile.Keyword.VISIBLE; + } + case 95: break; + case 12: + { return GUIDefaultsFile.Keyword.PINS; + } + case 96: break; + case 56: + { return GUIDefaultsFile.Keyword.COMPONENT_BACK; + } + case 97: break; + case 40: + { return GUIDefaultsFile.Keyword.GUI_DEFAULTS; + } + case 98: break; + case 15: + { return GUIDefaultsFile.Keyword.TRACES; + } + case 99: break; + case 73: + { return GUIDefaultsFile.Keyword.PULL_TIGHT_REGION; + } + case 100: break; + case 26: + { return GUIDefaultsFile.Keyword.VIA_RULES; + } + case 101: break; + case 77: + { return GUIDefaultsFile.Keyword.VIA_SNAP_TO_SMD_CENTER; + } + case 102: break; + case 38: + { return GUIDefaultsFile.Keyword.BOARD_FRAME; + } + case 103: break; + case 61: + { return GUIDefaultsFile.Keyword.ROUTE_PARAMETER; + } + case 104: break; + case 29: + { return GUIDefaultsFile.Keyword.PARAMETER; + } + case 105: break; + case 33: + { return GUIDefaultsFile.Keyword.CONDUCTION; + } + case 106: break; + case 48: + { return GUIDefaultsFile.Keyword.OBJECT_COLORS; + } + case 107: break; + case 28: + { return GUIDefaultsFile.Keyword.STITCHING; + } + case 108: break; + case 66: + { return GUIDefaultsFile.Keyword.SELECT_PARAMETER; + } + case 109: break; + case 72: + { return GUIDefaultsFile.Keyword.OBJECT_VISIBILITY; + } + case 110: break; + case 74: + { return GUIDefaultsFile.Keyword.PULL_TIGHT_ACCURACY; + } + case 111: break; + case 58: + { return GUIDefaultsFile.Keyword.DISPLAY_REGION; + } + case 112: break; + case 71: + { return GUIDefaultsFile.Keyword.INTERACTIVE_STATE; + } + case 113: break; + case 39: + { return GUIDefaultsFile.Keyword.NOT_VISIBLE; + } + case 114: break; + case 20: + { return GUIDefaultsFile.Keyword.DYNAMIC; + } + case 115: break; + case 84: + { return GUIDefaultsFile.Keyword.DESELECTED_SNAPSHOT_ATTRIBUTES; + } + case 116: break; + case 31: + { return GUIDefaultsFile.Keyword.BACKGROUND; + } + case 117: break; + case 64: + { return GUIDefaultsFile.Keyword.LAYER_VISIBILITY; + } + case 118: break; + case 43: + { return GUIDefaultsFile.Keyword.FIXED_TRACES; + } + case 119: break; + case 51: + { return GUIDefaultsFile.Keyword.PADSTACK_INFO; + } + case 120: break; + case 22: + { return GUIDefaultsFile.Keyword.HILIGHT; + } + case 121: break; + case 14: + { return GUIDefaultsFile.Keyword.BOUNDS; + } + case 122: break; + case 82: + { return GUIDefaultsFile.Keyword.DRAG_COMPONENTS_ENABLED; + } + case 123: break; + case 75: + { return GUIDefaultsFile.Keyword.MANUAL_RULE_SETTINGS; + } + case 124: break; + case 10: + { return GUIDefaultsFile.Keyword.VIAS; + } + case 125: break; + case 3: + { return yytext(); + } + case 126: break; + case 55: + { return GUIDefaultsFile.Keyword.COMPONENT_INFO; + } + case 127: break; + case 32: + { return GUIDefaultsFile.Keyword.ROUTE_MODE; + } + case 128: break; + case 50: + { return GUIDefaultsFile.Keyword.COLOR_MANAGER; + } + case 129: break; + case 30: + { return GUIDefaultsFile.Keyword.VIOLATIONS; + } + case 130: break; + case 67: + { return GUIDefaultsFile.Keyword.SELECTABLE_ITEMS; + } + case 131: break; + case 19: + { return GUIDefaultsFile.Keyword.OUTLINE; + } + case 132: break; + case 42: + { return GUIDefaultsFile.Keyword.CURRENT_ONLY; + } + case 133: break; + case 9: + { return GUIDefaultsFile.Keyword.OFF; + } + case 134: break; + case 45: + { return GUIDefaultsFile.Keyword.SHOVE_ENABLED; + } + case 135: break; + case 63: + { return GUIDefaultsFile.Keyword.ASSIGN_NET_RULES; + } + case 136: break; + case 25: + { return GUIDefaultsFile.Keyword.EDIT_VIAS; + } + case 137: break; + case 81: + { return GUIDefaultsFile.Keyword.IGNORE_CONDUCTION_AREAS; + } + case 138: break; + case 5: + { return GUIDefaultsFile.Keyword.OPEN_BRACKET; + } + case 139: break; + case 36: + { return GUIDefaultsFile.Keyword.VIA_KEEPOUT; + } + case 140: break; + case 8: + { return GUIDefaultsFile.Keyword.ON; + } + case 141: break; + case 16: + { return GUIDefaultsFile.Keyword.COLORS; + } + case 142: break; + case 68: + { return GUIDefaultsFile.Keyword.SELECTION_LAYERS; + } + case 143: break; + case 46: + { return GUIDefaultsFile.Keyword.NINETY_DEGREE; + } + case 144: break; + case 23: + { return GUIDefaultsFile.Keyword.WINDOWS; + } + case 145: break; + case 57: + { return GUIDefaultsFile.Keyword.COMPONENT_GRID; + } + case 146: break; + case 7: + { return new Double(yytext()); + } + case 147: break; + case 69: + { return GUIDefaultsFile.Keyword.CLEARANCE_MATRIX; + } + case 148: break; + case 65: + { return GUIDefaultsFile.Keyword.INCOMPLETES_INFO; + } + case 149: break; + case 62: + { return GUIDefaultsFile.Keyword.COMPONENT_FRONT; + } + case 150: break; + case 18: + { return GUIDefaultsFile.Keyword.UNFIXED; + } + case 151: break; + case 59: + { return GUIDefaultsFile.Keyword.LENGTH_MATCHING; + } + case 152: break; + case 80: + { return GUIDefaultsFile.Keyword.AUTOMATIC_LAYER_DIMMING; + } + case 153: break; + case 79: + { return GUIDefaultsFile.Keyword.PUSH_AND_SHOVE_ENABLED; + } + case 154: break; + case 24: + { return GUIDefaultsFile.Keyword.NET_INFO; + } + case 155: break; + case 78: + { return GUIDefaultsFile.Keyword.CLEARANCE_COMPENSATION; + } + case 156: break; + case 47: + { return GUIDefaultsFile.Keyword.ROUTE_DETAILS; + } + case 157: break; + case 2: + { /* ignore */ + } + case 158: break; + case 83: + { return GUIDefaultsFile.Keyword.HILIGHT_ROUTING_OBSTACLE; + } + case 159: break; + case 35: + { return GUIDefaultsFile.Keyword.ALL_VISIBLE; + } + case 160: break; + case 6: + { return GUIDefaultsFile.Keyword.CLOSED_BRACKET; + } + case 161: break; + case 1: + { throw new Error("Illegal character <"+ + yytext()+">"); + } + case 162: break; + case 37: + { return GUIDefaultsFile.Keyword.INCOMPLETES; + } + case 163: break; + case 49: + { return GUIDefaultsFile.Keyword.CURRENT_LAYER; + } + case 164: break; + case 21: + { return GUIDefaultsFile.Keyword.KEEPOUT; + } + case 165: break; + case 4: + { return new Integer(yytext()); + } + case 166: break; + case 13: + { return GUIDefaultsFile.Keyword.FIXED; + } + case 167: break; + case 27: + { return GUIDefaultsFile.Keyword.SNAPSHOTS; + } + case 168: break; + default: + if (zzInput == YYEOF && zzStartRead == zzCurrentPos) { + zzAtEOF = true; + return null; + } + else { + zzScanError(ZZ_NO_MATCH); + } + } + } + } + + +} diff --git a/gui/GUIDefaultsScanner.java~ b/src/main/java/gui/GUIDefaultsScanner.java~ similarity index 100% rename from gui/GUIDefaultsScanner.java~ rename to src/main/java/gui/GUIDefaultsScanner.java~ diff --git a/gui/MainApplication.java b/src/main/java/gui/MainApplication.java similarity index 69% rename from gui/MainApplication.java rename to src/main/java/gui/MainApplication.java index 115f2be..b0be659 100644 --- a/gui/MainApplication.java +++ b/src/main/java/gui/MainApplication.java @@ -27,19 +27,21 @@ * Main application for creating frames with new or existing board designs. * * @author Alfons Wirtz + * @version $Id: $Id */ public class MainApplication extends javax.swing.JFrame { /** * Main function of the Application + * + * @param p_args an array of {@link java.lang.String} objects. */ public static void main(String p_args[]) { boolean single_design_option = false; boolean test_version_option = false; boolean session_file_option = false; - boolean webstart_option = false; String design_file_name = null; String design_dir_name = null; java.util.Locale current_locale = java.util.Locale.ENGLISH; @@ -74,19 +76,11 @@ else if (p_args[i].startsWith("-s")) { session_file_option = true; } - else if (p_args[i].startsWith("-w")) - { - webstart_option = true; - } else if (p_args[i].startsWith("-test")) { test_version_option = true; } } - if (!(OFFLINE_ALLOWED || webstart_option)) - { - Runtime.getRuntime().exit(1); - } if (single_design_option) { @@ -101,7 +95,7 @@ else if (p_args[i].startsWith("-test")) { board_option = BoardFrame.Option.SINGLE_FRAME; } - DesignFile design_file = DesignFile.get_instance(design_file_name, false); + DesignFile design_file = DesignFile.get_instance(design_file_name); if (design_file == null) { System.out.print(resources.getString("message_6") + " "); @@ -129,20 +123,22 @@ public void windowClosed(java.awt.event.WindowEvent evt) } else { - new MainApplication(design_dir_name, test_version_option, webstart_option, current_locale).setVisible(true); + new MainApplication(design_dir_name, test_version_option, current_locale).setVisible(true); } } /** * Creates new form MainApplication * It takes the directory of the board designs as optional argument. + * + * @param p_design_dir a {@link java.lang.String} object. + * @param p_is_test_version a boolean. + * @param p_current_locale a {@link java.util.Locale} object. */ - public MainApplication(String p_design_dir, boolean p_is_test_version, - boolean p_webstart_option, java.util.Locale p_current_locale) + public MainApplication(String p_design_dir, boolean p_is_test_version, java.util.Locale p_current_locale) { this.design_dir_name = p_design_dir; this.is_test_version = p_is_test_version; - this.is_webstart = p_webstart_option; this.locale = p_current_locale; this.resources = java.util.ResourceBundle.getBundle("gui.resources.MainApplication", p_current_locale); @@ -155,56 +151,14 @@ public MainApplication(String p_design_dir, boolean p_is_test_version, gridbag_constraints.insets = new java.awt.Insets(10, 10, 10, 10); gridbag_constraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; - demonstration_button = new javax.swing.JButton(); - sample_board_button = new javax.swing.JButton(); open_board_button = new javax.swing.JButton(); - restore_defaults_button = new javax.swing.JButton(); message_field = new javax.swing.JTextField(); message_field.setText(""); - this.window_net_demonstrations = new WindowNetDemonstrations(p_current_locale); - java.awt.Point location = getLocation(); - this.window_net_demonstrations.setLocation((int) location.getX() + 50, (int) location.getY() + 50); - this.window_net_sample_designs = new WindowNetSampleDesigns(p_current_locale); - this.window_net_sample_designs.setLocation((int) location.getX() + 90, (int) location.getY() + 90); setTitle(resources.getString("title")); boolean add_buttons = true; - if (p_webstart_option) - { - - if (add_buttons) - { - demonstration_button.setText(resources.getString("router_demonstrations")); - demonstration_button.setToolTipText(resources.getString("router_demonstrations_tooltip")); - demonstration_button.addActionListener(new java.awt.event.ActionListener() - { - - public void actionPerformed(java.awt.event.ActionEvent evt) - { - window_net_demonstrations.setVisible(true); - } - }); - - gridbag.setConstraints(demonstration_button, gridbag_constraints); - main_panel.add(demonstration_button, gridbag_constraints); - - sample_board_button.setText(resources.getString("sample_designs")); - sample_board_button.setToolTipText(resources.getString("sample_designs_tooltip")); - sample_board_button.addActionListener(new java.awt.event.ActionListener() - { - - public void actionPerformed(java.awt.event.ActionEvent evt) - { - window_net_sample_designs.setVisible(true); - } - }); - - gridbag.setConstraints(sample_board_button, gridbag_constraints); - main_panel.add(sample_board_button, gridbag_constraints); - } - } - + open_board_button.setText(resources.getString("open_own_design")); open_board_button.setToolTipText(resources.getString("open_own_design_tooltip")); open_board_button.addActionListener(new java.awt.event.ActionListener() @@ -222,25 +176,6 @@ public void actionPerformed(java.awt.event.ActionEvent evt) main_panel.add(open_board_button, gridbag_constraints); } - if (p_webstart_option && add_buttons) - { - restore_defaults_button.setText(resources.getString("restore_defaults")); - restore_defaults_button.setToolTipText(resources.getString("restore_defaults_tooltip")); - restore_defaults_button.addActionListener(new java.awt.event.ActionListener() - { - - public void actionPerformed(java.awt.event.ActionEvent evt) - { - if (is_webstart) - { - restore_defaults_action(evt); - } - } - }); - - gridbag.setConstraints(restore_defaults_button, gridbag_constraints); - main_panel.add(restore_defaults_button, gridbag_constraints); - } message_field.setPreferredSize(new java.awt.Dimension(230, 20)); message_field.setRequestFocusEnabled(false); @@ -255,7 +190,7 @@ public void actionPerformed(java.awt.event.ActionEvent evt) private void open_board_design_action(java.awt.event.ActionEvent evt) { - DesignFile design_file = DesignFile.open_dialog(this.is_webstart, this.design_dir_name); + DesignFile design_file = DesignFile.open_dialog(this.design_dir_name); if (design_file == null) { @@ -264,14 +199,8 @@ private void open_board_design_action(java.awt.event.ActionEvent evt) } BoardFrame.Option option; - if (this.is_webstart) - { - option = BoardFrame.Option.WEBSTART; - } - else - { - option = BoardFrame.Option.FROM_START_MENU; - } + option = BoardFrame.Option.FROM_START_MENU; + String message = resources.getString("loading_design") + " " + design_file.get_name(); message_field.setText(message); WindowMessage welcome_window = WindowMessage.show(message); @@ -294,23 +223,7 @@ private void exitForm(java.awt.event.WindowEvent evt) System.exit(0); } - /** deletes the setting stored by the user if the application is run by Java Web Start */ - private void restore_defaults_action(java.awt.event.ActionEvent evt) - { - if (!is_webstart) - { - return; - } - boolean file_deleted = WebStart.delete_files(BoardFrame.GUI_DEFAULTS_FILE_NAME, resources.getString("confirm_delete")); - if (file_deleted) - { - message_field.setText(resources.getString("defaults_restored")); - } - else - { - message_field.setText(resources.getString("nothing_to_restore")); - } - } + /** * Creates a new board frame containing the data of the input design file. @@ -363,25 +276,13 @@ static private BoardFrame create_board_frame(DesignFile p_design_file, javax.swi return new_frame; } private final java.util.ResourceBundle resources; - private final javax.swing.JButton demonstration_button; - private final javax.swing.JButton sample_board_button; private final javax.swing.JButton open_board_button; - private final javax.swing.JButton restore_defaults_button; private javax.swing.JTextField message_field; private javax.swing.JPanel main_panel; - /** - * A Frame with routing demonstrations in the net. - */ - private final WindowNetSamples window_net_demonstrations; - /** - * A Frame with sample board designs in the net. - */ - private final WindowNetSamples window_net_sample_designs; - /** The list of open board frames */ + private java.util.Collection board_frames = new java.util.LinkedList(); private String design_dir_name = null; private final boolean is_test_version; - private final boolean is_webstart; private final java.util.Locale locale; private static final TestLevel DEBUG_LEVEL = TestLevel.CRITICAL_DEBUGGING_OUTPUT; @@ -429,18 +330,7 @@ public void windowClosing(java.awt.event.WindowEvent evt) } } - public void windowIconified(java.awt.event.WindowEvent evt) - { - window_net_sample_designs.parent_iconified(); - } - - public void windowDeiconified(java.awt.event.WindowEvent evt) - { - window_net_sample_designs.parent_deiconified(); - } - } - static final String WEB_FILE_BASE_NAME = "http://www.freerouting.net/java/"; - private static final boolean OFFLINE_ALLOWED = true; + } /** * Change this string when creating a new version */ diff --git a/gui/PopupMenuChangeLayer.java b/src/main/java/gui/PopupMenuChangeLayer.java similarity index 100% rename from gui/PopupMenuChangeLayer.java rename to src/main/java/gui/PopupMenuChangeLayer.java diff --git a/gui/PopupMenuCopy.java b/src/main/java/gui/PopupMenuCopy.java similarity index 99% rename from gui/PopupMenuCopy.java rename to src/main/java/gui/PopupMenuCopy.java index d88e5c6..233dc6d 100644 --- a/gui/PopupMenuCopy.java +++ b/src/main/java/gui/PopupMenuCopy.java @@ -24,6 +24,7 @@ * Popup menu used in the interactive copy item state. * * @author Alfons Wirtz + * @version $Id: $Id */ public class PopupMenuCopy extends PopupMenuDisplay { diff --git a/gui/PopupMenuDisplay.java b/src/main/java/gui/PopupMenuDisplay.java similarity index 94% rename from gui/PopupMenuDisplay.java rename to src/main/java/gui/PopupMenuDisplay.java index cbcb4d6..371b80f 100644 --- a/gui/PopupMenuDisplay.java +++ b/src/main/java/gui/PopupMenuDisplay.java @@ -25,13 +25,19 @@ package gui; /** + *

PopupMenuDisplay class.

* * @author Alfons Wirtz + * @version $Id: $Id */ public class PopupMenuDisplay extends javax.swing.JPopupMenu { - /** Creates a new instance of PopupMenuDisplay */ + /** + * Creates a new instance of PopupMenuDisplay + * + * @param p_board_frame a {@link gui.BoardFrame} object. + */ public PopupMenuDisplay(BoardFrame p_board_frame) { this.board_panel = p_board_frame.board_panel; diff --git a/gui/PopupMenuDynamicRoute.java b/src/main/java/gui/PopupMenuDynamicRoute.java similarity index 99% rename from gui/PopupMenuDynamicRoute.java rename to src/main/java/gui/PopupMenuDynamicRoute.java index 8052c80..22244c4 100644 --- a/gui/PopupMenuDynamicRoute.java +++ b/src/main/java/gui/PopupMenuDynamicRoute.java @@ -24,6 +24,7 @@ * Popup menu used in the interactive route state. * * @author Alfons Wirtz + * @version $Id: $Id */ public class PopupMenuDynamicRoute extends PopupMenuDisplay { diff --git a/gui/PopupMenuInsertCancel.java b/src/main/java/gui/PopupMenuInsertCancel.java similarity index 100% rename from gui/PopupMenuInsertCancel.java rename to src/main/java/gui/PopupMenuInsertCancel.java diff --git a/gui/PopupMenuMain.java b/src/main/java/gui/PopupMenuMain.java similarity index 100% rename from gui/PopupMenuMain.java rename to src/main/java/gui/PopupMenuMain.java diff --git a/gui/PopupMenuMove.java b/src/main/java/gui/PopupMenuMove.java similarity index 97% rename from gui/PopupMenuMove.java rename to src/main/java/gui/PopupMenuMove.java index ba9462e..97466d2 100644 --- a/gui/PopupMenuMove.java +++ b/src/main/java/gui/PopupMenuMove.java @@ -25,13 +25,19 @@ package gui; /** + *

PopupMenuMove class.

* * @author Alfons Wirtz + * @version $Id: $Id */ public class PopupMenuMove extends PopupMenuDisplay { - /** Creates a new instance of PopupMenuMove */ + /** + * Creates a new instance of PopupMenuMove + * + * @param p_board_frame a {@link gui.BoardFrame} object. + */ public PopupMenuMove(BoardFrame p_board_frame) { super(p_board_frame); diff --git a/gui/PopupMenuSelectedItems.java b/src/main/java/gui/PopupMenuSelectedItems.java similarity index 100% rename from gui/PopupMenuSelectedItems.java rename to src/main/java/gui/PopupMenuSelectedItems.java diff --git a/gui/PopupMenuStitchRoute.java b/src/main/java/gui/PopupMenuStitchRoute.java similarity index 94% rename from gui/PopupMenuStitchRoute.java rename to src/main/java/gui/PopupMenuStitchRoute.java index d0a5145..aa992d0 100644 --- a/gui/PopupMenuStitchRoute.java +++ b/src/main/java/gui/PopupMenuStitchRoute.java @@ -1,100 +1,106 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * PopupMenuStitchRoute.java - * - * Created on 7. Februar 2006, 08:10 - * - */ - -package gui; - -/** - * - * @author Alfons Wirtz - */ -public class PopupMenuStitchRoute extends PopupMenuDisplay -{ - - /** Creates a new instance of PopupMenuStitchRoute */ - public PopupMenuStitchRoute(BoardFrame p_board_frame) - { - super(p_board_frame); - board.LayerStructure layer_structure = board_panel.board_handling.get_routing_board().layer_structure; - - if (layer_structure.arr.length > 0) - { - change_layer_menu = new PopupMenuChangeLayer(p_board_frame); - this.add(change_layer_menu, 0); - } - else - { - change_layer_menu = null; - } - java.util.ResourceBundle resources = - java.util.ResourceBundle.getBundle("gui.resources.Default", p_board_frame.get_locale()); - javax.swing.JMenuItem insert_item = new javax.swing.JMenuItem(); - insert_item.setText(resources.getString("insert")); - insert_item.addActionListener(new java.awt.event.ActionListener() - { - public void actionPerformed(java.awt.event.ActionEvent evt) - { - board_panel.board_handling.left_button_clicked(board_panel.right_button_click_location); - } - }); - - this.add(insert_item, 0); - - javax.swing.JMenuItem done_item = new javax.swing.JMenuItem(); - done_item.setText(resources.getString("done")); - done_item.addActionListener(new java.awt.event.ActionListener() - { - public void actionPerformed(java.awt.event.ActionEvent evt) - { - board_panel.board_handling.return_from_state(); - } - }); - - this.add(done_item, 1); - - javax.swing.JMenuItem cancel_item = new javax.swing.JMenuItem(); - cancel_item.setText(resources.getString("cancel")); - cancel_item.addActionListener(new java.awt.event.ActionListener() - { - public void actionPerformed(java.awt.event.ActionEvent evt) - { - board_panel.board_handling.cancel_state(); - } - }); - - this.add(cancel_item, 2); - - board.Layer curr_layer = layer_structure.arr[board_panel.board_handling.settings.get_layer()]; - disable_layer_item(layer_structure.get_signal_layer_no(curr_layer)); - } - - /** - * Disables the p_no-th item in the change_layer_menu. - */ - void disable_layer_item( int p_no) - { - if (this.change_layer_menu != null) - { - this.change_layer_menu.disable_item(p_no); - } - } - - private final PopupMenuChangeLayer change_layer_menu; -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * PopupMenuStitchRoute.java + * + * Created on 7. Februar 2006, 08:10 + * + */ + +package gui; + +/** + *

PopupMenuStitchRoute class.

+ * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class PopupMenuStitchRoute extends PopupMenuDisplay +{ + + /** + * Creates a new instance of PopupMenuStitchRoute + * + * @param p_board_frame a {@link gui.BoardFrame} object. + */ + public PopupMenuStitchRoute(BoardFrame p_board_frame) + { + super(p_board_frame); + board.LayerStructure layer_structure = board_panel.board_handling.get_routing_board().layer_structure; + + if (layer_structure.arr.length > 0) + { + change_layer_menu = new PopupMenuChangeLayer(p_board_frame); + this.add(change_layer_menu, 0); + } + else + { + change_layer_menu = null; + } + java.util.ResourceBundle resources = + java.util.ResourceBundle.getBundle("gui.resources.Default", p_board_frame.get_locale()); + javax.swing.JMenuItem insert_item = new javax.swing.JMenuItem(); + insert_item.setText(resources.getString("insert")); + insert_item.addActionListener(new java.awt.event.ActionListener() + { + public void actionPerformed(java.awt.event.ActionEvent evt) + { + board_panel.board_handling.left_button_clicked(board_panel.right_button_click_location); + } + }); + + this.add(insert_item, 0); + + javax.swing.JMenuItem done_item = new javax.swing.JMenuItem(); + done_item.setText(resources.getString("done")); + done_item.addActionListener(new java.awt.event.ActionListener() + { + public void actionPerformed(java.awt.event.ActionEvent evt) + { + board_panel.board_handling.return_from_state(); + } + }); + + this.add(done_item, 1); + + javax.swing.JMenuItem cancel_item = new javax.swing.JMenuItem(); + cancel_item.setText(resources.getString("cancel")); + cancel_item.addActionListener(new java.awt.event.ActionListener() + { + public void actionPerformed(java.awt.event.ActionEvent evt) + { + board_panel.board_handling.cancel_state(); + } + }); + + this.add(cancel_item, 2); + + board.Layer curr_layer = layer_structure.arr[board_panel.board_handling.settings.get_layer()]; + disable_layer_item(layer_structure.get_signal_layer_no(curr_layer)); + } + + /** + * Disables the p_no-th item in the change_layer_menu. + */ + void disable_layer_item( int p_no) + { + if (this.change_layer_menu != null) + { + this.change_layer_menu.disable_item(p_no); + } + } + + private final PopupMenuChangeLayer change_layer_menu; +} diff --git a/gui/PupupMenuCornerItemConstruction.java b/src/main/java/gui/PupupMenuCornerItemConstruction.java similarity index 100% rename from gui/PupupMenuCornerItemConstruction.java rename to src/main/java/gui/PupupMenuCornerItemConstruction.java diff --git a/gui/WindowAbout.java b/src/main/java/gui/WindowAbout.java similarity index 95% rename from gui/WindowAbout.java rename to src/main/java/gui/WindowAbout.java index 65357a1..9581f85 100644 --- a/gui/WindowAbout.java +++ b/src/main/java/gui/WindowAbout.java @@ -26,9 +26,15 @@ * Displays general information about the freeroute software. * * @author Alfons Wirtz + * @version $Id: $Id */ public class WindowAbout extends BoardSavableSubWindow { + /** + *

Constructor for WindowAbout.

+ * + * @param p_locale a {@link java.util.Locale} object. + */ public WindowAbout(java.util.Locale p_locale) { java.util.ResourceBundle resources = diff --git a/gui/WindowAssignNetClass.java b/src/main/java/gui/WindowAssignNetClass.java similarity index 96% rename from gui/WindowAssignNetClass.java rename to src/main/java/gui/WindowAssignNetClass.java index dac7f5b..21baa8c 100644 --- a/gui/WindowAssignNetClass.java +++ b/src/main/java/gui/WindowAssignNetClass.java @@ -25,13 +25,19 @@ import rules.NetClass; /** + *

WindowAssignNetClass class.

* * @author Alfons Wirtz + * @version $Id: $Id */ public class WindowAssignNetClass extends BoardSavableSubWindow { - /** Creates a new instance of AssignNetRulesWindow */ + /** + * Creates a new instance of AssignNetRulesWindow + * + * @param p_board_frame a {@link gui.BoardFrame} object. + */ public WindowAssignNetClass(BoardFrame p_board_frame) { this.resources = java.util.ResourceBundle.getBundle("gui.resources.WindowAssignNetClass", p_board_frame.get_locale()); @@ -69,6 +75,9 @@ private void add_net_class_combo_box() this.table.getColumnModel().getColumn(1).setCellEditor(new javax.swing.DefaultCellEditor(net_rule_combo_box)); } + /** + *

refresh.

+ */ public void refresh() { // Reinsert the net class column. diff --git a/gui/WindowAutorouteDetailParameter.java b/src/main/java/gui/WindowAutorouteDetailParameter.java similarity index 97% rename from gui/WindowAutorouteDetailParameter.java rename to src/main/java/gui/WindowAutorouteDetailParameter.java index c058db4..5396a7a 100644 --- a/gui/WindowAutorouteDetailParameter.java +++ b/src/main/java/gui/WindowAutorouteDetailParameter.java @@ -1,568 +1,574 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * WindowAutorouteDetailParameter.java - * - * Created on 25. Juli 2006, 08:17 - * - */ -package gui; - -/** - * - * @author Alfons Wirtz - */ -public class WindowAutorouteDetailParameter extends BoardSavableSubWindow -{ - - /** Creates a new instance of WindowAutorouteDetailParameter */ - public WindowAutorouteDetailParameter(BoardFrame p_board_frame) - { - this.board_handling = p_board_frame.board_panel.board_handling; - java.util.ResourceBundle resources = - java.util.ResourceBundle.getBundle("gui.resources.WindowAutorouteParameter", p_board_frame.get_locale()); - this.setTitle(resources.getString("detail_autoroute_parameter")); - - // create main panel - - final javax.swing.JPanel main_panel = new javax.swing.JPanel(); - getContentPane().add(main_panel); - java.awt.GridBagLayout gridbag = new java.awt.GridBagLayout(); - main_panel.setLayout(gridbag); - java.awt.GridBagConstraints gridbag_constraints = new java.awt.GridBagConstraints(); - gridbag_constraints.anchor = java.awt.GridBagConstraints.WEST; - gridbag_constraints.insets = new java.awt.Insets(5, 10, 5, 10); - - // add label and number field for the via costs. - - gridbag_constraints.gridwidth = 2; - javax.swing.JLabel via_cost_label = new javax.swing.JLabel(resources.getString("via_costs")); - gridbag.setConstraints(via_cost_label, gridbag_constraints); - main_panel.add(via_cost_label); - - java.text.NumberFormat number_format = java.text.NumberFormat.getIntegerInstance(p_board_frame.get_locale()); - this.via_cost_field = new javax.swing.JFormattedTextField(number_format); - this.via_cost_field.setColumns(3); - this.via_cost_field.addKeyListener(new ViaCostFieldKeyListener()); - this.via_cost_field.addFocusListener(new ViaCostFieldFocusListener()); - gridbag_constraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; - gridbag.setConstraints(via_cost_field, gridbag_constraints); - main_panel.add(via_cost_field); - - this.plane_via_cost_field = new javax.swing.JFormattedTextField(number_format); - this.plane_via_cost_field.setColumns(3); - this.plane_via_cost_field.addKeyListener(new PlaneViaCostFieldKeyListener()); - this.plane_via_cost_field.addFocusListener(new PlaneViaCostFieldFocusListener()); - - gridbag_constraints.gridwidth = 2; - javax.swing.JLabel plane_via_cost_label = new javax.swing.JLabel(resources.getString("plane_via_costs")); - gridbag.setConstraints(plane_via_cost_label, gridbag_constraints); - main_panel.add(plane_via_cost_label); - gridbag_constraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; - gridbag.setConstraints(plane_via_cost_field, gridbag_constraints); - main_panel.add(plane_via_cost_field); - - // add label and number field for the start pass no. - - gridbag_constraints.gridwidth = 2; - javax.swing.JLabel start_pass_label = new javax.swing.JLabel(resources.getString("start_pass")); - gridbag.setConstraints(start_pass_label, gridbag_constraints); - main_panel.add(start_pass_label); - - start_pass_no = new javax.swing.JFormattedTextField(number_format); - start_pass_no.setColumns(2); - this.start_pass_no.addKeyListener(new StartPassFieldKeyListener()); - this.start_pass_no.addFocusListener(new StartPassFieldFocusListener()); - gridbag_constraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; - gridbag.setConstraints(start_pass_no, gridbag_constraints); - main_panel.add(start_pass_no); - - // add label and number field for the start ripup costs. - - gridbag_constraints.gridwidth = 2; - javax.swing.JLabel start_ripup_costs_label = new javax.swing.JLabel(); - start_ripup_costs_label.setText(resources.getString("start_ripup_costs")); - gridbag.setConstraints(start_ripup_costs_label, gridbag_constraints); - main_panel.add(start_ripup_costs_label); - - start_ripup_costs = new javax.swing.JFormattedTextField(number_format); - start_ripup_costs.setColumns(3); - this.start_ripup_costs.addKeyListener(new StartRipupCostFieldKeyListener()); - this.start_ripup_costs.addFocusListener(new StartRipupCostFieldFocusListener()); - gridbag_constraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; - gridbag.setConstraints(start_ripup_costs, gridbag_constraints); - main_panel.add(start_ripup_costs); - - - - // add label and combo box for the router speed (if the speed is set to slow, free angle geometry - // is used also in the 45 and 90 degree modes. - this.speed_fast = resources.getString("fast"); - this.speed_slow = resources.getString("slow"); - speed_combo_box = new javax.swing.JComboBox(); - speed_combo_box.addItem(this.speed_fast); - speed_combo_box.addItem(this.speed_slow); - speed_combo_box.addActionListener(new SpeedListener()); - - if (this.board_handling.get_routing_board().get_test_level() != board.TestLevel.RELEASE_VERSION) - { - gridbag_constraints.gridwidth = 2; - javax.swing.JLabel speed_label = new javax.swing.JLabel(); - speed_label.setText(resources.getString("speed")); - gridbag.setConstraints(speed_label, gridbag_constraints); - main_panel.add(speed_label); - - gridbag_constraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; - gridbag.setConstraints(speed_combo_box, gridbag_constraints); - main_panel.add(speed_combo_box); - } - - - javax.swing.JLabel separator = new javax.swing.JLabel("---------------------------------------------------------------- "); - gridbag.setConstraints(separator, gridbag_constraints); - main_panel.add(separator, gridbag_constraints); - - // add label and number field for the trace costs on each layer. - - gridbag_constraints.gridwidth = 3; - javax.swing.JLabel layer_label = new javax.swing.JLabel(resources.getString("trace_costs_on_layer")); - gridbag.setConstraints(layer_label, gridbag_constraints); - main_panel.add(layer_label); - - javax.swing.JLabel pref_dir_label = new javax.swing.JLabel(resources.getString("in_preferred_direction")); - gridbag.setConstraints(pref_dir_label, gridbag_constraints); - main_panel.add(pref_dir_label); - - gridbag_constraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; - javax.swing.JLabel against_pref_dir_label = new javax.swing.JLabel(resources.getString("against_preferred_direction")); - gridbag.setConstraints(against_pref_dir_label, gridbag_constraints); - main_panel.add(against_pref_dir_label); - - board.LayerStructure layer_structure = this.board_handling.get_routing_board().layer_structure; - int signal_layer_count = layer_structure.signal_layer_count(); - layer_name_arr = new javax.swing.JLabel[signal_layer_count]; - preferred_direction_trace_cost_arr = new javax.swing.JFormattedTextField[signal_layer_count]; - against_preferred_direction_trace_cost_arr = new javax.swing.JFormattedTextField[signal_layer_count]; - preferred_direction_trace_costs_input_completed = new boolean[signal_layer_count]; - against_preferred_direction_trace_costs_input_completed = new boolean[signal_layer_count]; - number_format = java.text.NumberFormat.getInstance(p_board_frame.get_locale()); - number_format.setMaximumFractionDigits(2); - final int TEXT_FIELD_LENGTH = 2; - for (int i = 0; i < signal_layer_count; ++i) - { - layer_name_arr[i] = new javax.swing.JLabel(); - board.Layer curr_signal_layer = layer_structure.get_signal_layer(i); - layer_name_arr[i].setText(curr_signal_layer.name); - gridbag_constraints.gridwidth = 3; - gridbag.setConstraints(layer_name_arr[i], gridbag_constraints); - main_panel.add(layer_name_arr[i]); - preferred_direction_trace_cost_arr[i] = new javax.swing.JFormattedTextField(number_format); - preferred_direction_trace_cost_arr[i].setColumns(TEXT_FIELD_LENGTH); - preferred_direction_trace_cost_arr[i].addKeyListener(new PreferredDirectionTraceCostKeyListener(i)); - preferred_direction_trace_cost_arr[i].addFocusListener(new PreferredDirectionTraceCostFocusListener(i)); - gridbag.setConstraints(preferred_direction_trace_cost_arr[i], gridbag_constraints); - main_panel.add(preferred_direction_trace_cost_arr[i]); - against_preferred_direction_trace_cost_arr[i] = new javax.swing.JFormattedTextField(number_format); - against_preferred_direction_trace_cost_arr[i].setColumns(TEXT_FIELD_LENGTH); - against_preferred_direction_trace_cost_arr[i].addKeyListener(new AgainstPreferredDirectionTraceCostKeyListener(i)); - against_preferred_direction_trace_cost_arr[i].addFocusListener(new AgainstPreferredDirectionTraceCostFocusListener(i)); - gridbag_constraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; - gridbag.setConstraints(against_preferred_direction_trace_cost_arr[i], gridbag_constraints); - main_panel.add(against_preferred_direction_trace_cost_arr[i]); - preferred_direction_trace_costs_input_completed[i] = true; - against_preferred_direction_trace_costs_input_completed[i] = true; - } - - p_board_frame.set_context_sensitive_help(this, "WindowAutorouteDetailParameter"); - - this.refresh(); - this.pack(); - this.setResizable(false); - } - - /** - * Recalculates all displayed values - */ - public void refresh() - { - interactive.AutorouteSettings settings = this.board_handling.settings.autoroute_settings; - board.LayerStructure layer_structure = this.board_handling.get_routing_board().layer_structure; - this.via_cost_field.setValue(settings.get_via_costs()); - this.plane_via_cost_field.setValue(settings.get_plane_via_costs()); - this.start_ripup_costs.setValue(settings.get_start_ripup_costs()); - this.start_pass_no.setValue(settings.get_pass_no()); - for (int i = 0; i < preferred_direction_trace_cost_arr.length; ++i) - { - this.preferred_direction_trace_cost_arr[i].setValue(settings.get_preferred_direction_trace_costs(layer_structure.get_layer_no(i))); - } - for (int i = 0; i < against_preferred_direction_trace_cost_arr.length; ++i) - { - this.against_preferred_direction_trace_cost_arr[i].setValue(settings.get_against_preferred_direction_trace_costs(layer_structure.get_layer_no(i))); - } - } - private final interactive.BoardHandling board_handling; - private final javax.swing.JFormattedTextField via_cost_field; - private final javax.swing.JFormattedTextField plane_via_cost_field; - private final javax.swing.JFormattedTextField start_ripup_costs; - private final javax.swing.JFormattedTextField start_pass_no; - private final javax.swing.JComboBox speed_combo_box; - private final String speed_fast; - private final String speed_slow; - private final javax.swing.JLabel[] layer_name_arr; - private final javax.swing.JFormattedTextField[] preferred_direction_trace_cost_arr; - private final javax.swing.JFormattedTextField[] against_preferred_direction_trace_cost_arr; - private boolean via_cost_input_completed = true; - private boolean plane_via_cost_input_completed = true; - private boolean start_ripup_cost_input_completed = true; - private final boolean[] preferred_direction_trace_costs_input_completed; - private final boolean[] against_preferred_direction_trace_costs_input_completed; - - private class ViaCostFieldKeyListener extends java.awt.event.KeyAdapter - { - - public void keyTyped(java.awt.event.KeyEvent p_evt) - { - if (p_evt.getKeyChar() == '\n') - { - int old_value = board_handling.settings.autoroute_settings.get_via_costs(); - Object input = via_cost_field.getValue(); - int input_value; - if (input instanceof Number) - { - input_value = ((Number) input).intValue(); - if (input_value <= 0) - { - input_value = 1; - via_cost_field.setValue(input_value); - } - } else - { - input_value = old_value; - via_cost_field.setValue(old_value); - } - board_handling.settings.autoroute_settings.set_via_costs(input_value); - via_cost_field.setValue(input_value); - via_cost_input_completed = true; - - } else - { - via_cost_input_completed = false; - } - } - } - - private class ViaCostFieldFocusListener implements java.awt.event.FocusListener - { - - public void focusLost(java.awt.event.FocusEvent p_evt) - { - if (!via_cost_input_completed) - { - via_cost_input_completed = true; - refresh(); - } - } - - public void focusGained(java.awt.event.FocusEvent p_evt) - { - } - } - - private class PlaneViaCostFieldKeyListener extends java.awt.event.KeyAdapter - { - - public void keyTyped(java.awt.event.KeyEvent p_evt) - { - if (p_evt.getKeyChar() == '\n') - { - int old_value = board_handling.settings.autoroute_settings.get_plane_via_costs(); - Object input = plane_via_cost_field.getValue(); - int input_value; - if (input instanceof Number) - { - input_value = ((Number) input).intValue(); - if (input_value <= 0) - { - input_value = 1; - plane_via_cost_field.setValue(input_value); - } - } else - { - input_value = old_value; - plane_via_cost_field.setValue(old_value); - } - board_handling.settings.autoroute_settings.set_plane_via_costs(input_value); - plane_via_cost_field.setValue(input_value); - plane_via_cost_input_completed = true; - - } else - { - plane_via_cost_input_completed = false; - } - } - } - - private class PlaneViaCostFieldFocusListener implements java.awt.event.FocusListener - { - - public void focusLost(java.awt.event.FocusEvent p_evt) - { - if (!plane_via_cost_input_completed) - { - plane_via_cost_input_completed = true; - refresh(); - } - } - - public void focusGained(java.awt.event.FocusEvent p_evt) - { - } - } - - private class StartRipupCostFieldKeyListener extends java.awt.event.KeyAdapter - { - - public void keyTyped(java.awt.event.KeyEvent p_evt) - { - if (p_evt.getKeyChar() == '\n') - { - int old_value = board_handling.settings.autoroute_settings.get_start_ripup_costs(); - Object input = start_ripup_costs.getValue(); - int input_value; - if (input instanceof Number) - { - input_value = ((Number) input).intValue(); - if (input_value <= 0) - { - input_value = 1; - } - } else - { - input_value = old_value; - } - board_handling.settings.autoroute_settings.set_start_ripup_costs(input_value); - start_ripup_costs.setValue(input_value); - start_ripup_cost_input_completed = true; - } else - { - start_ripup_cost_input_completed = false; - } - } - } - - private class StartRipupCostFieldFocusListener implements java.awt.event.FocusListener - { - - public void focusLost(java.awt.event.FocusEvent p_evt) - { - if (!start_ripup_cost_input_completed) - { - start_ripup_cost_input_completed = true; - refresh(); - } - } - - public void focusGained(java.awt.event.FocusEvent p_evt) - { - } - } - - private class StartPassFieldKeyListener extends java.awt.event.KeyAdapter - { - - public void keyTyped(java.awt.event.KeyEvent p_evt) - { - if (p_evt.getKeyChar() == '\n') - { - int old_value = board_handling.settings.autoroute_settings.get_pass_no(); - Object input = start_pass_no.getValue(); - int input_value; - if (input instanceof Number) - { - input_value = ((Number) input).intValue(); - if (input_value < 1) - { - input_value = 1; - } - if (input_value > 99) - { - input_value = 99; - } - } else - { - input_value = old_value; - } - board_handling.settings.autoroute_settings.set_pass_no(input_value); - start_pass_no.setValue(input_value); - - } - } - } - - private class StartPassFieldFocusListener implements java.awt.event.FocusListener - { - - public void focusLost(java.awt.event.FocusEvent p_evt) - { - if (!start_ripup_cost_input_completed) - { - refresh(); - } - } - - public void focusGained(java.awt.event.FocusEvent p_evt) - { - } - } - - private class SpeedListener implements java.awt.event.ActionListener - { - - public void actionPerformed(java.awt.event.ActionEvent p_evt) - { - boolean old_is_slow = board_handling.get_routing_board().rules.get_slow_autoroute_algorithm(); - boolean new_is_slow = speed_combo_box.getSelectedItem() == speed_slow; - if (old_is_slow != new_is_slow) - { - board_handling.get_routing_board().rules.set_slow_autoroute_algorithm(new_is_slow); - board_handling.get_routing_board().search_tree_manager.reset_compensated_trees(); - } - } - } - - private class PreferredDirectionTraceCostKeyListener extends java.awt.event.KeyAdapter - { - - public PreferredDirectionTraceCostKeyListener(int p_layer_no) - { - this.signal_layer_no = p_layer_no; - } - - public void keyTyped(java.awt.event.KeyEvent p_evt) - { - if (p_evt.getKeyChar() == '\n') - { - int curr_layer_no = board_handling.get_routing_board().layer_structure.get_layer_no(this.signal_layer_no); - double old_value = board_handling.settings.autoroute_settings.get_preferred_direction_trace_costs(curr_layer_no); - Object input = preferred_direction_trace_cost_arr[this.signal_layer_no].getValue(); - double input_value; - if (input instanceof Number) - { - input_value = ((Number) input).doubleValue(); - if (input_value <= 0) - { - input_value = old_value; - } - } else - { - input_value = old_value; - } - board_handling.settings.autoroute_settings.set_preferred_direction_trace_costs(curr_layer_no, input_value); - preferred_direction_trace_cost_arr[this.signal_layer_no].setValue(input_value); - preferred_direction_trace_costs_input_completed[this.signal_layer_no] = true; - - } else - { - preferred_direction_trace_costs_input_completed[this.signal_layer_no] = false; - } - } - private final int signal_layer_no; - } - - private class PreferredDirectionTraceCostFocusListener implements java.awt.event.FocusListener - { - - public PreferredDirectionTraceCostFocusListener(int p_layer_no) - { - this.signal_layer_no = p_layer_no; - } - - public void focusLost(java.awt.event.FocusEvent p_evt) - { - if (!preferred_direction_trace_costs_input_completed[this.signal_layer_no]) - { - start_ripup_cost_input_completed = true; - refresh(); - } - } - - public void focusGained(java.awt.event.FocusEvent p_evt) - { - } - private final int signal_layer_no; - } - - private class AgainstPreferredDirectionTraceCostKeyListener extends java.awt.event.KeyAdapter - { - - public AgainstPreferredDirectionTraceCostKeyListener(int p_layer_no) - { - this.signal_layer_no = p_layer_no; - } - - public void keyTyped(java.awt.event.KeyEvent p_evt) - { - if (p_evt.getKeyChar() == '\n') - { - int curr_layer_no = board_handling.get_routing_board().layer_structure.get_layer_no(this.signal_layer_no); - double old_value = board_handling.settings.autoroute_settings.get_against_preferred_direction_trace_costs(curr_layer_no); - Object input = against_preferred_direction_trace_cost_arr[this.signal_layer_no].getValue(); - double input_value; - if (input instanceof Number) - { - input_value = ((Number) input).doubleValue(); - if (input_value <= 0) - { - input_value = old_value; - } - } else - { - input_value = old_value; - } - board_handling.settings.autoroute_settings.set_against_preferred_direction_trace_costs(curr_layer_no, input_value); - against_preferred_direction_trace_cost_arr[this.signal_layer_no].setValue(input_value); - against_preferred_direction_trace_costs_input_completed[this.signal_layer_no] = true; - - } else - { - against_preferred_direction_trace_costs_input_completed[this.signal_layer_no] = false; - } - } - private final int signal_layer_no; - } - - private class AgainstPreferredDirectionTraceCostFocusListener implements java.awt.event.FocusListener - { - - public AgainstPreferredDirectionTraceCostFocusListener(int p_layer_no) - { - this.signal_layer_no = p_layer_no; - } - - public void focusLost(java.awt.event.FocusEvent p_evt) - { - if (!against_preferred_direction_trace_costs_input_completed[this.signal_layer_no]) - { - start_ripup_cost_input_completed = true; - refresh(); - } - } - - public void focusGained(java.awt.event.FocusEvent p_evt) - { - } - private final int signal_layer_no; - } -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * WindowAutorouteDetailParameter.java + * + * Created on 25. Juli 2006, 08:17 + * + */ +package gui; + +/** + *

WindowAutorouteDetailParameter class.

+ * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class WindowAutorouteDetailParameter extends BoardSavableSubWindow +{ + + /** + * Creates a new instance of WindowAutorouteDetailParameter + * + * @param p_board_frame a {@link gui.BoardFrame} object. + */ + public WindowAutorouteDetailParameter(BoardFrame p_board_frame) + { + this.board_handling = p_board_frame.board_panel.board_handling; + java.util.ResourceBundle resources = + java.util.ResourceBundle.getBundle("gui.resources.WindowAutorouteParameter", p_board_frame.get_locale()); + this.setTitle(resources.getString("detail_autoroute_parameter")); + + // create main panel + + final javax.swing.JPanel main_panel = new javax.swing.JPanel(); + getContentPane().add(main_panel); + java.awt.GridBagLayout gridbag = new java.awt.GridBagLayout(); + main_panel.setLayout(gridbag); + java.awt.GridBagConstraints gridbag_constraints = new java.awt.GridBagConstraints(); + gridbag_constraints.anchor = java.awt.GridBagConstraints.WEST; + gridbag_constraints.insets = new java.awt.Insets(5, 10, 5, 10); + + // add label and number field for the via costs. + + gridbag_constraints.gridwidth = 2; + javax.swing.JLabel via_cost_label = new javax.swing.JLabel(resources.getString("via_costs")); + gridbag.setConstraints(via_cost_label, gridbag_constraints); + main_panel.add(via_cost_label); + + java.text.NumberFormat number_format = java.text.NumberFormat.getIntegerInstance(p_board_frame.get_locale()); + this.via_cost_field = new javax.swing.JFormattedTextField(number_format); + this.via_cost_field.setColumns(3); + this.via_cost_field.addKeyListener(new ViaCostFieldKeyListener()); + this.via_cost_field.addFocusListener(new ViaCostFieldFocusListener()); + gridbag_constraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; + gridbag.setConstraints(via_cost_field, gridbag_constraints); + main_panel.add(via_cost_field); + + this.plane_via_cost_field = new javax.swing.JFormattedTextField(number_format); + this.plane_via_cost_field.setColumns(3); + this.plane_via_cost_field.addKeyListener(new PlaneViaCostFieldKeyListener()); + this.plane_via_cost_field.addFocusListener(new PlaneViaCostFieldFocusListener()); + + gridbag_constraints.gridwidth = 2; + javax.swing.JLabel plane_via_cost_label = new javax.swing.JLabel(resources.getString("plane_via_costs")); + gridbag.setConstraints(plane_via_cost_label, gridbag_constraints); + main_panel.add(plane_via_cost_label); + gridbag_constraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; + gridbag.setConstraints(plane_via_cost_field, gridbag_constraints); + main_panel.add(plane_via_cost_field); + + // add label and number field for the start pass no. + + gridbag_constraints.gridwidth = 2; + javax.swing.JLabel start_pass_label = new javax.swing.JLabel(resources.getString("start_pass")); + gridbag.setConstraints(start_pass_label, gridbag_constraints); + main_panel.add(start_pass_label); + + start_pass_no = new javax.swing.JFormattedTextField(number_format); + start_pass_no.setColumns(2); + this.start_pass_no.addKeyListener(new StartPassFieldKeyListener()); + this.start_pass_no.addFocusListener(new StartPassFieldFocusListener()); + gridbag_constraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; + gridbag.setConstraints(start_pass_no, gridbag_constraints); + main_panel.add(start_pass_no); + + // add label and number field for the start ripup costs. + + gridbag_constraints.gridwidth = 2; + javax.swing.JLabel start_ripup_costs_label = new javax.swing.JLabel(); + start_ripup_costs_label.setText(resources.getString("start_ripup_costs")); + gridbag.setConstraints(start_ripup_costs_label, gridbag_constraints); + main_panel.add(start_ripup_costs_label); + + start_ripup_costs = new javax.swing.JFormattedTextField(number_format); + start_ripup_costs.setColumns(3); + this.start_ripup_costs.addKeyListener(new StartRipupCostFieldKeyListener()); + this.start_ripup_costs.addFocusListener(new StartRipupCostFieldFocusListener()); + gridbag_constraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; + gridbag.setConstraints(start_ripup_costs, gridbag_constraints); + main_panel.add(start_ripup_costs); + + + + // add label and combo box for the router speed (if the speed is set to slow, free angle geometry + // is used also in the 45 and 90 degree modes. + this.speed_fast = resources.getString("fast"); + this.speed_slow = resources.getString("slow"); + speed_combo_box = new javax.swing.JComboBox(); + speed_combo_box.addItem(this.speed_fast); + speed_combo_box.addItem(this.speed_slow); + speed_combo_box.addActionListener(new SpeedListener()); + + if (this.board_handling.get_routing_board().get_test_level() != board.TestLevel.RELEASE_VERSION) + { + gridbag_constraints.gridwidth = 2; + javax.swing.JLabel speed_label = new javax.swing.JLabel(); + speed_label.setText(resources.getString("speed")); + gridbag.setConstraints(speed_label, gridbag_constraints); + main_panel.add(speed_label); + + gridbag_constraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; + gridbag.setConstraints(speed_combo_box, gridbag_constraints); + main_panel.add(speed_combo_box); + } + + + javax.swing.JLabel separator = new javax.swing.JLabel("---------------------------------------------------------------- "); + gridbag.setConstraints(separator, gridbag_constraints); + main_panel.add(separator, gridbag_constraints); + + // add label and number field for the trace costs on each layer. + + gridbag_constraints.gridwidth = 3; + javax.swing.JLabel layer_label = new javax.swing.JLabel(resources.getString("trace_costs_on_layer")); + gridbag.setConstraints(layer_label, gridbag_constraints); + main_panel.add(layer_label); + + javax.swing.JLabel pref_dir_label = new javax.swing.JLabel(resources.getString("in_preferred_direction")); + gridbag.setConstraints(pref_dir_label, gridbag_constraints); + main_panel.add(pref_dir_label); + + gridbag_constraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; + javax.swing.JLabel against_pref_dir_label = new javax.swing.JLabel(resources.getString("against_preferred_direction")); + gridbag.setConstraints(against_pref_dir_label, gridbag_constraints); + main_panel.add(against_pref_dir_label); + + board.LayerStructure layer_structure = this.board_handling.get_routing_board().layer_structure; + int signal_layer_count = layer_structure.signal_layer_count(); + layer_name_arr = new javax.swing.JLabel[signal_layer_count]; + preferred_direction_trace_cost_arr = new javax.swing.JFormattedTextField[signal_layer_count]; + against_preferred_direction_trace_cost_arr = new javax.swing.JFormattedTextField[signal_layer_count]; + preferred_direction_trace_costs_input_completed = new boolean[signal_layer_count]; + against_preferred_direction_trace_costs_input_completed = new boolean[signal_layer_count]; + number_format = java.text.NumberFormat.getInstance(p_board_frame.get_locale()); + number_format.setMaximumFractionDigits(2); + final int TEXT_FIELD_LENGTH = 2; + for (int i = 0; i < signal_layer_count; ++i) + { + layer_name_arr[i] = new javax.swing.JLabel(); + board.Layer curr_signal_layer = layer_structure.get_signal_layer(i); + layer_name_arr[i].setText(curr_signal_layer.name); + gridbag_constraints.gridwidth = 3; + gridbag.setConstraints(layer_name_arr[i], gridbag_constraints); + main_panel.add(layer_name_arr[i]); + preferred_direction_trace_cost_arr[i] = new javax.swing.JFormattedTextField(number_format); + preferred_direction_trace_cost_arr[i].setColumns(TEXT_FIELD_LENGTH); + preferred_direction_trace_cost_arr[i].addKeyListener(new PreferredDirectionTraceCostKeyListener(i)); + preferred_direction_trace_cost_arr[i].addFocusListener(new PreferredDirectionTraceCostFocusListener(i)); + gridbag.setConstraints(preferred_direction_trace_cost_arr[i], gridbag_constraints); + main_panel.add(preferred_direction_trace_cost_arr[i]); + against_preferred_direction_trace_cost_arr[i] = new javax.swing.JFormattedTextField(number_format); + against_preferred_direction_trace_cost_arr[i].setColumns(TEXT_FIELD_LENGTH); + against_preferred_direction_trace_cost_arr[i].addKeyListener(new AgainstPreferredDirectionTraceCostKeyListener(i)); + against_preferred_direction_trace_cost_arr[i].addFocusListener(new AgainstPreferredDirectionTraceCostFocusListener(i)); + gridbag_constraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; + gridbag.setConstraints(against_preferred_direction_trace_cost_arr[i], gridbag_constraints); + main_panel.add(against_preferred_direction_trace_cost_arr[i]); + preferred_direction_trace_costs_input_completed[i] = true; + against_preferred_direction_trace_costs_input_completed[i] = true; + } + + p_board_frame.set_context_sensitive_help(this, "WindowAutorouteDetailParameter"); + + this.refresh(); + this.pack(); + this.setResizable(false); + } + + /** + * Recalculates all displayed values + */ + public void refresh() + { + interactive.AutorouteSettings settings = this.board_handling.settings.autoroute_settings; + board.LayerStructure layer_structure = this.board_handling.get_routing_board().layer_structure; + this.via_cost_field.setValue(settings.get_via_costs()); + this.plane_via_cost_field.setValue(settings.get_plane_via_costs()); + this.start_ripup_costs.setValue(settings.get_start_ripup_costs()); + this.start_pass_no.setValue(settings.get_pass_no()); + for (int i = 0; i < preferred_direction_trace_cost_arr.length; ++i) + { + this.preferred_direction_trace_cost_arr[i].setValue(settings.get_preferred_direction_trace_costs(layer_structure.get_layer_no(i))); + } + for (int i = 0; i < against_preferred_direction_trace_cost_arr.length; ++i) + { + this.against_preferred_direction_trace_cost_arr[i].setValue(settings.get_against_preferred_direction_trace_costs(layer_structure.get_layer_no(i))); + } + } + private final interactive.BoardHandling board_handling; + private final javax.swing.JFormattedTextField via_cost_field; + private final javax.swing.JFormattedTextField plane_via_cost_field; + private final javax.swing.JFormattedTextField start_ripup_costs; + private final javax.swing.JFormattedTextField start_pass_no; + private final javax.swing.JComboBox speed_combo_box; + private final String speed_fast; + private final String speed_slow; + private final javax.swing.JLabel[] layer_name_arr; + private final javax.swing.JFormattedTextField[] preferred_direction_trace_cost_arr; + private final javax.swing.JFormattedTextField[] against_preferred_direction_trace_cost_arr; + private boolean via_cost_input_completed = true; + private boolean plane_via_cost_input_completed = true; + private boolean start_ripup_cost_input_completed = true; + private final boolean[] preferred_direction_trace_costs_input_completed; + private final boolean[] against_preferred_direction_trace_costs_input_completed; + + private class ViaCostFieldKeyListener extends java.awt.event.KeyAdapter + { + + public void keyTyped(java.awt.event.KeyEvent p_evt) + { + if (p_evt.getKeyChar() == '\n') + { + int old_value = board_handling.settings.autoroute_settings.get_via_costs(); + Object input = via_cost_field.getValue(); + int input_value; + if (input instanceof Number) + { + input_value = ((Number) input).intValue(); + if (input_value <= 0) + { + input_value = 1; + via_cost_field.setValue(input_value); + } + } else + { + input_value = old_value; + via_cost_field.setValue(old_value); + } + board_handling.settings.autoroute_settings.set_via_costs(input_value); + via_cost_field.setValue(input_value); + via_cost_input_completed = true; + + } else + { + via_cost_input_completed = false; + } + } + } + + private class ViaCostFieldFocusListener implements java.awt.event.FocusListener + { + + public void focusLost(java.awt.event.FocusEvent p_evt) + { + if (!via_cost_input_completed) + { + via_cost_input_completed = true; + refresh(); + } + } + + public void focusGained(java.awt.event.FocusEvent p_evt) + { + } + } + + private class PlaneViaCostFieldKeyListener extends java.awt.event.KeyAdapter + { + + public void keyTyped(java.awt.event.KeyEvent p_evt) + { + if (p_evt.getKeyChar() == '\n') + { + int old_value = board_handling.settings.autoroute_settings.get_plane_via_costs(); + Object input = plane_via_cost_field.getValue(); + int input_value; + if (input instanceof Number) + { + input_value = ((Number) input).intValue(); + if (input_value <= 0) + { + input_value = 1; + plane_via_cost_field.setValue(input_value); + } + } else + { + input_value = old_value; + plane_via_cost_field.setValue(old_value); + } + board_handling.settings.autoroute_settings.set_plane_via_costs(input_value); + plane_via_cost_field.setValue(input_value); + plane_via_cost_input_completed = true; + + } else + { + plane_via_cost_input_completed = false; + } + } + } + + private class PlaneViaCostFieldFocusListener implements java.awt.event.FocusListener + { + + public void focusLost(java.awt.event.FocusEvent p_evt) + { + if (!plane_via_cost_input_completed) + { + plane_via_cost_input_completed = true; + refresh(); + } + } + + public void focusGained(java.awt.event.FocusEvent p_evt) + { + } + } + + private class StartRipupCostFieldKeyListener extends java.awt.event.KeyAdapter + { + + public void keyTyped(java.awt.event.KeyEvent p_evt) + { + if (p_evt.getKeyChar() == '\n') + { + int old_value = board_handling.settings.autoroute_settings.get_start_ripup_costs(); + Object input = start_ripup_costs.getValue(); + int input_value; + if (input instanceof Number) + { + input_value = ((Number) input).intValue(); + if (input_value <= 0) + { + input_value = 1; + } + } else + { + input_value = old_value; + } + board_handling.settings.autoroute_settings.set_start_ripup_costs(input_value); + start_ripup_costs.setValue(input_value); + start_ripup_cost_input_completed = true; + } else + { + start_ripup_cost_input_completed = false; + } + } + } + + private class StartRipupCostFieldFocusListener implements java.awt.event.FocusListener + { + + public void focusLost(java.awt.event.FocusEvent p_evt) + { + if (!start_ripup_cost_input_completed) + { + start_ripup_cost_input_completed = true; + refresh(); + } + } + + public void focusGained(java.awt.event.FocusEvent p_evt) + { + } + } + + private class StartPassFieldKeyListener extends java.awt.event.KeyAdapter + { + + public void keyTyped(java.awt.event.KeyEvent p_evt) + { + if (p_evt.getKeyChar() == '\n') + { + int old_value = board_handling.settings.autoroute_settings.get_pass_no(); + Object input = start_pass_no.getValue(); + int input_value; + if (input instanceof Number) + { + input_value = ((Number) input).intValue(); + if (input_value < 1) + { + input_value = 1; + } + if (input_value > 99) + { + input_value = 99; + } + } else + { + input_value = old_value; + } + board_handling.settings.autoroute_settings.set_pass_no(input_value); + start_pass_no.setValue(input_value); + + } + } + } + + private class StartPassFieldFocusListener implements java.awt.event.FocusListener + { + + public void focusLost(java.awt.event.FocusEvent p_evt) + { + if (!start_ripup_cost_input_completed) + { + refresh(); + } + } + + public void focusGained(java.awt.event.FocusEvent p_evt) + { + } + } + + private class SpeedListener implements java.awt.event.ActionListener + { + + public void actionPerformed(java.awt.event.ActionEvent p_evt) + { + boolean old_is_slow = board_handling.get_routing_board().rules.get_slow_autoroute_algorithm(); + boolean new_is_slow = speed_combo_box.getSelectedItem() == speed_slow; + if (old_is_slow != new_is_slow) + { + board_handling.get_routing_board().rules.set_slow_autoroute_algorithm(new_is_slow); + board_handling.get_routing_board().search_tree_manager.reset_compensated_trees(); + } + } + } + + private class PreferredDirectionTraceCostKeyListener extends java.awt.event.KeyAdapter + { + + public PreferredDirectionTraceCostKeyListener(int p_layer_no) + { + this.signal_layer_no = p_layer_no; + } + + public void keyTyped(java.awt.event.KeyEvent p_evt) + { + if (p_evt.getKeyChar() == '\n') + { + int curr_layer_no = board_handling.get_routing_board().layer_structure.get_layer_no(this.signal_layer_no); + double old_value = board_handling.settings.autoroute_settings.get_preferred_direction_trace_costs(curr_layer_no); + Object input = preferred_direction_trace_cost_arr[this.signal_layer_no].getValue(); + double input_value; + if (input instanceof Number) + { + input_value = ((Number) input).doubleValue(); + if (input_value <= 0) + { + input_value = old_value; + } + } else + { + input_value = old_value; + } + board_handling.settings.autoroute_settings.set_preferred_direction_trace_costs(curr_layer_no, input_value); + preferred_direction_trace_cost_arr[this.signal_layer_no].setValue(input_value); + preferred_direction_trace_costs_input_completed[this.signal_layer_no] = true; + + } else + { + preferred_direction_trace_costs_input_completed[this.signal_layer_no] = false; + } + } + private final int signal_layer_no; + } + + private class PreferredDirectionTraceCostFocusListener implements java.awt.event.FocusListener + { + + public PreferredDirectionTraceCostFocusListener(int p_layer_no) + { + this.signal_layer_no = p_layer_no; + } + + public void focusLost(java.awt.event.FocusEvent p_evt) + { + if (!preferred_direction_trace_costs_input_completed[this.signal_layer_no]) + { + start_ripup_cost_input_completed = true; + refresh(); + } + } + + public void focusGained(java.awt.event.FocusEvent p_evt) + { + } + private final int signal_layer_no; + } + + private class AgainstPreferredDirectionTraceCostKeyListener extends java.awt.event.KeyAdapter + { + + public AgainstPreferredDirectionTraceCostKeyListener(int p_layer_no) + { + this.signal_layer_no = p_layer_no; + } + + public void keyTyped(java.awt.event.KeyEvent p_evt) + { + if (p_evt.getKeyChar() == '\n') + { + int curr_layer_no = board_handling.get_routing_board().layer_structure.get_layer_no(this.signal_layer_no); + double old_value = board_handling.settings.autoroute_settings.get_against_preferred_direction_trace_costs(curr_layer_no); + Object input = against_preferred_direction_trace_cost_arr[this.signal_layer_no].getValue(); + double input_value; + if (input instanceof Number) + { + input_value = ((Number) input).doubleValue(); + if (input_value <= 0) + { + input_value = old_value; + } + } else + { + input_value = old_value; + } + board_handling.settings.autoroute_settings.set_against_preferred_direction_trace_costs(curr_layer_no, input_value); + against_preferred_direction_trace_cost_arr[this.signal_layer_no].setValue(input_value); + against_preferred_direction_trace_costs_input_completed[this.signal_layer_no] = true; + + } else + { + against_preferred_direction_trace_costs_input_completed[this.signal_layer_no] = false; + } + } + private final int signal_layer_no; + } + + private class AgainstPreferredDirectionTraceCostFocusListener implements java.awt.event.FocusListener + { + + public AgainstPreferredDirectionTraceCostFocusListener(int p_layer_no) + { + this.signal_layer_no = p_layer_no; + } + + public void focusLost(java.awt.event.FocusEvent p_evt) + { + if (!against_preferred_direction_trace_costs_input_completed[this.signal_layer_no]) + { + start_ripup_cost_input_completed = true; + refresh(); + } + } + + public void focusGained(java.awt.event.FocusEvent p_evt) + { + } + private final int signal_layer_no; + } +} diff --git a/gui/WindowAutorouteParameter.java b/src/main/java/gui/WindowAutorouteParameter.java similarity index 97% rename from gui/WindowAutorouteParameter.java rename to src/main/java/gui/WindowAutorouteParameter.java index 6928b41..bce7412 100644 --- a/gui/WindowAutorouteParameter.java +++ b/src/main/java/gui/WindowAutorouteParameter.java @@ -1,315 +1,329 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * WindowAutorouteParameter.java - * - * Created on 24. Juli 2006, 07:20 - * - */ -package gui; - -/** - * Window handling parameters of the automatic routing. - * - * @author Alfons Wirtz - */ -public class WindowAutorouteParameter extends BoardSavableSubWindow -{ - - /** Creates a new instance of WindowAutorouteParameter */ - public WindowAutorouteParameter(BoardFrame p_board_frame) - { - this.board_handling = p_board_frame.board_panel.board_handling; - java.util.ResourceBundle resources = - java.util.ResourceBundle.getBundle("gui.resources.WindowAutorouteParameter", p_board_frame.get_locale()); - this.setTitle(resources.getString("title")); - - this.setDefaultCloseOperation(DISPOSE_ON_CLOSE); - - // create main panel - - final javax.swing.JPanel main_panel = new javax.swing.JPanel(); - getContentPane().add(main_panel); - java.awt.GridBagLayout gridbag = new java.awt.GridBagLayout(); - main_panel.setLayout(gridbag); - java.awt.GridBagConstraints gridbag_constraints = new java.awt.GridBagConstraints(); - gridbag_constraints.anchor = java.awt.GridBagConstraints.WEST; - gridbag_constraints.insets = new java.awt.Insets(1, 10, 1, 10); - - gridbag_constraints.gridwidth = 3; - javax.swing.JLabel layer_label = new javax.swing.JLabel(resources.getString("layer")); - gridbag.setConstraints(layer_label, gridbag_constraints); - main_panel.add(layer_label); - - javax.swing.JLabel active_label = new javax.swing.JLabel(resources.getString("active")); - gridbag.setConstraints(active_label, gridbag_constraints); - main_panel.add(active_label); - - gridbag_constraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; - javax.swing.JLabel preferred_direction_label = new javax.swing.JLabel(resources.getString("preferred_direction")); - gridbag.setConstraints(preferred_direction_label, gridbag_constraints); - main_panel.add(preferred_direction_label); - - this.horizontal = resources.getString("horizontal"); - this.vertical = resources.getString("vertical"); - - board.LayerStructure layer_structure = board_handling.get_routing_board().layer_structure; - int signal_layer_count = layer_structure.signal_layer_count(); - signal_layer_name_arr = new javax.swing.JLabel[signal_layer_count]; - signal_layer_active_arr = new javax.swing.JCheckBox[signal_layer_count]; - combo_box_arr = new javax.swing.JComboBox[signal_layer_count]; - for (int i = 0; i < signal_layer_count; ++i) - { - signal_layer_name_arr[i] = new javax.swing.JLabel(); - board.Layer curr_signal_layer = layer_structure.get_signal_layer(i); - signal_layer_name_arr[i].setText(curr_signal_layer.name); - gridbag_constraints.gridwidth = 3; - gridbag.setConstraints(signal_layer_name_arr[i], gridbag_constraints); - main_panel.add(signal_layer_name_arr[i]); - signal_layer_active_arr[i] = new javax.swing.JCheckBox(); - signal_layer_active_arr[i].addActionListener(new LayerActiveListener(i)); - gridbag.setConstraints(signal_layer_active_arr[i], gridbag_constraints); - main_panel.add(signal_layer_active_arr[i]); - combo_box_arr[i] = new javax.swing.JComboBox(); - combo_box_arr[i].addItem(this.horizontal); - combo_box_arr[i].addItem(this.vertical); - combo_box_arr[i].addActionListener(new PreferredDirectionListener(i)); - gridbag_constraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; - gridbag.setConstraints(combo_box_arr[i], gridbag_constraints); - main_panel.add(combo_box_arr[i]); - } - - javax.swing.JLabel separator = new javax.swing.JLabel("---------------------------------------- "); - gridbag.setConstraints(separator, gridbag_constraints); - main_panel.add(separator, gridbag_constraints); - - gridbag_constraints.gridwidth = java.awt.GridBagConstraints.RELATIVE; - javax.swing.JLabel vias_allowed_label = new javax.swing.JLabel(resources.getString("vias_allowed")); - gridbag.setConstraints(vias_allowed_label, gridbag_constraints); - main_panel.add(vias_allowed_label); - - this.vias_allowed = new javax.swing.JCheckBox(); - this.vias_allowed.addActionListener(new ViasAllowedListener()); - gridbag_constraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; - gridbag.setConstraints(vias_allowed, gridbag_constraints); - main_panel.add(vias_allowed); - - separator = new javax.swing.JLabel("---------------------------------------- "); - gridbag.setConstraints(separator, gridbag_constraints); - main_panel.add(separator, gridbag_constraints); - - javax.swing.JLabel passes_label = new javax.swing.JLabel(resources.getString("passes")); - - gridbag_constraints.gridwidth = java.awt.GridBagConstraints.RELATIVE; - gridbag_constraints.gridheight = 3; - gridbag.setConstraints(passes_label, gridbag_constraints); - main_panel.add(passes_label); - - this.fanout_pass_button = new javax.swing.JRadioButton(resources.getString("fanout")); - this.autoroute_pass_button = new javax.swing.JRadioButton(resources.getString("autoroute")); - this.postroute_pass_button = new javax.swing.JRadioButton(resources.getString("postroute")); - - fanout_pass_button.addActionListener(new FanoutListener()); - autoroute_pass_button.addActionListener(new AutorouteListener()); - postroute_pass_button.addActionListener(new PostrouteListener()); - - - fanout_pass_button.setSelected(false); - autoroute_pass_button.setSelected(true); - autoroute_pass_button.setSelected(true); - - - gridbag_constraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; - gridbag_constraints.gridheight = 1; - gridbag.setConstraints(fanout_pass_button, gridbag_constraints); - main_panel.add(fanout_pass_button, gridbag_constraints); - - gridbag.setConstraints(autoroute_pass_button, gridbag_constraints); - main_panel.add(autoroute_pass_button, gridbag_constraints); - gridbag.setConstraints(postroute_pass_button, gridbag_constraints); - main_panel.add(postroute_pass_button, gridbag_constraints); - - separator = new javax.swing.JLabel("---------------------------------------- "); - gridbag.setConstraints(separator, gridbag_constraints); - main_panel.add(separator, gridbag_constraints); - - detail_window = new WindowAutorouteDetailParameter(p_board_frame); - javax.swing.JButton detail_button = new javax.swing.JButton(resources.getString("detail_parameter")); - this.detail_listener = new DetailListener(); - detail_button.addActionListener(detail_listener); - gridbag.setConstraints(detail_button, gridbag_constraints); - - main_panel.add(detail_button); - - p_board_frame.set_context_sensitive_help(this, "WindowAutorouteParameter"); - - this.refresh(); - this.pack(); - this.setResizable(false); - } - - /** - * Recalculates all displayed values - */ - public void refresh() - { - interactive.AutorouteSettings settings = this.board_handling.settings.autoroute_settings; - board.LayerStructure layer_structure = this.board_handling.get_routing_board().layer_structure; - - this.vias_allowed.setSelected(settings.get_vias_allowed()); - this.fanout_pass_button.setSelected(settings.get_with_fanout()); - this.autoroute_pass_button.setSelected(settings.get_with_autoroute()); - this.postroute_pass_button.setSelected(settings.get_with_postroute()); - - for (int i = 0; i < signal_layer_active_arr.length; ++i) - { - this.signal_layer_active_arr[i].setSelected(settings.get_layer_active(layer_structure.get_layer_no(i))); - } - - for (int i = 0; i < combo_box_arr.length; ++i) - { - if (settings.get_preferred_direction_is_horizontal(layer_structure.get_layer_no(i))) - { - this.combo_box_arr[i].setSelectedItem(this.horizontal); - } - else - { - this.combo_box_arr[i].setSelectedItem(this.vertical); - } - } - this.detail_window.refresh(); - } - - public void dispose() - { - detail_window.dispose(); - super.dispose(); - } - - public void parent_iconified() - { - detail_window.parent_iconified(); - super.parent_iconified(); - } - - public void parent_deiconified() - { - detail_window.parent_deiconified(); - super.parent_deiconified(); - } - private final interactive.BoardHandling board_handling; - private final javax.swing.JLabel[] signal_layer_name_arr; - private final javax.swing.JCheckBox[] signal_layer_active_arr; - private final javax.swing.JComboBox[] combo_box_arr; - private final javax.swing.JCheckBox vias_allowed; - private final javax.swing.JRadioButton fanout_pass_button; - private final javax.swing.JRadioButton autoroute_pass_button; - private final javax.swing.JRadioButton postroute_pass_button; - private final WindowAutorouteDetailParameter detail_window; - private final DetailListener detail_listener; - private final String horizontal; - private final String vertical; - - private class DetailListener implements java.awt.event.ActionListener - { - - public void actionPerformed(java.awt.event.ActionEvent p_evt) - { - if (first_time) - { - java.awt.Point location = getLocation(); - detail_window.setLocation((int) location.getX() + 200, (int) location.getY() + 100); - first_time = false; - } - detail_window.setVisible(true); - } - private boolean first_time = true; - } - - private class LayerActiveListener implements java.awt.event.ActionListener - { - - public LayerActiveListener(int p_layer_no) - { - signal_layer_no = p_layer_no; - } - - public void actionPerformed(java.awt.event.ActionEvent p_evt) - { - int curr_layer_no = board_handling.get_routing_board().layer_structure.get_layer_no(this.signal_layer_no); - board_handling.settings.autoroute_settings.set_layer_active(curr_layer_no, signal_layer_active_arr[this.signal_layer_no].isSelected()); - } - private final int signal_layer_no; - } - - private class PreferredDirectionListener implements java.awt.event.ActionListener - { - - public PreferredDirectionListener(int p_layer_no) - { - signal_layer_no = p_layer_no; - } - - public void actionPerformed(java.awt.event.ActionEvent p_evt) - { - int curr_layer_no = board_handling.get_routing_board().layer_structure.get_layer_no(this.signal_layer_no); - board_handling.settings.autoroute_settings.set_preferred_direction_is_horizontal(curr_layer_no, - combo_box_arr[signal_layer_no].getSelectedItem() == horizontal); - } - private final int signal_layer_no; - } - - private class ViasAllowedListener implements java.awt.event.ActionListener - { - - public void actionPerformed(java.awt.event.ActionEvent p_evt) - { - board_handling.settings.autoroute_settings.set_vias_allowed(vias_allowed.isSelected()); - } - } - - private class FanoutListener implements java.awt.event.ActionListener - { - - public void actionPerformed(java.awt.event.ActionEvent p_evt) - { - interactive.AutorouteSettings autoroute_settings = board_handling.settings.autoroute_settings; - autoroute_settings.set_with_fanout(fanout_pass_button.isSelected()); - autoroute_settings.set_pass_no(1); - } - } - - private class AutorouteListener implements java.awt.event.ActionListener - { - - public void actionPerformed(java.awt.event.ActionEvent p_evt) - { - interactive.AutorouteSettings autoroute_settings = board_handling.settings.autoroute_settings; - autoroute_settings.set_with_autoroute(autoroute_pass_button.isSelected()); - autoroute_settings.set_pass_no(1); - } - } - - private class PostrouteListener implements java.awt.event.ActionListener - { - - public void actionPerformed(java.awt.event.ActionEvent p_evt) - { - interactive.AutorouteSettings autoroute_settings = board_handling.settings.autoroute_settings; - autoroute_settings.set_with_postroute(postroute_pass_button.isSelected()); - autoroute_settings.set_pass_no(1); - } - } -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * WindowAutorouteParameter.java + * + * Created on 24. Juli 2006, 07:20 + * + */ +package gui; + +/** + * Window handling parameters of the automatic routing. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class WindowAutorouteParameter extends BoardSavableSubWindow +{ + + /** + * Creates a new instance of WindowAutorouteParameter + * + * @param p_board_frame a {@link gui.BoardFrame} object. + */ + public WindowAutorouteParameter(BoardFrame p_board_frame) + { + this.board_handling = p_board_frame.board_panel.board_handling; + java.util.ResourceBundle resources = + java.util.ResourceBundle.getBundle("gui.resources.WindowAutorouteParameter", p_board_frame.get_locale()); + this.setTitle(resources.getString("title")); + + this.setDefaultCloseOperation(DISPOSE_ON_CLOSE); + + // create main panel + + final javax.swing.JPanel main_panel = new javax.swing.JPanel(); + getContentPane().add(main_panel); + java.awt.GridBagLayout gridbag = new java.awt.GridBagLayout(); + main_panel.setLayout(gridbag); + java.awt.GridBagConstraints gridbag_constraints = new java.awt.GridBagConstraints(); + gridbag_constraints.anchor = java.awt.GridBagConstraints.WEST; + gridbag_constraints.insets = new java.awt.Insets(1, 10, 1, 10); + + gridbag_constraints.gridwidth = 3; + javax.swing.JLabel layer_label = new javax.swing.JLabel(resources.getString("layer")); + gridbag.setConstraints(layer_label, gridbag_constraints); + main_panel.add(layer_label); + + javax.swing.JLabel active_label = new javax.swing.JLabel(resources.getString("active")); + gridbag.setConstraints(active_label, gridbag_constraints); + main_panel.add(active_label); + + gridbag_constraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; + javax.swing.JLabel preferred_direction_label = new javax.swing.JLabel(resources.getString("preferred_direction")); + gridbag.setConstraints(preferred_direction_label, gridbag_constraints); + main_panel.add(preferred_direction_label); + + this.horizontal = resources.getString("horizontal"); + this.vertical = resources.getString("vertical"); + + board.LayerStructure layer_structure = board_handling.get_routing_board().layer_structure; + int signal_layer_count = layer_structure.signal_layer_count(); + signal_layer_name_arr = new javax.swing.JLabel[signal_layer_count]; + signal_layer_active_arr = new javax.swing.JCheckBox[signal_layer_count]; + combo_box_arr = new javax.swing.JComboBox[signal_layer_count]; + for (int i = 0; i < signal_layer_count; ++i) + { + signal_layer_name_arr[i] = new javax.swing.JLabel(); + board.Layer curr_signal_layer = layer_structure.get_signal_layer(i); + signal_layer_name_arr[i].setText(curr_signal_layer.name); + gridbag_constraints.gridwidth = 3; + gridbag.setConstraints(signal_layer_name_arr[i], gridbag_constraints); + main_panel.add(signal_layer_name_arr[i]); + signal_layer_active_arr[i] = new javax.swing.JCheckBox(); + signal_layer_active_arr[i].addActionListener(new LayerActiveListener(i)); + gridbag.setConstraints(signal_layer_active_arr[i], gridbag_constraints); + main_panel.add(signal_layer_active_arr[i]); + combo_box_arr[i] = new javax.swing.JComboBox(); + combo_box_arr[i].addItem(this.horizontal); + combo_box_arr[i].addItem(this.vertical); + combo_box_arr[i].addActionListener(new PreferredDirectionListener(i)); + gridbag_constraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; + gridbag.setConstraints(combo_box_arr[i], gridbag_constraints); + main_panel.add(combo_box_arr[i]); + } + + javax.swing.JLabel separator = new javax.swing.JLabel("---------------------------------------- "); + gridbag.setConstraints(separator, gridbag_constraints); + main_panel.add(separator, gridbag_constraints); + + gridbag_constraints.gridwidth = java.awt.GridBagConstraints.RELATIVE; + javax.swing.JLabel vias_allowed_label = new javax.swing.JLabel(resources.getString("vias_allowed")); + gridbag.setConstraints(vias_allowed_label, gridbag_constraints); + main_panel.add(vias_allowed_label); + + this.vias_allowed = new javax.swing.JCheckBox(); + this.vias_allowed.addActionListener(new ViasAllowedListener()); + gridbag_constraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; + gridbag.setConstraints(vias_allowed, gridbag_constraints); + main_panel.add(vias_allowed); + + separator = new javax.swing.JLabel("---------------------------------------- "); + gridbag.setConstraints(separator, gridbag_constraints); + main_panel.add(separator, gridbag_constraints); + + javax.swing.JLabel passes_label = new javax.swing.JLabel(resources.getString("passes")); + + gridbag_constraints.gridwidth = java.awt.GridBagConstraints.RELATIVE; + gridbag_constraints.gridheight = 3; + gridbag.setConstraints(passes_label, gridbag_constraints); + main_panel.add(passes_label); + + this.fanout_pass_button = new javax.swing.JRadioButton(resources.getString("fanout")); + this.autoroute_pass_button = new javax.swing.JRadioButton(resources.getString("autoroute")); + this.postroute_pass_button = new javax.swing.JRadioButton(resources.getString("postroute")); + + fanout_pass_button.addActionListener(new FanoutListener()); + autoroute_pass_button.addActionListener(new AutorouteListener()); + postroute_pass_button.addActionListener(new PostrouteListener()); + + + fanout_pass_button.setSelected(false); + autoroute_pass_button.setSelected(true); + autoroute_pass_button.setSelected(true); + + + gridbag_constraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; + gridbag_constraints.gridheight = 1; + gridbag.setConstraints(fanout_pass_button, gridbag_constraints); + main_panel.add(fanout_pass_button, gridbag_constraints); + + gridbag.setConstraints(autoroute_pass_button, gridbag_constraints); + main_panel.add(autoroute_pass_button, gridbag_constraints); + gridbag.setConstraints(postroute_pass_button, gridbag_constraints); + main_panel.add(postroute_pass_button, gridbag_constraints); + + separator = new javax.swing.JLabel("---------------------------------------- "); + gridbag.setConstraints(separator, gridbag_constraints); + main_panel.add(separator, gridbag_constraints); + + detail_window = new WindowAutorouteDetailParameter(p_board_frame); + javax.swing.JButton detail_button = new javax.swing.JButton(resources.getString("detail_parameter")); + this.detail_listener = new DetailListener(); + detail_button.addActionListener(detail_listener); + gridbag.setConstraints(detail_button, gridbag_constraints); + + main_panel.add(detail_button); + + p_board_frame.set_context_sensitive_help(this, "WindowAutorouteParameter"); + + this.refresh(); + this.pack(); + this.setResizable(false); + } + + /** + * Recalculates all displayed values + */ + public void refresh() + { + interactive.AutorouteSettings settings = this.board_handling.settings.autoroute_settings; + board.LayerStructure layer_structure = this.board_handling.get_routing_board().layer_structure; + + this.vias_allowed.setSelected(settings.get_vias_allowed()); + this.fanout_pass_button.setSelected(settings.get_with_fanout()); + this.autoroute_pass_button.setSelected(settings.get_with_autoroute()); + this.postroute_pass_button.setSelected(settings.get_with_postroute()); + + for (int i = 0; i < signal_layer_active_arr.length; ++i) + { + this.signal_layer_active_arr[i].setSelected(settings.get_layer_active(layer_structure.get_layer_no(i))); + } + + for (int i = 0; i < combo_box_arr.length; ++i) + { + if (settings.get_preferred_direction_is_horizontal(layer_structure.get_layer_no(i))) + { + this.combo_box_arr[i].setSelectedItem(this.horizontal); + } + else + { + this.combo_box_arr[i].setSelectedItem(this.vertical); + } + } + this.detail_window.refresh(); + } + + /** + *

dispose.

+ */ + public void dispose() + { + detail_window.dispose(); + super.dispose(); + } + + /** + *

parent_iconified.

+ */ + public void parent_iconified() + { + detail_window.parent_iconified(); + super.parent_iconified(); + } + + /** + *

parent_deiconified.

+ */ + public void parent_deiconified() + { + detail_window.parent_deiconified(); + super.parent_deiconified(); + } + private final interactive.BoardHandling board_handling; + private final javax.swing.JLabel[] signal_layer_name_arr; + private final javax.swing.JCheckBox[] signal_layer_active_arr; + private final javax.swing.JComboBox[] combo_box_arr; + private final javax.swing.JCheckBox vias_allowed; + private final javax.swing.JRadioButton fanout_pass_button; + private final javax.swing.JRadioButton autoroute_pass_button; + private final javax.swing.JRadioButton postroute_pass_button; + private final WindowAutorouteDetailParameter detail_window; + private final DetailListener detail_listener; + private final String horizontal; + private final String vertical; + + private class DetailListener implements java.awt.event.ActionListener + { + + public void actionPerformed(java.awt.event.ActionEvent p_evt) + { + if (first_time) + { + java.awt.Point location = getLocation(); + detail_window.setLocation((int) location.getX() + 200, (int) location.getY() + 100); + first_time = false; + } + detail_window.setVisible(true); + } + private boolean first_time = true; + } + + private class LayerActiveListener implements java.awt.event.ActionListener + { + + public LayerActiveListener(int p_layer_no) + { + signal_layer_no = p_layer_no; + } + + public void actionPerformed(java.awt.event.ActionEvent p_evt) + { + int curr_layer_no = board_handling.get_routing_board().layer_structure.get_layer_no(this.signal_layer_no); + board_handling.settings.autoroute_settings.set_layer_active(curr_layer_no, signal_layer_active_arr[this.signal_layer_no].isSelected()); + } + private final int signal_layer_no; + } + + private class PreferredDirectionListener implements java.awt.event.ActionListener + { + + public PreferredDirectionListener(int p_layer_no) + { + signal_layer_no = p_layer_no; + } + + public void actionPerformed(java.awt.event.ActionEvent p_evt) + { + int curr_layer_no = board_handling.get_routing_board().layer_structure.get_layer_no(this.signal_layer_no); + board_handling.settings.autoroute_settings.set_preferred_direction_is_horizontal(curr_layer_no, + combo_box_arr[signal_layer_no].getSelectedItem() == horizontal); + } + private final int signal_layer_no; + } + + private class ViasAllowedListener implements java.awt.event.ActionListener + { + + public void actionPerformed(java.awt.event.ActionEvent p_evt) + { + board_handling.settings.autoroute_settings.set_vias_allowed(vias_allowed.isSelected()); + } + } + + private class FanoutListener implements java.awt.event.ActionListener + { + + public void actionPerformed(java.awt.event.ActionEvent p_evt) + { + interactive.AutorouteSettings autoroute_settings = board_handling.settings.autoroute_settings; + autoroute_settings.set_with_fanout(fanout_pass_button.isSelected()); + autoroute_settings.set_pass_no(1); + } + } + + private class AutorouteListener implements java.awt.event.ActionListener + { + + public void actionPerformed(java.awt.event.ActionEvent p_evt) + { + interactive.AutorouteSettings autoroute_settings = board_handling.settings.autoroute_settings; + autoroute_settings.set_with_autoroute(autoroute_pass_button.isSelected()); + autoroute_settings.set_pass_no(1); + } + } + + private class PostrouteListener implements java.awt.event.ActionListener + { + + public void actionPerformed(java.awt.event.ActionEvent p_evt) + { + interactive.AutorouteSettings autoroute_settings = board_handling.settings.autoroute_settings; + autoroute_settings.set_with_postroute(postroute_pass_button.isSelected()); + autoroute_settings.set_pass_no(1); + } + } +} diff --git a/gui/WindowClearanceMatrix.java b/src/main/java/gui/WindowClearanceMatrix.java similarity index 99% rename from gui/WindowClearanceMatrix.java rename to src/main/java/gui/WindowClearanceMatrix.java index 56d1c57..87fb5ac 100644 --- a/gui/WindowClearanceMatrix.java +++ b/src/main/java/gui/WindowClearanceMatrix.java @@ -28,11 +28,16 @@ * Window for interactive editing of the clearance Matrix. * * @author Alfons Wirtz + * @version $Id: $Id */ public class WindowClearanceMatrix extends BoardSavableSubWindow { - /** Creates a new instance of ClearanceMatrixWindow */ + /** + * Creates a new instance of ClearanceMatrixWindow + * + * @param p_board_frame a {@link gui.BoardFrame} object. + */ public WindowClearanceMatrix(BoardFrame p_board_frame) { this.board_frame = p_board_frame; diff --git a/gui/WindowClearanceViolations.java b/src/main/java/gui/WindowClearanceViolations.java similarity index 95% rename from gui/WindowClearanceViolations.java rename to src/main/java/gui/WindowClearanceViolations.java index 5665fd8..ff499bd 100644 --- a/gui/WindowClearanceViolations.java +++ b/src/main/java/gui/WindowClearanceViolations.java @@ -26,13 +26,19 @@ import interactive.ClearanceViolations; /** + *

WindowClearanceViolations class.

* * @author Alfons Wirtz + * @version $Id: $Id */ public class WindowClearanceViolations extends WindowObjectListWithFilter { - /** Creates a new instance of IncompletesWindow */ + /** + * Creates a new instance of IncompletesWindow + * + * @param p_board_frame a {@link gui.BoardFrame} object. + */ public WindowClearanceViolations(BoardFrame p_board_frame) { super(p_board_frame); @@ -43,6 +49,9 @@ public WindowClearanceViolations(BoardFrame p_board_frame) } + /** + *

fill_list.

+ */ protected void fill_list() { interactive.BoardHandling board_handling = this.board_frame.board_panel.board_handling; @@ -61,6 +70,9 @@ protected void fill_list() this.list.setVisibleRowCount(Math.min(sorted_set.size(), DEFAULT_TABLE_SIZE)); } + /** + *

select_instances.

+ */ protected void select_instances() { Object[] selected_violations = list.getSelectedValues(); @@ -173,4 +185,4 @@ public int compareTo(ViolationInfo p_other) public final ClearanceViolation violation; public final FloatPoint location; } -} \ No newline at end of file +} diff --git a/gui/WindowComponents.java b/src/main/java/gui/WindowComponents.java similarity index 94% rename from gui/WindowComponents.java rename to src/main/java/gui/WindowComponents.java index d6a742d..64cf0dd 100644 --- a/gui/WindowComponents.java +++ b/src/main/java/gui/WindowComponents.java @@ -26,11 +26,16 @@ * Window displaying the components on the board. * * @author Alfons Wirtz + * @version $Id: $Id */ public class WindowComponents extends WindowObjectListWithFilter { - /** Creates a new instance of ComponentsWindow */ + /** + * Creates a new instance of ComponentsWindow + * + * @param p_board_frame a {@link gui.BoardFrame} object. + */ public WindowComponents(BoardFrame p_board_frame) { super(p_board_frame); @@ -59,6 +64,9 @@ protected void fill_list() this.list.setVisibleRowCount(Math.min(components.count(), DEFAULT_TABLE_SIZE)); } + /** + *

select_instances.

+ */ protected void select_instances() { Object[] selected_components = list.getSelectedValues(); diff --git a/gui/WindowDisplayMisc.java b/src/main/java/gui/WindowDisplayMisc.java similarity index 99% rename from gui/WindowDisplayMisc.java rename to src/main/java/gui/WindowDisplayMisc.java index 0797a2c..b78c57b 100644 --- a/gui/WindowDisplayMisc.java +++ b/src/main/java/gui/WindowDisplayMisc.java @@ -24,11 +24,16 @@ * Window for interactive changing of miscellanious display properties. * * @author Alfons Wirtz + * @version $Id: $Id */ public class WindowDisplayMisc extends BoardSavableSubWindow { - /** Creates a new instance of DisplayMiscWindow */ + /** + * Creates a new instance of DisplayMiscWindow + * + * @param p_board_frame a {@link gui.BoardFrame} object. + */ public WindowDisplayMisc(BoardFrame p_board_frame) { this.panel = p_board_frame.board_panel; diff --git a/gui/WindowEditVias.java b/src/main/java/gui/WindowEditVias.java similarity index 98% rename from gui/WindowEditVias.java rename to src/main/java/gui/WindowEditVias.java index 1fa010a..c3bb4ee 100644 --- a/gui/WindowEditVias.java +++ b/src/main/java/gui/WindowEditVias.java @@ -28,11 +28,16 @@ * Edit window for the table of available vias. * * @author Alfons Wirtz + * @version $Id: $Id */ public class WindowEditVias extends BoardSavableSubWindow { - /** Creates a new instance of ViaTablePanel */ + /** + * Creates a new instance of ViaTablePanel + * + * @param p_board_frame a {@link gui.BoardFrame} object. + */ public WindowEditVias(BoardFrame p_board_frame) { this.resources = java.util.ResourceBundle.getBundle("gui.resources.WindowEditVias", p_board_frame.get_locale()); diff --git a/gui/WindowIncompletes.java b/src/main/java/gui/WindowIncompletes.java similarity index 91% rename from gui/WindowIncompletes.java rename to src/main/java/gui/WindowIncompletes.java index 44aefc5..d5e12d3 100644 --- a/gui/WindowIncompletes.java +++ b/src/main/java/gui/WindowIncompletes.java @@ -23,13 +23,19 @@ import interactive.RatsNest; /** + *

WindowIncompletes class.

* * @author Alfons Wirtz + * @version $Id: $Id */ public class WindowIncompletes extends WindowObjectListWithFilter { - /** Creates a new instance of IncompletesWindow */ + /** + * Creates a new instance of IncompletesWindow + * + * @param p_board_frame a {@link gui.BoardFrame} object. + */ public WindowIncompletes(BoardFrame p_board_frame) { super(p_board_frame); @@ -57,6 +63,9 @@ protected void fill_list() this.list.setVisibleRowCount(Math.min(sorted_arr.length, DEFAULT_TABLE_SIZE)); } + /** + *

select_instances.

+ */ protected void select_instances() { Object[] selected_incompletes = list.getSelectedValues(); diff --git a/gui/WindowLayerVisibility.java b/src/main/java/gui/WindowLayerVisibility.java similarity index 91% rename from gui/WindowLayerVisibility.java rename to src/main/java/gui/WindowLayerVisibility.java index 35eb519..8de98f3 100644 --- a/gui/WindowLayerVisibility.java +++ b/src/main/java/gui/WindowLayerVisibility.java @@ -24,10 +24,16 @@ * Interactive Frame to adjust the visibility of the individual board layers * * @author alfons + * @version $Id: $Id */ public class WindowLayerVisibility extends WindowVisibility { - /** Returns a new instance of LayerVisibilityFrame */ + /** + * Returns a new instance of LayerVisibilityFrame + * + * @param p_board_frame a {@link gui.BoardFrame} object. + * @return a {@link gui.WindowLayerVisibility} object. + */ public static WindowLayerVisibility get_instance(BoardFrame p_board_frame) { BoardPanel board_panel = p_board_frame.board_panel; @@ -57,11 +63,15 @@ private WindowLayerVisibility(BoardFrame p_board_frame, String p_title, String p super(p_board_frame, p_title, p_header_message, p_message_arr); } + /** {@inheritDoc} */ protected void set_changed_value(int p_index, double p_value) { get_board_handling().set_layer_visibility(p_index, p_value); } + /** + *

set_all_minimum.

+ */ protected void set_all_minimum() { int layer_count = this.get_board_handling().graphics_context.layer_count(); diff --git a/gui/WindowLengthViolations.java b/src/main/java/gui/WindowLengthViolations.java similarity index 94% rename from gui/WindowLengthViolations.java rename to src/main/java/gui/WindowLengthViolations.java index 67ff4fc..54f0b03 100644 --- a/gui/WindowLengthViolations.java +++ b/src/main/java/gui/WindowLengthViolations.java @@ -28,13 +28,19 @@ import interactive.RatsNest; /** + *

WindowLengthViolations class.

* * @author Alfons Wirtz + * @version $Id: $Id */ public class WindowLengthViolations extends WindowObjectListWithFilter { - /** Creates a new instance of WindowLengthViolations */ + /** + * Creates a new instance of WindowLengthViolations + * + * @param p_board_frame a {@link gui.BoardFrame} object. + */ public WindowLengthViolations(BoardFrame p_board_frame) { super(p_board_frame); @@ -44,6 +50,9 @@ public WindowLengthViolations(BoardFrame p_board_frame) p_board_frame.set_context_sensitive_help(this, "WindowObjectList_LengthViolations"); } + /** + *

fill_list.

+ */ protected void fill_list() { RatsNest ratsnest = this.board_frame.board_panel.board_handling.get_ratsnest(); @@ -66,6 +75,9 @@ protected void fill_list() this.list.setVisibleRowCount(Math.min(length_violations.size(), DEFAULT_TABLE_SIZE)); } + /** + *

select_instances.

+ */ protected void select_instances() { Object[] selected_violations = list.getSelectedValues(); diff --git a/gui/WindowManualRules.java b/src/main/java/gui/WindowManualRules.java similarity index 97% rename from gui/WindowManualRules.java rename to src/main/java/gui/WindowManualRules.java index 3cf21ee..e3803f1 100644 --- a/gui/WindowManualRules.java +++ b/src/main/java/gui/WindowManualRules.java @@ -23,11 +23,16 @@ * Used for manual choice of trace widths in interactive routing. * * @author Alfons Wirtz + * @version $Id: $Id */ public class WindowManualRules extends BoardSavableSubWindow { - /** Creates a new instance of TraceWidthWindow */ + /** + * Creates a new instance of TraceWidthWindow + * + * @param p_board_frame a {@link gui.BoardFrame} object. + */ public WindowManualRules(BoardFrame p_board_frame) { this.board_handling = p_board_frame.board_panel.board_handling; @@ -134,6 +139,11 @@ public void refresh() this.repaint(); } + /** + *

set_trace_width_field.

+ * + * @param p_half_width a int. + */ public void set_trace_width_field(int p_half_width) { if (p_half_width < 0) diff --git a/gui/WindowMessage.java b/src/main/java/gui/WindowMessage.java similarity index 87% rename from gui/WindowMessage.java rename to src/main/java/gui/WindowMessage.java index 0f81d75..14903dd 100644 --- a/gui/WindowMessage.java +++ b/src/main/java/gui/WindowMessage.java @@ -24,12 +24,16 @@ * Startup window visible when the program is loading. * * @author Alfons Wirtz + * @version $Id: $Id */ public class WindowMessage extends javax.swing.JFrame { /** * Displays a window with the input message at the center of the screen. + * + * @param p_message a {@link java.lang.String} object. + * @return a {@link gui.WindowMessage} object. */ public static WindowMessage show(String p_message) { @@ -40,6 +44,9 @@ public static WindowMessage show(String p_message) /** * Displays a window with the input messages at the center of the screen. + * + * @param p_messages an array of {@link java.lang.String} objects. + * @return a {@link gui.WindowMessage} object. */ public static WindowMessage show(String[] p_messages) { @@ -48,6 +55,9 @@ public static WindowMessage show(String[] p_messages) /** * Calls a confirm dialog. Returns true, if the user confirmed the action or if p_message is null. + * + * @param p_message a {@link java.lang.String} object. + * @return a boolean. */ public static boolean confirm(String p_message) { @@ -63,6 +73,8 @@ public static boolean confirm(String p_message) /** * Calls a dialog with an ok-button. + * + * @param p_message a {@link java.lang.String} object. */ public static void ok(String p_message) { diff --git a/gui/WindowMoveParameter.java b/src/main/java/gui/WindowMoveParameter.java similarity index 98% rename from gui/WindowMoveParameter.java rename to src/main/java/gui/WindowMoveParameter.java index 79fe985..fd8c84b 100644 --- a/gui/WindowMoveParameter.java +++ b/src/main/java/gui/WindowMoveParameter.java @@ -25,11 +25,16 @@ * Window with the parameters for moving components. * * @author Alfons Wirtz + * @version $Id: $Id */ public class WindowMoveParameter extends BoardSavableSubWindow { - /** Creates a new instance of WindowMoveParameter */ + /** + * Creates a new instance of WindowMoveParameter + * + * @param p_board_frame a {@link gui.BoardFrame} object. + */ public WindowMoveParameter(BoardFrame p_board_frame) { this.board_handling = p_board_frame.board_panel.board_handling; diff --git a/gui/WindowNetClasses.java b/src/main/java/gui/WindowNetClasses.java similarity index 99% rename from gui/WindowNetClasses.java rename to src/main/java/gui/WindowNetClasses.java index 69327ca..942fa0a 100644 --- a/gui/WindowNetClasses.java +++ b/src/main/java/gui/WindowNetClasses.java @@ -29,11 +29,16 @@ * Edit window for the table of net rules. * * @author Alfons Wirtz + * @version $Id: $Id */ public class WindowNetClasses extends BoardSavableSubWindow { - /** Creates a new instance of NetClassesWindow */ + /** + * Creates a new instance of NetClassesWindow + * + * @param p_board_frame a {@link gui.BoardFrame} object. + */ public WindowNetClasses(BoardFrame p_board_frame) { this.resources = java.util.ResourceBundle.getBundle("gui.resources.WindowNetClasses", p_board_frame.get_locale()); @@ -92,6 +97,9 @@ public WindowNetClasses(BoardFrame p_board_frame) this.setDefaultCloseOperation(DISPOSE_ON_CLOSE); } + /** + *

refresh.

+ */ public void refresh() { this.cl_class_combo_box.removeAllItems(); @@ -120,6 +128,9 @@ public void refresh() } } + /** + *

dispose.

+ */ public void dispose() { for (javax.swing.JFrame curr_subwindow : this.subwindows) diff --git a/gui/WindowNets.java b/src/main/java/gui/WindowNets.java similarity index 96% rename from gui/WindowNets.java rename to src/main/java/gui/WindowNets.java index f7943be..b6f4863 100644 --- a/gui/WindowNets.java +++ b/src/main/java/gui/WindowNets.java @@ -27,13 +27,19 @@ /** + *

WindowNets class.

* * @author Alfons Wirtz + * @version $Id: $Id */ public class WindowNets extends WindowObjectListWithFilter { - /** Creates a new instance of NetsWindow */ + /** + * Creates a new instance of NetsWindow + * + * @param p_board_frame a {@link gui.BoardFrame} object. + */ public WindowNets(BoardFrame p_board_frame) { super(p_board_frame); @@ -74,6 +80,9 @@ protected void fill_list() this.list.setVisibleRowCount(Math.min(sorted_arr.length, DEFAULT_TABLE_SIZE)); } + /** + *

select_instances.

+ */ protected void select_instances() { Object[] selected_nets = list.getSelectedValues(); diff --git a/gui/WindowObjectInfo.java b/src/main/java/gui/WindowObjectInfo.java similarity index 90% rename from gui/WindowObjectInfo.java rename to src/main/java/gui/WindowObjectInfo.java index 3ebbda2..f7f4119 100644 --- a/gui/WindowObjectInfo.java +++ b/src/main/java/gui/WindowObjectInfo.java @@ -27,6 +27,7 @@ * Window displaying text information for a list of objects implementing the ObjectInfoWindow.Printable interface. * * @author Alfons Wirtz + * @version $Id: $Id */ public class WindowObjectInfo extends BoardTemporarySubWindow implements board.ObjectInfoPanel { @@ -34,6 +35,11 @@ public class WindowObjectInfo extends BoardTemporarySubWindow implements board.O * Displays a new ObjectInfoWindow with information about the items in p_item_list. * p_coordinate_transform is for transforming board to user coordinates, * and p_location is the location of the window. + * + * @param p_item_list a {@link java.util.Collection} object. + * @param p_board_frame a {@link gui.BoardFrame} object. + * @param p_coordinate_transform a {@link board.CoordinateTransform} object. + * @param p_location a {@link java.awt.Point} object. */ public static void display(Collection p_item_list, BoardFrame p_board_frame, board.CoordinateTransform p_coordinate_transform, java.awt.Point p_location) @@ -126,6 +132,12 @@ else if (curr_object instanceof board.Trace) * Displays a new ObjectInfoWindow with information about the objects in p_object_list. * p_coordinate_transform is for transforming board to user coordinates, * and p_location is the location of the window. + * + * @param p_title a {@link java.lang.String} object. + * @param p_object_list a {@link java.util.Collection} object. + * @param p_board_frame a {@link gui.BoardFrame} object. + * @param p_coordinate_transform a {@link board.CoordinateTransform} object. + * @return a {@link gui.WindowObjectInfo} object. */ public static WindowObjectInfo display(String p_title, Collection p_object_list, BoardFrame p_board_frame, board.CoordinateTransform p_coordinate_transform) @@ -217,6 +229,9 @@ private boolean append(String p_string, String p_style) /** * Appends p_string to the text pane. * Returns false, if that was not possible. + * + * @param p_string a {@link java.lang.String} object. + * @return a boolean. */ public boolean append(String p_string) { @@ -224,6 +239,8 @@ public boolean append(String p_string) } /** + * {@inheritDoc} + * * Appends p_string in bold styleto the text pane. * Returns false, if that was not possible. */ @@ -236,6 +253,9 @@ public boolean append_bold(String p_string) * Appends p_value to the text pane after * transforming it to the user coordinate sytem. * Returns false, if that was not possible. + * + * @param p_value a double. + * @return a boolean. */ public boolean append(double p_value) { @@ -244,6 +264,8 @@ public boolean append(double p_value) } /** + * {@inheritDoc} + * * Appends p_value to the text pane without * transforming it to the user coordinate sytem. * Returns false, if that was not possible. @@ -255,6 +277,8 @@ public boolean append_without_transforming(double p_value) } /** + * {@inheritDoc} + * * Appends p_point to the text pane * after transforming to the user coordinate sytem. * Returns false, if that was not possible. @@ -266,6 +290,8 @@ public boolean append(geometry.planar.FloatPoint p_point) } /** + * {@inheritDoc} + * * Appends p_shape to the text pane * after transforming to the user coordinate sytem. * Returns false, if that was not possible. @@ -282,6 +308,8 @@ public boolean append(geometry.planar.Shape p_shape, java.util.Locale p_locale) /** * Begins a new line in the text pane. + * + * @return a boolean. */ public boolean newline() { @@ -290,6 +318,8 @@ public boolean newline() /** * Appends a fixed number of spaces to the text pane. + * + * @return a boolean. */ public boolean indent() { @@ -299,6 +329,11 @@ public boolean indent() /** * Appends a button for creating a new ObjectInfoWindow with the information * of p_object to the text pane. Returns false, if that was not possible. + * + * @param p_button_name a {@link java.lang.String} object. + * @param p_window_title a {@link java.lang.String} object. + * @param p_object a WindowObjectInfo.Printable object. + * @return a boolean. */ public boolean append( String p_button_name, String p_window_title, WindowObjectInfo.Printable p_object) { @@ -310,6 +345,11 @@ public boolean append( String p_button_name, String p_window_title, WindowObject /** * Appends a button for creating a new ObjectInfoWindow with the information * of p_items to the text pane. Returns false, if that was not possible. + * + * @param p_button_name a {@link java.lang.String} object. + * @param p_window_title a {@link java.lang.String} object. + * @param p_items a java$util$Collection object. + * @return a boolean. */ public boolean append_items( String p_button_name, String p_window_title, java.util.Collection p_items) { @@ -321,6 +361,11 @@ public boolean append_items( String p_button_name, String p_window_title, java.u /** * Appends a button for creating a new ObjectInfoWindow with the information * of p_objects to the text pane. Returns false, if that was not possible. + * + * @param p_button_name a {@link java.lang.String} object. + * @param p_window_title a {@link java.lang.String} object. + * @param p_objects a java$util$Collection object. + * @return a boolean. */ public boolean append_objects( String p_button_name, String p_window_title, java.util.Collection p_objects) @@ -358,6 +403,9 @@ public boolean append_objects( String p_button_name, String p_window_title, return true; } + /** + *

dispose.

+ */ public void dispose() { for (WindowObjectInfo curr_subwindow : this.subwindows) diff --git a/gui/WindowObjectList.java b/src/main/java/gui/WindowObjectList.java similarity index 95% rename from gui/WindowObjectList.java rename to src/main/java/gui/WindowObjectList.java index 058fbf1..1ea10f4 100644 --- a/gui/WindowObjectList.java +++ b/src/main/java/gui/WindowObjectList.java @@ -24,11 +24,16 @@ * Abstract class for windows displaying a list of objects * * @author Alfons Wirtz + * @version $Id: $Id */ public abstract class WindowObjectList extends BoardSavableSubWindow { - /** Creates a new instance of ObjectListWindow */ + /** + * Creates a new instance of ObjectListWindow + * + * @param p_board_frame a {@link gui.BoardFrame} object. + */ public WindowObjectList(BoardFrame p_board_frame) { this.board_frame = p_board_frame; @@ -92,6 +97,7 @@ public void windowClosing(java.awt.event.WindowEvent evt) }); } + /** {@inheritDoc} */ public void setVisible(boolean p_value) { if (p_value == true) @@ -101,6 +107,9 @@ public void setVisible(boolean p_value) super.setVisible(p_value); } + /** + *

recalculate.

+ */ protected void recalculate() { if (this.list_scroll_pane != null) @@ -136,6 +145,9 @@ public void mouseClicked(java.awt.event.MouseEvent evt) }); } + /** + *

dispose.

+ */ public void dispose() { for (WindowObjectInfo curr_subwindow : this.subwindows) @@ -148,6 +160,11 @@ public void dispose() super.dispose(); } + /** + *

add_to_list.

+ * + * @param p_object a {@link java.lang.Object} object. + */ protected void add_to_list(Object p_object) { this.list_model.addElement(p_object); @@ -158,6 +175,9 @@ protected void add_to_list(Object p_object) */ abstract protected void fill_list(); + /** + *

select_instances.

+ */ abstract protected void select_instances(); protected final BoardFrame board_frame; @@ -177,6 +197,7 @@ protected void add_to_list(Object p_object) private final java.util.ResourceBundle resources; + /** Constant DEFAULT_TABLE_SIZE=20 */ protected static final int DEFAULT_TABLE_SIZE = 20; @@ -241,6 +262,8 @@ public void actionPerformed(java.awt.event.ActionEvent p_evt) } /** + * {@inheritDoc} + * * Saves also the filter string to disk. */ public void save(java.io.ObjectOutputStream p_object_stream) @@ -265,6 +288,7 @@ public void save(java.io.ObjectOutputStream p_object_stream) super.save(p_object_stream); } + /** {@inheritDoc} */ public boolean read(java.io.ObjectInputStream p_object_stream) { int [] saved_selected_indices = null; diff --git a/gui/WindowObjectListWithFilter.java b/src/main/java/gui/WindowObjectListWithFilter.java similarity index 89% rename from gui/WindowObjectListWithFilter.java rename to src/main/java/gui/WindowObjectListWithFilter.java index 1443487..09eca1d 100644 --- a/gui/WindowObjectListWithFilter.java +++ b/src/main/java/gui/WindowObjectListWithFilter.java @@ -23,11 +23,18 @@ /** * Abstract class for windows displaying a list of objects * The object name can be filttered by an alphanumeric input string. * @author Alfons Wirtz + * + * @author harry + * @version $Id: $Id */ public abstract class WindowObjectListWithFilter extends WindowObjectList { - /** Creates a new instance of ObjectListWindowWithFilter */ + /** + * Creates a new instance of ObjectListWindowWithFilter + * + * @param p_board_frame a {@link gui.BoardFrame} object. + */ public WindowObjectListWithFilter(BoardFrame p_board_frame) { super(p_board_frame); @@ -45,6 +52,8 @@ public WindowObjectListWithFilter(BoardFrame p_board_frame) } /** + * {@inheritDoc} + * * Adds p_object to the list only if its name matches the filter. */ protected void add_to_list(Object p_object) @@ -67,6 +76,8 @@ protected void add_to_list(Object p_object) /** * Returns the filter text string of this window. + * + * @return a {@link gui.WindowObjectListWithFilter.SnapshotInfo} object. */ public SnapshotInfo get_snapshot_info() { @@ -82,6 +93,11 @@ public SnapshotInfo get_snapshot_info() return new SnapshotInfo(filter_string.getText(), selected_indices); } + /** + *

set_snapshot_info.

+ * + * @param p_snapshot_info a {@link gui.WindowObjectListWithFilter.SnapshotInfo} object. + */ public void set_snapshot_info(SnapshotInfo p_snapshot_info) { if (!p_snapshot_info.filter.equals(this.filter_string.getText())) @@ -96,6 +112,8 @@ public void set_snapshot_info(SnapshotInfo p_snapshot_info) } /** + * {@inheritDoc} + * * Saves also the filter string to disk. */ public void save(java.io.ObjectOutputStream p_object_stream) @@ -111,6 +129,7 @@ public void save(java.io.ObjectOutputStream p_object_stream) super.save(p_object_stream); } + /** {@inheritDoc} */ public boolean read(java.io.ObjectInputStream p_object_stream) { try diff --git a/gui/WindowObjectVisibility.java b/src/main/java/gui/WindowObjectVisibility.java similarity index 91% rename from gui/WindowObjectVisibility.java rename to src/main/java/gui/WindowObjectVisibility.java index 32fb104..c59144f 100644 --- a/gui/WindowObjectVisibility.java +++ b/src/main/java/gui/WindowObjectVisibility.java @@ -26,10 +26,16 @@ * Interactive Frame to adjust the visibility of the individual board items * * @author alfons + * @version $Id: $Id */ public class WindowObjectVisibility extends WindowVisibility { - /** Returns a new instance of ItemVisibilityFrame */ + /** + * Returns a new instance of ItemVisibilityFrame + * + * @param p_board_frame a {@link gui.BoardFrame} object. + * @return a {@link gui.WindowObjectVisibility} object. + */ public static WindowObjectVisibility get_instance(BoardFrame p_board_frame) { java.util.ResourceBundle resources = @@ -66,6 +72,7 @@ public void refresh() } } + /** {@inheritDoc} */ protected void set_changed_value(int p_index, double p_value) { diff --git a/gui/WindowPackages.java b/src/main/java/gui/WindowPackages.java similarity index 94% rename from gui/WindowPackages.java rename to src/main/java/gui/WindowPackages.java index a6e2676..a4f7595 100644 --- a/gui/WindowPackages.java +++ b/src/main/java/gui/WindowPackages.java @@ -27,11 +27,16 @@ * Window displaying the library packagess. * * @author Alfons Wirtz + * @version $Id: $Id */ public class WindowPackages extends WindowObjectListWithFilter { - /** Creates a new instance of PackagesWindow */ + /** + * Creates a new instance of PackagesWindow + * + * @param p_board_frame a {@link gui.BoardFrame} object. + */ public WindowPackages(BoardFrame p_board_frame) { super(p_board_frame); @@ -60,6 +65,9 @@ protected void fill_list() this.list.setVisibleRowCount(Math.min(packages.count(), DEFAULT_TABLE_SIZE)); } + /** + *

select_instances.

+ */ protected void select_instances() { Object[] selected_packages = list.getSelectedValues(); diff --git a/gui/WindowPadstacks.java b/src/main/java/gui/WindowPadstacks.java similarity index 94% rename from gui/WindowPadstacks.java rename to src/main/java/gui/WindowPadstacks.java index ad7bc9d..0093f5c 100644 --- a/gui/WindowPadstacks.java +++ b/src/main/java/gui/WindowPadstacks.java @@ -29,11 +29,16 @@ * Window displaying the library padstacks. * * @author Alfons Wirtz + * @version $Id: $Id */ public class WindowPadstacks extends WindowObjectListWithFilter { - /** Creates a new instance of PadstacksWindow */ + /** + * Creates a new instance of PadstacksWindow + * + * @param p_board_frame a {@link gui.BoardFrame} object. + */ public WindowPadstacks(BoardFrame p_board_frame) { super(p_board_frame); @@ -62,6 +67,9 @@ protected void fill_list() this.list.setVisibleRowCount(Math.min(padstacks.count(), DEFAULT_TABLE_SIZE)); } + /** + *

select_instances.

+ */ protected void select_instances() { Object[] selected_padstacks = list.getSelectedValues(); diff --git a/gui/WindowRouteDetail.java b/src/main/java/gui/WindowRouteDetail.java similarity index 98% rename from gui/WindowRouteDetail.java rename to src/main/java/gui/WindowRouteDetail.java index 9072458..c3557d2 100644 --- a/gui/WindowRouteDetail.java +++ b/src/main/java/gui/WindowRouteDetail.java @@ -26,11 +26,16 @@ * Window handling detail parameters of the interactive routing. * * @author Alfons Wirtz + * @version $Id: $Id */ public class WindowRouteDetail extends BoardSavableSubWindow { - /** Creates a new instance of RouteDetailWindow */ + /** + * Creates a new instance of RouteDetailWindow + * + * @param p_board_frame a {@link gui.BoardFrame} object. + */ public WindowRouteDetail(BoardFrame p_board_frame) { this.board_handling = p_board_frame.board_panel.board_handling; diff --git a/gui/WindowRouteParameter.java b/src/main/java/gui/WindowRouteParameter.java similarity index 98% rename from gui/WindowRouteParameter.java rename to src/main/java/gui/WindowRouteParameter.java index f87279b..614bde5 100644 --- a/gui/WindowRouteParameter.java +++ b/src/main/java/gui/WindowRouteParameter.java @@ -26,11 +26,16 @@ * Window handling parameters of the interactive routing. * * @author Alfons Wirtz + * @version $Id: $Id */ public class WindowRouteParameter extends BoardSavableSubWindow { - /** Creates a new instance of RouteParameterWindow */ + /** + * Creates a new instance of RouteParameterWindow + * + * @param p_board_frame a {@link gui.BoardFrame} object. + */ public WindowRouteParameter(BoardFrame p_board_frame) { this.board_handling = p_board_frame.board_panel.board_handling; @@ -276,6 +281,9 @@ public WindowRouteParameter(BoardFrame p_board_frame) this.setResizable(false); } + /** + *

dispose.

+ */ public void dispose() { detail_window.dispose(); @@ -284,6 +292,8 @@ public void dispose() } /** + * {@inheritDoc} + * * Reads the data of this frame from disk. * Returns false, if the reading failed. */ @@ -313,6 +323,8 @@ public boolean read(java.io.ObjectInputStream p_object_stream) } /** + * {@inheritDoc} + * * Saves this frame to disk. */ public void save(java.io.ObjectOutputStream p_object_stream) @@ -391,6 +403,9 @@ else if (snap_angle == board.AngleRestriction.FORTYFIVE_DEGREE) } } + /** + *

parent_iconified.

+ */ public void parent_iconified() { manual_rule_window.parent_iconified(); @@ -398,6 +413,9 @@ public void parent_iconified() super.parent_iconified(); } + /** + *

parent_deiconified.

+ */ public void parent_deiconified() { manual_rule_window.parent_deiconified(); diff --git a/gui/WindowRouteStubs.java b/src/main/java/gui/WindowRouteStubs.java similarity index 96% rename from gui/WindowRouteStubs.java rename to src/main/java/gui/WindowRouteStubs.java index 19fff85..12dd3a0 100644 --- a/gui/WindowRouteStubs.java +++ b/src/main/java/gui/WindowRouteStubs.java @@ -1,214 +1,226 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * WindowRouteStubs.java - * - * Created on 17. Februar 2006, 07:16 - * - */ - -package gui; - -import java.util.Collection; -import java.util.Set; -import java.util.SortedSet; -import java.util.Iterator; - -import datastructures.Signum; -import geometry.planar.FloatPoint; - -import board.Item; - -/** - * - * @author Alfons Wirtz - */ -public class WindowRouteStubs extends WindowObjectListWithFilter -{ - - /** Creates a new instance of WindowRouteStubs */ - public WindowRouteStubs(BoardFrame p_board_frame) - { - super(p_board_frame); - this.resources = java.util.ResourceBundle.getBundle("gui.resources.CleanupWindows", p_board_frame.get_locale()); - this.setTitle(resources.getString("route_stubs")); - this.list_empty_message.setText(resources.getString("no_route_stubs_found")); - p_board_frame.set_context_sensitive_help(this, "WindowObjectList_RouteStubs"); - } - - protected void fill_list() - { - board.BasicBoard routing_board = this.board_frame.board_panel.board_handling.get_routing_board(); - - SortedSet route_stub_info_set = new java.util.TreeSet(); - - Collection board_items = routing_board.get_items(); - for (Item curr_item : board_items) - { - if (!(curr_item instanceof board.Trace || curr_item instanceof board.Via)) - { - continue; - } - if (curr_item.net_count() != 1) - { - continue; - } - - FloatPoint stub_location; - int stub_layer; - if (curr_item instanceof board.Via) - { - Collection contact_list = curr_item.get_all_contacts(); - if (contact_list.isEmpty()) - { - stub_layer = curr_item.first_layer(); - } - else - { - Iterator it = contact_list.iterator(); - Item curr_contact_item = it.next(); - int first_contact_first_layer = curr_contact_item.first_layer(); - int first_contact_last_layer = curr_contact_item.last_layer(); - boolean all_contacts_on_one_layer = true; - while (it.hasNext()) - { - curr_contact_item = it.next(); - if (curr_contact_item.first_layer() != first_contact_first_layer - || curr_contact_item.last_layer() != first_contact_last_layer) - { - all_contacts_on_one_layer = false; - break; - } - } - if (!all_contacts_on_one_layer) - { - continue; - } - if (curr_item.first_layer() >= first_contact_first_layer && - curr_item.last_layer() <= first_contact_first_layer) - { - stub_layer = first_contact_first_layer; - } - else - { - stub_layer = first_contact_last_layer; - } - } - stub_location = ((board.Via)curr_item).get_center().to_float(); - } - else - { - board.Trace curr_trace = (board.Trace) curr_item; - if (curr_trace.get_start_contacts().isEmpty()) - { - stub_location = curr_trace.first_corner().to_float(); - } - else if (curr_trace.get_end_contacts().isEmpty()) - { - stub_location = curr_trace.last_corner().to_float(); - } - else - { - continue; - } - stub_layer = curr_trace.get_layer(); - } - RouteStubInfo curr_route_stub_info = new RouteStubInfo(curr_item, stub_location, stub_layer); - route_stub_info_set.add(curr_route_stub_info); - } - - for (RouteStubInfo curr_info : route_stub_info_set) - { - this.add_to_list(curr_info); - } - this.list.setVisibleRowCount(Math.min(route_stub_info_set.size(), DEFAULT_TABLE_SIZE)); - } - - protected void select_instances() - { - Object[] selected_list_values = list.getSelectedValues(); - if (selected_list_values.length <= 0) - { - return; - } - Set selected_items = new java.util.TreeSet(); - for (int i = 0; i < selected_list_values.length; ++i) - { - selected_items.add(((RouteStubInfo)selected_list_values[i]).stub_item); - } - interactive.BoardHandling board_handling = board_frame.board_panel.board_handling; - board_handling.select_items(selected_items); - board_handling.zoom_selection(); - } - - private final java.util.ResourceBundle resources; - - /** - * Describes information of a route stub in the list. - */ - private class RouteStubInfo implements Comparable - { - public RouteStubInfo(Item p_stub, FloatPoint p_location, int p_layer_no) - { - interactive.BoardHandling board_handling = board_frame.board_panel.board_handling; - this.stub_item = p_stub; - this.location = board_handling.coordinate_transform.board_to_user(p_location); - this.layer_no = p_layer_no; - int net_no = p_stub.get_net_no(0); - this.net = board_handling.get_routing_board().rules.nets.get(net_no); - } - - public String toString() - { - String item_string; - if (this.stub_item instanceof board.Trace) - { - item_string = resources.getString("trace"); - } - else - { - item_string = resources.getString("via"); - } - String layer_name = board_frame.board_panel.board_handling.get_routing_board().layer_structure.arr[layer_no].name; - String result = item_string + " " + resources.getString("stub_net") + " " + this.net.name + " " + - resources.getString("at") + " " + this.location.to_string(board_frame.get_locale()) + " " + - resources.getString("on_layer") + " " + layer_name; - return result; - } - - public int compareTo(RouteStubInfo p_other) - { - int result = this.net.name.compareTo(p_other.net.name); - if (result == 0) - { - result = Signum.as_int(this.location.x - p_other.location.x); - } - if (result == 0) - { - result = Signum.as_int(this.location.y - p_other.location.y); - } - if (result == 0) - { - result = this.layer_no - p_other.layer_no; - } - return result; - } - - private final Item stub_item; - private final rules.Net net; - private final FloatPoint location; - private final int layer_no; - } -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * WindowRouteStubs.java + * + * Created on 17. Februar 2006, 07:16 + * + */ + +package gui; + +import java.util.Collection; +import java.util.Set; +import java.util.SortedSet; +import java.util.Iterator; + +import datastructures.Signum; +import geometry.planar.FloatPoint; + +import board.Item; + +/** + *

WindowRouteStubs class.

+ * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class WindowRouteStubs extends WindowObjectListWithFilter +{ + + /** + * Creates a new instance of WindowRouteStubs + * + * @param p_board_frame a {@link gui.BoardFrame} object. + */ + public WindowRouteStubs(BoardFrame p_board_frame) + { + super(p_board_frame); + this.resources = java.util.ResourceBundle.getBundle("gui.resources.CleanupWindows", p_board_frame.get_locale()); + this.setTitle(resources.getString("route_stubs")); + this.list_empty_message.setText(resources.getString("no_route_stubs_found")); + p_board_frame.set_context_sensitive_help(this, "WindowObjectList_RouteStubs"); + } + + /** + *

fill_list.

+ */ + protected void fill_list() + { + board.BasicBoard routing_board = this.board_frame.board_panel.board_handling.get_routing_board(); + + SortedSet route_stub_info_set = new java.util.TreeSet(); + + Collection board_items = routing_board.get_items(); + for (Item curr_item : board_items) + { + if (!(curr_item instanceof board.Trace || curr_item instanceof board.Via)) + { + continue; + } + if (curr_item.net_count() != 1) + { + continue; + } + + FloatPoint stub_location; + int stub_layer; + if (curr_item instanceof board.Via) + { + Collection contact_list = curr_item.get_all_contacts(); + if (contact_list.isEmpty()) + { + stub_layer = curr_item.first_layer(); + } + else + { + Iterator it = contact_list.iterator(); + Item curr_contact_item = it.next(); + int first_contact_first_layer = curr_contact_item.first_layer(); + int first_contact_last_layer = curr_contact_item.last_layer(); + boolean all_contacts_on_one_layer = true; + while (it.hasNext()) + { + curr_contact_item = it.next(); + if (curr_contact_item.first_layer() != first_contact_first_layer + || curr_contact_item.last_layer() != first_contact_last_layer) + { + all_contacts_on_one_layer = false; + break; + } + } + if (!all_contacts_on_one_layer) + { + continue; + } + if (curr_item.first_layer() >= first_contact_first_layer && + curr_item.last_layer() <= first_contact_first_layer) + { + stub_layer = first_contact_first_layer; + } + else + { + stub_layer = first_contact_last_layer; + } + } + stub_location = ((board.Via)curr_item).get_center().to_float(); + } + else + { + board.Trace curr_trace = (board.Trace) curr_item; + if (curr_trace.get_start_contacts().isEmpty()) + { + stub_location = curr_trace.first_corner().to_float(); + } + else if (curr_trace.get_end_contacts().isEmpty()) + { + stub_location = curr_trace.last_corner().to_float(); + } + else + { + continue; + } + stub_layer = curr_trace.get_layer(); + } + RouteStubInfo curr_route_stub_info = new RouteStubInfo(curr_item, stub_location, stub_layer); + route_stub_info_set.add(curr_route_stub_info); + } + + for (RouteStubInfo curr_info : route_stub_info_set) + { + this.add_to_list(curr_info); + } + this.list.setVisibleRowCount(Math.min(route_stub_info_set.size(), DEFAULT_TABLE_SIZE)); + } + + /** + *

select_instances.

+ */ + protected void select_instances() + { + Object[] selected_list_values = list.getSelectedValues(); + if (selected_list_values.length <= 0) + { + return; + } + Set selected_items = new java.util.TreeSet(); + for (int i = 0; i < selected_list_values.length; ++i) + { + selected_items.add(((RouteStubInfo)selected_list_values[i]).stub_item); + } + interactive.BoardHandling board_handling = board_frame.board_panel.board_handling; + board_handling.select_items(selected_items); + board_handling.zoom_selection(); + } + + private final java.util.ResourceBundle resources; + + /** + * Describes information of a route stub in the list. + */ + private class RouteStubInfo implements Comparable + { + public RouteStubInfo(Item p_stub, FloatPoint p_location, int p_layer_no) + { + interactive.BoardHandling board_handling = board_frame.board_panel.board_handling; + this.stub_item = p_stub; + this.location = board_handling.coordinate_transform.board_to_user(p_location); + this.layer_no = p_layer_no; + int net_no = p_stub.get_net_no(0); + this.net = board_handling.get_routing_board().rules.nets.get(net_no); + } + + public String toString() + { + String item_string; + if (this.stub_item instanceof board.Trace) + { + item_string = resources.getString("trace"); + } + else + { + item_string = resources.getString("via"); + } + String layer_name = board_frame.board_panel.board_handling.get_routing_board().layer_structure.arr[layer_no].name; + String result = item_string + " " + resources.getString("stub_net") + " " + this.net.name + " " + + resources.getString("at") + " " + this.location.to_string(board_frame.get_locale()) + " " + + resources.getString("on_layer") + " " + layer_name; + return result; + } + + public int compareTo(RouteStubInfo p_other) + { + int result = this.net.name.compareTo(p_other.net.name); + if (result == 0) + { + result = Signum.as_int(this.location.x - p_other.location.x); + } + if (result == 0) + { + result = Signum.as_int(this.location.y - p_other.location.y); + } + if (result == 0) + { + result = this.layer_no - p_other.layer_no; + } + return result; + } + + private final Item stub_item; + private final rules.Net net; + private final FloatPoint location; + private final int layer_no; + } +} diff --git a/gui/WindowSelectParameter.java b/src/main/java/gui/WindowSelectParameter.java similarity index 98% rename from gui/WindowSelectParameter.java rename to src/main/java/gui/WindowSelectParameter.java index 877519d..7dd05e0 100644 --- a/gui/WindowSelectParameter.java +++ b/src/main/java/gui/WindowSelectParameter.java @@ -26,11 +26,16 @@ * Window for the handling of the interactive selection parameters, * * @author Alfons Wirtz + * @version $Id: $Id */ public class WindowSelectParameter extends BoardSavableSubWindow { - /** Creates a new instance of SelectWindow */ + /** + * Creates a new instance of SelectWindow + * + * @param p_board_frame a {@link gui.BoardFrame} object. + */ public WindowSelectParameter(BoardFrame p_board_frame) { this.board_handling = p_board_frame.board_panel.board_handling; @@ -166,6 +171,8 @@ public void refresh() /** * Selects the layer with the input signal number. + * + * @param p_signal_layer_no a int. */ public void select(int p_signal_layer_no) { diff --git a/gui/WindowSnapshot.java b/src/main/java/gui/WindowSnapshot.java similarity index 97% rename from gui/WindowSnapshot.java rename to src/main/java/gui/WindowSnapshot.java index bccbfae..c4b2a53 100644 --- a/gui/WindowSnapshot.java +++ b/src/main/java/gui/WindowSnapshot.java @@ -24,11 +24,16 @@ * Window handling snapshots of the interactive situation. * * @author Alfons Wirtz + * @version $Id: $Id */ public class WindowSnapshot extends BoardSavableSubWindow { - /** Creates a new instance of SnapshotFrame */ + /** + * Creates a new instance of SnapshotFrame + * + * @param p_board_frame a {@link gui.BoardFrame} object. + */ public WindowSnapshot(BoardFrame p_board_frame) { this.board_frame = p_board_frame; @@ -121,18 +126,27 @@ public void mouseClicked(java.awt.event.MouseEvent evt) this.pack(); } + /** + *

dispose.

+ */ public void dispose() { settings_window.dispose(); super.dispose(); } + /** + *

parent_iconified.

+ */ public void parent_iconified() { settings_window.parent_iconified(); super.parent_iconified(); } + /** + *

parent_deiconified.

+ */ public void parent_deiconified() { settings_window.parent_deiconified(); @@ -140,6 +154,8 @@ public void parent_deiconified() } /** + * {@inheritDoc} + * * Reads the data of this frame from disk. * Returns false, if the reading failed. */ @@ -166,6 +182,8 @@ public boolean read(java.io.ObjectInputStream p_object_stream) } /** + * {@inheritDoc} + * * Saves this frame to disk. */ public void save(java.io.ObjectOutputStream p_object_stream) diff --git a/gui/WindowSnapshotSettings.java b/src/main/java/gui/WindowSnapshotSettings.java similarity index 99% rename from gui/WindowSnapshotSettings.java rename to src/main/java/gui/WindowSnapshotSettings.java index 63e9640..609c92e 100644 --- a/gui/WindowSnapshotSettings.java +++ b/src/main/java/gui/WindowSnapshotSettings.java @@ -25,11 +25,16 @@ * Window for the settinngs of interactive snapshots. * * @author Alfons Wirtz + * @version $Id: $Id */ public class WindowSnapshotSettings extends BoardSavableSubWindow { - /** Creates a new instance of WindowSnapshotSettings */ + /** + * Creates a new instance of WindowSnapshotSettings + * + * @param p_board_frame a {@link gui.BoardFrame} object. + */ public WindowSnapshotSettings(BoardFrame p_board_frame) { this.board_handling = p_board_frame.board_panel.board_handling; diff --git a/gui/WindowUnconnectedRoute.java b/src/main/java/gui/WindowUnconnectedRoute.java similarity index 95% rename from gui/WindowUnconnectedRoute.java rename to src/main/java/gui/WindowUnconnectedRoute.java index 524cd6d..e68bfd8 100644 --- a/gui/WindowUnconnectedRoute.java +++ b/src/main/java/gui/WindowUnconnectedRoute.java @@ -1,177 +1,189 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * WindowUnconnectedRoute.java - * - * Created on 16. Februar 2006, 06:20 - * - */ - -package gui; - -import java.util.Collection; -import java.util.Set; -import java.util.SortedSet; - -import board.Item; - -/** - * - * @author Alfons Wirtz - */ -public class WindowUnconnectedRoute extends WindowObjectListWithFilter -{ - - /** Creates a new instance of WindowUnconnectedRoute */ - public WindowUnconnectedRoute(BoardFrame p_board_frame) - { - super(p_board_frame); - this.resources = java.util.ResourceBundle.getBundle("gui.resources.CleanupWindows", p_board_frame.get_locale()); - this.setTitle(resources.getString("unconnected_route")); - this.list_empty_message.setText(resources.getString("no_unconnected_route_found")); - p_board_frame.set_context_sensitive_help(this, "WindowObjectList_UnconnectedRoute"); - } - - protected void fill_list() - { - board.BasicBoard routing_board = this.board_frame.board_panel.board_handling.get_routing_board(); - - Set handled_items = new java.util.TreeSet(); - - SortedSet unconnected_route_info_set = new java.util.TreeSet(); - - Collection board_items = routing_board.get_items(); - for (Item curr_item : board_items) - { - if (!(curr_item instanceof board.Trace || curr_item instanceof board.Via)) - { - continue; - } - if (handled_items.contains(curr_item)) - { - continue; - } - Collection curr_connected_set = curr_item.get_connected_set(-1); - boolean terminal_item_found = false; - for (Item curr_connnected_item : curr_connected_set) - { - handled_items.add(curr_connnected_item); - if (!(curr_connnected_item instanceof board.Trace || curr_connnected_item instanceof board.Via)) - { - terminal_item_found = true; - } - } - if (!terminal_item_found) - { - // We have found unconnnected route - if (curr_item.net_count() == 1) - { - rules.Net curr_net = routing_board.rules.nets.get(curr_item.get_net_no(0)); - if (curr_net != null) - { - UnconnectedRouteInfo curr_unconnected_route_info = - new UnconnectedRouteInfo(curr_net, curr_connected_set); - unconnected_route_info_set.add(curr_unconnected_route_info); - } - } - else - { - System.out.println("WindowUnconnectedRoute.fill_list: net_count 1 expected"); - } - } - } - - for (UnconnectedRouteInfo curr_info : unconnected_route_info_set) - { - this.add_to_list(curr_info); - } - this.list.setVisibleRowCount(Math.min(unconnected_route_info_set.size(), DEFAULT_TABLE_SIZE)); - } - - protected void select_instances() - { - Object[] selected_list_values = list.getSelectedValues(); - if (selected_list_values.length <= 0) - { - return; - } - Set selected_items = new java.util.TreeSet(); - for (int i = 0; i < selected_list_values.length; ++i) - { - selected_items.addAll(((UnconnectedRouteInfo)selected_list_values[i]).item_list); - } - interactive.BoardHandling board_handling = board_frame.board_panel.board_handling; - board_handling.select_items(selected_items); - board_handling.zoom_selection(); - } - - private final java.util.ResourceBundle resources; - private int max_unconnected_route_info_id_no = 0; - - /** - * Describes information of a connected set of unconnected traces and vias. - */ - private class UnconnectedRouteInfo implements Comparable - { - public UnconnectedRouteInfo(rules.Net p_net, Collection p_item_list) - { - this.net = p_net; - this.item_list = p_item_list; - ++max_unconnected_route_info_id_no; - this.id_no = max_unconnected_route_info_id_no; - int curr_trace_count = 0; - int curr_via_count = 0; - for (Item curr_item: p_item_list) - { - if (curr_item instanceof board.Trace) - { - ++curr_trace_count; - } - else if (curr_item instanceof board.Via) - { - ++curr_via_count; - } - } - this.trace_count = curr_trace_count; - this.via_count = curr_via_count; - } - - public String toString() - { - - String result = resources.getString("net") + " " + this.net.name + ": " - + resources.getString("trace_count") + " " + this.trace_count.toString() + ", " - + resources.getString("via_count") + " " + this.via_count.toString(); - - return result; - } - - public int compareTo(UnconnectedRouteInfo p_other) - { - int result = this.net.name.compareTo(p_other.net.name); - if (result == 0) - { - result = this.id_no - p_other.id_no; - } - return result; - } - - private final rules.Net net; - private final Collection item_list; - private final int id_no; - private final Integer trace_count; - private final Integer via_count; - } -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * WindowUnconnectedRoute.java + * + * Created on 16. Februar 2006, 06:20 + * + */ + +package gui; + +import java.util.Collection; +import java.util.Set; +import java.util.SortedSet; + +import board.Item; + +/** + *

WindowUnconnectedRoute class.

+ * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class WindowUnconnectedRoute extends WindowObjectListWithFilter +{ + + /** + * Creates a new instance of WindowUnconnectedRoute + * + * @param p_board_frame a {@link gui.BoardFrame} object. + */ + public WindowUnconnectedRoute(BoardFrame p_board_frame) + { + super(p_board_frame); + this.resources = java.util.ResourceBundle.getBundle("gui.resources.CleanupWindows", p_board_frame.get_locale()); + this.setTitle(resources.getString("unconnected_route")); + this.list_empty_message.setText(resources.getString("no_unconnected_route_found")); + p_board_frame.set_context_sensitive_help(this, "WindowObjectList_UnconnectedRoute"); + } + + /** + *

fill_list.

+ */ + protected void fill_list() + { + board.BasicBoard routing_board = this.board_frame.board_panel.board_handling.get_routing_board(); + + Set handled_items = new java.util.TreeSet(); + + SortedSet unconnected_route_info_set = new java.util.TreeSet(); + + Collection board_items = routing_board.get_items(); + for (Item curr_item : board_items) + { + if (!(curr_item instanceof board.Trace || curr_item instanceof board.Via)) + { + continue; + } + if (handled_items.contains(curr_item)) + { + continue; + } + Collection curr_connected_set = curr_item.get_connected_set(-1); + boolean terminal_item_found = false; + for (Item curr_connnected_item : curr_connected_set) + { + handled_items.add(curr_connnected_item); + if (!(curr_connnected_item instanceof board.Trace || curr_connnected_item instanceof board.Via)) + { + terminal_item_found = true; + } + } + if (!terminal_item_found) + { + // We have found unconnnected route + if (curr_item.net_count() == 1) + { + rules.Net curr_net = routing_board.rules.nets.get(curr_item.get_net_no(0)); + if (curr_net != null) + { + UnconnectedRouteInfo curr_unconnected_route_info = + new UnconnectedRouteInfo(curr_net, curr_connected_set); + unconnected_route_info_set.add(curr_unconnected_route_info); + } + } + else + { + System.out.println("WindowUnconnectedRoute.fill_list: net_count 1 expected"); + } + } + } + + for (UnconnectedRouteInfo curr_info : unconnected_route_info_set) + { + this.add_to_list(curr_info); + } + this.list.setVisibleRowCount(Math.min(unconnected_route_info_set.size(), DEFAULT_TABLE_SIZE)); + } + + /** + *

select_instances.

+ */ + protected void select_instances() + { + Object[] selected_list_values = list.getSelectedValues(); + if (selected_list_values.length <= 0) + { + return; + } + Set selected_items = new java.util.TreeSet(); + for (int i = 0; i < selected_list_values.length; ++i) + { + selected_items.addAll(((UnconnectedRouteInfo)selected_list_values[i]).item_list); + } + interactive.BoardHandling board_handling = board_frame.board_panel.board_handling; + board_handling.select_items(selected_items); + board_handling.zoom_selection(); + } + + private final java.util.ResourceBundle resources; + private int max_unconnected_route_info_id_no = 0; + + /** + * Describes information of a connected set of unconnected traces and vias. + */ + private class UnconnectedRouteInfo implements Comparable + { + public UnconnectedRouteInfo(rules.Net p_net, Collection p_item_list) + { + this.net = p_net; + this.item_list = p_item_list; + ++max_unconnected_route_info_id_no; + this.id_no = max_unconnected_route_info_id_no; + int curr_trace_count = 0; + int curr_via_count = 0; + for (Item curr_item: p_item_list) + { + if (curr_item instanceof board.Trace) + { + ++curr_trace_count; + } + else if (curr_item instanceof board.Via) + { + ++curr_via_count; + } + } + this.trace_count = curr_trace_count; + this.via_count = curr_via_count; + } + + public String toString() + { + + String result = resources.getString("net") + " " + this.net.name + ": " + + resources.getString("trace_count") + " " + this.trace_count.toString() + ", " + + resources.getString("via_count") + " " + this.via_count.toString(); + + return result; + } + + public int compareTo(UnconnectedRouteInfo p_other) + { + int result = this.net.name.compareTo(p_other.net.name); + if (result == 0) + { + result = this.id_no - p_other.id_no; + } + return result; + } + + private final rules.Net net; + private final Collection item_list; + private final int id_no; + private final Integer trace_count; + private final Integer via_count; + } +} diff --git a/gui/WindowVia.java b/src/main/java/gui/WindowVia.java similarity index 99% rename from gui/WindowVia.java rename to src/main/java/gui/WindowVia.java index e1ea91f..b12f23b 100644 --- a/gui/WindowVia.java +++ b/src/main/java/gui/WindowVia.java @@ -29,11 +29,16 @@ * Window for interactive editing of via rules. * * @author Alfons Wirtz + * @version $Id: $Id */ public class WindowVia extends BoardSavableSubWindow { - /** Creates a new instance of ViaWindow */ + /** + * Creates a new instance of ViaWindow + * + * @param p_board_frame a {@link gui.BoardFrame} object. + */ public WindowVia(BoardFrame p_board_frame) { this.resources = java.util.ResourceBundle.getBundle("gui.resources.WindowVia", p_board_frame.get_locale()); @@ -163,6 +168,9 @@ public WindowVia(BoardFrame p_board_frame) this.setDefaultCloseOperation(DISPOSE_ON_CLOSE ); } + /** + *

refresh.

+ */ public void refresh() { // reinsert the elements in the rule list @@ -187,6 +195,9 @@ public void refresh() } } + /** + *

dispose.

+ */ public void dispose() { for (javax.swing.JFrame curr_subwindow : this.subwindows) diff --git a/gui/WindowViaRule.java b/src/main/java/gui/WindowViaRule.java similarity index 97% rename from gui/WindowViaRule.java rename to src/main/java/gui/WindowViaRule.java index 7a90ab7..0b17614 100644 --- a/gui/WindowViaRule.java +++ b/src/main/java/gui/WindowViaRule.java @@ -28,11 +28,18 @@ * Window for editing a single via rule. * * @author Alfons Wirtz + * @version $Id: $Id */ public class WindowViaRule extends javax.swing.JFrame { - /** Creates a new instance of ViaRuleWindow */ + /** + * Creates a new instance of ViaRuleWindow + * + * @param p_via_rule a {@link rules.ViaRule} object. + * @param p_via_list a {@link rules.ViaInfos} object. + * @param p_board_frame a {@link gui.BoardFrame} object. + */ public WindowViaRule(ViaRule p_via_rule, ViaInfos p_via_list, BoardFrame p_board_frame) { this.via_rule = p_via_rule; diff --git a/gui/WindowVisibility.java b/src/main/java/gui/WindowVisibility.java similarity index 90% rename from gui/WindowVisibility.java rename to src/main/java/gui/WindowVisibility.java index 5f3a064..1aa369c 100644 --- a/gui/WindowVisibility.java +++ b/src/main/java/gui/WindowVisibility.java @@ -24,11 +24,19 @@ * Interactive Frame to adjust the visibility of a set of objects * * @author Alfons Wirtz + * @version $Id: $Id */ public abstract class WindowVisibility extends BoardSavableSubWindow { - /** Creates a new instance of VisibilityFrame */ + /** + * Creates a new instance of VisibilityFrame + * + * @param p_board_frame a {@link gui.BoardFrame} object. + * @param p_title a {@link java.lang.String} object. + * @param p_header_message a {@link java.lang.String} object. + * @param p_message_arr an array of {@link java.lang.String} objects. + */ public WindowVisibility(BoardFrame p_board_frame, String p_title, String p_header_message, String[] p_message_arr) { this.board_panel = p_board_frame.board_panel; @@ -86,6 +94,9 @@ public WindowVisibility(BoardFrame p_board_frame, String p_title, String p_heade /** * Sets the values of the p_no-ths slider contained in this frame. + * + * @param p_no a int. + * @param p_value a double. */ public void set_slider_value( int p_no, double p_value) { @@ -93,11 +104,19 @@ public void set_slider_value( int p_no, double p_value) slider_arr[p_no].setValue(visibility); } + /** + *

get_board_handling.

+ * + * @return a {@link interactive.BoardHandling} object. + */ protected interactive.BoardHandling get_board_handling() { return board_panel.board_handling; } + /** + *

set_all_minimum.

+ */ protected void set_all_minimum() { for (int i = 0; i < slider_arr.length; ++i) @@ -107,6 +126,9 @@ protected void set_all_minimum() } } + /** + *

set_all_maximum.

+ */ protected void set_all_maximum() { for (int i = 0; i < slider_arr.length; ++i) @@ -118,6 +140,9 @@ protected void set_all_maximum() /** * Stores the new value in the board database, when a slider value was changed. + * + * @param p_index a int. + * @param p_value a double. */ protected abstract void set_changed_value(int p_index, double p_value); diff --git a/gui/package.html b/src/main/java/gui/package.html similarity index 100% rename from gui/package.html rename to src/main/java/gui/package.html diff --git a/helpset/de/Help.hs b/src/main/java/helpset/de/Help.hs similarity index 100% rename from helpset/de/Help.hs rename to src/main/java/helpset/de/Help.hs diff --git a/helpset/de/HelpIndex.xml b/src/main/java/helpset/de/HelpIndex.xml similarity index 100% rename from helpset/de/HelpIndex.xml rename to src/main/java/helpset/de/HelpIndex.xml diff --git a/helpset/de/HelpTOC.xml b/src/main/java/helpset/de/HelpTOC.xml similarity index 100% rename from helpset/de/HelpTOC.xml rename to src/main/java/helpset/de/HelpTOC.xml diff --git a/helpset/de/JavaHelpSearch/DOCS b/src/main/java/helpset/de/JavaHelpSearch/DOCS similarity index 100% rename from helpset/de/JavaHelpSearch/DOCS rename to src/main/java/helpset/de/JavaHelpSearch/DOCS diff --git a/helpset/de/JavaHelpSearch/DOCS.TAB b/src/main/java/helpset/de/JavaHelpSearch/DOCS.TAB similarity index 100% rename from helpset/de/JavaHelpSearch/DOCS.TAB rename to src/main/java/helpset/de/JavaHelpSearch/DOCS.TAB diff --git a/helpset/de/JavaHelpSearch/OFFSETS b/src/main/java/helpset/de/JavaHelpSearch/OFFSETS similarity index 100% rename from helpset/de/JavaHelpSearch/OFFSETS rename to src/main/java/helpset/de/JavaHelpSearch/OFFSETS diff --git a/helpset/de/JavaHelpSearch/POSITIONS b/src/main/java/helpset/de/JavaHelpSearch/POSITIONS similarity index 100% rename from helpset/de/JavaHelpSearch/POSITIONS rename to src/main/java/helpset/de/JavaHelpSearch/POSITIONS diff --git a/helpset/de/JavaHelpSearch/SCHEMA b/src/main/java/helpset/de/JavaHelpSearch/SCHEMA similarity index 100% rename from helpset/de/JavaHelpSearch/SCHEMA rename to src/main/java/helpset/de/JavaHelpSearch/SCHEMA diff --git a/helpset/de/JavaHelpSearch/TMAP b/src/main/java/helpset/de/JavaHelpSearch/TMAP similarity index 100% rename from helpset/de/JavaHelpSearch/TMAP rename to src/main/java/helpset/de/JavaHelpSearch/TMAP diff --git a/helpset/de/Map.jhm b/src/main/java/helpset/de/Map.jhm similarity index 100% rename from helpset/de/Map.jhm rename to src/main/java/helpset/de/Map.jhm diff --git a/helpset/de/html_files/FileMenu.html b/src/main/java/helpset/de/html_files/FileMenu.html similarity index 100% rename from helpset/de/html_files/FileMenu.html rename to src/main/java/helpset/de/html_files/FileMenu.html diff --git a/helpset/de/html_files/MenuState.html b/src/main/java/helpset/de/html_files/MenuState.html similarity index 100% rename from helpset/de/html_files/MenuState.html rename to src/main/java/helpset/de/html_files/MenuState.html diff --git a/helpset/de/html_files/MoveItemState.html b/src/main/java/helpset/de/html_files/MoveItemState.html similarity index 100% rename from helpset/de/html_files/MoveItemState.html rename to src/main/java/helpset/de/html_files/MoveItemState.html diff --git a/helpset/de/html_files/RouteState.html b/src/main/java/helpset/de/html_files/RouteState.html similarity index 100% rename from helpset/de/html_files/RouteState.html rename to src/main/java/helpset/de/html_files/RouteState.html diff --git a/helpset/de/html_files/SelectedItemState.html b/src/main/java/helpset/de/html_files/SelectedItemState.html similarity index 100% rename from helpset/de/html_files/SelectedItemState.html rename to src/main/java/helpset/de/html_files/SelectedItemState.html diff --git a/helpset/de/html_files/WindowAutorouteDetailParameter.html b/src/main/java/helpset/de/html_files/WindowAutorouteDetailParameter.html similarity index 100% rename from helpset/de/html_files/WindowAutorouteDetailParameter.html rename to src/main/java/helpset/de/html_files/WindowAutorouteDetailParameter.html diff --git a/helpset/de/html_files/WindowAutorouteParameter.html b/src/main/java/helpset/de/html_files/WindowAutorouteParameter.html similarity index 100% rename from helpset/de/html_files/WindowAutorouteParameter.html rename to src/main/java/helpset/de/html_files/WindowAutorouteParameter.html diff --git a/helpset/de/html_files/WindowClearanceMatrix.html b/src/main/java/helpset/de/html_files/WindowClearanceMatrix.html similarity index 100% rename from helpset/de/html_files/WindowClearanceMatrix.html rename to src/main/java/helpset/de/html_files/WindowClearanceMatrix.html diff --git a/helpset/de/html_files/WindowDisplay.html b/src/main/java/helpset/de/html_files/WindowDisplay.html similarity index 100% rename from helpset/de/html_files/WindowDisplay.html rename to src/main/java/helpset/de/html_files/WindowDisplay.html diff --git a/helpset/de/html_files/WindowManualRules.html b/src/main/java/helpset/de/html_files/WindowManualRules.html similarity index 100% rename from helpset/de/html_files/WindowManualRules.html rename to src/main/java/helpset/de/html_files/WindowManualRules.html diff --git a/helpset/de/html_files/WindowMoveParameter.html b/src/main/java/helpset/de/html_files/WindowMoveParameter.html similarity index 100% rename from helpset/de/html_files/WindowMoveParameter.html rename to src/main/java/helpset/de/html_files/WindowMoveParameter.html diff --git a/helpset/de/html_files/WindowNetClasses.html b/src/main/java/helpset/de/html_files/WindowNetClasses.html similarity index 100% rename from helpset/de/html_files/WindowNetClasses.html rename to src/main/java/helpset/de/html_files/WindowNetClasses.html diff --git a/helpset/de/html_files/WindowObjectList.html b/src/main/java/helpset/de/html_files/WindowObjectList.html similarity index 100% rename from helpset/de/html_files/WindowObjectList.html rename to src/main/java/helpset/de/html_files/WindowObjectList.html diff --git a/helpset/de/html_files/WindowRouteParameter.html b/src/main/java/helpset/de/html_files/WindowRouteParameter.html similarity index 100% rename from helpset/de/html_files/WindowRouteParameter.html rename to src/main/java/helpset/de/html_files/WindowRouteParameter.html diff --git a/helpset/de/html_files/WindowSelectParameter.html b/src/main/java/helpset/de/html_files/WindowSelectParameter.html similarity index 100% rename from helpset/de/html_files/WindowSelectParameter.html rename to src/main/java/helpset/de/html_files/WindowSelectParameter.html diff --git a/helpset/de/html_files/WindowSnapshots.html b/src/main/java/helpset/de/html_files/WindowSnapshots.html similarity index 100% rename from helpset/de/html_files/WindowSnapshots.html rename to src/main/java/helpset/de/html_files/WindowSnapshots.html diff --git a/helpset/de/html_files/WindowVia.html b/src/main/java/helpset/de/html_files/WindowVia.html similarity index 100% rename from helpset/de/html_files/WindowVia.html rename to src/main/java/helpset/de/html_files/WindowVia.html diff --git a/helpset/de/index.html b/src/main/java/helpset/de/index.html similarity index 100% rename from helpset/de/index.html rename to src/main/java/helpset/de/index.html diff --git a/helpset/en/Help.hs b/src/main/java/helpset/en/Help.hs similarity index 100% rename from helpset/en/Help.hs rename to src/main/java/helpset/en/Help.hs diff --git a/helpset/en/HelpIndex.xml b/src/main/java/helpset/en/HelpIndex.xml similarity index 100% rename from helpset/en/HelpIndex.xml rename to src/main/java/helpset/en/HelpIndex.xml diff --git a/helpset/en/HelpTOC.xml b/src/main/java/helpset/en/HelpTOC.xml similarity index 100% rename from helpset/en/HelpTOC.xml rename to src/main/java/helpset/en/HelpTOC.xml diff --git a/helpset/en/JavaHelpSearch/DOCS b/src/main/java/helpset/en/JavaHelpSearch/DOCS similarity index 100% rename from helpset/en/JavaHelpSearch/DOCS rename to src/main/java/helpset/en/JavaHelpSearch/DOCS diff --git a/helpset/en/JavaHelpSearch/DOCS.TAB b/src/main/java/helpset/en/JavaHelpSearch/DOCS.TAB similarity index 100% rename from helpset/en/JavaHelpSearch/DOCS.TAB rename to src/main/java/helpset/en/JavaHelpSearch/DOCS.TAB diff --git a/helpset/en/JavaHelpSearch/OFFSETS b/src/main/java/helpset/en/JavaHelpSearch/OFFSETS similarity index 100% rename from helpset/en/JavaHelpSearch/OFFSETS rename to src/main/java/helpset/en/JavaHelpSearch/OFFSETS diff --git a/helpset/en/JavaHelpSearch/POSITIONS b/src/main/java/helpset/en/JavaHelpSearch/POSITIONS similarity index 100% rename from helpset/en/JavaHelpSearch/POSITIONS rename to src/main/java/helpset/en/JavaHelpSearch/POSITIONS diff --git a/helpset/en/JavaHelpSearch/SCHEMA b/src/main/java/helpset/en/JavaHelpSearch/SCHEMA similarity index 100% rename from helpset/en/JavaHelpSearch/SCHEMA rename to src/main/java/helpset/en/JavaHelpSearch/SCHEMA diff --git a/helpset/en/JavaHelpSearch/TMAP b/src/main/java/helpset/en/JavaHelpSearch/TMAP similarity index 100% rename from helpset/en/JavaHelpSearch/TMAP rename to src/main/java/helpset/en/JavaHelpSearch/TMAP diff --git a/helpset/en/Map.jhm b/src/main/java/helpset/en/Map.jhm similarity index 100% rename from helpset/en/Map.jhm rename to src/main/java/helpset/en/Map.jhm diff --git a/helpset/en/html_files/FileMenu.html b/src/main/java/helpset/en/html_files/FileMenu.html similarity index 100% rename from helpset/en/html_files/FileMenu.html rename to src/main/java/helpset/en/html_files/FileMenu.html diff --git a/helpset/en/html_files/MenuState.html b/src/main/java/helpset/en/html_files/MenuState.html similarity index 100% rename from helpset/en/html_files/MenuState.html rename to src/main/java/helpset/en/html_files/MenuState.html diff --git a/helpset/en/html_files/MoveItemState.html b/src/main/java/helpset/en/html_files/MoveItemState.html similarity index 100% rename from helpset/en/html_files/MoveItemState.html rename to src/main/java/helpset/en/html_files/MoveItemState.html diff --git a/helpset/en/html_files/RouteState.html b/src/main/java/helpset/en/html_files/RouteState.html similarity index 100% rename from helpset/en/html_files/RouteState.html rename to src/main/java/helpset/en/html_files/RouteState.html diff --git a/helpset/en/html_files/SelectedItemState.html b/src/main/java/helpset/en/html_files/SelectedItemState.html similarity index 100% rename from helpset/en/html_files/SelectedItemState.html rename to src/main/java/helpset/en/html_files/SelectedItemState.html diff --git a/helpset/en/html_files/WindowAutorouteDetailParameter.html b/src/main/java/helpset/en/html_files/WindowAutorouteDetailParameter.html similarity index 100% rename from helpset/en/html_files/WindowAutorouteDetailParameter.html rename to src/main/java/helpset/en/html_files/WindowAutorouteDetailParameter.html diff --git a/helpset/en/html_files/WindowAutorouteParameter.html b/src/main/java/helpset/en/html_files/WindowAutorouteParameter.html similarity index 100% rename from helpset/en/html_files/WindowAutorouteParameter.html rename to src/main/java/helpset/en/html_files/WindowAutorouteParameter.html diff --git a/helpset/en/html_files/WindowClearanceMatrix.html b/src/main/java/helpset/en/html_files/WindowClearanceMatrix.html similarity index 100% rename from helpset/en/html_files/WindowClearanceMatrix.html rename to src/main/java/helpset/en/html_files/WindowClearanceMatrix.html diff --git a/helpset/en/html_files/WindowDisplay.html b/src/main/java/helpset/en/html_files/WindowDisplay.html similarity index 100% rename from helpset/en/html_files/WindowDisplay.html rename to src/main/java/helpset/en/html_files/WindowDisplay.html diff --git a/helpset/en/html_files/WindowManualRules.html b/src/main/java/helpset/en/html_files/WindowManualRules.html similarity index 100% rename from helpset/en/html_files/WindowManualRules.html rename to src/main/java/helpset/en/html_files/WindowManualRules.html diff --git a/helpset/en/html_files/WindowMoveParameter.html b/src/main/java/helpset/en/html_files/WindowMoveParameter.html similarity index 100% rename from helpset/en/html_files/WindowMoveParameter.html rename to src/main/java/helpset/en/html_files/WindowMoveParameter.html diff --git a/helpset/en/html_files/WindowNetClasses.html b/src/main/java/helpset/en/html_files/WindowNetClasses.html similarity index 100% rename from helpset/en/html_files/WindowNetClasses.html rename to src/main/java/helpset/en/html_files/WindowNetClasses.html diff --git a/helpset/en/html_files/WindowObjectList.html b/src/main/java/helpset/en/html_files/WindowObjectList.html similarity index 100% rename from helpset/en/html_files/WindowObjectList.html rename to src/main/java/helpset/en/html_files/WindowObjectList.html diff --git a/helpset/en/html_files/WindowRouteParameter.html b/src/main/java/helpset/en/html_files/WindowRouteParameter.html similarity index 100% rename from helpset/en/html_files/WindowRouteParameter.html rename to src/main/java/helpset/en/html_files/WindowRouteParameter.html diff --git a/helpset/en/html_files/WindowSelectParameter.html b/src/main/java/helpset/en/html_files/WindowSelectParameter.html similarity index 100% rename from helpset/en/html_files/WindowSelectParameter.html rename to src/main/java/helpset/en/html_files/WindowSelectParameter.html diff --git a/helpset/en/html_files/WindowSnapshots.html b/src/main/java/helpset/en/html_files/WindowSnapshots.html similarity index 100% rename from helpset/en/html_files/WindowSnapshots.html rename to src/main/java/helpset/en/html_files/WindowSnapshots.html diff --git a/helpset/en/html_files/WindowVia.html b/src/main/java/helpset/en/html_files/WindowVia.html similarity index 100% rename from helpset/en/html_files/WindowVia.html rename to src/main/java/helpset/en/html_files/WindowVia.html diff --git a/helpset/en/images/popup.gif b/src/main/java/helpset/en/images/popup.gif similarity index 100% rename from helpset/en/images/popup.gif rename to src/main/java/helpset/en/images/popup.gif diff --git a/helpset/en/index.html b/src/main/java/helpset/en/index.html similarity index 100% rename from helpset/en/index.html rename to src/main/java/helpset/en/index.html diff --git a/interactive/AutorouteSettings.java b/src/main/java/interactive/AutorouteSettings.java similarity index 78% rename from interactive/AutorouteSettings.java rename to src/main/java/interactive/AutorouteSettings.java index 36ab06d..b49b277 100644 --- a/interactive/AutorouteSettings.java +++ b/src/main/java/interactive/AutorouteSettings.java @@ -1,351 +1,510 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * AutorouteSettings.java - * - * Created on 27. Juli 2006, 09:16 - * - */ -package interactive; - -import board.RoutingBoard; -import autoroute.AutorouteControl.ExpansionCostFactor; - -/** - * Contains the interactive settings for the autorouter. - * - * @author Alfons Wirtz - */ -public class AutorouteSettings implements java.io.Serializable -{ - - /** Creates a new instance of AutorouteSettings */ - public AutorouteSettings(int p_layer_count) - { - layer_active_arr = new boolean[p_layer_count]; - preferred_direction_is_horizontal_arr = new boolean[p_layer_count]; - preferred_direction_trace_cost_arr = new double[p_layer_count]; - against_preferred_direction_trace_cost_arr = new double[p_layer_count]; - } - - /** Creates a new instance of AutorouteSettings */ - public AutorouteSettings(RoutingBoard p_board) - { - this(p_board.get_layer_count()); - - // set default values - - start_ripup_costs = 100; - start_pass_no = 1; - vias_allowed = true; - with_fanout = false; - with_autoroute = true; - with_postroute = true; - via_costs = 50; - plane_via_costs = 5; - - double horizontal_width = p_board.bounding_box.width(); - double vertical_width = p_board.bounding_box.height(); - - int layer_count = p_board.get_layer_count(); - - // additional costs aagainst preferred direcction with 1 digit behind the decimal point. - double horizontal_add_costs_against_preferred_dir = 0.1 * Math.round(10 * horizontal_width / vertical_width); - - double vertical_add_costs_against_preferred_dir = 0.1 * Math.round(10 * vertical_width / horizontal_width); - - // make more horizontal pefered direction, if the board is horizontal. - - boolean curr_preferred_direction_is_horizontal = horizontal_width < vertical_width; - for (int i = 0; i < layer_count; ++i) - { - layer_active_arr[i] = p_board.layer_structure.arr[i].is_signal; - if (p_board.layer_structure.arr[i].is_signal) - { - curr_preferred_direction_is_horizontal = !curr_preferred_direction_is_horizontal; - } - preferred_direction_is_horizontal_arr[i] = curr_preferred_direction_is_horizontal; - preferred_direction_trace_cost_arr[i] = 1; - against_preferred_direction_trace_cost_arr[i] = 1; - if (curr_preferred_direction_is_horizontal) - { - against_preferred_direction_trace_cost_arr[i] += horizontal_add_costs_against_preferred_dir; - } - else - { - against_preferred_direction_trace_cost_arr[i] += vertical_add_costs_against_preferred_dir; - } - } - int signal_layer_count = p_board.layer_structure.signal_layer_count(); - if (signal_layer_count > 2) - { - double outer_add_costs = 0.2 * signal_layer_count; - // increase costs on the outer layers. - preferred_direction_trace_cost_arr[0] += outer_add_costs; - preferred_direction_trace_cost_arr[layer_count - 1] += outer_add_costs; - against_preferred_direction_trace_cost_arr[0] += outer_add_costs; - against_preferred_direction_trace_cost_arr[layer_count - 1] += outer_add_costs; - } - } - - /** - * Copy constructor - */ - public AutorouteSettings(AutorouteSettings p_settings) - { - start_ripup_costs = p_settings.start_ripup_costs; - start_pass_no = p_settings.start_pass_no; - via_costs = p_settings.via_costs; - plane_via_costs = p_settings.plane_via_costs; - layer_active_arr = new boolean[p_settings.layer_active_arr.length]; - System.arraycopy(p_settings.layer_active_arr, 0, this.layer_active_arr, 0, layer_active_arr.length); - preferred_direction_is_horizontal_arr = new boolean[p_settings.preferred_direction_is_horizontal_arr.length]; - System.arraycopy(p_settings.preferred_direction_is_horizontal_arr, 0, this.preferred_direction_is_horizontal_arr, 0, - preferred_direction_is_horizontal_arr.length); - preferred_direction_trace_cost_arr = new double[p_settings.preferred_direction_trace_cost_arr.length]; - System.arraycopy(p_settings.preferred_direction_trace_cost_arr, 0, preferred_direction_trace_cost_arr, 0, - preferred_direction_trace_cost_arr.length); - against_preferred_direction_trace_cost_arr = new double[p_settings.against_preferred_direction_trace_cost_arr.length]; - System.arraycopy(p_settings.against_preferred_direction_trace_cost_arr, 0, against_preferred_direction_trace_cost_arr, 0, - against_preferred_direction_trace_cost_arr.length); - } - - public void set_start_ripup_costs(int p_value) - { - start_ripup_costs = Math.max(p_value, 1); - } - - public int get_start_ripup_costs() - { - return start_ripup_costs; - } - - public void set_pass_no(int p_value) - { - start_pass_no = Math.max(p_value, 1); - start_pass_no = Math.min(start_pass_no, 99); - } - - public int get_pass_no() - { - return start_pass_no; - } - - public void increment_pass_no() - { - ++start_pass_no; - } - - public void set_with_fanout(boolean p_value) - { - with_fanout = p_value; - } - - public boolean get_with_fanout() - { - return with_fanout; - } - - public void set_with_autoroute(boolean p_value) - { - with_autoroute = p_value; - } - - public boolean get_with_autoroute() - { - return with_autoroute; - } - - public void set_with_postroute(boolean p_value) - { - with_postroute = p_value; - } - - public boolean get_with_postroute() - { - return with_postroute; - } - - public void set_vias_allowed(boolean p_value) - { - vias_allowed = p_value; - } - - public boolean get_vias_allowed() - { - return vias_allowed; - } - - public void set_via_costs(int p_value) - { - via_costs = Math.max(p_value, 1); - } - - public int get_via_costs() - { - return via_costs; - } - - public void set_plane_via_costs(int p_value) - { - plane_via_costs = Math.max(p_value, 1); - } - - public int get_plane_via_costs() - { - return plane_via_costs; - } - - public void set_layer_active(int p_layer, boolean p_value) - { - if (p_layer < 0 || p_layer >= layer_active_arr.length) - { - System.out.println("AutorouteSettings.set_layer_active: p_layer out of range"); - return; - } - layer_active_arr[p_layer] = p_value; - } - - public boolean get_layer_active(int p_layer) - { - if (p_layer < 0 || p_layer >= layer_active_arr.length) - { - System.out.println("AutorouteSettings.get_layer_active: p_layer out of range"); - return false; - } - return layer_active_arr[p_layer]; - } - - public void set_preferred_direction_is_horizontal(int p_layer, boolean p_value) - { - if (p_layer < 0 || p_layer >= layer_active_arr.length) - { - System.out.println("AutorouteSettings.set_preferred_direction_is_horizontal: p_layer out of range"); - return; - } - preferred_direction_is_horizontal_arr[p_layer] = p_value; - } - - public boolean get_preferred_direction_is_horizontal(int p_layer) - { - if (p_layer < 0 || p_layer >= layer_active_arr.length) - { - System.out.println("AutorouteSettings.get_preferred_direction_is_horizontal: p_layer out of range"); - return false; - } - return preferred_direction_is_horizontal_arr[p_layer]; - } - - public void set_preferred_direction_trace_costs(int p_layer, double p_value) - { - if (p_layer < 0 || p_layer >= layer_active_arr.length) - { - System.out.println("AutorouteSettings.set_preferred_direction_trace_costs: p_layer out of range"); - return; - } - preferred_direction_trace_cost_arr[p_layer] = Math.max(p_value, 0.1); - } - - public double get_preferred_direction_trace_costs(int p_layer) - { - if (p_layer < 0 || p_layer >= layer_active_arr.length) - { - System.out.println("AutorouteSettings.get_preferred_direction_trace_costs: p_layer out of range"); - return 0; - } - return preferred_direction_trace_cost_arr[p_layer]; - } - - public double get_against_preferred_direction_trace_costs(int p_layer) - { - if (p_layer < 0 || p_layer >= layer_active_arr.length) - { - System.out.println("AutorouteSettings.get_against_preferred_direction_trace_costs: p_layer out of range"); - return 0; - } - return against_preferred_direction_trace_cost_arr[p_layer]; - } - - public double get_horizontal_trace_costs(int p_layer) - { - if (p_layer < 0 || p_layer >= layer_active_arr.length) - { - System.out.println("AutorouteSettings.get_preferred_direction_trace_costs: p_layer out of range"); - return 0; - } - double result; - if (preferred_direction_is_horizontal_arr[p_layer]) - { - result = preferred_direction_trace_cost_arr[p_layer]; - } - else - { - result = against_preferred_direction_trace_cost_arr[p_layer]; - } - return result; - } - - public void set_against_preferred_direction_trace_costs(int p_layer, double p_value) - { - if (p_layer < 0 || p_layer >= layer_active_arr.length) - { - System.out.println("AutorouteSettings.set_against_preferred_direction_trace_costs: p_layer out of range"); - return; - } - against_preferred_direction_trace_cost_arr[p_layer] = Math.max(p_value, 0.1); - } - - public double get_vertical_trace_costs(int p_layer) - { - if (p_layer < 0 || p_layer >= layer_active_arr.length) - { - System.out.println("AutorouteSettings.get_against_preferred_direction_trace_costs: p_layer out of range"); - return 0; - } - double result; - if (preferred_direction_is_horizontal_arr[p_layer]) - { - result = against_preferred_direction_trace_cost_arr[p_layer]; - } - else - { - result = preferred_direction_trace_cost_arr[p_layer]; - } - return result; - } - - public ExpansionCostFactor[] get_trace_cost_arr() - { - ExpansionCostFactor[] result = new ExpansionCostFactor[preferred_direction_trace_cost_arr.length]; - for (int i = 0; i < result.length; ++i) - { - result[i] = new ExpansionCostFactor(get_horizontal_trace_costs(i), get_vertical_trace_costs(i)); - } - return result; - } - - private boolean with_fanout; - private boolean with_autoroute; - private boolean with_postroute; - private boolean vias_allowed; - private int via_costs; - private int plane_via_costs; - private int start_ripup_costs; - private int start_pass_no; - private final boolean[] layer_active_arr; - private final boolean[] preferred_direction_is_horizontal_arr; - private final double[] preferred_direction_trace_cost_arr; - private final double[] against_preferred_direction_trace_cost_arr; -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * AutorouteSettings.java + * + * Created on 27. Juli 2006, 09:16 + * + */ +package interactive; + +import board.RoutingBoard; +import autoroute.AutorouteControl.ExpansionCostFactor; + +/** + * Contains the interactive settings for the autorouter. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class AutorouteSettings implements java.io.Serializable +{ + + /** + * Creates a new instance of AutorouteSettings + * + * @param p_layer_count a int. + */ + public AutorouteSettings(int p_layer_count) + { + layer_active_arr = new boolean[p_layer_count]; + preferred_direction_is_horizontal_arr = new boolean[p_layer_count]; + preferred_direction_trace_cost_arr = new double[p_layer_count]; + against_preferred_direction_trace_cost_arr = new double[p_layer_count]; + } + + /** + * Creates a new instance of AutorouteSettings + * + * @param p_board a {@link board.RoutingBoard} object. + */ + public AutorouteSettings(RoutingBoard p_board) + { + this(p_board.get_layer_count()); + + // set default values + + start_ripup_costs = 100; + start_pass_no = 1; + vias_allowed = true; + with_fanout = false; + with_autoroute = true; + with_postroute = true; + via_costs = 50; + plane_via_costs = 5; + + double horizontal_width = p_board.bounding_box.width(); + double vertical_width = p_board.bounding_box.height(); + + int layer_count = p_board.get_layer_count(); + + // additional costs aagainst preferred direcction with 1 digit behind the decimal point. + double horizontal_add_costs_against_preferred_dir = 0.1 * Math.round(10 * horizontal_width / vertical_width); + + double vertical_add_costs_against_preferred_dir = 0.1 * Math.round(10 * vertical_width / horizontal_width); + + // make more horizontal pefered direction, if the board is horizontal. + + boolean curr_preferred_direction_is_horizontal = horizontal_width < vertical_width; + for (int i = 0; i < layer_count; ++i) + { + layer_active_arr[i] = p_board.layer_structure.arr[i].is_signal; + if (p_board.layer_structure.arr[i].is_signal) + { + curr_preferred_direction_is_horizontal = !curr_preferred_direction_is_horizontal; + } + preferred_direction_is_horizontal_arr[i] = curr_preferred_direction_is_horizontal; + preferred_direction_trace_cost_arr[i] = 1; + against_preferred_direction_trace_cost_arr[i] = 1; + if (curr_preferred_direction_is_horizontal) + { + against_preferred_direction_trace_cost_arr[i] += horizontal_add_costs_against_preferred_dir; + } + else + { + against_preferred_direction_trace_cost_arr[i] += vertical_add_costs_against_preferred_dir; + } + } + int signal_layer_count = p_board.layer_structure.signal_layer_count(); + if (signal_layer_count > 2) + { + double outer_add_costs = 0.2 * signal_layer_count; + // increase costs on the outer layers. + preferred_direction_trace_cost_arr[0] += outer_add_costs; + preferred_direction_trace_cost_arr[layer_count - 1] += outer_add_costs; + against_preferred_direction_trace_cost_arr[0] += outer_add_costs; + against_preferred_direction_trace_cost_arr[layer_count - 1] += outer_add_costs; + } + } + + /** + * Copy constructor + * + * @param p_settings a {@link interactive.AutorouteSettings} object. + */ + public AutorouteSettings(AutorouteSettings p_settings) + { + start_ripup_costs = p_settings.start_ripup_costs; + start_pass_no = p_settings.start_pass_no; + via_costs = p_settings.via_costs; + plane_via_costs = p_settings.plane_via_costs; + layer_active_arr = new boolean[p_settings.layer_active_arr.length]; + System.arraycopy(p_settings.layer_active_arr, 0, this.layer_active_arr, 0, layer_active_arr.length); + preferred_direction_is_horizontal_arr = new boolean[p_settings.preferred_direction_is_horizontal_arr.length]; + System.arraycopy(p_settings.preferred_direction_is_horizontal_arr, 0, this.preferred_direction_is_horizontal_arr, 0, + preferred_direction_is_horizontal_arr.length); + preferred_direction_trace_cost_arr = new double[p_settings.preferred_direction_trace_cost_arr.length]; + System.arraycopy(p_settings.preferred_direction_trace_cost_arr, 0, preferred_direction_trace_cost_arr, 0, + preferred_direction_trace_cost_arr.length); + against_preferred_direction_trace_cost_arr = new double[p_settings.against_preferred_direction_trace_cost_arr.length]; + System.arraycopy(p_settings.against_preferred_direction_trace_cost_arr, 0, against_preferred_direction_trace_cost_arr, 0, + against_preferred_direction_trace_cost_arr.length); + } + + /** + *

set_start_ripup_costs.

+ * + * @param p_value a int. + */ + public void set_start_ripup_costs(int p_value) + { + start_ripup_costs = Math.max(p_value, 1); + } + + /** + *

get_start_ripup_costs.

+ * + * @return a int. + */ + public int get_start_ripup_costs() + { + return start_ripup_costs; + } + + /** + *

set_pass_no.

+ * + * @param p_value a int. + */ + public void set_pass_no(int p_value) + { + start_pass_no = Math.max(p_value, 1); + start_pass_no = Math.min(start_pass_no, 99); + } + + /** + *

get_pass_no.

+ * + * @return a int. + */ + public int get_pass_no() + { + return start_pass_no; + } + + /** + *

increment_pass_no.

+ */ + public void increment_pass_no() + { + ++start_pass_no; + } + + /** + *

set_with_fanout.

+ * + * @param p_value a boolean. + */ + public void set_with_fanout(boolean p_value) + { + with_fanout = p_value; + } + + /** + *

get_with_fanout.

+ * + * @return a boolean. + */ + public boolean get_with_fanout() + { + return with_fanout; + } + + /** + *

set_with_autoroute.

+ * + * @param p_value a boolean. + */ + public void set_with_autoroute(boolean p_value) + { + with_autoroute = p_value; + } + + /** + *

get_with_autoroute.

+ * + * @return a boolean. + */ + public boolean get_with_autoroute() + { + return with_autoroute; + } + + /** + *

set_with_postroute.

+ * + * @param p_value a boolean. + */ + public void set_with_postroute(boolean p_value) + { + with_postroute = p_value; + } + + /** + *

get_with_postroute.

+ * + * @return a boolean. + */ + public boolean get_with_postroute() + { + return with_postroute; + } + + /** + *

set_vias_allowed.

+ * + * @param p_value a boolean. + */ + public void set_vias_allowed(boolean p_value) + { + vias_allowed = p_value; + } + + /** + *

get_vias_allowed.

+ * + * @return a boolean. + */ + public boolean get_vias_allowed() + { + return vias_allowed; + } + + /** + *

set_via_costs.

+ * + * @param p_value a int. + */ + public void set_via_costs(int p_value) + { + via_costs = Math.max(p_value, 1); + } + + /** + *

get_via_costs.

+ * + * @return a int. + */ + public int get_via_costs() + { + return via_costs; + } + + /** + *

set_plane_via_costs.

+ * + * @param p_value a int. + */ + public void set_plane_via_costs(int p_value) + { + plane_via_costs = Math.max(p_value, 1); + } + + /** + *

get_plane_via_costs.

+ * + * @return a int. + */ + public int get_plane_via_costs() + { + return plane_via_costs; + } + + /** + *

set_layer_active.

+ * + * @param p_layer a int. + * @param p_value a boolean. + */ + public void set_layer_active(int p_layer, boolean p_value) + { + if (p_layer < 0 || p_layer >= layer_active_arr.length) + { + System.out.println("AutorouteSettings.set_layer_active: p_layer out of range"); + return; + } + layer_active_arr[p_layer] = p_value; + } + + /** + *

get_layer_active.

+ * + * @param p_layer a int. + * @return a boolean. + */ + public boolean get_layer_active(int p_layer) + { + if (p_layer < 0 || p_layer >= layer_active_arr.length) + { + System.out.println("AutorouteSettings.get_layer_active: p_layer out of range"); + return false; + } + return layer_active_arr[p_layer]; + } + + /** + *

set_preferred_direction_is_horizontal.

+ * + * @param p_layer a int. + * @param p_value a boolean. + */ + public void set_preferred_direction_is_horizontal(int p_layer, boolean p_value) + { + if (p_layer < 0 || p_layer >= layer_active_arr.length) + { + System.out.println("AutorouteSettings.set_preferred_direction_is_horizontal: p_layer out of range"); + return; + } + preferred_direction_is_horizontal_arr[p_layer] = p_value; + } + + /** + *

get_preferred_direction_is_horizontal.

+ * + * @param p_layer a int. + * @return a boolean. + */ + public boolean get_preferred_direction_is_horizontal(int p_layer) + { + if (p_layer < 0 || p_layer >= layer_active_arr.length) + { + System.out.println("AutorouteSettings.get_preferred_direction_is_horizontal: p_layer out of range"); + return false; + } + return preferred_direction_is_horizontal_arr[p_layer]; + } + + /** + *

set_preferred_direction_trace_costs.

+ * + * @param p_layer a int. + * @param p_value a double. + */ + public void set_preferred_direction_trace_costs(int p_layer, double p_value) + { + if (p_layer < 0 || p_layer >= layer_active_arr.length) + { + System.out.println("AutorouteSettings.set_preferred_direction_trace_costs: p_layer out of range"); + return; + } + preferred_direction_trace_cost_arr[p_layer] = Math.max(p_value, 0.1); + } + + /** + *

get_preferred_direction_trace_costs.

+ * + * @param p_layer a int. + * @return a double. + */ + public double get_preferred_direction_trace_costs(int p_layer) + { + if (p_layer < 0 || p_layer >= layer_active_arr.length) + { + System.out.println("AutorouteSettings.get_preferred_direction_trace_costs: p_layer out of range"); + return 0; + } + return preferred_direction_trace_cost_arr[p_layer]; + } + + /** + *

get_against_preferred_direction_trace_costs.

+ * + * @param p_layer a int. + * @return a double. + */ + public double get_against_preferred_direction_trace_costs(int p_layer) + { + if (p_layer < 0 || p_layer >= layer_active_arr.length) + { + System.out.println("AutorouteSettings.get_against_preferred_direction_trace_costs: p_layer out of range"); + return 0; + } + return against_preferred_direction_trace_cost_arr[p_layer]; + } + + /** + *

get_horizontal_trace_costs.

+ * + * @param p_layer a int. + * @return a double. + */ + public double get_horizontal_trace_costs(int p_layer) + { + if (p_layer < 0 || p_layer >= layer_active_arr.length) + { + System.out.println("AutorouteSettings.get_preferred_direction_trace_costs: p_layer out of range"); + return 0; + } + double result; + if (preferred_direction_is_horizontal_arr[p_layer]) + { + result = preferred_direction_trace_cost_arr[p_layer]; + } + else + { + result = against_preferred_direction_trace_cost_arr[p_layer]; + } + return result; + } + + /** + *

set_against_preferred_direction_trace_costs.

+ * + * @param p_layer a int. + * @param p_value a double. + */ + public void set_against_preferred_direction_trace_costs(int p_layer, double p_value) + { + if (p_layer < 0 || p_layer >= layer_active_arr.length) + { + System.out.println("AutorouteSettings.set_against_preferred_direction_trace_costs: p_layer out of range"); + return; + } + against_preferred_direction_trace_cost_arr[p_layer] = Math.max(p_value, 0.1); + } + + /** + *

get_vertical_trace_costs.

+ * + * @param p_layer a int. + * @return a double. + */ + public double get_vertical_trace_costs(int p_layer) + { + if (p_layer < 0 || p_layer >= layer_active_arr.length) + { + System.out.println("AutorouteSettings.get_against_preferred_direction_trace_costs: p_layer out of range"); + return 0; + } + double result; + if (preferred_direction_is_horizontal_arr[p_layer]) + { + result = against_preferred_direction_trace_cost_arr[p_layer]; + } + else + { + result = preferred_direction_trace_cost_arr[p_layer]; + } + return result; + } + + /** + *

get_trace_cost_arr.

+ * + * @return an array of {@link autoroute.AutorouteControl.ExpansionCostFactor} objects. + */ + public ExpansionCostFactor[] get_trace_cost_arr() + { + ExpansionCostFactor[] result = new ExpansionCostFactor[preferred_direction_trace_cost_arr.length]; + for (int i = 0; i < result.length; ++i) + { + result[i] = new ExpansionCostFactor(get_horizontal_trace_costs(i), get_vertical_trace_costs(i)); + } + return result; + } + + private boolean with_fanout; + private boolean with_autoroute; + private boolean with_postroute; + private boolean vias_allowed; + private int via_costs; + private int plane_via_costs; + private int start_ripup_costs; + private int start_pass_no; + private final boolean[] layer_active_arr; + private final boolean[] preferred_direction_is_horizontal_arr; + private final double[] preferred_direction_trace_cost_arr; + private final double[] against_preferred_direction_trace_cost_arr; +} diff --git a/interactive/BatchAutorouterThread.java b/src/main/java/interactive/BatchAutorouterThread.java similarity index 96% rename from interactive/BatchAutorouterThread.java rename to src/main/java/interactive/BatchAutorouterThread.java index 3f099ab..7d495ff 100644 --- a/interactive/BatchAutorouterThread.java +++ b/src/main/java/interactive/BatchAutorouterThread.java @@ -1,161 +1,170 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * BatchAutorouterThread.java - * - * Created on 25. April 2006, 07:58 - * - */ -package interactive; - -import geometry.planar.FloatPoint; -import geometry.planar.FloatLine; - -import board.Unit; - -import autoroute.BatchAutorouter; -import autoroute.BatchFanout; -import autoroute.BatchOptRoute; - -/** - * Thread for the batch autorouter. - * - * @author Alfons Wirtz - */ -public class BatchAutorouterThread extends InteractiveActionThread -{ - - /** Creates a new instance of BatchAutorouterThread */ - protected BatchAutorouterThread(BoardHandling p_board_handling) - { - super(p_board_handling); - AutorouteSettings autoroute_settings = p_board_handling.settings.autoroute_settings; - this.batch_autorouter = new BatchAutorouter(this, !autoroute_settings.get_with_fanout(), true, autoroute_settings.get_start_ripup_costs()); - this.batch_opt_route = new BatchOptRoute(this); - - } - - protected void thread_action() - { - try - { - java.util.ResourceBundle resources = - java.util.ResourceBundle.getBundle("interactive.resources.InteractiveState", hdlg.get_locale()); - boolean saved_board_read_only = hdlg.is_board_read_only(); - hdlg.set_board_read_only(true); - boolean ratsnest_hidden_before = hdlg.get_ratsnest().is_hidden(); - if (!ratsnest_hidden_before) - { - hdlg.get_ratsnest().hide(); - } - String start_message = resources.getString("batch_autorouter") + " " + resources.getString("stop_message"); - hdlg.screen_messages.set_status_message(start_message); - boolean fanout_first = - hdlg.settings.autoroute_settings.get_with_fanout() && - hdlg.settings.autoroute_settings.get_pass_no() <= 1; - if (fanout_first) - { - BatchFanout.fanout_board(this); - } - if (hdlg.settings.autoroute_settings.get_with_autoroute() && !this.is_stop_requested()) - { - batch_autorouter.autoroute_passes(); - } - hdlg.get_routing_board().finish_autoroute(); - if (hdlg.settings.autoroute_settings.get_with_postroute() && !this.is_stop_requested()) - { - String opt_message = resources.getString("batch_optimizer") + " " + resources.getString("stop_message"); - hdlg.screen_messages.set_status_message(opt_message); - this.batch_opt_route.optimize_board(); - String curr_message; - if (this.is_stop_requested()) - { - curr_message = resources.getString("interrupted"); - } - else - { - curr_message = resources.getString("completed"); - } - String end_message = resources.getString("postroute") + " " + curr_message; - hdlg.screen_messages.set_status_message(end_message); - } - else - { - hdlg.screen_messages.clear(); - String curr_message; - if (this.is_stop_requested()) - { - curr_message = resources.getString("interrupted"); - } - else - { - curr_message = resources.getString("completed"); - } - Integer incomplete_count = hdlg.get_ratsnest().incomplete_count(); - String end_message = resources.getString("autoroute") + " " + curr_message + ", " + incomplete_count.toString() + - " " + resources.getString("connections_not_found"); - hdlg.screen_messages.set_status_message(end_message); - } - - hdlg.set_board_read_only(saved_board_read_only); - hdlg.update_ratsnest(); - if (!ratsnest_hidden_before) - { - hdlg.get_ratsnest().show(); - } - - hdlg.get_panel().board_frame.refresh_windows(); - if (hdlg.get_routing_board().rules.get_trace_angle_restriction() == board.AngleRestriction.FORTYFIVE_DEGREE && hdlg.get_routing_board().get_test_level() != board.TestLevel.RELEASE_VERSION) - { - tests.Validate.multiple_of_45_degree("after autoroute: ", hdlg.get_routing_board()); - } - } catch (Exception e) - { - - } - } - - public void draw(java.awt.Graphics p_graphics) - { - FloatLine curr_air_line = batch_autorouter.get_air_line(); - if (curr_air_line != null) - { - FloatPoint[] draw_line = new FloatPoint[2]; - draw_line[0] = curr_air_line.a; - draw_line[1] = curr_air_line.b; - // draw the incomplete - java.awt.Color draw_color = this.hdlg.graphics_context.get_incomplete_color(); - double draw_width = Math.min (this.hdlg.get_routing_board().communication.get_resolution(Unit.MIL) * 3, 300); // problem with low resolution on Kicad300; - this.hdlg.graphics_context.draw(draw_line, draw_width, draw_color, p_graphics, 1); - } - FloatPoint current_opt_position = batch_opt_route.get_current_position(); - int radius = 10 * this.hdlg.get_routing_board().rules.get_default_trace_half_width(0); - if (current_opt_position != null) - { - final int draw_width = 1; - java.awt.Color draw_color = this.hdlg.graphics_context.get_incomplete_color(); - FloatPoint[] draw_points = new FloatPoint[2]; - draw_points[0] = new FloatPoint(current_opt_position.x - radius, current_opt_position.y - radius); - draw_points[1] = new FloatPoint(current_opt_position.x + radius, current_opt_position.y + radius); - this.hdlg.graphics_context.draw(draw_points, draw_width, draw_color, p_graphics, 1); - draw_points[0] = new FloatPoint(current_opt_position.x + radius, current_opt_position.y - radius); - draw_points[1] = new FloatPoint(current_opt_position.x - radius, current_opt_position.y + radius); - this.hdlg.graphics_context.draw(draw_points, draw_width, draw_color, p_graphics, 1); - this.hdlg.graphics_context.draw_circle(current_opt_position, radius, draw_width, draw_color, p_graphics, 1); - } - } - private final BatchAutorouter batch_autorouter; - private final BatchOptRoute batch_opt_route; -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * BatchAutorouterThread.java + * + * Created on 25. April 2006, 07:58 + * + */ +package interactive; + +import geometry.planar.FloatPoint; +import geometry.planar.FloatLine; + +import board.Unit; + +import autoroute.BatchAutorouter; +import autoroute.BatchFanout; +import autoroute.BatchOptRoute; + +/** + * Thread for the batch autorouter. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class BatchAutorouterThread extends InteractiveActionThread +{ + + /** + * Creates a new instance of BatchAutorouterThread + * + * @param p_board_handling a {@link interactive.BoardHandling} object. + */ + protected BatchAutorouterThread(BoardHandling p_board_handling) + { + super(p_board_handling); + AutorouteSettings autoroute_settings = p_board_handling.settings.autoroute_settings; + this.batch_autorouter = new BatchAutorouter(this, !autoroute_settings.get_with_fanout(), true, autoroute_settings.get_start_ripup_costs()); + this.batch_opt_route = new BatchOptRoute(this); + + } + + /** + *

thread_action.

+ */ + protected void thread_action() + { + try + { + java.util.ResourceBundle resources = + java.util.ResourceBundle.getBundle("interactive.resources.InteractiveState", hdlg.get_locale()); + boolean saved_board_read_only = hdlg.is_board_read_only(); + hdlg.set_board_read_only(true); + boolean ratsnest_hidden_before = hdlg.get_ratsnest().is_hidden(); + if (!ratsnest_hidden_before) + { + hdlg.get_ratsnest().hide(); + } + String start_message = resources.getString("batch_autorouter") + " " + resources.getString("stop_message"); + hdlg.screen_messages.set_status_message(start_message); + boolean fanout_first = + hdlg.settings.autoroute_settings.get_with_fanout() && + hdlg.settings.autoroute_settings.get_pass_no() <= 1; + if (fanout_first) + { + BatchFanout.fanout_board(this); + } + if (hdlg.settings.autoroute_settings.get_with_autoroute() && !this.is_stop_requested()) + { + batch_autorouter.autoroute_passes(); + } + hdlg.get_routing_board().finish_autoroute(); + if (hdlg.settings.autoroute_settings.get_with_postroute() && !this.is_stop_requested()) + { + String opt_message = resources.getString("batch_optimizer") + " " + resources.getString("stop_message"); + hdlg.screen_messages.set_status_message(opt_message); + this.batch_opt_route.optimize_board(); + String curr_message; + if (this.is_stop_requested()) + { + curr_message = resources.getString("interrupted"); + } + else + { + curr_message = resources.getString("completed"); + } + String end_message = resources.getString("postroute") + " " + curr_message; + hdlg.screen_messages.set_status_message(end_message); + } + else + { + hdlg.screen_messages.clear(); + String curr_message; + if (this.is_stop_requested()) + { + curr_message = resources.getString("interrupted"); + } + else + { + curr_message = resources.getString("completed"); + } + Integer incomplete_count = hdlg.get_ratsnest().incomplete_count(); + String end_message = resources.getString("autoroute") + " " + curr_message + ", " + incomplete_count.toString() + + " " + resources.getString("connections_not_found"); + hdlg.screen_messages.set_status_message(end_message); + } + + hdlg.set_board_read_only(saved_board_read_only); + hdlg.update_ratsnest(); + if (!ratsnest_hidden_before) + { + hdlg.get_ratsnest().show(); + } + + hdlg.get_panel().board_frame.refresh_windows(); + if (hdlg.get_routing_board().rules.get_trace_angle_restriction() == board.AngleRestriction.FORTYFIVE_DEGREE && hdlg.get_routing_board().get_test_level() != board.TestLevel.RELEASE_VERSION) + { + tests.Validate.multiple_of_45_degree("after autoroute: ", hdlg.get_routing_board()); + } + } catch (Exception e) + { + + } + } + + /** {@inheritDoc} */ + public void draw(java.awt.Graphics p_graphics) + { + FloatLine curr_air_line = batch_autorouter.get_air_line(); + if (curr_air_line != null) + { + FloatPoint[] draw_line = new FloatPoint[2]; + draw_line[0] = curr_air_line.a; + draw_line[1] = curr_air_line.b; + // draw the incomplete + java.awt.Color draw_color = this.hdlg.graphics_context.get_incomplete_color(); + double draw_width = Math.min (this.hdlg.get_routing_board().communication.get_resolution(Unit.MIL) * 3, 300); // problem with low resolution on Kicad300; + this.hdlg.graphics_context.draw(draw_line, draw_width, draw_color, p_graphics, 1); + } + FloatPoint current_opt_position = batch_opt_route.get_current_position(); + int radius = 10 * this.hdlg.get_routing_board().rules.get_default_trace_half_width(0); + if (current_opt_position != null) + { + final int draw_width = 1; + java.awt.Color draw_color = this.hdlg.graphics_context.get_incomplete_color(); + FloatPoint[] draw_points = new FloatPoint[2]; + draw_points[0] = new FloatPoint(current_opt_position.x - radius, current_opt_position.y - radius); + draw_points[1] = new FloatPoint(current_opt_position.x + radius, current_opt_position.y + radius); + this.hdlg.graphics_context.draw(draw_points, draw_width, draw_color, p_graphics, 1); + draw_points[0] = new FloatPoint(current_opt_position.x + radius, current_opt_position.y - radius); + draw_points[1] = new FloatPoint(current_opt_position.x - radius, current_opt_position.y + radius); + this.hdlg.graphics_context.draw(draw_points, draw_width, draw_color, p_graphics, 1); + this.hdlg.graphics_context.draw_circle(current_opt_position, radius, draw_width, draw_color, p_graphics, 1); + } + } + private final BatchAutorouter batch_autorouter; + private final BatchOptRoute batch_opt_route; +} diff --git a/interactive/BoardHandling.java b/src/main/java/interactive/BoardHandling.java similarity index 91% rename from interactive/BoardHandling.java rename to src/main/java/interactive/BoardHandling.java index c0d58f7..88e360e 100644 --- a/interactive/BoardHandling.java +++ b/src/main/java/interactive/BoardHandling.java @@ -57,12 +57,16 @@ * the board database. * * @author Alfons Wirtz + * @version $Id: $Id */ public class BoardHandling { /** * Creates a new BoardHandling + * + * @param p_panel a {@link gui.BoardPanel} object. + * @param p_locale a {@link java.util.Locale} object. */ public BoardHandling(gui.BoardPanel p_panel, java.util.Locale p_locale) { @@ -77,6 +81,8 @@ public BoardHandling(gui.BoardPanel p_panel, java.util.Locale p_locale) /** * Sets the board to read only for example when running a seperate action thread * to avoid unsynchronized change of the board. + * + * @param p_value a boolean. */ public void set_board_read_only(boolean p_value) { @@ -86,6 +92,8 @@ public void set_board_read_only(boolean p_value) /** * Return true, if the board is set to read only. + * + * @return a boolean. */ public boolean is_board_read_only() { @@ -94,6 +102,8 @@ public boolean is_board_read_only() /** * Return the current language for the GUI messages. + * + * @return a {@link java.util.Locale} object. */ public java.util.Locale get_locale() { @@ -102,6 +112,8 @@ public java.util.Locale get_locale() /** * returns the number of layers of the board design. + * + * @return a int. */ public int get_layer_count() { @@ -114,6 +126,8 @@ public int get_layer_count() /** * Gets the routing board of this board handling. + * + * @return a {@link board.RoutingBoard} object. */ public RoutingBoard get_routing_board() { @@ -122,6 +136,8 @@ public RoutingBoard get_routing_board() /** * Returns the current position of the mouse pointer. + * + * @return a {@link geometry.planar.FloatPoint} object. */ public FloatPoint get_current_mouse_position() { @@ -139,6 +155,8 @@ void set_current_mouse_position(FloatPoint p_point) /** * * Tells the router, if conduction areas should be ignored.. + * + * @param p_value a boolean. */ public void set_ignore_conduction(boolean p_value) { @@ -151,6 +169,11 @@ public void set_ignore_conduction(boolean p_value) logfile.start_scope(LogfileScope.SET_IGNORE_CONDUCTION, p_value); } + /** + *

set_pin_edge_to_turn_dist.

+ * + * @param p_value a double. + */ public void set_pin_edge_to_turn_dist(double p_value) { if (board_is_read_only) @@ -186,6 +209,9 @@ public void set_pin_edge_to_turn_dist(double p_value) /** * Changes the visibility of the input layer to the input value. * p_value is expected between 0 and 1 + * + * @param p_layer a int. + * @param p_value a double. */ public void set_layer_visibility(int p_layer, double p_value) { @@ -212,6 +238,10 @@ public void set_layer_visibility(int p_layer, double p_value) /** * Gets the trace half width used in interactive routing for the input net on the input layer. + * + * @param p_net_no a int. + * @param p_layer a int. + * @return a int. */ public int get_trace_halfwidth(int p_net_no, int p_layer) { @@ -229,6 +259,10 @@ public int get_trace_halfwidth(int p_net_no, int p_layer) /** * Returns if p_layer is active for interactive routing of traces. + * + * @param p_net_no a int. + * @param p_layer a int. + * @return a boolean. */ public boolean is_active_routing_layer(int p_net_no, int p_layer) { @@ -249,7 +283,12 @@ public boolean is_active_routing_layer(int p_net_no, int p_layer) return curr_net_class.is_active_routing_layer(p_layer); } - /** Gets the trace clearance class used in interactive routing. */ + /** + * Gets the trace clearance class used in interactive routing. + * + * @param p_net_no a int. + * @return a int. + */ public int get_trace_clearance_class(int p_net_no) { int result; @@ -264,7 +303,12 @@ public int get_trace_clearance_class(int p_net_no) return result; } - /** Gets the via rule used in interactive routing. */ + /** + * Gets the via rule used in interactive routing. + * + * @param p_net_no a int. + * @return a {@link rules.ViaRule} object. + */ public rules.ViaRule get_via_rule(int p_net_no) { rules.ViaRule result = null; @@ -281,6 +325,9 @@ public rules.ViaRule get_via_rule(int p_net_no) /** * Changes the default trace halfwidth currently used in interactive routing on the input layer. + * + * @param p_layer a int. + * @param p_value a int. */ public void set_default_trace_halfwidth(int p_layer, int p_value) { @@ -298,6 +345,8 @@ public void set_default_trace_halfwidth(int p_layer, int p_value) /** * Switches clearance compansation on or off. + * + * @param p_value a boolean. */ public void set_clearance_compensation(boolean p_value) { @@ -311,6 +360,8 @@ public void set_clearance_compensation(boolean p_value) /** * Changes the current snap angle in the interactive board handling. + * + * @param p_snap_angle a {@link board.AngleRestriction} object. */ public void set_current_snap_angle(board.AngleRestriction p_snap_angle) { @@ -324,6 +375,8 @@ public void set_current_snap_angle(board.AngleRestriction p_snap_angle) /** * Changes the current layer in the interactive board handling. + * + * @param p_layer a int. */ public void set_current_layer(int p_layer) { @@ -388,7 +441,10 @@ public void initialize_manual_trace_half_widths() /** * Sets the manual trace half width used in interactive routing. - * If p_layer_no < 0, the manual trace half width is changed on all layers. + * If {@code p_layer_no < 0}, the manual trace half width is changed on all layers. + * + * @param p_layer_no a int. + * @param p_value a int. */ public void set_manual_trace_half_width(int p_layer_no, int p_value) { @@ -414,6 +470,9 @@ else if (p_layer_no == gui.ComboBoxLayer.INNER_LAYER_INDEX) /** * Changes the interactive selectability of p_item_type. + * + * @param p_item_type a {@link board.ItemSelectionFilter.SelectableChoices} object. + * @param p_value a boolean. */ public void set_selectable(ItemSelectionFilter.SelectableChoices p_item_type, boolean p_value) { @@ -441,6 +500,9 @@ public void toggle_ratsnest() repaint(); } + /** + *

toggle_clearance_violations.

+ */ public void toggle_clearance_violations() { if (clearance_violations == null) @@ -545,6 +607,8 @@ public void remove_ratsnest() /** * Returns the ratsnest with the information about the incomplete connections. + * + * @return a {@link interactive.RatsNest} object. */ public RatsNest get_ratsnest() { @@ -555,6 +619,9 @@ public RatsNest get_ratsnest() return this.ratsnest; } + /** + *

recalculate_length_violations.

+ */ public void recalculate_length_violations() { if (this.ratsnest != null) @@ -571,6 +638,9 @@ public void recalculate_length_violations() /** * Sets the visibility filter for the incompletes of the input net. + * + * @param p_net_no a int. + * @param p_value a boolean. */ public void set_incompletes_filter(int p_net_no, boolean p_value) { @@ -582,6 +652,14 @@ public void set_incompletes_filter(int p_net_no, boolean p_value) /** * Creates the Routingboard, the graphic context and the interactive settings. + * + * @param p_bounding_box a {@link geometry.planar.IntBox} object. + * @param p_layer_structure a {@link board.LayerStructure} object. + * @param p_outline_shapes an array of {@link geometry.planar.PolylineShape} objects. + * @param p_outline_clearance_class_name a {@link java.lang.String} object. + * @param p_rules a rules$BoardRules object. + * @param p_board_communication a {@link board.Communication} object. + * @param p_test_level a {@link board.TestLevel} object. */ public void create_board(IntBox p_bounding_box, LayerStructure p_layer_structure, PolylineShape[] p_outline_shapes, String p_outline_clearance_class_name, @@ -622,6 +700,8 @@ public void create_board(IntBox p_bounding_box, LayerStructure p_layer_structure /** * Changes the factor of the user unit. + * + * @param p_new_factor a double. */ public void change_user_unit_factor(double p_new_factor) { @@ -633,6 +713,8 @@ public void change_user_unit_factor(double p_new_factor) /** * Changes the user unit. + * + * @param p_unit a {@link board.Unit} object. */ public void change_user_unit(Unit p_unit) { @@ -644,6 +726,8 @@ public void change_user_unit(Unit p_unit) /** * From here on the interactive actions are written to a logfile. + * + * @param p_filename a {@link java.io.File} object. */ public void start_logfile(File p_filename) { @@ -672,6 +756,8 @@ public void repaint() /** * Repaints a rectangle of board panel on the screen. + * + * @param p_rect a {@link java.awt.Rectangle} object. */ public void repaint(Rectangle p_rect) { @@ -696,6 +782,8 @@ gui.BoardPanel get_panel() /** * Gets the popup menu used in the current interactive state. * Returns null, if the current state uses no popup menu. + * + * @return a {@link javax.swing.JPopupMenu} object. */ public javax.swing.JPopupMenu get_current_popup_menu() { @@ -714,6 +802,8 @@ public javax.swing.JPopupMenu get_current_popup_menu() /** * Draws the board and all temporary construction graphics in the * current interactive state. + * + * @param p_graphics a {@link java.awt.Graphics} object. */ public void draw(Graphics p_graphics) { @@ -741,6 +831,9 @@ public void draw(Graphics p_graphics) } } + /** + *

generate_snapshot.

+ */ public void generate_snapshot() { if (board_is_read_only) @@ -812,6 +905,8 @@ public void redo() /** * Actions to be taken in the current interactive state * when the left mouse butten is clicked. + * + * @param p_point a java$awt$geom$Point2D object. */ public void left_button_clicked(Point2D p_point) { @@ -841,6 +936,8 @@ public void left_button_clicked(Point2D p_point) /** * Actions to be taken in the current interactive state * when the mouse pointer has moved. + * + * @param p_point a java$awt$geom$Point2D object. */ public void mouse_moved(Point2D p_point) { @@ -868,6 +965,8 @@ public void mouse_moved(Point2D p_point) /** * Actions to be taken when the mouse button is pressed. + * + * @param p_point a java$awt$geom$Point2D object. */ public void mouse_pressed(Point2D p_point) { @@ -882,6 +981,8 @@ public void mouse_pressed(Point2D p_point) /** * Actions to be taken in the current interactive state * when the mouse is dragged. + * + * @param p_point a java$awt$geom$Point2D object. */ public void mouse_dragged(Point2D p_point) { @@ -919,6 +1020,8 @@ public void button_released() /** * Actions to be taken in the current interactive state * when the mouse wheel is moved + * + * @param p_rotation a int. */ public void mouse_wheel_moved(int p_rotation) { @@ -936,6 +1039,8 @@ public void mouse_wheel_moved(int p_rotation) /** * Action to be taken in the current interactive state * when a key on the keyboard is typed. + * + * @param p_key_char a char. */ public void key_typed_action(char p_key_char) { @@ -1001,6 +1106,9 @@ public void cancel_state() * Actions to be taken in the current interactive state when * the current board layer is changed. * Returns false, if the layer change failed. + * + * @param p_new_layer a int. + * @return a boolean. */ public boolean change_layer_action(int p_new_layer) { @@ -1042,6 +1150,10 @@ public void set_drag_menu_state() /** * Reads an existing board design from the input stream. * Returns false, if the input stream does not contains a legal board design. + * + * @param p_design a {@link java.io.ObjectInputStream} object. + * @param p_test_level a {@link board.TestLevel} object. + * @return a boolean. */ public boolean read_design(java.io.ObjectInputStream p_design, TestLevel p_test_level) { @@ -1067,6 +1179,12 @@ public boolean read_design(java.io.ObjectInputStream p_design, TestLevel p_test_ * The parameters p_item_observers and p_item_id_no_generator are used, * in case the board is embedded into a host system. * Returns false, if the dsn-file is currupted. + * + * @param p_design a java$io$InputStream object. + * @param p_observers a {@link board.BoardObservers} object. + * @param p_item_id_no_generator a {@link datastructures.IdNoGenerator} object. + * @param p_test_level a {@link board.TestLevel} object. + * @return a {@link designformats.specctra.DsnFile.ReadResult} object. */ public DsnFile.ReadResult import_design(java.io.InputStream p_design, board.BoardObservers p_observers, @@ -1115,6 +1233,11 @@ public DsnFile.ReadResult import_design(java.io.InputStream p_design, * Writes the currently edited board design to a text file in the Specctra dsn format. * If p_compat_mode is true, only standard speecctra dsn scopes are written, so that any * host system with an specctra interface can read them. + * + * @param p_output_stream a {@link java.io.OutputStream} object. + * @param p_design_name a {@link java.lang.String} object. + * @param p_compat_mode a boolean. + * @return a boolean. */ public boolean export_to_dsn_file(OutputStream p_output_stream, String p_design_name, boolean p_compat_mode) { @@ -1127,6 +1250,10 @@ public boolean export_to_dsn_file(OutputStream p_output_stream, String p_design_ /** * Writes a session file ins the Eaglea scr format. + * + * @param p_input_stream a java$io$InputStream object. + * @param p_output_stream a {@link java.io.OutputStream} object. + * @return a boolean. */ public boolean export_eagle_session_file(java.io.InputStream p_input_stream, OutputStream p_output_stream) { @@ -1139,6 +1266,10 @@ public boolean export_eagle_session_file(java.io.InputStream p_input_stream, Out /** * Writes a session file ins the Specctra ses-format. + * + * @param p_design_name a {@link java.lang.String} object. + * @param p_output_stream a {@link java.io.OutputStream} object. + * @return a boolean. */ public boolean export_specctra_session_file(String p_design_name, OutputStream p_output_stream) { @@ -1151,6 +1282,9 @@ public boolean export_specctra_session_file(String p_design_name, OutputStream p /** * Saves the currently edited board design to p_design_file. + * + * @param p_object_stream a {@link java.io.ObjectOutputStream} object. + * @return a boolean. */ public boolean save_design_file(java.io.ObjectOutputStream p_object_stream) { @@ -1172,6 +1306,8 @@ public boolean save_design_file(java.io.ObjectOutputStream p_object_stream) /** * Processes the actions stored in the input logfile. + * + * @param p_input_stream a java$io$InputStream object. */ public void read_logfile(InputStream p_input_stream) { @@ -1196,6 +1332,8 @@ public void close_files() /** * Starts interactive routing at the input location. + * + * @param p_point a java$awt$geom$Point2D object. */ public void start_route(Point2D p_point) { @@ -1212,6 +1350,8 @@ public void start_route(Point2D p_point) /** * Selects board items at the input location. + * + * @param p_point a java$awt$geom$Point2D object. */ public void select_items(Point2D p_point) { @@ -1240,6 +1380,8 @@ public void select_items_in_region() /** * Selects all items in the input collection. + * + * @param p_items a {@link java.util.Set} object. */ public void select_items(Set p_items) { @@ -1263,6 +1405,8 @@ else if (interactive_state instanceof SelectedItemState) /** * Looks for a swappable pin at p_location. * Prepares for pin swap if a swappable pin was found. + * + * @param p_location a java$awt$geom$Point2D object. */ public void swap_pin(Point2D p_location) { @@ -1296,6 +1440,8 @@ public void zoom_selection() * Removes it from the selected_items list, if it is already in there, * otherwise adds it to the list. * Changes to the selected items state, if something was selected. + * + * @param p_point a java$awt$geom$Point2D object. */ public void toggle_select_action(Point2D p_point) { @@ -1406,6 +1552,8 @@ public void cutout_selected_items() /** * Assigns the input clearance class to the selected items + * + * @param p_cl_class_index a int. */ public void assign_clearance_classs_to_selected_items(int p_cl_class_index) { @@ -1419,6 +1567,8 @@ public void assign_clearance_classs_to_selected_items(int p_cl_class_index) /** * Moves or rotates the selected items + * + * @param p_from_location a java$awt$geom$Point2D object. */ public void move_selected_items(Point2D p_from_location) { @@ -1437,6 +1587,8 @@ public void move_selected_items(Point2D p_from_location) /** * Copies all selected items. + * + * @param p_from_location a java$awt$geom$Point2D object. */ public void copy_selected_items(Point2D p_from_location) { @@ -1569,6 +1721,11 @@ public void toggle_selected_item_violations() ((SelectedItemState) interactive_state).toggle_clearance_violations(); } + /** + *

turn_45_degree.

+ * + * @param p_factor a int. + */ public void turn_45_degree(int p_factor) { if (board_is_read_only || !(interactive_state instanceof MoveItemState)) @@ -1579,6 +1736,9 @@ public void turn_45_degree(int p_factor) ((MoveItemState) interactive_state).turn_45_degree(p_factor); } + /** + *

change_placement_side.

+ */ public void change_placement_side() { if (board_is_read_only || !(interactive_state instanceof MoveItemState)) @@ -1599,6 +1759,8 @@ public void zoom_region() /** * Start interactively creating a circle obstacle. + * + * @param p_point a java$awt$geom$Point2D object. */ public void start_circle(Point2D p_point) { @@ -1613,6 +1775,8 @@ public void start_circle(Point2D p_point) /** * Start interactively creating a tile shaped obstacle. + * + * @param p_point a java$awt$geom$Point2D object. */ public void start_tile(Point2D p_point) { @@ -1627,6 +1791,8 @@ public void start_tile(Point2D p_point) /** * Start interactively creating a polygon shaped obstacle. + * + * @param p_point a java$awt$geom$Point2D object. */ public void start_polygonshape_item(Point2D p_point) { @@ -1643,6 +1809,8 @@ public void start_polygonshape_item(Point2D p_point) /** * Actions to be taken, when adding a hole to an existing obstacle shape * on the board is started. + * + * @param p_point a java$awt$geom$Point2D object. */ public void start_adding_hole(Point2D p_point) { @@ -1723,12 +1891,19 @@ void move_mouse(FloatPoint p_to_location) /** * Gets the current interactive state. + * + * @return a {@link interactive.InteractiveState} object. */ public InteractiveState get_interactive_state() { return this.interactive_state; } + /** + *

set_interactive_state.

+ * + * @param p_state a {@link interactive.InteractiveState} object. + */ public void set_interactive_state(InteractiveState p_state) { if (p_state != null && p_state != interactive_state) diff --git a/interactive/CircleConstructionState.java b/src/main/java/interactive/CircleConstructionState.java similarity index 87% rename from interactive/CircleConstructionState.java rename to src/main/java/interactive/CircleConstructionState.java index 9603921..42d737f 100644 --- a/interactive/CircleConstructionState.java +++ b/src/main/java/interactive/CircleConstructionState.java @@ -35,12 +35,19 @@ * Interactive creation of a circle obstacle * * @author Alfons Wirtz + * @version $Id: $Id */ public class CircleConstructionState extends InteractiveState { /** * Returns a new instance of this class. * If p_logfile != null; the creation of this item is stored in a logfile + * + * @param p_location a {@link geometry.planar.FloatPoint} object. + * @param p_parent_state a {@link interactive.InteractiveState} object. + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_logfile a {@link interactive.Logfile} object. + * @return a {@link interactive.CircleConstructionState} object. */ public static CircleConstructionState get_instance(FloatPoint p_location, InteractiveState p_parent_state, BoardHandling p_board_handling, Logfile p_logfile) @@ -60,6 +67,7 @@ private CircleConstructionState(FloatPoint p_location, InteractiveState p_parent } } + /** {@inheritDoc} */ public InteractiveState left_button_clicked(FloatPoint p_location) { if (logfile != null) @@ -69,6 +77,11 @@ public InteractiveState left_button_clicked(FloatPoint p_location) return this.complete(); } + /** + *

mouse_moved.

+ * + * @return a {@link interactive.InteractiveState} object. + */ public InteractiveState mouse_moved() { super.mouse_moved(); @@ -78,6 +91,8 @@ public InteractiveState mouse_moved() /** * completes the circle construction state + * + * @return a {@link interactive.InteractiveState} object. */ public InteractiveState complete() { @@ -134,6 +149,8 @@ else if (hdlg.get_routing_board().rules.get_trace_angle_restriction() == AngleRe } /** + * {@inheritDoc} + * * Used when reading the next point from a logfile. * Calls complete, because only 1 additional point is stored in the logfile. */ @@ -144,6 +161,8 @@ public InteractiveState process_logfile_point(FloatPoint p_point) } /** + * {@inheritDoc} + * * draws the graphic construction aid for the circle */ public void draw(java.awt.Graphics p_graphics) @@ -157,11 +176,19 @@ public void draw(java.awt.Graphics p_graphics) hdlg.graphics_context.draw_circle(circle_center, circle_radius, 300, java.awt.Color.white, p_graphics, 1); } + /** + *

get_popup_menu.

+ * + * @return a {@link javax.swing.JPopupMenu} object. + */ public javax.swing.JPopupMenu get_popup_menu() { return hdlg.get_panel().popup_menu_insert_cancel; } + /** + *

display_default_message.

+ */ public void display_default_message() { hdlg.screen_messages.set_status_message(resources.getString("creating_circle")); diff --git a/interactive/ClearanceViolations.java b/src/main/java/interactive/ClearanceViolations.java similarity index 85% rename from interactive/ClearanceViolations.java rename to src/main/java/interactive/ClearanceViolations.java index 8fe90d6..63f8335 100644 --- a/interactive/ClearanceViolations.java +++ b/src/main/java/interactive/ClearanceViolations.java @@ -36,11 +36,16 @@ * To display the clearance violations between items on the screen. * * @author alfons + * @version $Id: $Id */ public class ClearanceViolations { - /** Creates a new instance of ClearanceViolations */ + /** + * Creates a new instance of ClearanceViolations + * + * @param p_item_list a java$util$Collection object. + */ public ClearanceViolations(Collection p_item_list) { this.list = new LinkedList(); @@ -52,6 +57,13 @@ public ClearanceViolations(Collection p_item_list) } } + /** + *

draw.

+ * + * @param p_graphics a {@link java.awt.Graphics} object. + * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object. + * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object. + */ public void draw(Graphics p_graphics, GraphicsContext p_graphics_context) { java.awt.Color draw_color = p_graphics_context.get_violations_color(); diff --git a/interactive/CopyItemState.java b/src/main/java/interactive/CopyItemState.java similarity index 94% rename from interactive/CopyItemState.java rename to src/main/java/interactive/CopyItemState.java index dd844a2..2a1aa55 100644 --- a/interactive/CopyItemState.java +++ b/src/main/java/interactive/CopyItemState.java @@ -45,11 +45,19 @@ * Interactive copying of items. * * @author Alfons Wirtz + * @version $Id: $Id */ public class CopyItemState extends InteractiveState { /** * Returns a new instance of CopyItemState or null, if p_item_list is empty. + * + * @param p_location a {@link geometry.planar.FloatPoint} object. + * @param p_item_list a {@link java.util.Collection} object. + * @param p_parent_state a {@link interactive.InteractiveState} object. + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_logfile a {@link interactive.Logfile} object. + * @return a {@link interactive.CopyItemState} object. */ public static CopyItemState get_instance(FloatPoint p_location, Collection p_item_list, InteractiveState p_parent_state, BoardHandling p_board_handling, Logfile p_logfile) @@ -90,6 +98,11 @@ private CopyItemState(FloatPoint p_location, Collection p_item_list, } } + /** + *

mouse_moved.

+ * + * @return a {@link interactive.InteractiveState} object. + */ public InteractiveState mouse_moved() { super.mouse_moved(); @@ -118,6 +131,8 @@ private void change_position(FloatPoint p_new_position) } /** + * {@inheritDoc} + * * Changes the first layer of the items in the copy list to p_new_layer. */ public boolean change_layer_action(int p_new_layer) @@ -265,12 +280,14 @@ public void insert() hdlg.repaint(); } + /** {@inheritDoc} */ public InteractiveState left_button_clicked(FloatPoint p_location) { insert(); return this; } + /** {@inheritDoc} */ public InteractiveState process_logfile_point(FloatPoint p_location) { change_position(p_location); @@ -278,6 +295,7 @@ public InteractiveState process_logfile_point(FloatPoint p_location) return this; } + /** {@inheritDoc} */ public void draw(java.awt.Graphics p_graphics) { if (item_list == null) @@ -293,6 +311,11 @@ public void draw(java.awt.Graphics p_graphics) } } + /** + *

get_popup_menu.

+ * + * @return a {@link javax.swing.JPopupMenu} object. + */ public javax.swing.JPopupMenu get_popup_menu() { return hdlg.get_panel().popup_menu_copy; diff --git a/interactive/CornerItemConstructionState.java b/src/main/java/interactive/CornerItemConstructionState.java similarity index 88% rename from interactive/CornerItemConstructionState.java rename to src/main/java/interactive/CornerItemConstructionState.java index 613de87..412089a 100644 --- a/interactive/CornerItemConstructionState.java +++ b/src/main/java/interactive/CornerItemConstructionState.java @@ -28,11 +28,18 @@ * Common class for constructing an obstacle with a polygonal shape. * * @author Alfons Wirtz + * @version $Id: $Id */ public class CornerItemConstructionState extends InteractiveState { - /** Creates a new instance of CornerItemConstructionState */ + /** + * Creates a new instance of CornerItemConstructionState + * + * @param p_parent_state a {@link interactive.InteractiveState} object. + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_logfile a {@link interactive.Logfile} object. + */ protected CornerItemConstructionState(InteractiveState p_parent_state, BoardHandling p_board_handling, Logfile p_logfile) { super(p_parent_state, p_board_handling, p_logfile); @@ -40,6 +47,8 @@ protected CornerItemConstructionState(InteractiveState p_parent_state, BoardHand } /** + * {@inheritDoc} + * * adds a corner to the polygon of the item under construction */ public InteractiveState left_button_clicked(FloatPoint p_location) @@ -49,6 +58,9 @@ public InteractiveState left_button_clicked(FloatPoint p_location) /** * adds a corner to the polygon of the item under construction + * + * @param p_location a {@link geometry.planar.FloatPoint} object. + * @return a {@link interactive.InteractiveState} object. */ public InteractiveState add_corner(FloatPoint p_location) { @@ -63,6 +75,7 @@ public InteractiveState add_corner(FloatPoint p_location) return this; } + /** {@inheritDoc} */ public InteractiveState process_logfile_point(FloatPoint p_point) { return add_corner(p_point); @@ -70,6 +83,8 @@ public InteractiveState process_logfile_point(FloatPoint p_point) /** * stores the location of the mouse pointer after snapping it to the snap_angle + * + * @return a {@link interactive.InteractiveState} object. */ public InteractiveState mouse_moved() { @@ -81,12 +96,19 @@ public InteractiveState mouse_moved() } + /** + *

get_popup_menu.

+ * + * @return a {@link javax.swing.JPopupMenu} object. + */ public javax.swing.JPopupMenu get_popup_menu() { return hdlg.get_panel().popup_menu_corneritem_construction; } /** + * {@inheritDoc} + * * draws the polygon constructed so far as a visual aid */ public void draw(java.awt.Graphics p_graphics) diff --git a/interactive/CutoutRouteState.java b/src/main/java/interactive/CutoutRouteState.java similarity index 83% rename from interactive/CutoutRouteState.java rename to src/main/java/interactive/CutoutRouteState.java index 1936185..fd15566 100644 --- a/interactive/CutoutRouteState.java +++ b/src/main/java/interactive/CutoutRouteState.java @@ -34,14 +34,22 @@ import board.PolylineTrace; /** + *

CutoutRouteState class.

* * @author Alfons Wirtz + * @version $Id: $Id */ public class CutoutRouteState extends SelectRegionState { /** * Returns a new instance of this class. + * + * @param p_item_list a {@link java.util.Collection} object. + * @param p_parent_state a {@link interactive.InteractiveState} object. + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_logfile a {@link interactive.Logfile} object. + * @return a {@link interactive.CutoutRouteState} object. */ public static CutoutRouteState get_instance( Collection p_item_list, InteractiveState p_parent_state, BoardHandling p_board_handling, Logfile p_logfile) @@ -51,6 +59,13 @@ public static CutoutRouteState get_instance( Collection p_item_list, Inter /** * Returns a new instance of this class. + * + * @param p_item_list a {@link java.util.Collection} object. + * @param p_location a {@link geometry.planar.FloatPoint} object. + * @param p_parent_state a {@link interactive.InteractiveState} object. + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_logfile a {@link interactive.Logfile} object. + * @return a {@link interactive.CutoutRouteState} object. */ public static CutoutRouteState get_instance( Collection p_item_list, FloatPoint p_location, InteractiveState p_parent_state, BoardHandling p_board_handling, Logfile p_logfile) @@ -88,6 +103,11 @@ private CutoutRouteState(Collection p_item_list, InteractiveState this.trace_list = p_item_list; } + /** + *

complete.

+ * + * @return a {@link interactive.InteractiveState} object. + */ public InteractiveState complete() { hdlg.screen_messages.set_status_message(""); @@ -134,6 +154,7 @@ private void cutout_route() } } + /** {@inheritDoc} */ public void draw(java.awt.Graphics p_graphics) { if (trace_list == null) diff --git a/interactive/DragItemState.java b/src/main/java/interactive/DragItemState.java similarity index 91% rename from interactive/DragItemState.java rename to src/main/java/interactive/DragItemState.java index 66b914a..75c6ca6 100644 --- a/interactive/DragItemState.java +++ b/src/main/java/interactive/DragItemState.java @@ -36,11 +36,20 @@ * Class for interactive dragging items with the mouse on a routing board * * @author Alfons Wirtz + * @version $Id: $Id */ public class DragItemState extends DragState { - /** Creates a new instance of MoveItemState */ + /** + * Creates a new instance of MoveItemState + * + * @param p_item_to_move a {@link board.Item} object. + * @param p_location a {@link geometry.planar.FloatPoint} object. + * @param p_parent_state a {@link interactive.InteractiveState} object. + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_logfile a {@link interactive.Logfile} object. + */ protected DragItemState(Item p_item_to_move, FloatPoint p_location, InteractiveState p_parent_state, BoardHandling p_board_handling, Logfile p_logfile) { super(p_location, p_parent_state, p_board_handling, p_logfile); @@ -48,12 +57,17 @@ protected DragItemState(Item p_item_to_move, FloatPoint p_location, InteractiveS } + /** + *

display_default_message.

+ */ public void display_default_message() { hdlg.screen_messages.set_status_message(resources.getString("dragging_item")); } /** + * {@inheritDoc} + * * Moves the items of the group to p_to_location. * Return this.return_state, if an error eccured while moving, * so that an undo may be necessary. @@ -136,6 +150,11 @@ else if (hdlg.get_routing_board().rules.get_trace_angle_restriction() == AngleRe return this; } + /** + *

button_released.

+ * + * @return a {@link interactive.InteractiveState} object. + */ public InteractiveState button_released() { if (this.observers_activated) diff --git a/interactive/DragMenuState.java b/src/main/java/interactive/DragMenuState.java similarity index 70% rename from interactive/DragMenuState.java rename to src/main/java/interactive/DragMenuState.java index 3aefd97..31904f8 100644 --- a/interactive/DragMenuState.java +++ b/src/main/java/interactive/DragMenuState.java @@ -26,27 +26,45 @@ * Class implementing the different functionality in the drag menu * * @author alfons + * @version $Id: $Id */ public class DragMenuState extends MenuState { - /** Returns a new instance of DragMenuState */ + /** + * Returns a new instance of DragMenuState + * + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_logfile a {@link interactive.Logfile} object. + * @return a {@link interactive.DragMenuState} object. + */ public static DragMenuState get_instance(BoardHandling p_board_handling, Logfile p_logfile) { DragMenuState new_state = new DragMenuState(p_board_handling, p_logfile); return new_state; } - /** Creates a new instance of DragMenuState */ + /** + * Creates a new instance of DragMenuState + * + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_logfile a {@link interactive.Logfile} object. + */ public DragMenuState(BoardHandling p_board_handling, Logfile p_logfile) { super(p_board_handling, p_logfile); } + /** {@inheritDoc} */ public InteractiveState mouse_pressed(FloatPoint p_point) { return DragState.get_instance(p_point, this, hdlg, logfile); } + /** + *

get_help_id.

+ * + * @return a {@link java.lang.String} object. + */ public String get_help_id() { return "MenuState_DragMenuState"; diff --git a/interactive/DragState.java b/src/main/java/interactive/DragState.java similarity index 82% rename from interactive/DragState.java rename to src/main/java/interactive/DragState.java index c584925..f993a70 100644 --- a/interactive/DragState.java +++ b/src/main/java/interactive/DragState.java @@ -32,12 +32,19 @@ * Class implementing functionality when the mouse is dragged on a routing board * * @author Alfons Wirtz + * @version $Id: $Id */ public abstract class DragState extends InteractiveState { /** * Returns a new instance of this state, if a item to drag was found at the input * location; null otherwise. + * + * @param p_location a {@link geometry.planar.FloatPoint} object. + * @param p_parent_state a {@link interactive.InteractiveState} object. + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_logfile a {@link interactive.Logfile} object. + * @return a {@link interactive.DragState} object. */ public static DragState get_instance(FloatPoint p_location, InteractiveState p_parent_state, BoardHandling p_board_handling, Logfile p_logfile) @@ -108,16 +115,30 @@ else if (!item_found) return result; } - /** Creates a new instance of DragState */ + /** + * Creates a new instance of DragState + * + * @param p_location a {@link geometry.planar.FloatPoint} object. + * @param p_parent_state a {@link interactive.InteractiveState} object. + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_logfile a {@link interactive.Logfile} object. + */ protected DragState(FloatPoint p_location, InteractiveState p_parent_state, BoardHandling p_board_handling, Logfile p_logfile) { super(p_parent_state, p_board_handling, p_logfile); previous_location = p_location; } + /** + *

move_to.

+ * + * @param p_to_location a {@link geometry.planar.FloatPoint} object. + * @return a {@link interactive.InteractiveState} object. + */ public abstract InteractiveState move_to(FloatPoint p_to_location); + /** {@inheritDoc} */ public InteractiveState mouse_dragged(FloatPoint p_point) { InteractiveState result = this.move_to(p_point); @@ -141,12 +162,18 @@ public InteractiveState mouse_dragged(FloatPoint p_point) return result; } + /** + *

complete.

+ * + * @return a {@link interactive.InteractiveState} object. + */ public InteractiveState complete() { return this.button_released(); } + /** {@inheritDoc} */ public InteractiveState process_logfile_point(FloatPoint p_point) { return move_to(p_point); @@ -156,4 +183,4 @@ public InteractiveState process_logfile_point(FloatPoint p_point) protected FloatPoint previous_location; protected boolean something_dragged = false; protected boolean observers_activated = false; -} \ No newline at end of file +} diff --git a/interactive/DynamicRouteState.java b/src/main/java/interactive/DynamicRouteState.java similarity index 78% rename from interactive/DynamicRouteState.java rename to src/main/java/interactive/DynamicRouteState.java index aebbdc7..1437763 100644 --- a/interactive/DynamicRouteState.java +++ b/src/main/java/interactive/DynamicRouteState.java @@ -26,16 +26,28 @@ * State for dynamic interactive routing, which is routing while moving the mouse pointer. * * @author Alfons Wirtz + * @version $Id: $Id */ public class DynamicRouteState extends RouteState { - /** Creates a new instance of DynamicRouteState */ + /** + * Creates a new instance of DynamicRouteState + * + * @param p_parent_state a {@link interactive.InteractiveState} object. + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_logfile a {@link interactive.Logfile} object. + */ protected DynamicRouteState(InteractiveState p_parent_state, BoardHandling p_board_handling, Logfile p_logfile) { super(p_parent_state, p_board_handling, p_logfile); } + /** + *

mouse_moved.

+ * + * @return a {@link interactive.InteractiveState} object. + */ public InteractiveState mouse_moved() { super.mouse_moved(); @@ -43,6 +55,8 @@ public InteractiveState mouse_moved() } /** + * {@inheritDoc} + * * ends routing */ public InteractiveState left_button_clicked(FloatPoint p_location) @@ -64,6 +78,8 @@ public InteractiveState left_button_clicked(FloatPoint p_location) } /** + * {@inheritDoc} + * * Action to be taken when a key is pressed (Shortcut). */ public InteractiveState key_typed(char p_key_char) @@ -80,11 +96,21 @@ public InteractiveState key_typed(char p_key_char) return curr_return_state; } + /** + *

get_popup_menu.

+ * + * @return a {@link javax.swing.JPopupMenu} object. + */ public javax.swing.JPopupMenu get_popup_menu() { return hdlg.get_panel().popup_menu_dynamic_route; } + /** + *

get_help_id.

+ * + * @return a {@link java.lang.String} object. + */ public String get_help_id() { return "RouteState_DynamicRouteState"; diff --git a/interactive/ExpandTestState.java b/src/main/java/interactive/ExpandTestState.java similarity index 94% rename from interactive/ExpandTestState.java rename to src/main/java/interactive/ExpandTestState.java index 6dacb24..d9d90ab 100644 --- a/interactive/ExpandTestState.java +++ b/src/main/java/interactive/ExpandTestState.java @@ -43,10 +43,19 @@ * State for testing the expanding algorithm of the autorouter. * * @author Alfons Wirtz + * @version $Id: $Id */ public class ExpandTestState extends InteractiveState { + /** + *

get_instance.

+ * + * @param p_location a {@link geometry.planar.FloatPoint} object. + * @param p_return_state a {@link interactive.InteractiveState} object. + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @return a {@link interactive.ExpandTestState} object. + */ public static ExpandTestState get_instance(FloatPoint p_location, InteractiveState p_return_state, BoardHandling p_board_handling) { ExpandTestState result = new ExpandTestState(p_location, p_return_state, p_board_handling); @@ -61,6 +70,7 @@ private ExpandTestState(FloatPoint p_location, InteractiveState p_return_state, } + /** {@inheritDoc} */ public InteractiveState key_typed(char p_key_char) { InteractiveState result; @@ -151,22 +161,34 @@ else if (Character.isDigit(p_key_char)) return result; } + /** {@inheritDoc} */ public InteractiveState left_button_clicked(FloatPoint p_location) { return cancel(); } + /** + *

cancel.

+ * + * @return a {@link interactive.InteractiveState} object. + */ public InteractiveState cancel() { autoroute_engine.clear(); return this.return_state; } + /** + *

complete.

+ * + * @return a {@link interactive.InteractiveState} object. + */ public InteractiveState complete() { return cancel(); } + /** {@inheritDoc} */ public void draw(java.awt.Graphics p_graphics) { autoroute_engine.draw(p_graphics, hdlg.graphics_context, 0.1); diff --git a/interactive/HoleConstructionState.java b/src/main/java/interactive/HoleConstructionState.java similarity index 93% rename from interactive/HoleConstructionState.java rename to src/main/java/interactive/HoleConstructionState.java index 20b01f3..56d149d 100644 --- a/interactive/HoleConstructionState.java +++ b/src/main/java/interactive/HoleConstructionState.java @@ -38,6 +38,7 @@ * Interactive cutting a hole into an obstacle shape * * @author Alfons Wirtz + * @version $Id: $Id */ public class HoleConstructionState extends CornerItemConstructionState { @@ -45,6 +46,12 @@ public class HoleConstructionState extends CornerItemConstructionState * Returns a new instance of this class or null, * if that was not possible with the input parameters. * If p_logfile != null, the construction of this hole is stored in a logfile. + * + * @param p_location a {@link geometry.planar.FloatPoint} object. + * @param p_parent_state a {@link interactive.InteractiveState} object. + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_logfile a {@link interactive.Logfile} object. + * @return a {@link interactive.HoleConstructionState} object. */ public static HoleConstructionState get_instance(FloatPoint p_location, InteractiveState p_parent_state, BoardHandling p_board_handling, Logfile p_logfile) { @@ -103,6 +110,8 @@ private boolean start_ok(FloatPoint p_location) } /** + * {@inheritDoc} + * * Adds a corner to the polygon of the the hole under construction. */ public InteractiveState left_button_clicked(FloatPoint p_next_corner) @@ -122,6 +131,8 @@ public InteractiveState left_button_clicked(FloatPoint p_next_corner) /** * adds the just constructed hole to the item under modification, * if that is possible without clearance violations + * + * @return a {@link interactive.InteractiveState} object. */ public InteractiveState complete() { @@ -206,6 +217,9 @@ public InteractiveState complete() return this.return_state; } + /** + *

display_default_message.

+ */ public void display_default_message() { hdlg.screen_messages.set_status_message(resources.getString("adding_hole_to_obstacle_area")); diff --git a/interactive/InteractiveActionThread.java b/src/main/java/interactive/InteractiveActionThread.java similarity index 82% rename from interactive/InteractiveActionThread.java rename to src/main/java/interactive/InteractiveActionThread.java index cf20938..d62be64 100644 --- a/interactive/InteractiveActionThread.java +++ b/src/main/java/interactive/InteractiveActionThread.java @@ -1,233 +1,288 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - * - * InteractiveActionThread.java - * - * Created on 2. Maerz 2006, 07:23 - * - */ -package interactive; - -/** - * Used for running an interactive action in a seperate Thread, - * that can be stopped by the user. - * - * @author Alfons Wirtz - */ -public abstract class InteractiveActionThread extends Thread implements datastructures.Stoppable -{ - - public static InteractiveActionThread get_autoroute_instance(BoardHandling p_board_handling) - { - return new AutorouteThread(p_board_handling); - } - - public static InteractiveActionThread get_batch_autorouter_instance(BoardHandling p_board_handling) - { - return new BatchAutorouterThread(p_board_handling); - } - - public static InteractiveActionThread get_fanout_instance(BoardHandling p_board_handling) - { - return new FanoutThread(p_board_handling); - } - - public static InteractiveActionThread get_pull_tight_instance(BoardHandling p_board_handling) - { - return new PullTightThread(p_board_handling); - } - - public static InteractiveActionThread get_read_logfile_instance(BoardHandling p_board_handling, java.io.InputStream p_input_stream) - { - return new ReadLogfileThread(p_board_handling, p_input_stream); - } - - /** Creates a new instance of InteractiveActionThread */ - protected InteractiveActionThread(BoardHandling p_board_handling) - { - this.hdlg = p_board_handling; - } - - protected abstract void thread_action(); - - public void run() - { - thread_action(); - hdlg.repaint(); - } - - public synchronized void request_stop() - { - stop_requested = true; - } - - public synchronized boolean is_stop_requested() - { - return stop_requested; - } - - public synchronized void draw(java.awt.Graphics p_graphics) - { - // Can be overwritten in derived classes. - } - private boolean stop_requested = false; - public final BoardHandling hdlg; - - private static class AutorouteThread extends InteractiveActionThread - { - - private AutorouteThread(BoardHandling p_board_handling) - { - super(p_board_handling); - } - - protected void thread_action() - { - if (!(hdlg.interactive_state instanceof SelectedItemState)) - { - return; - } - InteractiveState return_state = ((SelectedItemState) hdlg.interactive_state).autoroute(this); - hdlg.set_interactive_state(return_state); - } - } - - private static class FanoutThread extends InteractiveActionThread - { - - private FanoutThread(BoardHandling p_board_handling) - { - super(p_board_handling); - } - - protected void thread_action() - { - if (!(hdlg.interactive_state instanceof SelectedItemState)) - { - return; - } - InteractiveState return_state = ((SelectedItemState) hdlg.interactive_state).fanout(this); - hdlg.set_interactive_state(return_state); - } - } - - private static class PullTightThread extends InteractiveActionThread - { - - private PullTightThread(BoardHandling p_board_handling) - { - super(p_board_handling); - } - - protected void thread_action() - { - if (!(hdlg.interactive_state instanceof SelectedItemState)) - { - return; - } - InteractiveState return_state = ((SelectedItemState) hdlg.interactive_state).pull_tight(this); - hdlg.set_interactive_state(return_state); - } - } - - private static class ReadLogfileThread extends InteractiveActionThread - { - - private ReadLogfileThread(BoardHandling p_board_handling, java.io.InputStream p_input_stream) - { - super(p_board_handling); - this.input_stream = p_input_stream; - } - - protected void thread_action() - { - - java.util.ResourceBundle resources = - java.util.ResourceBundle.getBundle("interactive.resources.InteractiveState", hdlg.get_locale()); - boolean saved_board_read_only = hdlg.is_board_read_only(); - hdlg.set_board_read_only(true); - String start_message = resources.getString("logfile") + " " + resources.getString("stop_message"); - hdlg.screen_messages.set_status_message(start_message); - hdlg.screen_messages.set_write_protected(true); - boolean done = false; - InteractiveState previous_state = hdlg.interactive_state; - if (!hdlg.logfile.start_read(this.input_stream)) - { - done = true; - } - boolean interrupted = false; - int debug_counter = 0; - hdlg.get_panel().board_frame.refresh_windows(); - hdlg.paint_immediately = true; - while (!done) - { - if (is_stop_requested()) - { - interrupted = true; - done = true; - } - ++debug_counter; - LogfileScope logfile_scope = hdlg.logfile.start_read_scope(); - if (logfile_scope == null) - { - done = true; // end of logfile - } - if (!done) - { - try - { - InteractiveState new_state = - logfile_scope.read_scope(hdlg.logfile, hdlg.interactive_state, hdlg); - if (new_state == null) - { - System.out.println("BoardHandling:read_logfile: inconsistent logfile scope"); - new_state = previous_state; - } - hdlg.repaint(); - hdlg.set_interactive_state(new_state); - } catch (Exception e) - { - done = true; - } - - } - } - hdlg.paint_immediately = false; - try - { - this.input_stream.close(); - } catch (java.io.IOException e) - { - System.out.println("ReadLogfileThread: unable to close input stream"); - } - hdlg.get_panel().board_frame.refresh_windows(); - hdlg.screen_messages.set_write_protected(false); - String curr_message; - if (interrupted) - { - curr_message = resources.getString("interrupted"); - } - else - { - curr_message = resources.getString("completed"); - } - String end_message = resources.getString("logfile") + " " + curr_message; - hdlg.screen_messages.set_status_message(end_message); - hdlg.set_board_read_only(saved_board_read_only); - hdlg.get_panel().board_frame.repaint_all(); - } - private final java.io.InputStream input_stream; - } -} +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + * + * InteractiveActionThread.java + * + * Created on 2. Maerz 2006, 07:23 + * + */ +package interactive; + +/** + * Used for running an interactive action in a seperate Thread, + * that can be stopped by the user. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public abstract class InteractiveActionThread extends Thread implements datastructures.Stoppable +{ + + /** + *

get_autoroute_instance.

+ * + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @return a {@link interactive.InteractiveActionThread} object. + */ + public static InteractiveActionThread get_autoroute_instance(BoardHandling p_board_handling) + { + return new AutorouteThread(p_board_handling); + } + + /** + *

get_batch_autorouter_instance.

+ * + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @return a {@link interactive.InteractiveActionThread} object. + */ + public static InteractiveActionThread get_batch_autorouter_instance(BoardHandling p_board_handling) + { + return new BatchAutorouterThread(p_board_handling); + } + + /** + *

get_fanout_instance.

+ * + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @return a {@link interactive.InteractiveActionThread} object. + */ + public static InteractiveActionThread get_fanout_instance(BoardHandling p_board_handling) + { + return new FanoutThread(p_board_handling); + } + + /** + *

get_pull_tight_instance.

+ * + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @return a {@link interactive.InteractiveActionThread} object. + */ + public static InteractiveActionThread get_pull_tight_instance(BoardHandling p_board_handling) + { + return new PullTightThread(p_board_handling); + } + + /** + *

get_read_logfile_instance.

+ * + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_input_stream a {@link java.io.InputStream} object. + * @return a {@link interactive.InteractiveActionThread} object. + */ + public static InteractiveActionThread get_read_logfile_instance(BoardHandling p_board_handling, java.io.InputStream p_input_stream) + { + return new ReadLogfileThread(p_board_handling, p_input_stream); + } + + /** + * Creates a new instance of InteractiveActionThread + * + * @param p_board_handling a {@link interactive.BoardHandling} object. + */ + protected InteractiveActionThread(BoardHandling p_board_handling) + { + this.hdlg = p_board_handling; + } + + /** + *

thread_action.

+ */ + protected abstract void thread_action(); + + /** + *

run.

+ */ + public void run() + { + thread_action(); + hdlg.repaint(); + } + + /** + *

request_stop.

+ */ + public synchronized void request_stop() + { + stop_requested = true; + } + + /** + *

is_stop_requested.

+ * + * @return a boolean. + */ + public synchronized boolean is_stop_requested() + { + return stop_requested; + } + + /** + *

draw.

+ * + * @param p_graphics a {@link java.awt.Graphics} object. + */ + public synchronized void draw(java.awt.Graphics p_graphics) + { + // Can be overwritten in derived classes. + } + private boolean stop_requested = false; + public final BoardHandling hdlg; + + private static class AutorouteThread extends InteractiveActionThread + { + + private AutorouteThread(BoardHandling p_board_handling) + { + super(p_board_handling); + } + + protected void thread_action() + { + if (!(hdlg.interactive_state instanceof SelectedItemState)) + { + return; + } + InteractiveState return_state = ((SelectedItemState) hdlg.interactive_state).autoroute(this); + hdlg.set_interactive_state(return_state); + } + } + + private static class FanoutThread extends InteractiveActionThread + { + + private FanoutThread(BoardHandling p_board_handling) + { + super(p_board_handling); + } + + protected void thread_action() + { + if (!(hdlg.interactive_state instanceof SelectedItemState)) + { + return; + } + InteractiveState return_state = ((SelectedItemState) hdlg.interactive_state).fanout(this); + hdlg.set_interactive_state(return_state); + } + } + + private static class PullTightThread extends InteractiveActionThread + { + + private PullTightThread(BoardHandling p_board_handling) + { + super(p_board_handling); + } + + protected void thread_action() + { + if (!(hdlg.interactive_state instanceof SelectedItemState)) + { + return; + } + InteractiveState return_state = ((SelectedItemState) hdlg.interactive_state).pull_tight(this); + hdlg.set_interactive_state(return_state); + } + } + + private static class ReadLogfileThread extends InteractiveActionThread + { + + private ReadLogfileThread(BoardHandling p_board_handling, java.io.InputStream p_input_stream) + { + super(p_board_handling); + this.input_stream = p_input_stream; + } + + protected void thread_action() + { + + java.util.ResourceBundle resources = + java.util.ResourceBundle.getBundle("interactive.resources.InteractiveState", hdlg.get_locale()); + boolean saved_board_read_only = hdlg.is_board_read_only(); + hdlg.set_board_read_only(true); + String start_message = resources.getString("logfile") + " " + resources.getString("stop_message"); + hdlg.screen_messages.set_status_message(start_message); + hdlg.screen_messages.set_write_protected(true); + boolean done = false; + InteractiveState previous_state = hdlg.interactive_state; + if (!hdlg.logfile.start_read(this.input_stream)) + { + done = true; + } + boolean interrupted = false; + int debug_counter = 0; + hdlg.get_panel().board_frame.refresh_windows(); + hdlg.paint_immediately = true; + while (!done) + { + if (is_stop_requested()) + { + interrupted = true; + done = true; + } + ++debug_counter; + LogfileScope logfile_scope = hdlg.logfile.start_read_scope(); + if (logfile_scope == null) + { + done = true; // end of logfile + } + if (!done) + { + try + { + InteractiveState new_state = + logfile_scope.read_scope(hdlg.logfile, hdlg.interactive_state, hdlg); + if (new_state == null) + { + System.out.println("BoardHandling:read_logfile: inconsistent logfile scope"); + new_state = previous_state; + } + hdlg.repaint(); + hdlg.set_interactive_state(new_state); + } catch (Exception e) + { + done = true; + } + + } + } + hdlg.paint_immediately = false; + try + { + this.input_stream.close(); + } catch (java.io.IOException e) + { + System.out.println("ReadLogfileThread: unable to close input stream"); + } + hdlg.get_panel().board_frame.refresh_windows(); + hdlg.screen_messages.set_write_protected(false); + String curr_message; + if (interrupted) + { + curr_message = resources.getString("interrupted"); + } + else + { + curr_message = resources.getString("completed"); + } + String end_message = resources.getString("logfile") + " " + curr_message; + hdlg.screen_messages.set_status_message(end_message); + hdlg.set_board_read_only(saved_board_read_only); + hdlg.get_panel().board_frame.repaint_all(); + } + private final java.io.InputStream input_stream; + } +} diff --git a/interactive/InteractiveState.java b/src/main/java/interactive/InteractiveState.java similarity index 84% rename from interactive/InteractiveState.java rename to src/main/java/interactive/InteractiveState.java index 5cab9b7..c4ef8c3 100644 --- a/interactive/InteractiveState.java +++ b/src/main/java/interactive/InteractiveState.java @@ -28,11 +28,17 @@ * Common base class of all interaction states with the graphical interface * * @author Alfons Wirtz - * + * @version $Id: $Id */ public class InteractiveState { - /** Creates a new instance of InteractiveState */ + /** + * Creates a new instance of InteractiveState + * + * @param p_return_state a {@link interactive.InteractiveState} object. + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_logfile a {@link interactive.Logfile} object. + */ protected InteractiveState(InteractiveState p_return_state, BoardHandling p_board_handling, Logfile p_logfile) { this.return_state = p_return_state; @@ -44,6 +50,8 @@ protected InteractiveState(InteractiveState p_return_state, BoardHandling p_boar /** * default draw function to be overwritten in derived classes + * + * @param p_graphics a {@link java.awt.Graphics} object. */ public void draw(Graphics p_graphics) { @@ -53,6 +61,9 @@ public void draw(Graphics p_graphics) * Default function to be overwritten in derived classes. * Returns the return_state of this state, if the state is left * after the method, or else this state. + * + * @param p_location a {@link geometry.planar.FloatPoint} object. + * @return a {@link interactive.InteractiveState} object. */ public InteractiveState left_button_clicked(FloatPoint p_location) { @@ -65,6 +76,11 @@ public InteractiveState left_button_clicked(FloatPoint p_location) * Returns the return_state of this state, if the state is left * after the method, or else this state. */ + /** + *

button_released.

+ * + * @return a {@link interactive.InteractiveState} object. + */ public InteractiveState button_released() { return this; @@ -75,6 +91,8 @@ public InteractiveState button_released() * Default function to be overwritten in derived classes. * Returns the return_state of this state, if the state ends * after the method, or else this state. + * + * @return a {@link interactive.InteractiveState} object. */ public InteractiveState mouse_moved() { @@ -89,6 +107,9 @@ public InteractiveState mouse_moved() * Default function to be overwritten in derived classes. * Returns the return_state of this state, if the state is left * after the method, or else this state. + * + * @param p_point a {@link geometry.planar.FloatPoint} object. + * @return a {@link interactive.InteractiveState} object. */ public InteractiveState mouse_dragged(FloatPoint p_point) { @@ -100,6 +121,9 @@ public InteractiveState mouse_dragged(FloatPoint p_point) * Default function to be overwritten in derived classes. * Returns the return_state of this state, if the state is left * after the method, or else this state. + * + * @param p_point a {@link geometry.planar.FloatPoint} object. + * @return a {@link interactive.InteractiveState} object. */ public InteractiveState mouse_pressed(FloatPoint p_point) { @@ -108,6 +132,9 @@ public InteractiveState mouse_pressed(FloatPoint p_point) /** * Action to be taken, when the mouse wheel was turned.. + * + * @param p_rotation a int. + * @return a {@link interactive.InteractiveState} object. */ public InteractiveState mouse_wheel_moved(int p_rotation) { @@ -120,6 +147,9 @@ public InteractiveState mouse_wheel_moved(int p_rotation) /** * Default actions when a key shortcut is pressed. * Overwritten in derived classes for other key shortcut actions. + * + * @param p_key_char a char. + * @return a {@link interactive.InteractiveState} object. */ public InteractiveState key_typed(char p_key_char) { @@ -189,6 +219,8 @@ else if (Character.isDigit(p_key_char)) * Action to be taken, when this state is completed and exited. * Default function to be overwritten in derived classes. * Returns the return_state of this state. + * + * @return a {@link interactive.InteractiveState} object. */ public InteractiveState complete() { @@ -203,6 +235,8 @@ public InteractiveState complete() * Actions to be taken, when this state gets cancelled. * Default function to be overwritten in derived classes. * Returns the parent state of this state. + * + * @return a {@link interactive.InteractiveState} object. */ public InteractiveState cancel() { @@ -217,6 +251,9 @@ public InteractiveState cancel() * Action to be taken, when the current layer is changed. * returns false, if the layer could not be changed, * Default function to be overwritten in derived classes. + * + * @param p_new_layer a int. + * @return a boolean. */ public boolean change_layer_action(int p_new_layer) { @@ -227,6 +264,9 @@ public boolean change_layer_action(int p_new_layer) /** * Used when reading the next point from a logfile. * Default function to be overwritten in derived classes. + * + * @param p_point a {@link geometry.planar.FloatPoint} object. + * @return a {@link interactive.InteractiveState} object. */ public InteractiveState process_logfile_point(FloatPoint p_point) { @@ -242,6 +282,8 @@ public void display_default_message() /** * Gets the identifier for displaying help for the user about this state. + * + * @return a {@link java.lang.String} object. */ public String get_help_id() { @@ -252,6 +294,8 @@ public String get_help_id() /** * Returns the popup menu from board_panel, which is used in this interactive state. * Default function to be overwritten in derived classes. + * + * @return a {@link javax.swing.JPopupMenu} object. */ public javax.swing.JPopupMenu get_popup_menu() { diff --git a/interactive/Logfile.java b/src/main/java/interactive/Logfile.java similarity index 88% rename from interactive/Logfile.java rename to src/main/java/interactive/Logfile.java index 3973787..ac78c1a 100644 --- a/interactive/Logfile.java +++ b/src/main/java/interactive/Logfile.java @@ -1,279 +1,305 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - */ - -package interactive; - -import geometry.planar.FloatPoint; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStream; - -/** - * Logfile to track the actions in the interactive board handling - * for automatic replay. - * - * @author Alfons Wirtz - * - */ - -public class Logfile -{ - /** - * opens the logfile for reading - */ - public boolean start_read(InputStream p_input_stream) - { - this.scanner = new LogfileScanner(p_input_stream); - return (this.scanner != null); - } - - /** - * Reads the next corner from the logfile. - * Return null, if no valid corner is found. - */ - public FloatPoint read_corner() - { - - double x = 0; - double y = 0; - for (int i = 0; i < 2; ++i) - { - Object curr_ob = this.next_token(); - if (!(curr_ob instanceof Double)) - { - this.pending_token = curr_ob; - return null; - } - double f = ((Double) curr_ob).doubleValue(); - if (i == 0) - { - x = f; - } - else - { - y = f; - } - } - return new FloatPoint(x, y); - } - - /** - * closes the logfile after writing - */ - public void close_output() - { - if (this.file_writer != null) - { - try - { - this.file_writer.close(); - } - catch (IOException e) - { - System.out.println("unable to close logfile"); - } - } - this.write_enabled = false; - } - - /** - * opens a logfile for writing - */ - public boolean start_write(File p_file) - { - try - { - this.file_writer = new FileWriter(p_file); - } - catch (IOException e) - { - System.out.println("unable to create logfile"); - return false; - } - write_enabled = true; - return true; - } - - /** - * Marks the beginning of a new item in the olutput stream - */ - public void start_scope(LogfileScope p_logfile_scope) - { - if (write_enabled) - { - try - { - this.file_writer.write(p_logfile_scope.name); - this.file_writer.write("\n"); - } - catch (IOException e2) - { - System.out.println("Logfile.start_scope: write failed"); - } - } - } - - /** - * Marks the beginning of a new scope in the olutput stream - * Writes also an integer value. - */ - public void start_scope(LogfileScope p_logfile_scope, int p_int_value) - { - start_scope(p_logfile_scope); - add_int(p_int_value); - } - - /** - * Marks the beginning of a new scope in the olutput stream - * Writes also 1, if p_boolean_value is true, or 0, if p_boolean_value is false; - */ - public void start_scope(LogfileScope p_logfile_scope, boolean p_boolean_value) - { - start_scope(p_logfile_scope); - int int_value; - if (p_boolean_value) - { - int_value = 1; - } - else - { - int_value = 0; - } - add_int(int_value); - } - - /** - * Marks the beginning of a new item in the olutput stream - * Writes also the start corner. - */ - public void start_scope(LogfileScope p_logfile_scope, FloatPoint p_start_corner) - { - start_scope(p_logfile_scope); - add_corner(p_start_corner); - } - - - - /** - * Reads the next scope iidentifier from the logfile. - * Returns null if no more item scope was found. - */ - public LogfileScope start_read_scope() - { - Object curr_ob = this.next_token(); - if (curr_ob == null) - { - return null; - } - if (!(curr_ob instanceof String)) - { - System.out.println("Logfile.start_read_scope: String expected"); - this.pending_token = curr_ob; - return null; - } - LogfileScope result = LogfileScope.get_scope((String) curr_ob); - return result; - } - - /** - * adds an int to the logfile - */ - public void add_int(int p_int) - { - - if (write_enabled) - { - try - { - this.file_writer.write((new Integer(p_int)).toString()); - this.file_writer.write("\n"); - } - catch (IOException e2) - { - System.out.println("unable to write integer to logfile"); - } - } - } - - /** - * Reads the next int from the logfile. - * Returns -1, if no valid integer was found. - */ - public int read_int() - { - Object curr_ob = this.next_token(); - if (!(curr_ob instanceof Integer)) - { - System.out.println("Logfile.read_int: Integer expected"); - this.pending_token = curr_ob; - return -1; - } - return (((Integer) curr_ob).intValue()); - } - - /** - * adds a FloatPoint to the logfile - */ - public void add_corner(FloatPoint p_corner) - { - if (write_enabled) - { - if (p_corner == null) - { - System.out.println("logfile.add_corner: p_corner is null"); - return; - } - try - { - this.file_writer.write((new Double(p_corner.x)).toString()); - this.file_writer.write(" "); - this.file_writer.write((new Double(p_corner.y)).toString()); - this.file_writer.write("\n"); - } - catch (IOException e2) - { - System.out.println("unable to write to logfile while adding corner"); - } - } - } - - private Object next_token() - { - if (this.pending_token != null) - { - Object result = this.pending_token; - this.pending_token = null; - return result; - } - try - { - Object result = this.scanner.next_token(); - return result; - } - catch (IOException e) - { - System.out.println("Logfile.next_token: IO error scanning file"); - return null; - } - } - - private LogfileScanner scanner = null; - private FileWriter file_writer = null; - private boolean write_enabled = false; - private Object pending_token = null; -} \ No newline at end of file +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + */ + +package interactive; + +import geometry.planar.FloatPoint; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; + +/** + * Logfile to track the actions in the interactive board handling + * for automatic replay. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class Logfile +{ + /** + * opens the logfile for reading + * + * @param p_input_stream a {@link java.io.InputStream} object. + * @return a boolean. + */ + public boolean start_read(InputStream p_input_stream) + { + this.scanner = new LogfileScanner(p_input_stream); + return (this.scanner != null); + } + + /** + * Reads the next corner from the logfile. + * Return null, if no valid corner is found. + * + * @return a {@link geometry.planar.FloatPoint} object. + */ + public FloatPoint read_corner() + { + + double x = 0; + double y = 0; + for (int i = 0; i < 2; ++i) + { + Object curr_ob = this.next_token(); + if (!(curr_ob instanceof Double)) + { + this.pending_token = curr_ob; + return null; + } + double f = ((Double) curr_ob).doubleValue(); + if (i == 0) + { + x = f; + } + else + { + y = f; + } + } + return new FloatPoint(x, y); + } + + /** + * closes the logfile after writing + */ + public void close_output() + { + if (this.file_writer != null) + { + try + { + this.file_writer.close(); + } + catch (IOException e) + { + System.out.println("unable to close logfile"); + } + } + this.write_enabled = false; + } + + /** + * opens a logfile for writing + * + * @param p_file a {@link java.io.File} object. + * @return a boolean. + */ + public boolean start_write(File p_file) + { + try + { + this.file_writer = new FileWriter(p_file); + } + catch (IOException e) + { + System.out.println("unable to create logfile"); + return false; + } + write_enabled = true; + return true; + } + + /** + * Marks the beginning of a new item in the olutput stream + * + * @param p_logfile_scope a {@link interactive.LogfileScope} object. + */ + public void start_scope(LogfileScope p_logfile_scope) + { + if (write_enabled) + { + try + { + this.file_writer.write(p_logfile_scope.name); + this.file_writer.write("\n"); + } + catch (IOException e2) + { + System.out.println("Logfile.start_scope: write failed"); + } + } + } + + /** + * Marks the beginning of a new scope in the olutput stream + * Writes also an integer value. + * + * @param p_logfile_scope a {@link interactive.LogfileScope} object. + * @param p_int_value a int. + */ + public void start_scope(LogfileScope p_logfile_scope, int p_int_value) + { + start_scope(p_logfile_scope); + add_int(p_int_value); + } + + /** + * Marks the beginning of a new scope in the olutput stream + * Writes also 1, if p_boolean_value is true, or 0, if p_boolean_value is false; + * + * @param p_logfile_scope a {@link interactive.LogfileScope} object. + * @param p_boolean_value a boolean. + */ + public void start_scope(LogfileScope p_logfile_scope, boolean p_boolean_value) + { + start_scope(p_logfile_scope); + int int_value; + if (p_boolean_value) + { + int_value = 1; + } + else + { + int_value = 0; + } + add_int(int_value); + } + + /** + * Marks the beginning of a new item in the olutput stream + * Writes also the start corner. + * + * @param p_logfile_scope a {@link interactive.LogfileScope} object. + * @param p_start_corner a {@link geometry.planar.FloatPoint} object. + */ + public void start_scope(LogfileScope p_logfile_scope, FloatPoint p_start_corner) + { + start_scope(p_logfile_scope); + add_corner(p_start_corner); + } + + + + /** + * Reads the next scope iidentifier from the logfile. + * Returns null if no more item scope was found. + * + * @return a {@link interactive.LogfileScope} object. + */ + public LogfileScope start_read_scope() + { + Object curr_ob = this.next_token(); + if (curr_ob == null) + { + return null; + } + if (!(curr_ob instanceof String)) + { + System.out.println("Logfile.start_read_scope: String expected"); + this.pending_token = curr_ob; + return null; + } + LogfileScope result = LogfileScope.get_scope((String) curr_ob); + return result; + } + + /** + * adds an int to the logfile + * + * @param p_int a int. + */ + public void add_int(int p_int) + { + + if (write_enabled) + { + try + { + this.file_writer.write((new Integer(p_int)).toString()); + this.file_writer.write("\n"); + } + catch (IOException e2) + { + System.out.println("unable to write integer to logfile"); + } + } + } + + /** + * Reads the next int from the logfile. + * Returns -1, if no valid integer was found. + * + * @return a int. + */ + public int read_int() + { + Object curr_ob = this.next_token(); + if (!(curr_ob instanceof Integer)) + { + System.out.println("Logfile.read_int: Integer expected"); + this.pending_token = curr_ob; + return -1; + } + return (((Integer) curr_ob).intValue()); + } + + /** + * adds a FloatPoint to the logfile + * + * @param p_corner a {@link geometry.planar.FloatPoint} object. + */ + public void add_corner(FloatPoint p_corner) + { + if (write_enabled) + { + if (p_corner == null) + { + System.out.println("logfile.add_corner: p_corner is null"); + return; + } + try + { + this.file_writer.write((new Double(p_corner.x)).toString()); + this.file_writer.write(" "); + this.file_writer.write((new Double(p_corner.y)).toString()); + this.file_writer.write("\n"); + } + catch (IOException e2) + { + System.out.println("unable to write to logfile while adding corner"); + } + } + } + + private Object next_token() + { + if (this.pending_token != null) + { + Object result = this.pending_token; + this.pending_token = null; + return result; + } + try + { + Object result = this.scanner.next_token(); + return result; + } + catch (IOException e) + { + System.out.println("Logfile.next_token: IO error scanning file"); + return null; + } + } + + private LogfileScanner scanner = null; + private FileWriter file_writer = null; + private boolean write_enabled = false; + private Object pending_token = null; +} diff --git a/interactive/LogfileDescription.flex b/src/main/java/interactive/LogfileDescription.flex similarity index 100% rename from interactive/LogfileDescription.flex rename to src/main/java/interactive/LogfileDescription.flex diff --git a/interactive/LogfileScanner.java b/src/main/java/interactive/LogfileScanner.java similarity index 89% rename from interactive/LogfileScanner.java rename to src/main/java/interactive/LogfileScanner.java index 17e4e6b..0f56454 100644 --- a/interactive/LogfileScanner.java +++ b/src/main/java/interactive/LogfileScanner.java @@ -1,542 +1,549 @@ -/* The following code was generated by JFlex 1.4 on 06.07.05 18:12 */ - -package interactive; -@SuppressWarnings("all") - -/** - * This class is a scanner generated by - * JFlex 1.4 - * on 06.07.05 18:12 from the specification file - * C:/Dokumente und Einstellungen/alfons/Eigene Dateien/freeroute/interactive/LogfileDescription.flex - */ -class LogfileScanner { - - /** This character denotes the end of file */ - public static final int YYEOF = -1; - - /** initial size of the lookahead buffer */ - private static final int ZZ_BUFFERSIZE = 16384; - - /** lexical states */ - public static final int YYINITIAL = 0; - - /** - * Translates characters to character classes - */ - private static final String ZZ_CMAP_PACKED = - "\11\0\1\3\1\2\1\0\1\3\1\1\22\0\1\3\2\0\1\6"+ - "\1\7\5\0\1\5\1\14\1\0\1\12\1\11\1\4\1\13\11\10"+ - "\7\0\32\7\4\0\1\7\1\0\32\7\uff85\0"; - - /** - * Translates characters to character classes - */ - private static final char [] ZZ_CMAP = zzUnpackCMap(ZZ_CMAP_PACKED); - - /** - * Translates DFA states to action switch labels. - */ - private static final int [] ZZ_ACTION = zzUnpackAction(); - - private static final String ZZ_ACTION_PACKED_0 = - "\1\0\1\1\2\2\3\3\1\4\1\1\1\4\1\1"+ - "\3\0\1\5\2\0\1\5\1\0"; - - private static int [] zzUnpackAction() { - int [] result = new int[19]; - int offset = 0; - offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result); - return result; - } - - private static int zzUnpackAction(String packed, int offset, int [] result) { - int i = 0; /* index in packed string */ - int j = offset; /* index in unpacked array */ - int l = packed.length(); - while (i < l) { - int count = packed.charAt(i++); - int value = packed.charAt(i++); - do result[j++] = value; while (--count > 0); - } - return j; - } - - - /** - * Translates a state to a row index in the transition table - */ - private static final int [] ZZ_ROWMAP = zzUnpackRowMap(); - - private static final String ZZ_ROWMAP_PACKED_0 = - "\0\0\0\15\0\32\0\15\0\47\0\64\0\101\0\116"+ - "\0\133\0\150\0\165\0\202\0\217\0\234\0\150\0\251"+ - "\0\266\0\234\0\303"; - - private static int [] zzUnpackRowMap() { - int [] result = new int[19]; - int offset = 0; - offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result); - return result; - } - - private static int zzUnpackRowMap(String packed, int offset, int [] result) { - int i = 0; /* index in packed string */ - int j = offset; /* index in unpacked array */ - int l = packed.length(); - while (i < l) { - int high = packed.charAt(i++) << 16; - result[j++] = high | packed.charAt(i++); - } - return j; - } - - /** - * The transition table of the DFA - */ - private static final int [] ZZ_TRANS = zzUnpackTrans(); - - private static final String ZZ_TRANS_PACKED_0 = - "\1\2\1\3\2\4\1\5\1\2\1\6\1\7\1\10"+ - "\1\7\1\11\1\12\1\13\17\0\1\4\16\0\1\7"+ - "\1\14\4\7\1\0\1\7\1\0\1\15\1\3\1\4"+ - "\1\15\1\6\1\15\4\6\1\15\1\6\1\15\4\0"+ - "\1\7\1\0\4\7\1\0\1\7\11\0\1\10\1\16"+ - "\1\0\1\10\11\0\1\10\2\0\1\12\11\0\1\17"+ - "\1\16\1\0\1\17\11\0\1\17\2\0\1\17\1\0"+ - "\5\20\1\21\7\20\1\15\1\3\1\4\12\15\10\0"+ - "\1\22\2\0\1\22\1\0\5\20\1\23\7\20\4\0"+ - "\1\4\1\21\7\0\4\20\1\4\1\23\7\20"; - - private static int [] zzUnpackTrans() { - int [] result = new int[208]; - int offset = 0; - offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result); - return result; - } - - private static int zzUnpackTrans(String packed, int offset, int [] result) { - int i = 0; /* index in packed string */ - int j = offset; /* index in unpacked array */ - int l = packed.length(); - while (i < l) { - int count = packed.charAt(i++); - int value = packed.charAt(i++); - value--; - do result[j++] = value; while (--count > 0); - } - return j; - } - - - /* error codes */ - private static final int ZZ_UNKNOWN_ERROR = 0; - private static final int ZZ_NO_MATCH = 1; - private static final int ZZ_PUSHBACK_2BIG = 2; - - /* error messages for the codes above */ - private static final String ZZ_ERROR_MSG[] = { - "Unkown internal scanner error", - "Error: could not match input", - "Error: pushback value was too large" - }; - - /** - * ZZ_ATTRIBUTE[aState] contains the attributes of state aState - */ - private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute(); - - private static final String ZZ_ATTRIBUTE_PACKED_0 = - "\1\0\1\11\1\1\1\11\7\1\3\0\1\1\2\0"+ - "\1\1\1\0"; - - private static int [] zzUnpackAttribute() { - int [] result = new int[19]; - int offset = 0; - offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result); - return result; - } - - private static int zzUnpackAttribute(String packed, int offset, int [] result) { - int i = 0; /* index in packed string */ - int j = offset; /* index in unpacked array */ - int l = packed.length(); - while (i < l) { - int count = packed.charAt(i++); - int value = packed.charAt(i++); - do result[j++] = value; while (--count > 0); - } - return j; - } - - /** the input device */ - private java.io.Reader zzReader; - - /** the current state of the DFA */ - private int zzState; - - /** the current lexical state */ - private int zzLexicalState = YYINITIAL; - - /** this buffer contains the current text to be matched and is - the source of the yytext() string */ - private char zzBuffer[] = new char[ZZ_BUFFERSIZE]; - - /** the textposition at the last accepting state */ - private int zzMarkedPos; - - /** the textposition at the last state to be included in yytext */ - private int zzPushbackPos; - - /** the current text position in the buffer */ - private int zzCurrentPos; - - /** startRead marks the beginning of the yytext() string in the buffer */ - private int zzStartRead; - - /** endRead marks the last character in the buffer, that has been read - from input */ - private int zzEndRead; - - /** number of newlines encountered up to the start of the matched text */ - private int yyline; - - /** the number of characters up to the start of the matched text */ - private int yychar; - - /** - * the number of characters from the last newline up to the start of the - * matched text - */ - private int yycolumn; - - /** - * zzAtBOL == true <=> the scanner is currently at the beginning of a line - */ - private boolean zzAtBOL = true; - - /** zzAtEOF == true <=> the scanner is at the EOF */ - private boolean zzAtEOF; - - - /** - * Creates a new scanner - * There is also a java.io.InputStream version of this constructor. - * - * @param in the java.io.Reader to read input from. - */ - LogfileScanner(java.io.Reader in) { - this.zzReader = in; - } - - /** - * Creates a new scanner. - * There is also java.io.Reader version of this constructor. - * - * @param in the java.io.Inputstream to read input from. - */ - LogfileScanner(java.io.InputStream in) { - this(new java.io.InputStreamReader(in)); - } - - /** - * Unpacks the compressed character translation table. - * - * @param packed the packed character translation table - * @return the unpacked character translation table - */ - private static char [] zzUnpackCMap(String packed) { - char [] map = new char[0x10000]; - int i = 0; /* index in packed string */ - int j = 0; /* index in unpacked array */ - while (i < 54) { - int count = packed.charAt(i++); - char value = packed.charAt(i++); - do map[j++] = value; while (--count > 0); - } - return map; - } - - - /** - * Refills the input buffer. - * - * @return false, iff there was new input. - * - * @exception java.io.IOException if any I/O-Error occurs - */ - private boolean zzRefill() throws java.io.IOException { - - /* first: make room (if you can) */ - if (zzStartRead > 0) { - System.arraycopy(zzBuffer, zzStartRead, - zzBuffer, 0, - zzEndRead-zzStartRead); - - /* translate stored positions */ - zzEndRead-= zzStartRead; - zzCurrentPos-= zzStartRead; - zzMarkedPos-= zzStartRead; - zzPushbackPos-= zzStartRead; - zzStartRead = 0; - } - - /* is the buffer big enough? */ - if (zzCurrentPos >= zzBuffer.length) { - /* if not: blow it up */ - char newBuffer[] = new char[zzCurrentPos*2]; - System.arraycopy(zzBuffer, 0, newBuffer, 0, zzBuffer.length); - zzBuffer = newBuffer; - } - - /* finally: fill the buffer with new input */ - int numRead = zzReader.read(zzBuffer, zzEndRead, - zzBuffer.length-zzEndRead); - - if (numRead < 0) { - return true; - } - else { - zzEndRead+= numRead; - return false; - } - } - - - /** - * Closes the input stream. - */ - public final void yyclose() throws java.io.IOException { - zzAtEOF = true; /* indicate end of file */ - zzEndRead = zzStartRead; /* invalidate buffer */ - - if (zzReader != null) - zzReader.close(); - } - - - /** - * Resets the scanner to read from a new input stream. - * Does not close the old reader. - * - * All internal variables are reset, the old input stream - * cannot be reused (internal buffer is discarded and lost). - * Lexical state is set to ZZ_INITIAL. - * - * @param reader the new input stream - */ - public final void yyreset(java.io.Reader reader) { - zzReader = reader; - zzAtBOL = true; - zzAtEOF = false; - zzEndRead = zzStartRead = 0; - zzCurrentPos = zzMarkedPos = zzPushbackPos = 0; - yyline = yychar = yycolumn = 0; - zzLexicalState = YYINITIAL; - } - - - /** - * Returns the current lexical state. - */ - public final int yystate() { - return zzLexicalState; - } - - - /** - * Enters a new lexical state - * - * @param newState the new lexical state - */ - public final void yybegin(int newState) { - zzLexicalState = newState; - } - - - /** - * Returns the text matched by the current regular expression. - */ - public final String yytext() { - return new String( zzBuffer, zzStartRead, zzMarkedPos-zzStartRead ); - } - - - /** - * Returns the character at position pos from the - * matched text. - * - * It is equivalent to yytext().charAt(pos), but faster - * - * @param pos the position of the character to fetch. - * A value from 0 to yylength()-1. - * - * @return the character at position pos - */ - public final char yycharat(int pos) { - return zzBuffer[zzStartRead+pos]; - } - - - /** - * Returns the length of the matched text region. - */ - public final int yylength() { - return zzMarkedPos-zzStartRead; - } - - - /** - * Reports an error that occured while scanning. - * - * In a wellformed scanner (no or only correct usage of - * yypushback(int) and a match-all fallback rule) this method - * will only be called with things that "Can't Possibly Happen". - * If this method is called, something is seriously wrong - * (e.g. a JFlex bug producing a faulty scanner etc.). - * - * Usual syntax/scanner level error handling should be done - * in error fallback rules. - * - * @param errorCode the code of the errormessage to display - */ - private void zzScanError(int errorCode) { - String message; - try { - message = ZZ_ERROR_MSG[errorCode]; - } - catch (ArrayIndexOutOfBoundsException e) { - message = ZZ_ERROR_MSG[ZZ_UNKNOWN_ERROR]; - } - - throw new Error(message); - } - - - /** - * Pushes the specified amount of characters back into the input stream. - * - * They will be read again by then next call of the scanning method - * - * @param number the number of characters to be read again. - * This number must not be greater than yylength()! - */ - public void yypushback(int number) { - if ( number > yylength() ) - zzScanError(ZZ_PUSHBACK_2BIG); - - zzMarkedPos -= number; - } - - - /** - * Resumes scanning until the next regular expression is matched, - * the end of input is encountered or an I/O-Error occurs. - * - * @return the next token - * @exception java.io.IOException if any I/O-Error occurs - */ - public Object next_token() throws java.io.IOException { - int zzInput; - int zzAction; - - // cached fields: - int zzCurrentPosL; - int zzMarkedPosL; - int zzEndReadL = zzEndRead; - char [] zzBufferL = zzBuffer; - char [] zzCMapL = ZZ_CMAP; - - int [] zzTransL = ZZ_TRANS; - int [] zzRowMapL = ZZ_ROWMAP; - int [] zzAttrL = ZZ_ATTRIBUTE; - - while (true) { - zzMarkedPosL = zzMarkedPos; - - zzAction = -1; - - zzCurrentPosL = zzCurrentPos = zzStartRead = zzMarkedPosL; - - zzState = zzLexicalState; - - - zzForAction: { - while (true) { - - if (zzCurrentPosL < zzEndReadL) - zzInput = zzBufferL[zzCurrentPosL++]; - else if (zzAtEOF) { - zzInput = YYEOF; - break zzForAction; - } - else { - // store back cached positions - zzCurrentPos = zzCurrentPosL; - zzMarkedPos = zzMarkedPosL; - boolean eof = zzRefill(); - // get translated positions and possibly new buffer - zzCurrentPosL = zzCurrentPos; - zzMarkedPosL = zzMarkedPos; - zzBufferL = zzBuffer; - zzEndReadL = zzEndRead; - if (eof) { - zzInput = YYEOF; - break zzForAction; - } - else { - zzInput = zzBufferL[zzCurrentPosL++]; - } - } - int zzNext = zzTransL[ zzRowMapL[zzState] + zzCMapL[zzInput] ]; - if (zzNext == -1) break zzForAction; - zzState = zzNext; - - int zzAttributes = zzAttrL[zzState]; - if ( (zzAttributes & 1) == 1 ) { - zzAction = zzState; - zzMarkedPosL = zzCurrentPosL; - if ( (zzAttributes & 8) == 8 ) break zzForAction; - } - - } - } - - // store back cached position - zzMarkedPos = zzMarkedPosL; - - switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) { - case 3: - { return yytext(); - } - case 6: break; - case 4: - { return new Integer(yytext()); - } - case 7: break; - case 2: - { /* ignore */ - } - case 8: break; - case 5: - { return new Double(yytext()); - } - case 9: break; - case 1: - { throw new Error("Illegal character <"+ - yytext()+">"); - } - case 10: break; - default: - if (zzInput == YYEOF && zzStartRead == zzCurrentPos) { - zzAtEOF = true; - return null; - } - else { - zzScanError(ZZ_NO_MATCH); - } - } - } - } - - -} +/* The following code was generated by JFlex 1.4 on 06.07.05 18:12 */ + +package interactive; +@SuppressWarnings("all") + +/** + * This class is a scanner generated by + * JFlex 1.4 + * on 06.07.05 18:12 from the specification file + * C:/Dokumente und Einstellungen/alfons/Eigene Dateien/freeroute/interactive/LogfileDescription.flex + */ +class LogfileScanner { + + /** This character denotes the end of file */ + public static final int YYEOF = -1; + + /** initial size of the lookahead buffer */ + private static final int ZZ_BUFFERSIZE = 16384; + + /** lexical states */ + public static final int YYINITIAL = 0; + + /** + * Translates characters to character classes + */ + private static final String ZZ_CMAP_PACKED = + "\11\0\1\3\1\2\1\0\1\3\1\1\22\0\1\3\2\0\1\6"+ + "\1\7\5\0\1\5\1\14\1\0\1\12\1\11\1\4\1\13\11\10"+ + "\7\0\32\7\4\0\1\7\1\0\32\7\uff85\0"; + + /** + * Translates characters to character classes + */ + private static final char [] ZZ_CMAP = zzUnpackCMap(ZZ_CMAP_PACKED); + + /** + * Translates DFA states to action switch labels. + */ + private static final int [] ZZ_ACTION = zzUnpackAction(); + + private static final String ZZ_ACTION_PACKED_0 = + "\1\0\1\1\2\2\3\3\1\4\1\1\1\4\1\1"+ + "\3\0\1\5\2\0\1\5\1\0"; + + private static int [] zzUnpackAction() { + int [] result = new int[19]; + int offset = 0; + offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackAction(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int count = packed.charAt(i++); + int value = packed.charAt(i++); + do result[j++] = value; while (--count > 0); + } + return j; + } + + + /** + * Translates a state to a row index in the transition table + */ + private static final int [] ZZ_ROWMAP = zzUnpackRowMap(); + + private static final String ZZ_ROWMAP_PACKED_0 = + "\0\0\0\15\0\32\0\15\0\47\0\64\0\101\0\116"+ + "\0\133\0\150\0\165\0\202\0\217\0\234\0\150\0\251"+ + "\0\266\0\234\0\303"; + + private static int [] zzUnpackRowMap() { + int [] result = new int[19]; + int offset = 0; + offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackRowMap(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int high = packed.charAt(i++) << 16; + result[j++] = high | packed.charAt(i++); + } + return j; + } + + /** + * The transition table of the DFA + */ + private static final int [] ZZ_TRANS = zzUnpackTrans(); + + private static final String ZZ_TRANS_PACKED_0 = + "\1\2\1\3\2\4\1\5\1\2\1\6\1\7\1\10"+ + "\1\7\1\11\1\12\1\13\17\0\1\4\16\0\1\7"+ + "\1\14\4\7\1\0\1\7\1\0\1\15\1\3\1\4"+ + "\1\15\1\6\1\15\4\6\1\15\1\6\1\15\4\0"+ + "\1\7\1\0\4\7\1\0\1\7\11\0\1\10\1\16"+ + "\1\0\1\10\11\0\1\10\2\0\1\12\11\0\1\17"+ + "\1\16\1\0\1\17\11\0\1\17\2\0\1\17\1\0"+ + "\5\20\1\21\7\20\1\15\1\3\1\4\12\15\10\0"+ + "\1\22\2\0\1\22\1\0\5\20\1\23\7\20\4\0"+ + "\1\4\1\21\7\0\4\20\1\4\1\23\7\20"; + + private static int [] zzUnpackTrans() { + int [] result = new int[208]; + int offset = 0; + offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackTrans(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int count = packed.charAt(i++); + int value = packed.charAt(i++); + value--; + do result[j++] = value; while (--count > 0); + } + return j; + } + + + /* error codes */ + private static final int ZZ_UNKNOWN_ERROR = 0; + private static final int ZZ_NO_MATCH = 1; + private static final int ZZ_PUSHBACK_2BIG = 2; + + /* error messages for the codes above */ + private static final String ZZ_ERROR_MSG[] = { + "Unkown internal scanner error", + "Error: could not match input", + "Error: pushback value was too large" + }; + + /** + * ZZ_ATTRIBUTE[aState] contains the attributes of state aState + */ + private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute(); + + private static final String ZZ_ATTRIBUTE_PACKED_0 = + "\1\0\1\11\1\1\1\11\7\1\3\0\1\1\2\0"+ + "\1\1\1\0"; + + private static int [] zzUnpackAttribute() { + int [] result = new int[19]; + int offset = 0; + offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackAttribute(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int count = packed.charAt(i++); + int value = packed.charAt(i++); + do result[j++] = value; while (--count > 0); + } + return j; + } + + /** the input device */ + private java.io.Reader zzReader; + + /** the current state of the DFA */ + private int zzState; + + /** the current lexical state */ + private int zzLexicalState = YYINITIAL; + + /** this buffer contains the current text to be matched and is + the source of the yytext() string */ + private char zzBuffer[] = new char[ZZ_BUFFERSIZE]; + + /** the textposition at the last accepting state */ + private int zzMarkedPos; + + /** the textposition at the last state to be included in yytext */ + private int zzPushbackPos; + + /** the current text position in the buffer */ + private int zzCurrentPos; + + /** startRead marks the beginning of the yytext() string in the buffer */ + private int zzStartRead; + + /** endRead marks the last character in the buffer, that has been read + from input */ + private int zzEndRead; + + /** number of newlines encountered up to the start of the matched text */ + private int yyline; + + /** the number of characters up to the start of the matched text */ + private int yychar; + + /** + * the number of characters from the last newline up to the start of the + * matched text + */ + private int yycolumn; + + /** + * zzAtBOL == true <=> the scanner is currently at the beginning of a line + */ + private boolean zzAtBOL = true; + + /** zzAtEOF == true <=> the scanner is at the EOF */ + private boolean zzAtEOF; + + + /** + * Creates a new scanner + * There is also a java.io.InputStream version of this constructor. + * + * @param in the java.io.Reader to read input from. + */ + LogfileScanner(java.io.Reader in) { + this.zzReader = in; + } + + /** + * Creates a new scanner. + * There is also java.io.Reader version of this constructor. + * + * @param in the java.io.Inputstream to read input from. + */ + LogfileScanner(java.io.InputStream in) { + this(new java.io.InputStreamReader(in)); + } + + /** + * Unpacks the compressed character translation table. + * + * @param packed the packed character translation table + * @return the unpacked character translation table + */ + private static char [] zzUnpackCMap(String packed) { + char [] map = new char[0x10000]; + int i = 0; /* index in packed string */ + int j = 0; /* index in unpacked array */ + while (i < 54) { + int count = packed.charAt(i++); + char value = packed.charAt(i++); + do map[j++] = value; while (--count > 0); + } + return map; + } + + + /** + * Refills the input buffer. + * + * @return false, iff there was new input. + * + * @exception java.io.IOException if any I/O-Error occurs + */ + private boolean zzRefill() throws java.io.IOException { + /* first: make room (if you can) */ + if (zzStartRead > 0) { + System.arraycopy(zzBuffer, zzStartRead, + zzBuffer, 0, + zzEndRead-zzStartRead); + + /* translate stored positions */ + zzEndRead-= zzStartRead; + zzCurrentPos-= zzStartRead; + zzMarkedPos-= zzStartRead; + zzPushbackPos-= zzStartRead; + zzStartRead = 0; + } + + /* is the buffer big enough? */ + if (zzCurrentPos >= zzBuffer.length) { + /* if not: blow it up */ + char newBuffer[] = new char[zzCurrentPos*2]; + System.arraycopy(zzBuffer, 0, newBuffer, 0, zzBuffer.length); + zzBuffer = newBuffer; + } + + /* finally: fill the buffer with new input */ + int numRead = zzReader.read(zzBuffer, zzEndRead, + zzBuffer.length-zzEndRead); + + if (numRead < 0) { + return true; + } + else { + zzEndRead+= numRead; + return false; + } + } + + + /** + * Closes the input stream. + * + * @throws java.io.IOException if any. + */ + public final void yyclose() throws java.io.IOException { + zzAtEOF = true; /* indicate end of file */ + zzEndRead = zzStartRead; /* invalidate buffer */ + + if (zzReader != null) + zzReader.close(); + } + + + /** + * Resets the scanner to read from a new input stream. + * Does not close the old reader. + * + * All internal variables are reset, the old input stream + * cannot be reused (internal buffer is discarded and lost). + * Lexical state is set to ZZ_INITIAL. + * + * @param reader the new input stream + */ + public final void yyreset(java.io.Reader reader) { + zzReader = reader; + zzAtBOL = true; + zzAtEOF = false; + zzEndRead = zzStartRead = 0; + zzCurrentPos = zzMarkedPos = zzPushbackPos = 0; + yyline = yychar = yycolumn = 0; + zzLexicalState = YYINITIAL; + } + + + /** + * Returns the current lexical state. + * + * @return a int. + */ + public final int yystate() { + return zzLexicalState; + } + + + /** + * Enters a new lexical state + * + * @param newState the new lexical state + */ + public final void yybegin(int newState) { + zzLexicalState = newState; + } + + + /** + * Returns the text matched by the current regular expression. + * + * @return a {@link java.lang.String} object. + */ + public final String yytext() { + return new String( zzBuffer, zzStartRead, zzMarkedPos-zzStartRead ); + } + + + /** + * Returns the character at position pos from the + * matched text. + * + * It is equivalent to yytext().charAt(pos), but faster + * + * @param pos the position of the character to fetch. + * A value from 0 to yylength()-1. + * @return the character at position pos + */ + public final char yycharat(int pos) { + return zzBuffer[zzStartRead+pos]; + } + + + /** + * Returns the length of the matched text region. + * + * @return a int. + */ + public final int yylength() { + return zzMarkedPos-zzStartRead; + } + + + /** + * Reports an error that occured while scanning. + * + * In a wellformed scanner (no or only correct usage of + * yypushback(int) and a match-all fallback rule) this method + * will only be called with things that "Can't Possibly Happen". + * If this method is called, something is seriously wrong + * (e.g. a JFlex bug producing a faulty scanner etc.). + * + * Usual syntax/scanner level error handling should be done + * in error fallback rules. + * + * @param errorCode the code of the errormessage to display + */ + private void zzScanError(int errorCode) { + String message; + try { + message = ZZ_ERROR_MSG[errorCode]; + } + catch (ArrayIndexOutOfBoundsException e) { + message = ZZ_ERROR_MSG[ZZ_UNKNOWN_ERROR]; + } + + throw new Error(message); + } + + + /** + * Pushes the specified amount of characters back into the input stream. + * + * They will be read again by then next call of the scanning method + * + * @param number the number of characters to be read again. + * This number must not be greater than yylength()! + */ + public void yypushback(int number) { + if ( number > yylength() ) + zzScanError(ZZ_PUSHBACK_2BIG); + + zzMarkedPos -= number; + } + + + /** + * Resumes scanning until the next regular expression is matched, + * the end of input is encountered or an I/O-Error occurs. + * + * @return the next token + * @exception java.io.IOException if any I/O-Error occurs + * @throws java.io.IOException if any. + */ + public Object next_token() throws java.io.IOException { + int zzInput; + int zzAction; + + // cached fields: + int zzCurrentPosL; + int zzMarkedPosL; + int zzEndReadL = zzEndRead; + char [] zzBufferL = zzBuffer; + char [] zzCMapL = ZZ_CMAP; + + int [] zzTransL = ZZ_TRANS; + int [] zzRowMapL = ZZ_ROWMAP; + int [] zzAttrL = ZZ_ATTRIBUTE; + + while (true) { + zzMarkedPosL = zzMarkedPos; + + zzAction = -1; + + zzCurrentPosL = zzCurrentPos = zzStartRead = zzMarkedPosL; + + zzState = zzLexicalState; + + + zzForAction: { + while (true) { + + if (zzCurrentPosL < zzEndReadL) + zzInput = zzBufferL[zzCurrentPosL++]; + else if (zzAtEOF) { + zzInput = YYEOF; + break zzForAction; + } + else { + // store back cached positions + zzCurrentPos = zzCurrentPosL; + zzMarkedPos = zzMarkedPosL; + boolean eof = zzRefill(); + // get translated positions and possibly new buffer + zzCurrentPosL = zzCurrentPos; + zzMarkedPosL = zzMarkedPos; + zzBufferL = zzBuffer; + zzEndReadL = zzEndRead; + if (eof) { + zzInput = YYEOF; + break zzForAction; + } + else { + zzInput = zzBufferL[zzCurrentPosL++]; + } + } + int zzNext = zzTransL[ zzRowMapL[zzState] + zzCMapL[zzInput] ]; + if (zzNext == -1) break zzForAction; + zzState = zzNext; + + int zzAttributes = zzAttrL[zzState]; + if ( (zzAttributes & 1) == 1 ) { + zzAction = zzState; + zzMarkedPosL = zzCurrentPosL; + if ( (zzAttributes & 8) == 8 ) break zzForAction; + } + + } + } + + // store back cached position + zzMarkedPos = zzMarkedPosL; + + switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) { + case 3: + { return yytext(); + } + case 6: break; + case 4: + { return new Integer(yytext()); + } + case 7: break; + case 2: + { /* ignore */ + } + case 8: break; + case 5: + { return new Double(yytext()); + } + case 9: break; + case 1: + { throw new Error("Illegal character <"+ + yytext()+">"); + } + case 10: break; + default: + if (zzInput == YYEOF && zzStartRead == zzCurrentPos) { + zzAtEOF = true; + return null; + } + else { + zzScanError(ZZ_NO_MATCH); + } + } + } + } + + +} diff --git a/interactive/LogfileScope.java b/src/main/java/interactive/LogfileScope.java similarity index 93% rename from interactive/LogfileScope.java rename to src/main/java/interactive/LogfileScope.java index d2bdb26..3b8c86a 100644 --- a/interactive/LogfileScope.java +++ b/src/main/java/interactive/LogfileScope.java @@ -28,6 +28,7 @@ * Each Object of the class must implement the read_scope method. * * @author Alfons Wirtz + * @version $Id: $Id */ public abstract class LogfileScope { @@ -37,67 +38,119 @@ public abstract class LogfileScope // scpopes logging undo and redo public static final LogfileScope UNDO = new UndoScope("undo"); + /** Constant REDO */ public static final LogfileScope REDO = new RedoScope("redo"); + /** Constant GENERATE_SNAPSHOT */ public static final LogfileScope GENERATE_SNAPSHOT = new GenerateSnapshotScope("generate_snapshot"); // Scopes for logging changes in the interactive setting: + /** Constant SET_CLEARANCE_COMPENSATION */ public static final LogfileScope SET_CLEARANCE_COMPENSATION = new SetClearanceCompensationScope("set_clearance_compensation"); + /** Constant SET_DRAG_COMPONENTS_ENABLED */ public static final LogfileScope SET_DRAG_COMPONENTS_ENABLED = new SetDragComponentsEnabledScope("set_drag_componente_enabled"); + /** Constant SET_LAYER */ public static final LogfileScope SET_LAYER = new SetLayerScope("set_layer"); + /** Constant SET_MANUAL_TRACE_CLEARANCE_CLASS */ public static final LogfileScope SET_MANUAL_TRACE_CLEARANCE_CLASS = new SetManualTraceClearanceClassScope("set_manual_trace_clearance_class"); + /** Constant SET_MANUAL_TRACE_HALF_WIDTH */ public static final LogfileScope SET_MANUAL_TRACE_HALF_WIDTH = new SetManualTraceHalfWidthScope("set_manual_trace_half_width"); + /** Constant SET_MANUAL_TRACEWITH_SELECTION */ public static final LogfileScope SET_MANUAL_TRACEWITH_SELECTION = new SetManualTraceWidthSelectionScope("set_manual_tracewidth_selection"); + /** Constant SET_PULL_TIGHT_ACCURACY */ public static final LogfileScope SET_PULL_TIGHT_ACCURACY = new SetPullTightAccuracyScope("set_pull_tight_accuracy"); + /** Constant SET_PULL_TIGHT_REGION_WIDTH */ public static final LogfileScope SET_PULL_TIGHT_REGION_WIDTH = new SetPullTightRegionWidthScope("set_pull_tight_region_width"); + /** Constant SET_PUSH_ENABLED */ public static final LogfileScope SET_PUSH_ENABLED = new SetPushEnabledScope("set_push_enabled"); + /** Constant SET_SNAP_ANGLE */ public static final LogfileScope SET_SNAP_ANGLE = new SetSnapAngleScope("set_snap_angle"); + /** Constant SET_SELECTABLE */ public static final LogfileScope SET_SELECTABLE = new SetSelectableScope(" set_selectable"); + /** Constant SET_SELECT_ON_ALL_LAYER */ public static final LogfileScope SET_SELECT_ON_ALL_LAYER = new SetSelectOnAllLayerScope(" set_select_on_all_layer"); + /** Constant SET_STITCH_ROUTE */ public static final LogfileScope SET_STITCH_ROUTE = new SetStitchRouteScope(" set_stitch_route"); + /** Constant SET_TRACE_HALF_WIDTH */ public static final LogfileScope SET_TRACE_HALF_WIDTH = new SetTraceHalfWidthScope("set_trace_halfwidth"); + /** Constant SET_IGNORE_CONDUCTION */ public static final LogfileScope SET_IGNORE_CONDUCTION = new SetIgnoreConductionScope("set_ignore_conduction"); // scopes for logging changes in the interactively selected set of items: + /** Constant START_SELECT */ public static final LogfileScope START_SELECT = new StartSelectScope("start_select"); + /** Constant TOGGLE_SELECT */ public static final LogfileScope TOGGLE_SELECT = new ToggleSelectScope("toggle_select"); + /** Constant SELECT_REGION */ public static final LogfileScope SELECT_REGION = new SelectRegionScope("select_region"); + /** Constant EXTEND_TO_WHOLE_CONNECTED_SETS */ public static final LogfileScope EXTEND_TO_WHOLE_CONNECTED_SETS = new ExtendToWholeConnectedSetsScope("extend_to_whole_connected_sets"); + /** Constant EXTEND_TO_WHOLE_CONNECTIONS */ public static final LogfileScope EXTEND_TO_WHOLE_CONNECTIONS = new ExtendToWholeConnectionsScope("extend_to_whole_connections"); + /** Constant EXTEND_TO_WHOLE_COMPONENTS */ public static final LogfileScope EXTEND_TO_WHOLE_COMPONENTS = new ExtendToWholeComponentsScope("extend_to_whole_components"); + /** Constant EXTEND_TO_WHOLE_NETS */ public static final LogfileScope EXTEND_TO_WHOLE_NETS = new ExtendToWholeNetsScope("extend_to_whole_nets"); // scopes for logging actions on the interactively selected set of items: + /** Constant ASSIGN_CLEARANCE_CLASS */ public static final LogfileScope ASSIGN_CLEARANCE_CLASS = new AssignClearanceClassScope("assign_clearance_class"); + /** Constant ASSIGN_SELECTED_TO_NEW_NET */ public static final LogfileScope ASSIGN_SELECTED_TO_NEW_NET = new AssignSelectedToNewNetScope("assign_selected_to_new_net"); + /** Constant ASSIGN_SELECTED_TO_NEW_GROUP */ public static final LogfileScope ASSIGN_SELECTED_TO_NEW_GROUP = new AssignSelectedToNewGroupScope("assign_selected_to_new_group"); + /** Constant FIX_SELECTED_ITEMS */ public static final LogfileScope FIX_SELECTED_ITEMS = new FixSelectedScope("fix_selected_items"); + /** Constant UNFIX_SELECTED_ITEMS */ public static final LogfileScope UNFIX_SELECTED_ITEMS = new UnfixSelectedScope("unfix_selected_items"); + /** Constant DELETE_SELECTED */ public static final LogfileScope DELETE_SELECTED = new DeleteSelectedScope("delete_selected"); + /** Constant CUTOUT_ROUTE */ public static final LogfileScope CUTOUT_ROUTE = new CutoutRouteScope("cutout_route"); + /** Constant OPTIMIZE_SELECTED */ public static final LogfileScope OPTIMIZE_SELECTED = new OptimizeSelectedScope("optmize_selected"); + /** Constant AUTOROUTE_SELECTED */ public static final LogfileScope AUTOROUTE_SELECTED = new AutorouteSelectedScope("autoroute_selected"); + /** Constant FANOUT_SELECTED */ public static final LogfileScope FANOUT_SELECTED = new FanoutSelectedScope("fanout_selected"); // scopes for logging interactive creating or moving items. + /** Constant COMPLETE_SCOPE */ public static final LogfileScope COMPLETE_SCOPE = new CompleteScope("complete_scope"); + /** Constant CANCEL_SCOPE */ public static final LogfileScope CANCEL_SCOPE = new CancelScope("cancel_scope"); + /** Constant CREATING_TILE */ public static final LogfileScope CREATING_TILE = new CreateTileScope("creating_tile"); + /** Constant CREATING_CIRCLE */ public static final LogfileScope CREATING_CIRCLE = new CreateCircleScope("creating_circle"); + /** Constant CREATING_POLYGONSHAPE */ public static final LogfileScope CREATING_POLYGONSHAPE = new CreatePolygonShapeScope("creating_polygonshape"); + /** Constant ADDING_HOLE */ public static final LogfileScope ADDING_HOLE = new AddHoleScope("adding_hole"); + /** Constant CREATING_TRACE */ public static final LogfileScope CREATING_TRACE = new CreateTraceScope("creating_trace"); + /** Constant CHANGE_LAYER */ public static final LogfileScope CHANGE_LAYER = new ChangeLayerScope("change_layer"); + /** Constant DRAGGING_ITEMS */ public static final LogfileScope DRAGGING_ITEMS = new DragItemScope("dragging_items"); + /** Constant MAKING_SPACE */ public static final LogfileScope MAKING_SPACE = new MakeSpaceScope("making_space"); + /** Constant COPYING_ITEMS */ public static final LogfileScope COPYING_ITEMS = new CopyItemScope("copying_items"); + /** Constant MOVE_ITEMS */ public static final LogfileScope MOVE_ITEMS = new MoveItemScope("moving_items"); + /** Constant TURN_90_DEGREE */ public static final LogfileScope TURN_90_DEGREE = new Turn90DegreeScope("turn_90_degree"); + /** Constant ROTATE */ public static final LogfileScope ROTATE = new RotateScope("rotate"); + /** Constant CHANGE_PLACEMENT_SIDE */ public static final LogfileScope CHANGE_PLACEMENT_SIDE = new ChangePlacementSideScope("change_placement_side"); + /** Constant SET_ZOOM_WITH_WHEEL */ public static final LogfileScope SET_ZOOM_WITH_WHEEL = new SetZoomWithWheelScope("set_zoom_with_wheel"); // scopes for logging displax changes + /** Constant CENTER_DISPLAY */ public static final LogfileScope CENTER_DISPLAY = new CenterDisplayScope("center_display"); + /** Constant ZOOM_FRAME */ public static final LogfileScope ZOOM_FRAME = new ZoomFrameScope("zoom_frame"); @@ -127,12 +180,20 @@ public abstract class LogfileScope /** * Reads the scope from the input logfile. * Returns the active interactive state after reading the scope. + * + * @param p_logfile a {@link interactive.Logfile} object. + * @param p_return_state a {@link interactive.InteractiveState} object. + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @return a {@link interactive.InteractiveState} object. */ public abstract InteractiveState read_scope(Logfile p_logfile, InteractiveState p_return_state, BoardHandling p_board_handling); /** * Returns the LogfileScope with name p_name if it exists, else null. + * + * @param p_name a {@link java.lang.String} object. + * @return a {@link interactive.LogfileScope} object. */ public static LogfileScope get_scope(String p_name) { diff --git a/interactive/MakeSpaceState.java b/src/main/java/interactive/MakeSpaceState.java similarity index 89% rename from interactive/MakeSpaceState.java rename to src/main/java/interactive/MakeSpaceState.java index edade1e..f8f50be 100644 --- a/interactive/MakeSpaceState.java +++ b/src/main/java/interactive/MakeSpaceState.java @@ -30,11 +30,19 @@ * For that purpose traces of an unvisible net are created tempory for shoving. * * @author Alfons Wirtz + * @version $Id: $Id */ public class MakeSpaceState extends DragState { - /** Creates a new instance of MakeSpaceState */ + /** + * Creates a new instance of MakeSpaceState + * + * @param p_location a {@link geometry.planar.FloatPoint} object. + * @param p_parent_state a {@link interactive.InteractiveState} object. + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_logfile a {@link interactive.Logfile} object. + */ public MakeSpaceState(FloatPoint p_location, InteractiveState p_parent_state, BoardHandling p_board_handling, Logfile p_logfile) { super(p_location, p_parent_state, p_board_handling, p_logfile); @@ -55,6 +63,7 @@ public MakeSpaceState(FloatPoint p_location, InteractiveState p_parent_state, Bo false, false, false, hdlg.settings.hilight_routing_obstacle); } + /** {@inheritDoc} */ public InteractiveState move_to(FloatPoint p_to_location) { if (!something_dragged) @@ -89,6 +98,11 @@ public InteractiveState move_to(FloatPoint p_to_location) return this; } + /** + *

button_released.

+ * + * @return a {@link interactive.InteractiveState} object. + */ public InteractiveState button_released() { int delete_net_no = rules.Nets.hidden_net_no; @@ -107,6 +121,7 @@ public InteractiveState button_released() return this.return_state; } + /** {@inheritDoc} */ public void draw(java.awt.Graphics p_graphics) { if (route != null) diff --git a/interactive/MenuState.java b/src/main/java/interactive/MenuState.java similarity index 91% rename from interactive/MenuState.java rename to src/main/java/interactive/MenuState.java index 4824ed1..068eaa8 100644 --- a/interactive/MenuState.java +++ b/src/main/java/interactive/MenuState.java @@ -32,6 +32,7 @@ * Common base class for the main menus, which can be selected in the tool bar. * * @author Alfons Wirtz + * @version $Id: $Id */ public class MenuState extends InteractiveState { @@ -43,6 +44,11 @@ public class MenuState extends InteractiveState this.return_state = this; } + /** + *

get_popup_menu.

+ * + * @return a {@link javax.swing.JPopupMenu} object. + */ public javax.swing.JPopupMenu get_popup_menu() { return hdlg.get_panel().popup_menu_main; @@ -52,6 +58,9 @@ public javax.swing.JPopupMenu get_popup_menu() * Selects items at p_location. * Returns a new instance of SelectedItemState with the selected items, * if somthing was selected. + * + * @param p_location a {@link geometry.planar.FloatPoint} object. + * @return a {@link interactive.InteractiveState} object. */ public InteractiveState select_items(FloatPoint p_location) { @@ -76,6 +85,12 @@ public InteractiveState select_items(FloatPoint p_location) return result; } + /** + *

swap_pin.

+ * + * @param p_location a {@link geometry.planar.FloatPoint} object. + * @return a {@link interactive.InteractiveState} object. + */ public InteractiveState swap_pin(FloatPoint p_location) { ItemSelectionFilter selection_filter = new ItemSelectionFilter(ItemSelectionFilter.SelectableChoices.PINS); @@ -101,6 +116,8 @@ public InteractiveState swap_pin(FloatPoint p_location) } /** + * {@inheritDoc} + * * Action to be taken when a key shortcut is pressed. */ public InteractiveState key_typed(char p_key_char) @@ -204,6 +221,8 @@ else if (p_key_char == '-') /** * Do nothing on complete. + * + * @return a {@link interactive.InteractiveState} object. */ public InteractiveState complete() { @@ -212,12 +231,17 @@ public InteractiveState complete() /** * Do nothing on cancel. + * + * @return a {@link interactive.InteractiveState} object. */ public InteractiveState cancel() { return this; } + /** + *

set_toolbar.

+ */ public void set_toolbar() { hdlg.get_panel().board_frame.set_menu_toolbar(); diff --git a/interactive/MoveItemState.java b/src/main/java/interactive/MoveItemState.java similarity index 94% rename from interactive/MoveItemState.java rename to src/main/java/interactive/MoveItemState.java index a6e3af2..fa9e7fa 100644 --- a/interactive/MoveItemState.java +++ b/src/main/java/interactive/MoveItemState.java @@ -39,14 +39,23 @@ import board.LayerStructure; /** + *

MoveItemState class.

* * @author Alfons Wirtz + * @version $Id: $Id */ public class MoveItemState extends InteractiveState { /** * Returns a new instance of MoveComponentState, or null, if the items of p_itemlist do not belong * to a single component. + * + * @param p_location a {@link geometry.planar.FloatPoint} object. + * @param p_item_list a {@link java.util.Collection} object. + * @param p_parent_state a {@link interactive.InteractiveState} object. + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_logfile a {@link interactive.Logfile} object. + * @return a {@link interactive.MoveItemState} object. */ public static MoveItemState get_instance(FloatPoint p_location, Collection p_item_list, InteractiveState p_parent_state, BoardHandling p_board_handling, Logfile p_logfile) @@ -232,6 +241,11 @@ private void add_to_net_items_list(Item p_item, int p_net_no) this.net_items_list.add(new_net_items); } + /** + *

mouse_moved.

+ * + * @return a {@link interactive.InteractiveState} object. + */ public InteractiveState mouse_moved() { super.mouse_moved(); @@ -243,17 +257,24 @@ public InteractiveState mouse_moved() return this; } + /** {@inheritDoc} */ public InteractiveState process_logfile_point(FloatPoint p_point) { move(p_point); return this; } + /** {@inheritDoc} */ public InteractiveState left_button_clicked(FloatPoint p_location) { return this.complete(); } + /** + *

complete.

+ * + * @return a {@link interactive.InteractiveState} object. + */ public InteractiveState complete() { for (Item curr_item : this.item_list) @@ -290,6 +311,11 @@ public InteractiveState complete() return this.return_state; } + /** + *

cancel.

+ * + * @return a {@link interactive.InteractiveState} object. + */ public InteractiveState cancel() { hdlg.get_routing_board().undo(null); @@ -304,6 +330,7 @@ public InteractiveState cancel() return this.return_state; } + /** {@inheritDoc} */ public InteractiveState mouse_wheel_moved(int p_rotation) { if (hdlg.settings.zoom_with_wheel) @@ -365,6 +392,8 @@ private Vector adjust_to_placement_grid(Vector p_vector) /** * Turns the items in the list by p_factor times 90 degree around the current position. + * + * @param p_factor a int. */ public void turn_90_degree(int p_factor) { @@ -395,6 +424,11 @@ public void turn_90_degree(int p_factor) } + /** + *

rotate.

+ * + * @param p_angle_in_degree a double. + */ public void rotate(double p_angle_in_degree) { if (p_angle_in_degree == 0) @@ -427,6 +461,8 @@ public void rotate(double p_angle_in_degree) /** * Turns the items in the list by p_factor times 90 degree around the current position. + * + * @param p_factor a int. */ public void turn_45_degree(int p_factor) { @@ -502,6 +538,9 @@ else if (curr_item.first_layer() == curr_item.last_layer()) + /** + *

reset_rotation.

+ */ public void reset_rotation() { Component component_to_reset = null; @@ -531,6 +570,8 @@ else if (component_to_reset.get_rotation_in_degree() != curr_component.get_rotat /** + * {@inheritDoc} + * * Action to be taken when a key is pressed (Shortcut). */ public InteractiveState key_typed(char p_key_char) @@ -567,16 +608,27 @@ else if (p_key_char == 'z') return curr_return_state; } + /** + *

get_popup_menu.

+ * + * @return a {@link javax.swing.JPopupMenu} object. + */ public javax.swing.JPopupMenu get_popup_menu() { return hdlg.get_panel().popup_menu_move; } + /** + *

get_help_id.

+ * + * @return a {@link java.lang.String} object. + */ public String get_help_id() { return "MoveItemState"; } + /** {@inheritDoc} */ public void draw(java.awt.Graphics p_graphics) { if (this.item_list == null) diff --git a/interactive/NetIncompletes.java b/src/main/java/interactive/NetIncompletes.java similarity index 95% rename from interactive/NetIncompletes.java rename to src/main/java/interactive/NetIncompletes.java index 0681468..67b6aa0 100644 --- a/interactive/NetIncompletes.java +++ b/src/main/java/interactive/NetIncompletes.java @@ -42,11 +42,19 @@ * Creates the Incompletes (Ratsnest) of one net to display them on the screen. * * @author Alfons Wirtz + * @version $Id: $Id */ public class NetIncompletes { - /** Creates a new instance of NetIncompletes */ + /** + * Creates a new instance of NetIncompletes + * + * @param p_net_no a int. + * @param p_net_items a java$util$Collection object. + * @param p_board a {@link board.BasicBoard} object. + * @param p_locale a {@link java.util.Locale} object. + */ public NetIncompletes(int p_net_no, Collection p_net_items, BasicBoard p_board, java.util.Locale p_locale) { this.draw_marker_radius = p_board.rules.get_min_trace_half_width() * 2; @@ -101,6 +109,8 @@ public NetIncompletes(int p_net_no, Collection p_net_items, BasicBoard p_b /** * Returns the number of incompletes of this net. + * + * @return a int. */ public int count() { @@ -147,6 +157,14 @@ boolean calc_length_violation() return this.length_violation; } + /** + *

draw.

+ * + * @param p_graphics a {@link java.awt.Graphics} object. + * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object. + * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object. + * @param p_length_violations_only a boolean. + */ public void draw(Graphics p_graphics, GraphicsContext p_graphics_context, boolean p_length_violations_only) { if (!p_length_violations_only) diff --git a/interactive/PinSwapState.java b/src/main/java/interactive/PinSwapState.java similarity index 90% rename from interactive/PinSwapState.java rename to src/main/java/interactive/PinSwapState.java index 73673b3..11a406b 100644 --- a/interactive/PinSwapState.java +++ b/src/main/java/interactive/PinSwapState.java @@ -27,11 +27,22 @@ import board.ItemSelectionFilter; /** + *

PinSwapState class.

* * @author Alfons Wirtz + * @version $Id: $Id */ public class PinSwapState extends InteractiveState { + /** + *

get_instance.

+ * + * @param p_pin_to_swap a {@link board.Pin} object. + * @param p_return_state a {@link interactive.InteractiveState} object. + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_logfile a {@link interactive.Logfile} object. + * @return a {@link interactive.InteractiveState} object. + */ public static InteractiveState get_instance(Pin p_pin_to_swap, InteractiveState p_return_state, BoardHandling p_board_handling, Logfile p_logfile) { PinSwapState new_state = new PinSwapState(p_pin_to_swap, p_return_state, p_board_handling, p_logfile); @@ -52,6 +63,7 @@ private PinSwapState(Pin p_pin_to_swap, InteractiveState p_return_state, BoardHa } + /** {@inheritDoc} */ public InteractiveState left_button_clicked(FloatPoint p_location) { ItemSelectionFilter selection_filter = new ItemSelectionFilter(ItemSelectionFilter.SelectableChoices.PINS); @@ -76,6 +88,11 @@ public InteractiveState left_button_clicked(FloatPoint p_location) return complete(); } + /** + *

complete.

+ * + * @return a {@link interactive.InteractiveState} object. + */ public InteractiveState complete() { if (this.from_pin == null || this.to_pin == null) @@ -130,6 +147,7 @@ public InteractiveState complete() return this.return_state; } + /** {@inheritDoc} */ public void draw(java.awt.Graphics p_graphics) { java.awt.Color highlight_color = hdlg.graphics_context.get_hilight_color(); diff --git a/interactive/PolygonShapeConstructionState.java b/src/main/java/interactive/PolygonShapeConstructionState.java similarity index 89% rename from interactive/PolygonShapeConstructionState.java rename to src/main/java/interactive/PolygonShapeConstructionState.java index cffcd89..128e7ca 100644 --- a/interactive/PolygonShapeConstructionState.java +++ b/src/main/java/interactive/PolygonShapeConstructionState.java @@ -32,12 +32,19 @@ * Interactive state for constructing an obstacle with a polygon shape. * * @author Alfons Wirtz + * @version $Id: $Id */ public class PolygonShapeConstructionState extends CornerItemConstructionState { /** * Returns a new instance of this class * If p_logfile != null; the creation of this item is stored in a logfile + * + * @param p_location a {@link geometry.planar.FloatPoint} object. + * @param p_parent_state a {@link interactive.InteractiveState} object. + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_logfile a {@link interactive.Logfile} object. + * @return a {@link interactive.PolygonShapeConstructionState} object. */ public static PolygonShapeConstructionState get_instance(FloatPoint p_location, InteractiveState p_parent_state, BoardHandling p_board_handling, Logfile p_logfile) { @@ -58,6 +65,8 @@ private PolygonShapeConstructionState(FloatPoint p_location, InteractiveState p_ /** * Inserts the polygon shape item into the board, if possible * and returns to the main state + * + * @return a {@link interactive.InteractiveState} object. */ public InteractiveState complete() { @@ -116,6 +125,9 @@ public InteractiveState complete() return this.return_state; } + /** + *

display_default_message.

+ */ public void display_default_message() { hdlg.screen_messages.set_status_message(resources.getString("creating_polygonshape")); diff --git a/interactive/RatsNest.java b/src/main/java/interactive/RatsNest.java similarity index 86% rename from interactive/RatsNest.java rename to src/main/java/interactive/RatsNest.java index cd18122..9b77611 100644 --- a/interactive/RatsNest.java +++ b/src/main/java/interactive/RatsNest.java @@ -42,11 +42,17 @@ * Creates all Incompletes (Ratsnest) to display them on the screen * * @author Alfons Wirtz + * @version $Id: $Id */ public class RatsNest { - /** Creates a new instance of RatsNest */ + /** + * Creates a new instance of RatsNest + * + * @param p_board a {@link board.BasicBoard} object. + * @param p_locale a {@link java.util.Locale} object. + */ public RatsNest(BasicBoard p_board, java.util.Locale p_locale) { this.locale = p_locale; @@ -84,6 +90,9 @@ public RatsNest(BasicBoard p_board, java.util.Locale p_locale) /** * Recalculates the incomplete connections for the input net + * + * @param p_net_no a int. + * @param p_board a {@link board.BasicBoard} object. */ public void recalculate(int p_net_no, BasicBoard p_board) { @@ -96,6 +105,10 @@ public void recalculate(int p_net_no, BasicBoard p_board) /** * Recalculates the incomplete connections for the input net with the input item list. + * + * @param p_net_no a int. + * @param p_item_list a {@link java.util.Collection} object. + * @param p_board a {@link board.BasicBoard} object. */ public void recalculate(int p_net_no, Collection p_item_list, BasicBoard p_board) { @@ -107,6 +120,11 @@ public void recalculate(int p_net_no, Collection p_item_list, BasicBoard p } } + /** + *

incomplete_count.

+ * + * @return a int. + */ public int incomplete_count() { int result = 0; @@ -117,6 +135,12 @@ public int incomplete_count() return result; } + /** + *

incomplete_count.

+ * + * @param p_net_no a int. + * @return a int. + */ public int incomplete_count(int p_net_no) { if (p_net_no <= 0 || p_net_no > net_incompletes.length) @@ -126,6 +150,11 @@ public int incomplete_count(int p_net_no) return net_incompletes[p_net_no - 1].count(); } + /** + *

length_violation_count.

+ * + * @return a int. + */ public int length_violation_count() { int result = 0; @@ -141,9 +170,13 @@ public int length_violation_count() /** * Returns the length of the violation of the length restriction of the net with number p_net_no, - * > 0, if the cumulative trace length is to big, - * < 0, if the trace length is to smalll, - * 0, if the thace length is ok or the net has no length restrictions + * {@code + > 0, if the cumulative trace length is to big, + < 0, if the trace length is to smalll, + 0, if the thace length is ok or the net has no length restrictions + } + * @param p_net_no a int. + * @return a double. */ public double get_length_violation(int p_net_no) { @@ -156,6 +189,8 @@ public double get_length_violation(int p_net_no) /** * Returns all airlines of the ratsnest. + * + * @return an array of {@link interactive.RatsNest.AirLine} objects. */ public AirLine [] get_airlines() { @@ -173,11 +208,17 @@ public double get_length_violation(int p_net_no) return result; } + /** + *

hide.

+ */ public void hide() { hidden = true; } + /** + *

show.

+ */ public void show() { hidden = false; @@ -186,6 +227,8 @@ public void show() /** * Recalculate the length matching violations. * Return false, if the length violations have not changed. + * + * @return a boolean. */ public boolean recalculate_length_violations() { @@ -202,6 +245,8 @@ public boolean recalculate_length_violations() /** * Used for example to hide the incompletes during interactive routiing. + * + * @return a boolean. */ public boolean is_hidden() { @@ -211,6 +256,9 @@ public boolean is_hidden() /** * Sets the visibility filter for the incompletes of the input net. + * + * @param p_net_no a int. + * @param p_value a boolean. */ public void set_filter(int p_net_no, boolean p_value) { @@ -221,6 +269,13 @@ public void set_filter(int p_net_no, boolean p_value) is_filtered[p_net_no - 1] = p_value; } + /** + *

draw.

+ * + * @param p_graphics a {@link java.awt.Graphics} object. + * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object. + * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object. + */ public void draw(Graphics p_graphics, GraphicsContext p_graphics_context) { boolean draw_length_violations_only = this.hidden; diff --git a/interactive/Route.java b/src/main/java/interactive/Route.java similarity index 95% rename from interactive/Route.java rename to src/main/java/interactive/Route.java index 99d4826..d37638a 100644 --- a/interactive/Route.java +++ b/src/main/java/interactive/Route.java @@ -1,946 +1,990 @@ -/* - * Copyright (C) 2014 Alfons Wirtz - * website www.freerouting.net - * - * 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 at - * for more details. - */ -package interactive; - -import datastructures.TimeLimit; - -import geometry.planar.Area; -import geometry.planar.FloatPoint; -import geometry.planar.IntBox; -import geometry.planar.IntOctagon; -import geometry.planar.IntPoint; -import geometry.planar.Vector; -import geometry.planar.Point; -import geometry.planar.Polyline; -import geometry.planar.Ellipse; - -import java.awt.Graphics; -import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.Set; - -import library.Padstack; - -import rules.ViaRule; -import rules.ViaInfo; -import rules.Net; - -import board.AngleRestriction; -import board.Trace; -import board.ConductionArea; -import board.DrillItem; -import board.Item; -import board.PolylineTrace; -import board.RoutingBoard; -import board.ItemSelectionFilter; -import board.TestLevel; -import board.Unit; - -import boardgraphics.GraphicsContext; - -/** - * - * Functionality for interactive routing. - * - * @author Alfons Wirtz - */ -public class Route -{ - - /** - * Starts routing a connection. - * p_pen_half_width_arr is provided because it may be different from - * the half width array in p_board.rules. - */ - public Route(Point p_start_corner, int p_layer, int[] p_pen_half_width_arr, boolean[] p_layer_active_arr, int[] p_net_no_arr, - int p_clearance_class, ViaRule p_via_rule, boolean p_push_enabled, - int p_trace_tidy_width, int p_pull_tight_accuracy, Item p_start_item, Set p_target_set, - RoutingBoard p_board, boolean p_is_stitch_mode, boolean p_with_neckdown, boolean p_via_snap_to_smd_center, - boolean p_hilight_shove_failing_obstacle) - { - board = p_board; - layer = p_layer; - if (p_push_enabled) - { - max_shove_trace_recursion_depth = 20; - max_shove_via_recursion_depth = 8; - max_spring_over_recursion_depth = 5; - } - else - { - max_shove_trace_recursion_depth = 0; - max_shove_via_recursion_depth = 0; - max_spring_over_recursion_depth = 0; - } - trace_tidy_width = p_trace_tidy_width; - pull_tight_accuracy = p_pull_tight_accuracy; - prev_corner = p_start_corner; - net_no_arr = p_net_no_arr; - pen_half_width_arr = p_pen_half_width_arr; - layer_active = p_layer_active_arr; - clearance_class = p_clearance_class; - via_rule = p_via_rule; - start_item = p_start_item; - target_set = p_target_set; - is_stitch_mode = p_is_stitch_mode; - with_neckdown = p_with_neckdown; - via_snap_to_smd_center = p_via_snap_to_smd_center; - hilight_shove_failing_obstacle = p_hilight_shove_failing_obstacle; - if (p_board.get_test_level() == TestLevel.RELEASE_VERSION) - { - this.pull_tight_time_limit = PULL_TIGHT_TIME_LIMIT; - } - else - { - this.pull_tight_time_limit = 0; - } - calculate_target_points_and_areas(); - swap_pin_infos = calculate_swap_pin_infos(); - } - - /** - * Append a line to the trace routed so far. - * Return true, if the route is completed by connecting - * to a target. - */ - public boolean next_corner(FloatPoint p_corner) - { - if (!this.layer_active[this.layer]) - { - return false; - } - IntPoint curr_corner = p_corner.round(); - if (!(board.contains(prev_corner) && board.contains(curr_corner) && board.layer_structure.arr[this.layer].is_signal)) - { - return false; - } - - if (curr_corner.equals(prev_corner)) - { - return false; - } - if (nearest_target_item instanceof DrillItem) - { - DrillItem target = (DrillItem) nearest_target_item; - if (this.prev_corner.equals(target.get_center())) - { - return true; // connection already completed at prev_corner. - } - } - this.shove_failing_obstacle = null; - AngleRestriction angle_restriction = this.board.rules.get_trace_angle_restriction(); - if (angle_restriction != AngleRestriction.NONE && !(prev_corner instanceof IntPoint)) - { - return false; - } - if (angle_restriction == AngleRestriction.NINETY_DEGREE) - { - curr_corner = curr_corner.orthogonal_projection((IntPoint) prev_corner); - } - else if (angle_restriction == AngleRestriction.FORTYFIVE_DEGREE) - { - curr_corner = curr_corner.fortyfive_degree_projection((IntPoint) prev_corner); - } - Item end_routing_item = board.pick_nearest_routing_item(prev_corner, this.layer, null); - // look for a nearby item of this net, which is not connected to end_routing_item. - nearest_target_item = board.pick_nearest_routing_item(curr_corner, this.layer, end_routing_item); - TimeLimit check_forced_trace_time_limit; - if (is_stitch_mode || this.board.get_test_level() != TestLevel.RELEASE_VERSION) - { - // because no check before inserting in this case - check_forced_trace_time_limit = null; - } - else - { - check_forced_trace_time_limit = new TimeLimit(CHECK_FORCED_TRACE_TIME_LIMIT); - } - - - // tests.Validate.check("before insert", board); - Point ok_point = board.insert_forced_trace_segment(prev_corner, - curr_corner, pen_half_width_arr[layer], layer, net_no_arr, clearance_class, - max_shove_trace_recursion_depth, max_shove_via_recursion_depth, max_spring_over_recursion_depth, - trace_tidy_width, pull_tight_accuracy, !is_stitch_mode, check_forced_trace_time_limit); - // tests.Validate.check("after insert", board); - if (ok_point == prev_corner && this.with_neckdown) - { - ok_point = try_neckdown_at_start(curr_corner); - } - if (ok_point == prev_corner && this.with_neckdown) - { - ok_point = try_neckdown_at_end(this.prev_corner, curr_corner); - } - if (ok_point == null) - { - // database may be damaged, restore previous situation - board.undo(null); - // end routing in case it is dynamic - return (!is_stitch_mode); - } - - if (ok_point == prev_corner) - { - set_shove_failing_obstacle(board.get_shove_failing_obstacle()); - return false; - } - this.prev_corner = ok_point; - // check, if a target is reached - boolean route_completed = false; - if (ok_point == curr_corner) - { - route_completed = connect_to_target(curr_corner); - } - - IntOctagon tidy_clip_shape; - if (trace_tidy_width == Integer.MAX_VALUE) - { - tidy_clip_shape = null; - } - else if (trace_tidy_width == 0) - { - tidy_clip_shape = IntOctagon.EMPTY; - } - else - { - tidy_clip_shape = ok_point.surrounding_octagon().enlarge(trace_tidy_width); - } - int[] opt_net_no_arr; - if (max_shove_trace_recursion_depth <= 0) - { - opt_net_no_arr = net_no_arr; - } - else - { - opt_net_no_arr = new int[0]; - } - if (route_completed) - { - this.board.reduce_nets_of_route_items(); - for (int curr_net_no : this.net_no_arr) - { - this.board.combine_traces(curr_net_no); - } - } - else - { - calc_nearest_target_point(this.prev_corner.to_float()); - } - board.opt_changed_area(opt_net_no_arr, tidy_clip_shape, pull_tight_accuracy, - null, null, pull_tight_time_limit, ok_point, layer); - return route_completed; - } - - /** - * Changing the layer in interactive route and inserting a via. - * Returns false, if changing the layer was not possible. - */ - public boolean change_layer(int p_to_layer) - { - if (this.layer == p_to_layer) - { - return true; - } - if (p_to_layer < 0 || p_to_layer >= this.layer_active.length) - { - System.out.println("Route.change_layer: p_to_layer out of range"); - return false; - } - if (!this.layer_active[p_to_layer]) - { - return false; - } - if (this.via_rule == null) - { - return false; - } - this.shove_failing_obstacle = null; - if (this.via_snap_to_smd_center) - { - boolean snapped_to_smd_center = snap_to_smd_center(p_to_layer); - if (!snapped_to_smd_center) - { - snap_to_smd_center(this.layer); - } - } - boolean result = true; - int min_layer = Math.min(this.layer, p_to_layer); - int max_layer = Math.max(this.layer, p_to_layer); - boolean via_found = false; - for (int i = 0; i < this.via_rule.via_count(); ++i) - { - ViaInfo curr_via_info = this.via_rule.get_via(i); - Padstack curr_via_padstack = curr_via_info.get_padstack(); - if (min_layer < curr_via_padstack.from_layer() || max_layer > curr_via_padstack.to_layer()) - { - continue; - } - // make the current situation restorable by undo - board.generate_snapshot(); - result = board.forced_via(curr_via_info, this.prev_corner, this.net_no_arr, clearance_class, - pen_half_width_arr, max_shove_trace_recursion_depth, - 0, this.trace_tidy_width, this.pull_tight_accuracy, pull_tight_time_limit); - if (result) - { - via_found = true; - break; - } - set_shove_failing_obstacle(board.get_shove_failing_obstacle()); - board.undo(null); - } - if (via_found) - { - this.layer = p_to_layer; - } - return result; - } - - /** - * Snaps to the center of an smd pin, if the location location on p_layer is inside an smd pin of the own net, - */ - private boolean snap_to_smd_center(int p_layer) - { - ItemSelectionFilter selection_filter = new ItemSelectionFilter(ItemSelectionFilter.SelectableChoices.PINS); - java.util.Collection picked_items = board.pick_items(this.prev_corner, p_layer, selection_filter); - board.Pin found_smd_pin = null; - for (Item curr_item : picked_items) - { - if (curr_item instanceof board.Pin && curr_item.shares_net_no(this.net_no_arr)) - { - board.Pin curr_pin = (board.Pin) curr_item; - if (curr_pin.first_layer() == p_layer && curr_pin.last_layer() == p_layer) - { - found_smd_pin = curr_pin; - break; - } - } - } - if (found_smd_pin == null) - { - return false; - } - Point pin_center = found_smd_pin.get_center(); - if (!(pin_center instanceof IntPoint)) - { - return false; - } - IntPoint to_corner = (IntPoint) pin_center; - if (this.connect(this.prev_corner, to_corner)) - { - this.prev_corner = to_corner; - } - return true; - } - - /** - * If p_from_point is already on a target item, a connection - * to the target is made and true returned. - */ - private boolean connect_to_target(IntPoint p_from_point) - { - if (nearest_target_item != null && target_set != null && !target_set.contains(nearest_target_item)) - { - nearest_target_item = null; - } - if (nearest_target_item == null || !nearest_target_item.shares_net_no(this.net_no_arr)) - { - return false; - } - boolean route_completed = false; - Point connection_point = null; - if (nearest_target_item instanceof DrillItem) - { - DrillItem target = (DrillItem) nearest_target_item; - connection_point = target.get_center(); - } - else if (nearest_target_item instanceof PolylineTrace) - { - return board.connect_to_trace(p_from_point, (PolylineTrace) nearest_target_item, - this.pen_half_width_arr[layer], this.clearance_class); - } - else if (nearest_target_item instanceof ConductionArea) - { - connection_point = p_from_point; - } - if (connection_point != null && connection_point instanceof IntPoint) - { - route_completed = connect(p_from_point, (IntPoint) connection_point); - } - return route_completed; - } - - /** - * Tries to make a trace connection from p_from_point to p_to_point according to the angle restriction. - * Returns true, if the connection succeeded. - */ - private boolean connect(Point p_from_point, IntPoint p_to_point) - { - Point[] corners = angled_connection(p_from_point, p_to_point); - boolean connection_succeeded = true; - for (int i = 1; i < corners.length; ++i) - { - Point from_corner = corners[i - 1]; - Point to_corner = corners[i]; - TimeLimit time_limit = new TimeLimit(CHECK_FORCED_TRACE_TIME_LIMIT); - while (!from_corner.equals(to_corner)) - { - Point curr_ok_point = board.insert_forced_trace_segment(from_corner, - to_corner, pen_half_width_arr[layer], this.layer, net_no_arr, - clearance_class, max_shove_trace_recursion_depth, - max_shove_via_recursion_depth, max_spring_over_recursion_depth, - trace_tidy_width, pull_tight_accuracy, !is_stitch_mode, time_limit); - if (curr_ok_point == null) - { - // database may be damaged, restore previous situation - board.undo(null); - return true; - } - if (curr_ok_point.equals(from_corner) && this.with_neckdown) - { - curr_ok_point = try_neckdown_at_end(from_corner, to_corner); - } - if (curr_ok_point.equals(from_corner)) - { - this.prev_corner = from_corner; - connection_succeeded = false; - break; - } - from_corner = curr_ok_point; - } - } - return connection_succeeded; - } - - /** Calculates the nearest layer of the nearest target item - * to this.layer. - */ - public int nearest_target_layer() - { - if (nearest_target_item == null) - { - return this.layer; - } - int result; - int first_layer = nearest_target_item.first_layer(); - int last_layer = nearest_target_item.last_layer(); - if (this.layer < first_layer) - { - result = first_layer; - } - else if (this.layer > last_layer) - { - result = last_layer; - } - else - { - result = this.layer; - } - return result; - } - - /** - * Returns all pins, which can be reached by a pin swap from a srtart or target pin. - */ - private Set calculate_swap_pin_infos() - { - Set result = new java.util.TreeSet(); - if (this.target_set == null) - { - return result; - } - for (Item curr_item : this.target_set) - { - if (curr_item instanceof board.Pin) - { - Collection curr_swapppable_pins = ((board.Pin) curr_item).get_swappable_pins(); - for (board.Pin curr_swappable_pin : curr_swapppable_pins) - { - result.add(new SwapPinInfo(curr_swappable_pin)); - } - } - } - // add the from item, if it is a pin - ItemSelectionFilter selection_filter = new ItemSelectionFilter(ItemSelectionFilter.SelectableChoices.PINS); - java.util.Collection picked_items = board.pick_items(this.prev_corner, this.layer, selection_filter); - for (Item curr_item : picked_items) - { - if (curr_item instanceof board.Pin) - { - Collection curr_swapppable_pins = ((board.Pin) curr_item).get_swappable_pins(); - for (board.Pin curr_swappable_pin : curr_swapppable_pins) - { - result.add(new SwapPinInfo(curr_swappable_pin)); - } - } - } - return result; - } - - /** - * Hilights the targets and draws the incomplete. - */ - public void draw(Graphics p_graphics, GraphicsContext p_graphics_context) - { - if (this.hilight_shove_failing_obstacle && this.shove_failing_obstacle != null) - { - this.shove_failing_obstacle.draw(p_graphics, p_graphics_context, p_graphics_context.get_violations_color(), 1); - } - if (target_set == null || net_no_arr.length < 1) - { - return; - } - Net curr_net = board.rules.nets.get(net_no_arr[0]); - if (curr_net == null) - { - return; - } - java.awt.Color highlight_color = p_graphics_context.get_hilight_color(); - double highligt_color_intensity = p_graphics_context.get_hilight_color_intensity(); - - - // hilight the swapppable pins and their incompletes - for (SwapPinInfo curr_info : this.swap_pin_infos) - { - curr_info.pin.draw(p_graphics, p_graphics_context, highlight_color, 0.3 * highligt_color_intensity); - if (curr_info.incomplete != null) - { - // draw the swap pin incomplete - FloatPoint[] draw_points = new FloatPoint[2]; - draw_points[0] = curr_info.incomplete.a; - draw_points[1] = curr_info.incomplete.b; - java.awt.Color draw_color = p_graphics_context.get_incomplete_color(); - p_graphics_context.draw(draw_points, 1, draw_color, p_graphics, highligt_color_intensity); - } - } - - // hilight the target set - for (Item curr_item : target_set) - { - if (!(curr_item instanceof ConductionArea)) - { - curr_item.draw(p_graphics, p_graphics_context, highlight_color, highligt_color_intensity); - } - } - FloatPoint from_corner = this.prev_corner.to_float(); - if (nearest_target_point != null && prev_corner != null) - { - boolean curr_length_matching_ok = true; // used for drawing the incomplete as violation - double max_trace_length = curr_net.get_class().get_maximum_trace_length(); - double min_trace_length = curr_net.get_class().get_minimum_trace_length(); - double length_matching_color_intensity = p_graphics_context.get_length_matching_area_color_intensity(); - if (max_trace_length > 0 || min_trace_length > 0 && length_matching_color_intensity > 0) - { - - // draw the length matching area - double trace_length_add = from_corner.distance(this.prev_corner.to_float()); - // trace_length_add is != 0 only in stitching mode. - if (max_trace_length <= 0) - { - // max_trace_length not provided. Create an ellipse containing the whole board. - max_trace_length = 0.3 * geometry.planar.Limits.CRIT_INT; - } - double curr_max_trace_length = max_trace_length - (curr_net.get_trace_length() + trace_length_add); - double curr_min_trace_length = min_trace_length - (curr_net.get_trace_length() + trace_length_add); - double incomplete_length = nearest_target_point.distance(from_corner); - if (incomplete_length < curr_max_trace_length && min_trace_length <= max_trace_length) - { - Vector delta = nearest_target_point.round().difference_by(prev_corner); - double rotation = delta.angle_approx(); - FloatPoint center = from_corner.middle_point(nearest_target_point); - double bigger_radius = 0.5 * curr_max_trace_length; - // dist_focus_to_center^2 = bigger_radius^2 - smaller_radius^2 - double smaller_radius = 0.5 * Math.sqrt(curr_max_trace_length * curr_max_trace_length - incomplete_length * incomplete_length); - int ellipse_count; - if (min_trace_length <= 0 || incomplete_length >= curr_min_trace_length) - { - ellipse_count = 1; - } - else - { - // display an ellipse ring. - ellipse_count = 2; - } - Ellipse[] ellipse_arr = new Ellipse[ellipse_count]; - ellipse_arr[0] = new Ellipse(center, rotation, bigger_radius, smaller_radius); - IntBox bounding_box = new IntBox(prev_corner.to_float().round(), nearest_target_point.round()); - bounding_box = bounding_box.offset(curr_max_trace_length - incomplete_length); - board.join_graphics_update_box(bounding_box); - if (ellipse_count == 2) - { - bigger_radius = 0.5 * curr_min_trace_length; - smaller_radius = 0.5 * Math.sqrt(curr_min_trace_length * curr_min_trace_length - incomplete_length * incomplete_length); - ellipse_arr[1] = new Ellipse(center, rotation, bigger_radius, smaller_radius); - } - p_graphics_context.fill_ellipse_arr(ellipse_arr, p_graphics, - p_graphics_context.get_length_matching_area_color(), length_matching_color_intensity); - } - else - { - curr_length_matching_ok = false; - } - } - - // draw the incomplete - FloatPoint[] draw_points = new FloatPoint[2]; - draw_points[0] = from_corner; - draw_points[1] = nearest_target_point; - java.awt.Color draw_color = p_graphics_context.get_incomplete_color(); - double draw_width = Math.min (this.board.communication.get_resolution(Unit.MIL), 100); // problem with low resolution on Kicad - if (!curr_length_matching_ok) - { - draw_color = p_graphics_context.get_violations_color(); - draw_width *= 3; - } - p_graphics_context.draw(draw_points, draw_width, draw_color, p_graphics, highligt_color_intensity); - if (this.nearest_target_item != null && !this.nearest_target_item.is_on_layer(this.layer)) - { - // draw a marker to indicate the layer change. - NetIncompletes.draw_layer_change_marker(draw_points[0], 4 * pen_half_width_arr[0], p_graphics, p_graphics_context); - } - } - - } - - /** - * Makes a connection polygon from p_from_point to p_to_point - * whose lines fulfill the angle restriction. - */ - private Point[] angled_connection(Point p_from_point, Point p_to_point) - { - IntPoint add_corner = null; - if (p_from_point instanceof IntPoint && p_to_point instanceof IntPoint) - { - AngleRestriction angle_restriction = this.board.rules.get_trace_angle_restriction(); - if (angle_restriction == AngleRestriction.NINETY_DEGREE) - { - add_corner = ((IntPoint) p_from_point).ninety_degree_corner((IntPoint) p_to_point, true); - } - else if (angle_restriction == AngleRestriction.FORTYFIVE_DEGREE) - { - add_corner = ((IntPoint) p_from_point).fortyfive_degree_corner((IntPoint) p_to_point, true); - } - } - int new_corner_count = 2; - if (add_corner != null) - { - ++new_corner_count; - } - Point[] result = new Point[new_corner_count]; - result[0] = p_from_point; - if (add_corner != null) - { - result[1] = add_corner; - } - result[result.length - 1] = p_to_point; - return result; - } - - /** - * Calculates a list of the center points of DrillItems, - * end points of traces and areas of ConductionAreas in the target set. - */ - private void calculate_target_points_and_areas() - { - target_points = new LinkedList(); - target_traces_and_areas = new LinkedList(); - if (target_set == null) - { - return; - } - Iterator it = target_set.iterator(); - while (it.hasNext()) - { - Item curr_ob = it.next(); - if (curr_ob instanceof DrillItem) - { - Point curr_point = ((DrillItem) curr_ob).get_center(); - target_points.add(new TargetPoint(curr_point.to_float(), curr_ob)); - } - else if (curr_ob instanceof Trace || curr_ob instanceof ConductionArea) - { - target_traces_and_areas.add(curr_ob); - } - } - } - - public Point get_last_corner() - { - return prev_corner; - } - - public boolean is_layer_active(int p_layer) - { - if (p_layer < 0 || p_layer >= layer_active.length) - { - return false; - } - return layer_active[p_layer]; - } - - /** - * The nearest point is used for drowing the incomplete - */ - void calc_nearest_target_point(FloatPoint p_from_point) - { - double min_dist = Double.MAX_VALUE; - FloatPoint nearest_point = null; - Item nearest_item = null; - for (TargetPoint curr_target_point : target_points) - { - double curr_dist = p_from_point.distance(curr_target_point.location); - if (curr_dist < min_dist) - { - min_dist = curr_dist; - nearest_point = curr_target_point.location; - nearest_item = curr_target_point.item; - } - } - Iterator it = target_traces_and_areas.iterator(); - while (it.hasNext()) - { - Item curr_item = it.next(); - if (curr_item instanceof PolylineTrace) - { - PolylineTrace curr_trace = (PolylineTrace) curr_item; - Polyline curr_polyline = curr_trace.polyline(); - if (curr_polyline.bounding_box().distance(p_from_point) < min_dist) - { - FloatPoint curr_nearest_point = curr_polyline.nearest_point_approx(p_from_point); - double curr_dist = p_from_point.distance(curr_nearest_point); - if (curr_dist < min_dist) - { - min_dist = curr_dist; - nearest_point = curr_nearest_point; - nearest_item = curr_trace; - } - } - } - else if (curr_item instanceof ConductionArea && curr_item.tile_shape_count() > 0) - { - ConductionArea curr_conduction_area = (ConductionArea) curr_item; - Area curr_area = curr_conduction_area.get_area(); - if (curr_area.bounding_box().distance(p_from_point) < min_dist) - { - FloatPoint curr_nearest_point = curr_area.nearest_point_approx(p_from_point); - double curr_dist = p_from_point.distance(curr_nearest_point); - if (curr_dist < min_dist) - { - min_dist = curr_dist; - nearest_point = curr_nearest_point; - nearest_item = curr_conduction_area; - } - } - } - } - if (nearest_point == null) - { - return; // target set is empty - } - nearest_target_point = nearest_point; - nearest_target_item = nearest_item; - // join the graphics update box by the nearest item, so that the incomplete - // is completely displayed. - board.join_graphics_update_box(nearest_item.bounding_box()); - } - - private void set_shove_failing_obstacle(Item p_item) - { - this.shove_failing_obstacle = p_item; - if (p_item != null) - { - this.board.join_graphics_update_box(p_item.bounding_box()); - } - } - - /** - * If the routed starts at a pin and the route failed with the normal trace width, - * another try with the smalllest pin width is done. - * Returns the ok_point of the try, which is this.prev_point, if the try failed. - */ - private Point try_neckdown_at_start(IntPoint p_to_corner) - { - if (!(this.start_item instanceof board.Pin)) - { - return this.prev_corner; - } - board.Pin start_pin = (board.Pin) this.start_item; - if (!start_pin.is_on_layer(this.layer)) - { - return this.prev_corner; - } - FloatPoint pin_center = start_pin.get_center().to_float(); - double curr_clearance = - this.board.rules.clearance_matrix.value(this.clearance_class, start_pin.clearance_class_no(), this.layer); - double pin_neck_down_distance = - 2 * (0.5 * start_pin.get_max_width(this.layer) + curr_clearance); - if (pin_center.distance(this.prev_corner.to_float()) >= pin_neck_down_distance) - { - return this.prev_corner; - } - - int neck_down_halfwidth = start_pin.get_trace_neckdown_halfwidth(this.layer); - if (neck_down_halfwidth >= this.pen_half_width_arr[this.layer]) - { - return this.prev_corner; - } - - // check, that the neck_down started inside the pin shape - if (!this.prev_corner.equals(start_pin.get_center())) - { - Item picked_item = this.board.pick_nearest_routing_item(this.prev_corner, this.layer, null); - if (picked_item instanceof Trace) - { - if (((Trace) picked_item).get_half_width() > neck_down_halfwidth) - { - return this.prev_corner; - } - } - } - TimeLimit time_limit = new TimeLimit(CHECK_FORCED_TRACE_TIME_LIMIT); - Point ok_point = board.insert_forced_trace_segment(prev_corner, - p_to_corner, neck_down_halfwidth, layer, net_no_arr, clearance_class, max_shove_trace_recursion_depth, - max_shove_via_recursion_depth, max_spring_over_recursion_depth, trace_tidy_width, - pull_tight_accuracy, !is_stitch_mode, time_limit); - return ok_point; - } - - /** - * If the routed ends at a pin and the route failed with the normal trace width, - * another try with the smalllest pin width is done. - * Returns the ok_point of the try, which is p_from_corner, if the try failed. - */ - private Point try_neckdown_at_end(Point p_from_corner, Point p_to_corner) - { - if (!(this.nearest_target_item instanceof board.Pin)) - { - return p_from_corner; - } - board.Pin target_pin = (board.Pin) this.nearest_target_item; - if (!target_pin.is_on_layer(this.layer)) - { - return p_from_corner; - } - FloatPoint pin_center = target_pin.get_center().to_float(); - double curr_clearance = - this.board.rules.clearance_matrix.value(this.clearance_class, target_pin.clearance_class_no(), this.layer); - double pin_neck_down_distance = - 2 * (0.5 * target_pin.get_max_width(this.layer) + curr_clearance); - if (pin_center.distance(p_from_corner.to_float()) >= pin_neck_down_distance) - { - return p_from_corner; - } - int neck_down_halfwidth = target_pin.get_trace_neckdown_halfwidth(this.layer); - if (neck_down_halfwidth >= this.pen_half_width_arr[this.layer]) - { - return p_from_corner; - } - TimeLimit time_limit = new TimeLimit(CHECK_FORCED_TRACE_TIME_LIMIT); - Point ok_point = board.insert_forced_trace_segment(p_from_corner, - p_to_corner, neck_down_halfwidth, layer, net_no_arr, clearance_class, - max_shove_trace_recursion_depth, max_shove_via_recursion_depth, - max_spring_over_recursion_depth, trace_tidy_width, - pull_tight_accuracy, !is_stitch_mode, time_limit); - return ok_point; - } - /** The net numbers used for routing */ - final int[] net_no_arr; - private Point prev_corner; - private int layer; - private final Item start_item; - private final Set target_set; - /** Pins, which can be reached by a pin swap by a target pin. */ - private final Set swap_pin_infos; - private Collection target_points; // from drill_items - private Collection target_traces_and_areas; // from traces and conduction areas - private FloatPoint nearest_target_point; - private Item nearest_target_item; - private final int[] pen_half_width_arr; - private final boolean[] layer_active; - private final int clearance_class; - private final ViaRule via_rule; - private final int max_shove_trace_recursion_depth; - private final int max_shove_via_recursion_depth; - private final int max_spring_over_recursion_depth; - private final int trace_tidy_width; - private final int pull_tight_accuracy; - private final RoutingBoard board; - private final boolean is_stitch_mode; - private final boolean with_neckdown; - private final boolean via_snap_to_smd_center; - private final boolean hilight_shove_failing_obstacle; - private final int pull_tight_time_limit; - private Item shove_failing_obstacle = null; - /** The time limit in milliseconds for the pull tight algorithm */ - private static final int CHECK_FORCED_TRACE_TIME_LIMIT = 3000; - /** The time limit in milliseconds for the pull tight algorithm */ - private static final int PULL_TIGHT_TIME_LIMIT = 2000; - - private static class TargetPoint - { - - TargetPoint(FloatPoint p_location, Item p_item) - { - location = p_location; - item = p_item; - } - final FloatPoint location; - final Item item; - } - - private class SwapPinInfo implements Comparable - { - - SwapPinInfo(board.Pin p_pin) - { - pin = p_pin; - incomplete = null; - if (p_pin.is_connected() || p_pin.net_count() != 1) - { - return; - } - // calculate the incomplete of p_pin - FloatPoint pin_center = p_pin.get_center().to_float(); - double min_dist = Double.MAX_VALUE; - FloatPoint nearest_point = null; - Collection net_items = board.get_connectable_items(p_pin.get_net_no(0)); - for (Item curr_item : net_items) - { - if (curr_item == this.pin || !(curr_item instanceof DrillItem)) - { - continue; - } - FloatPoint curr_point = ((DrillItem) curr_item).get_center().to_float(); - double curr_dist = pin_center.distance_square(curr_point); - if (curr_dist < min_dist) - { - min_dist = curr_dist; - nearest_point = curr_point; - } - } - if (nearest_point != null) - { - incomplete = new geometry.planar.FloatLine(pin_center, nearest_point); - } - } - - public int compareTo(SwapPinInfo p_other) - { - return this.pin.compareTo(p_other.pin); - } - final board.Pin pin; - geometry.planar.FloatLine incomplete; - } -} \ No newline at end of file +/* + * Copyright (C) 2014 Alfons Wirtz + * website www.freerouting.net + * + * 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 at + * for more details. + */ +package interactive; + +import datastructures.TimeLimit; + +import geometry.planar.Area; +import geometry.planar.FloatPoint; +import geometry.planar.IntBox; +import geometry.planar.IntOctagon; +import geometry.planar.IntPoint; +import geometry.planar.Vector; +import geometry.planar.Point; +import geometry.planar.Polyline; +import geometry.planar.Ellipse; + +import java.awt.Graphics; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Set; + +import library.Padstack; + +import rules.ViaRule; +import rules.ViaInfo; +import rules.Net; + +import board.AngleRestriction; +import board.Trace; +import board.ConductionArea; +import board.DrillItem; +import board.Item; +import board.PolylineTrace; +import board.RoutingBoard; +import board.ItemSelectionFilter; +import board.TestLevel; +import board.Unit; + +import boardgraphics.GraphicsContext; + +/** + * + * Functionality for interactive routing. + * + * @author Alfons Wirtz + * @version $Id: $Id + */ +public class Route +{ + + /** + * Starts routing a connection. + * p_pen_half_width_arr is provided because it may be different from + * the half width array in p_board.rules. + * + * @param p_start_corner a {@link geometry.planar.Point} object. + * @param p_layer a int. + * @param p_layer_active_arr an array of boolean. + * @param p_pen_half_width_arr an array of int. + * @param p_layer_active_arr an array of boolean. + * @param p_net_no_arr an array of int. + * @param p_clearance_class a int. + * @param p_via_rule a {@link rules.ViaRule} object. + * @param p_push_enabled a boolean. + * @param p_trace_tidy_width a int. + * @param p_pull_tight_accuracy a int. + * @param p_start_item a {@link board.Item} object. + * @param p_target_set a {@link java.util.Set} object. + * @param p_board a {@link board.RoutingBoard} object. + * @param p_is_stitch_mode a boolean. + * @param p_with_neckdown a boolean. + * @param p_via_snap_to_smd_center a boolean. + * @param p_hilight_shove_failing_obstacle a boolean. + */ + public Route(Point p_start_corner, int p_layer, int[] p_pen_half_width_arr, boolean[] p_layer_active_arr, int[] p_net_no_arr, + int p_clearance_class, ViaRule p_via_rule, boolean p_push_enabled, + int p_trace_tidy_width, int p_pull_tight_accuracy, Item p_start_item, Set p_target_set, + RoutingBoard p_board, boolean p_is_stitch_mode, boolean p_with_neckdown, boolean p_via_snap_to_smd_center, + boolean p_hilight_shove_failing_obstacle) + { + board = p_board; + layer = p_layer; + if (p_push_enabled) + { + max_shove_trace_recursion_depth = 20; + max_shove_via_recursion_depth = 8; + max_spring_over_recursion_depth = 5; + } + else + { + max_shove_trace_recursion_depth = 0; + max_shove_via_recursion_depth = 0; + max_spring_over_recursion_depth = 0; + } + trace_tidy_width = p_trace_tidy_width; + pull_tight_accuracy = p_pull_tight_accuracy; + prev_corner = p_start_corner; + net_no_arr = p_net_no_arr; + pen_half_width_arr = p_pen_half_width_arr; + layer_active = p_layer_active_arr; + clearance_class = p_clearance_class; + via_rule = p_via_rule; + start_item = p_start_item; + target_set = p_target_set; + is_stitch_mode = p_is_stitch_mode; + with_neckdown = p_with_neckdown; + via_snap_to_smd_center = p_via_snap_to_smd_center; + hilight_shove_failing_obstacle = p_hilight_shove_failing_obstacle; + if (p_board.get_test_level() == TestLevel.RELEASE_VERSION) + { + this.pull_tight_time_limit = PULL_TIGHT_TIME_LIMIT; + } + else + { + this.pull_tight_time_limit = 0; + } + calculate_target_points_and_areas(); + swap_pin_infos = calculate_swap_pin_infos(); + } + + /** + * Append a line to the trace routed so far. + * Return true, if the route is completed by connecting + * to a target. + * + * @param p_corner a {@link geometry.planar.FloatPoint} object. + * @return a boolean. + */ + public boolean next_corner(FloatPoint p_corner) + { + if (!this.layer_active[this.layer]) + { + return false; + } + IntPoint curr_corner = p_corner.round(); + if (!(board.contains(prev_corner) && board.contains(curr_corner) && board.layer_structure.arr[this.layer].is_signal)) + { + return false; + } + + if (curr_corner.equals(prev_corner)) + { + return false; + } + if (nearest_target_item instanceof DrillItem) + { + DrillItem target = (DrillItem) nearest_target_item; + if (this.prev_corner.equals(target.get_center())) + { + return true; // connection already completed at prev_corner. + } + } + this.shove_failing_obstacle = null; + AngleRestriction angle_restriction = this.board.rules.get_trace_angle_restriction(); + if (angle_restriction != AngleRestriction.NONE && !(prev_corner instanceof IntPoint)) + { + return false; + } + if (angle_restriction == AngleRestriction.NINETY_DEGREE) + { + curr_corner = curr_corner.orthogonal_projection((IntPoint) prev_corner); + } + else if (angle_restriction == AngleRestriction.FORTYFIVE_DEGREE) + { + curr_corner = curr_corner.fortyfive_degree_projection((IntPoint) prev_corner); + } + Item end_routing_item = board.pick_nearest_routing_item(prev_corner, this.layer, null); + // look for a nearby item of this net, which is not connected to end_routing_item. + nearest_target_item = board.pick_nearest_routing_item(curr_corner, this.layer, end_routing_item); + TimeLimit check_forced_trace_time_limit; + if (is_stitch_mode || this.board.get_test_level() != TestLevel.RELEASE_VERSION) + { + // because no check before inserting in this case + check_forced_trace_time_limit = null; + } + else + { + check_forced_trace_time_limit = new TimeLimit(CHECK_FORCED_TRACE_TIME_LIMIT); + } + + + // tests.Validate.check("before insert", board); + Point ok_point = board.insert_forced_trace_segment(prev_corner, + curr_corner, pen_half_width_arr[layer], layer, net_no_arr, clearance_class, + max_shove_trace_recursion_depth, max_shove_via_recursion_depth, max_spring_over_recursion_depth, + trace_tidy_width, pull_tight_accuracy, !is_stitch_mode, check_forced_trace_time_limit); + // tests.Validate.check("after insert", board); + if (ok_point == prev_corner && this.with_neckdown) + { + ok_point = try_neckdown_at_start(curr_corner); + } + if (ok_point == prev_corner && this.with_neckdown) + { + ok_point = try_neckdown_at_end(this.prev_corner, curr_corner); + } + if (ok_point == null) + { + // database may be damaged, restore previous situation + board.undo(null); + // end routing in case it is dynamic + return (!is_stitch_mode); + } + + if (ok_point == prev_corner) + { + set_shove_failing_obstacle(board.get_shove_failing_obstacle()); + return false; + } + this.prev_corner = ok_point; + // check, if a target is reached + boolean route_completed = false; + if (ok_point == curr_corner) + { + route_completed = connect_to_target(curr_corner); + } + + IntOctagon tidy_clip_shape; + if (trace_tidy_width == Integer.MAX_VALUE) + { + tidy_clip_shape = null; + } + else if (trace_tidy_width == 0) + { + tidy_clip_shape = IntOctagon.EMPTY; + } + else + { + tidy_clip_shape = ok_point.surrounding_octagon().enlarge(trace_tidy_width); + } + int[] opt_net_no_arr; + if (max_shove_trace_recursion_depth <= 0) + { + opt_net_no_arr = net_no_arr; + } + else + { + opt_net_no_arr = new int[0]; + } + if (route_completed) + { + this.board.reduce_nets_of_route_items(); + for (int curr_net_no : this.net_no_arr) + { + this.board.combine_traces(curr_net_no); + } + } + else + { + calc_nearest_target_point(this.prev_corner.to_float()); + } + board.opt_changed_area(opt_net_no_arr, tidy_clip_shape, pull_tight_accuracy, + null, null, pull_tight_time_limit, ok_point, layer); + return route_completed; + } + + /** + * Changing the layer in interactive route and inserting a via. + * Returns false, if changing the layer was not possible. + * + * @param p_to_layer a int. + * @return a boolean. + */ + public boolean change_layer(int p_to_layer) + { + if (this.layer == p_to_layer) + { + return true; + } + if (p_to_layer < 0 || p_to_layer >= this.layer_active.length) + { + System.out.println("Route.change_layer: p_to_layer out of range"); + return false; + } + if (!this.layer_active[p_to_layer]) + { + return false; + } + if (this.via_rule == null) + { + return false; + } + this.shove_failing_obstacle = null; + if (this.via_snap_to_smd_center) + { + boolean snapped_to_smd_center = snap_to_smd_center(p_to_layer); + if (!snapped_to_smd_center) + { + snap_to_smd_center(this.layer); + } + } + boolean result = true; + int min_layer = Math.min(this.layer, p_to_layer); + int max_layer = Math.max(this.layer, p_to_layer); + boolean via_found = false; + for (int i = 0; i < this.via_rule.via_count(); ++i) + { + ViaInfo curr_via_info = this.via_rule.get_via(i); + Padstack curr_via_padstack = curr_via_info.get_padstack(); + if (min_layer < curr_via_padstack.from_layer() || max_layer > curr_via_padstack.to_layer()) + { + continue; + } + // make the current situation restorable by undo + board.generate_snapshot(); + result = board.forced_via(curr_via_info, this.prev_corner, this.net_no_arr, clearance_class, + pen_half_width_arr, max_shove_trace_recursion_depth, + 0, this.trace_tidy_width, this.pull_tight_accuracy, pull_tight_time_limit); + if (result) + { + via_found = true; + break; + } + set_shove_failing_obstacle(board.get_shove_failing_obstacle()); + board.undo(null); + } + if (via_found) + { + this.layer = p_to_layer; + } + return result; + } + + /** + * Snaps to the center of an smd pin, if the location location on p_layer is inside an smd pin of the own net, + */ + private boolean snap_to_smd_center(int p_layer) + { + ItemSelectionFilter selection_filter = new ItemSelectionFilter(ItemSelectionFilter.SelectableChoices.PINS); + java.util.Collection picked_items = board.pick_items(this.prev_corner, p_layer, selection_filter); + board.Pin found_smd_pin = null; + for (Item curr_item : picked_items) + { + if (curr_item instanceof board.Pin && curr_item.shares_net_no(this.net_no_arr)) + { + board.Pin curr_pin = (board.Pin) curr_item; + if (curr_pin.first_layer() == p_layer && curr_pin.last_layer() == p_layer) + { + found_smd_pin = curr_pin; + break; + } + } + } + if (found_smd_pin == null) + { + return false; + } + Point pin_center = found_smd_pin.get_center(); + if (!(pin_center instanceof IntPoint)) + { + return false; + } + IntPoint to_corner = (IntPoint) pin_center; + if (this.connect(this.prev_corner, to_corner)) + { + this.prev_corner = to_corner; + } + return true; + } + + /** + * If p_from_point is already on a target item, a connection + * to the target is made and true returned. + */ + private boolean connect_to_target(IntPoint p_from_point) + { + if (nearest_target_item != null && target_set != null && !target_set.contains(nearest_target_item)) + { + nearest_target_item = null; + } + if (nearest_target_item == null || !nearest_target_item.shares_net_no(this.net_no_arr)) + { + return false; + } + boolean route_completed = false; + Point connection_point = null; + if (nearest_target_item instanceof DrillItem) + { + DrillItem target = (DrillItem) nearest_target_item; + connection_point = target.get_center(); + } + else if (nearest_target_item instanceof PolylineTrace) + { + return board.connect_to_trace(p_from_point, (PolylineTrace) nearest_target_item, + this.pen_half_width_arr[layer], this.clearance_class); + } + else if (nearest_target_item instanceof ConductionArea) + { + connection_point = p_from_point; + } + if (connection_point != null && connection_point instanceof IntPoint) + { + route_completed = connect(p_from_point, (IntPoint) connection_point); + } + return route_completed; + } + + /** + * Tries to make a trace connection from p_from_point to p_to_point according to the angle restriction. + * Returns true, if the connection succeeded. + */ + private boolean connect(Point p_from_point, IntPoint p_to_point) + { + Point[] corners = angled_connection(p_from_point, p_to_point); + boolean connection_succeeded = true; + for (int i = 1; i < corners.length; ++i) + { + Point from_corner = corners[i - 1]; + Point to_corner = corners[i]; + TimeLimit time_limit = new TimeLimit(CHECK_FORCED_TRACE_TIME_LIMIT); + while (!from_corner.equals(to_corner)) + { + Point curr_ok_point = board.insert_forced_trace_segment(from_corner, + to_corner, pen_half_width_arr[layer], this.layer, net_no_arr, + clearance_class, max_shove_trace_recursion_depth, + max_shove_via_recursion_depth, max_spring_over_recursion_depth, + trace_tidy_width, pull_tight_accuracy, !is_stitch_mode, time_limit); + if (curr_ok_point == null) + { + // database may be damaged, restore previous situation + board.undo(null); + return true; + } + if (curr_ok_point.equals(from_corner) && this.with_neckdown) + { + curr_ok_point = try_neckdown_at_end(from_corner, to_corner); + } + if (curr_ok_point.equals(from_corner)) + { + this.prev_corner = from_corner; + connection_succeeded = false; + break; + } + from_corner = curr_ok_point; + } + } + return connection_succeeded; + } + + /** + * Calculates the nearest layer of the nearest target item + * to this.layer. + * + * @return a int. + */ + public int nearest_target_layer() + { + if (nearest_target_item == null) + { + return this.layer; + } + int result; + int first_layer = nearest_target_item.first_layer(); + int last_layer = nearest_target_item.last_layer(); + if (this.layer < first_layer) + { + result = first_layer; + } + else if (this.layer > last_layer) + { + result = last_layer; + } + else + { + result = this.layer; + } + return result; + } + + /** + * Returns all pins, which can be reached by a pin swap from a srtart or target pin. + */ + private Set calculate_swap_pin_infos() + { + Set result = new java.util.TreeSet(); + if (this.target_set == null) + { + return result; + } + for (Item curr_item : this.target_set) + { + if (curr_item instanceof board.Pin) + { + Collection curr_swapppable_pins = ((board.Pin) curr_item).get_swappable_pins(); + for (board.Pin curr_swappable_pin : curr_swapppable_pins) + { + result.add(new SwapPinInfo(curr_swappable_pin)); + } + } + } + // add the from item, if it is a pin + ItemSelectionFilter selection_filter = new ItemSelectionFilter(ItemSelectionFilter.SelectableChoices.PINS); + java.util.Collection picked_items = board.pick_items(this.prev_corner, this.layer, selection_filter); + for (Item curr_item : picked_items) + { + if (curr_item instanceof board.Pin) + { + Collection curr_swapppable_pins = ((board.Pin) curr_item).get_swappable_pins(); + for (board.Pin curr_swappable_pin : curr_swapppable_pins) + { + result.add(new SwapPinInfo(curr_swappable_pin)); + } + } + } + return result; + } + + /** + * Hilights the targets and draws the incomplete. + * + * @param p_graphics a {@link java.awt.Graphics} object. + * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object. + * @param p_graphics_context a {@link boardgraphics.GraphicsContext} object. + */ + public void draw(Graphics p_graphics, GraphicsContext p_graphics_context) + { + if (this.hilight_shove_failing_obstacle && this.shove_failing_obstacle != null) + { + this.shove_failing_obstacle.draw(p_graphics, p_graphics_context, p_graphics_context.get_violations_color(), 1); + } + if (target_set == null || net_no_arr.length < 1) + { + return; + } + Net curr_net = board.rules.nets.get(net_no_arr[0]); + if (curr_net == null) + { + return; + } + java.awt.Color highlight_color = p_graphics_context.get_hilight_color(); + double highligt_color_intensity = p_graphics_context.get_hilight_color_intensity(); + + + // hilight the swapppable pins and their incompletes + for (SwapPinInfo curr_info : this.swap_pin_infos) + { + curr_info.pin.draw(p_graphics, p_graphics_context, highlight_color, 0.3 * highligt_color_intensity); + if (curr_info.incomplete != null) + { + // draw the swap pin incomplete + FloatPoint[] draw_points = new FloatPoint[2]; + draw_points[0] = curr_info.incomplete.a; + draw_points[1] = curr_info.incomplete.b; + java.awt.Color draw_color = p_graphics_context.get_incomplete_color(); + p_graphics_context.draw(draw_points, 1, draw_color, p_graphics, highligt_color_intensity); + } + } + + // hilight the target set + for (Item curr_item : target_set) + { + if (!(curr_item instanceof ConductionArea)) + { + curr_item.draw(p_graphics, p_graphics_context, highlight_color, highligt_color_intensity); + } + } + FloatPoint from_corner = this.prev_corner.to_float(); + if (nearest_target_point != null && prev_corner != null) + { + boolean curr_length_matching_ok = true; // used for drawing the incomplete as violation + double max_trace_length = curr_net.get_class().get_maximum_trace_length(); + double min_trace_length = curr_net.get_class().get_minimum_trace_length(); + double length_matching_color_intensity = p_graphics_context.get_length_matching_area_color_intensity(); + if (max_trace_length > 0 || min_trace_length > 0 && length_matching_color_intensity > 0) + { + + // draw the length matching area + double trace_length_add = from_corner.distance(this.prev_corner.to_float()); + // trace_length_add is != 0 only in stitching mode. + if (max_trace_length <= 0) + { + // max_trace_length not provided. Create an ellipse containing the whole board. + max_trace_length = 0.3 * geometry.planar.Limits.CRIT_INT; + } + double curr_max_trace_length = max_trace_length - (curr_net.get_trace_length() + trace_length_add); + double curr_min_trace_length = min_trace_length - (curr_net.get_trace_length() + trace_length_add); + double incomplete_length = nearest_target_point.distance(from_corner); + if (incomplete_length < curr_max_trace_length && min_trace_length <= max_trace_length) + { + Vector delta = nearest_target_point.round().difference_by(prev_corner); + double rotation = delta.angle_approx(); + FloatPoint center = from_corner.middle_point(nearest_target_point); + double bigger_radius = 0.5 * curr_max_trace_length; + // dist_focus_to_center^2 = bigger_radius^2 - smaller_radius^2 + double smaller_radius = 0.5 * Math.sqrt(curr_max_trace_length * curr_max_trace_length - incomplete_length * incomplete_length); + int ellipse_count; + if (min_trace_length <= 0 || incomplete_length >= curr_min_trace_length) + { + ellipse_count = 1; + } + else + { + // display an ellipse ring. + ellipse_count = 2; + } + Ellipse[] ellipse_arr = new Ellipse[ellipse_count]; + ellipse_arr[0] = new Ellipse(center, rotation, bigger_radius, smaller_radius); + IntBox bounding_box = new IntBox(prev_corner.to_float().round(), nearest_target_point.round()); + bounding_box = bounding_box.offset(curr_max_trace_length - incomplete_length); + board.join_graphics_update_box(bounding_box); + if (ellipse_count == 2) + { + bigger_radius = 0.5 * curr_min_trace_length; + smaller_radius = 0.5 * Math.sqrt(curr_min_trace_length * curr_min_trace_length - incomplete_length * incomplete_length); + ellipse_arr[1] = new Ellipse(center, rotation, bigger_radius, smaller_radius); + } + p_graphics_context.fill_ellipse_arr(ellipse_arr, p_graphics, + p_graphics_context.get_length_matching_area_color(), length_matching_color_intensity); + } + else + { + curr_length_matching_ok = false; + } + } + + // draw the incomplete + FloatPoint[] draw_points = new FloatPoint[2]; + draw_points[0] = from_corner; + draw_points[1] = nearest_target_point; + java.awt.Color draw_color = p_graphics_context.get_incomplete_color(); + double draw_width = Math.min (this.board.communication.get_resolution(Unit.MIL), 100); // problem with low resolution on Kicad + if (!curr_length_matching_ok) + { + draw_color = p_graphics_context.get_violations_color(); + draw_width *= 3; + } + p_graphics_context.draw(draw_points, draw_width, draw_color, p_graphics, highligt_color_intensity); + if (this.nearest_target_item != null && !this.nearest_target_item.is_on_layer(this.layer)) + { + // draw a marker to indicate the layer change. + NetIncompletes.draw_layer_change_marker(draw_points[0], 4 * pen_half_width_arr[0], p_graphics, p_graphics_context); + } + } + + } + + /** + * Makes a connection polygon from p_from_point to p_to_point + * whose lines fulfill the angle restriction. + */ + private Point[] angled_connection(Point p_from_point, Point p_to_point) + { + IntPoint add_corner = null; + if (p_from_point instanceof IntPoint && p_to_point instanceof IntPoint) + { + AngleRestriction angle_restriction = this.board.rules.get_trace_angle_restriction(); + if (angle_restriction == AngleRestriction.NINETY_DEGREE) + { + add_corner = ((IntPoint) p_from_point).ninety_degree_corner((IntPoint) p_to_point, true); + } + else if (angle_restriction == AngleRestriction.FORTYFIVE_DEGREE) + { + add_corner = ((IntPoint) p_from_point).fortyfive_degree_corner((IntPoint) p_to_point, true); + } + } + int new_corner_count = 2; + if (add_corner != null) + { + ++new_corner_count; + } + Point[] result = new Point[new_corner_count]; + result[0] = p_from_point; + if (add_corner != null) + { + result[1] = add_corner; + } + result[result.length - 1] = p_to_point; + return result; + } + + /** + * Calculates a list of the center points of DrillItems, + * end points of traces and areas of ConductionAreas in the target set. + */ + private void calculate_target_points_and_areas() + { + target_points = new LinkedList(); + target_traces_and_areas = new LinkedList(); + if (target_set == null) + { + return; + } + Iterator it = target_set.iterator(); + while (it.hasNext()) + { + Item curr_ob = it.next(); + if (curr_ob instanceof DrillItem) + { + Point curr_point = ((DrillItem) curr_ob).get_center(); + target_points.add(new TargetPoint(curr_point.to_float(), curr_ob)); + } + else if (curr_ob instanceof Trace || curr_ob instanceof ConductionArea) + { + target_traces_and_areas.add(curr_ob); + } + } + } + + /** + *

get_last_corner.

+ * + * @return a {@link geometry.planar.Point} object. + */ + public Point get_last_corner() + { + return prev_corner; + } + + /** + *

is_layer_active.

+ * + * @param p_layer a int. + * @return a boolean. + */ + public boolean is_layer_active(int p_layer) + { + if (p_layer < 0 || p_layer >= layer_active.length) + { + return false; + } + return layer_active[p_layer]; + } + + /** + * The nearest point is used for drowing the incomplete + */ + void calc_nearest_target_point(FloatPoint p_from_point) + { + double min_dist = Double.MAX_VALUE; + FloatPoint nearest_point = null; + Item nearest_item = null; + for (TargetPoint curr_target_point : target_points) + { + double curr_dist = p_from_point.distance(curr_target_point.location); + if (curr_dist < min_dist) + { + min_dist = curr_dist; + nearest_point = curr_target_point.location; + nearest_item = curr_target_point.item; + } + } + Iterator it = target_traces_and_areas.iterator(); + while (it.hasNext()) + { + Item curr_item = it.next(); + if (curr_item instanceof PolylineTrace) + { + PolylineTrace curr_trace = (PolylineTrace) curr_item; + Polyline curr_polyline = curr_trace.polyline(); + if (curr_polyline.bounding_box().distance(p_from_point) < min_dist) + { + FloatPoint curr_nearest_point = curr_polyline.nearest_point_approx(p_from_point); + double curr_dist = p_from_point.distance(curr_nearest_point); + if (curr_dist < min_dist) + { + min_dist = curr_dist; + nearest_point = curr_nearest_point; + nearest_item = curr_trace; + } + } + } + else if (curr_item instanceof ConductionArea && curr_item.tile_shape_count() > 0) + { + ConductionArea curr_conduction_area = (ConductionArea) curr_item; + Area curr_area = curr_conduction_area.get_area(); + if (curr_area.bounding_box().distance(p_from_point) < min_dist) + { + FloatPoint curr_nearest_point = curr_area.nearest_point_approx(p_from_point); + double curr_dist = p_from_point.distance(curr_nearest_point); + if (curr_dist < min_dist) + { + min_dist = curr_dist; + nearest_point = curr_nearest_point; + nearest_item = curr_conduction_area; + } + } + } + } + if (nearest_point == null) + { + return; // target set is empty + } + nearest_target_point = nearest_point; + nearest_target_item = nearest_item; + // join the graphics update box by the nearest item, so that the incomplete + // is completely displayed. + board.join_graphics_update_box(nearest_item.bounding_box()); + } + + private void set_shove_failing_obstacle(Item p_item) + { + this.shove_failing_obstacle = p_item; + if (p_item != null) + { + this.board.join_graphics_update_box(p_item.bounding_box()); + } + } + + /** + * If the routed starts at a pin and the route failed with the normal trace width, + * another try with the smalllest pin width is done. + * Returns the ok_point of the try, which is this.prev_point, if the try failed. + */ + private Point try_neckdown_at_start(IntPoint p_to_corner) + { + if (!(this.start_item instanceof board.Pin)) + { + return this.prev_corner; + } + board.Pin start_pin = (board.Pin) this.start_item; + if (!start_pin.is_on_layer(this.layer)) + { + return this.prev_corner; + } + FloatPoint pin_center = start_pin.get_center().to_float(); + double curr_clearance = + this.board.rules.clearance_matrix.value(this.clearance_class, start_pin.clearance_class_no(), this.layer); + double pin_neck_down_distance = + 2 * (0.5 * start_pin.get_max_width(this.layer) + curr_clearance); + if (pin_center.distance(this.prev_corner.to_float()) >= pin_neck_down_distance) + { + return this.prev_corner; + } + + int neck_down_halfwidth = start_pin.get_trace_neckdown_halfwidth(this.layer); + if (neck_down_halfwidth >= this.pen_half_width_arr[this.layer]) + { + return this.prev_corner; + } + + // check, that the neck_down started inside the pin shape + if (!this.prev_corner.equals(start_pin.get_center())) + { + Item picked_item = this.board.pick_nearest_routing_item(this.prev_corner, this.layer, null); + if (picked_item instanceof Trace) + { + if (((Trace) picked_item).get_half_width() > neck_down_halfwidth) + { + return this.prev_corner; + } + } + } + TimeLimit time_limit = new TimeLimit(CHECK_FORCED_TRACE_TIME_LIMIT); + Point ok_point = board.insert_forced_trace_segment(prev_corner, + p_to_corner, neck_down_halfwidth, layer, net_no_arr, clearance_class, max_shove_trace_recursion_depth, + max_shove_via_recursion_depth, max_spring_over_recursion_depth, trace_tidy_width, + pull_tight_accuracy, !is_stitch_mode, time_limit); + return ok_point; + } + + /** + * If the routed ends at a pin and the route failed with the normal trace width, + * another try with the smalllest pin width is done. + * Returns the ok_point of the try, which is p_from_corner, if the try failed. + */ + private Point try_neckdown_at_end(Point p_from_corner, Point p_to_corner) + { + if (!(this.nearest_target_item instanceof board.Pin)) + { + return p_from_corner; + } + board.Pin target_pin = (board.Pin) this.nearest_target_item; + if (!target_pin.is_on_layer(this.layer)) + { + return p_from_corner; + } + FloatPoint pin_center = target_pin.get_center().to_float(); + double curr_clearance = + this.board.rules.clearance_matrix.value(this.clearance_class, target_pin.clearance_class_no(), this.layer); + double pin_neck_down_distance = + 2 * (0.5 * target_pin.get_max_width(this.layer) + curr_clearance); + if (pin_center.distance(p_from_corner.to_float()) >= pin_neck_down_distance) + { + return p_from_corner; + } + int neck_down_halfwidth = target_pin.get_trace_neckdown_halfwidth(this.layer); + if (neck_down_halfwidth >= this.pen_half_width_arr[this.layer]) + { + return p_from_corner; + } + TimeLimit time_limit = new TimeLimit(CHECK_FORCED_TRACE_TIME_LIMIT); + Point ok_point = board.insert_forced_trace_segment(p_from_corner, + p_to_corner, neck_down_halfwidth, layer, net_no_arr, clearance_class, + max_shove_trace_recursion_depth, max_shove_via_recursion_depth, + max_spring_over_recursion_depth, trace_tidy_width, + pull_tight_accuracy, !is_stitch_mode, time_limit); + return ok_point; + } + /** The net numbers used for routing */ + final int[] net_no_arr; + private Point prev_corner; + private int layer; + private final Item start_item; + private final Set target_set; + /** Pins, which can be reached by a pin swap by a target pin. */ + private final Set swap_pin_infos; + private Collection target_points; // from drill_items + private Collection target_traces_and_areas; // from traces and conduction areas + private FloatPoint nearest_target_point; + private Item nearest_target_item; + private final int[] pen_half_width_arr; + private final boolean[] layer_active; + private final int clearance_class; + private final ViaRule via_rule; + private final int max_shove_trace_recursion_depth; + private final int max_shove_via_recursion_depth; + private final int max_spring_over_recursion_depth; + private final int trace_tidy_width; + private final int pull_tight_accuracy; + private final RoutingBoard board; + private final boolean is_stitch_mode; + private final boolean with_neckdown; + private final boolean via_snap_to_smd_center; + private final boolean hilight_shove_failing_obstacle; + private final int pull_tight_time_limit; + private Item shove_failing_obstacle = null; + /** The time limit in milliseconds for the pull tight algorithm */ + private static final int CHECK_FORCED_TRACE_TIME_LIMIT = 3000; + /** The time limit in milliseconds for the pull tight algorithm */ + private static final int PULL_TIGHT_TIME_LIMIT = 2000; + + private static class TargetPoint + { + + TargetPoint(FloatPoint p_location, Item p_item) + { + location = p_location; + item = p_item; + } + final FloatPoint location; + final Item item; + } + + private class SwapPinInfo implements Comparable + { + + SwapPinInfo(board.Pin p_pin) + { + pin = p_pin; + incomplete = null; + if (p_pin.is_connected() || p_pin.net_count() != 1) + { + return; + } + // calculate the incomplete of p_pin + FloatPoint pin_center = p_pin.get_center().to_float(); + double min_dist = Double.MAX_VALUE; + FloatPoint nearest_point = null; + Collection net_items = board.get_connectable_items(p_pin.get_net_no(0)); + for (Item curr_item : net_items) + { + if (curr_item == this.pin || !(curr_item instanceof DrillItem)) + { + continue; + } + FloatPoint curr_point = ((DrillItem) curr_item).get_center().to_float(); + double curr_dist = pin_center.distance_square(curr_point); + if (curr_dist < min_dist) + { + min_dist = curr_dist; + nearest_point = curr_point; + } + } + if (nearest_point != null) + { + incomplete = new geometry.planar.FloatLine(pin_center, nearest_point); + } + } + + public int compareTo(SwapPinInfo p_other) + { + return this.pin.compareTo(p_other.pin); + } + final board.Pin pin; + geometry.planar.FloatLine incomplete; + } +} diff --git a/interactive/RouteMenuState.java b/src/main/java/interactive/RouteMenuState.java similarity index 79% rename from interactive/RouteMenuState.java rename to src/main/java/interactive/RouteMenuState.java index 565be01..cf3740c 100644 --- a/interactive/RouteMenuState.java +++ b/src/main/java/interactive/RouteMenuState.java @@ -27,10 +27,17 @@ * especially the different behaviour of the mouse button 1. * * @author Alfons Wirtz + * @version $Id: $Id */ public class RouteMenuState extends MenuState { - /** Returns a new instance of RouteMenuState */ + /** + * Returns a new instance of RouteMenuState + * + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_logfile a {@link interactive.Logfile} object. + * @return a {@link interactive.RouteMenuState} object. + */ public static RouteMenuState get_instance(BoardHandling p_board_handling, Logfile p_logfile) { RouteMenuState new_state = new RouteMenuState(p_board_handling, p_logfile); @@ -43,16 +50,25 @@ private RouteMenuState(BoardHandling p_board_handling, Logfile p_logfile) super(p_board_handling, p_logfile); } + /** {@inheritDoc} */ public InteractiveState left_button_clicked(FloatPoint p_location) { return RouteState.get_instance(p_location, this, hdlg, logfile); } + /** + *

display_default_message.

+ */ public void display_default_message() { hdlg.screen_messages.set_status_message(" in route menu"); } + /** + *

get_help_id.

+ * + * @return a {@link java.lang.String} object. + */ public String get_help_id() { return "MenuState_RouteMenuState"; diff --git a/interactive/RouteState.java b/src/main/java/interactive/RouteState.java similarity index 94% rename from interactive/RouteState.java rename to src/main/java/interactive/RouteState.java index 7bbff13..e558956 100644 --- a/interactive/RouteState.java +++ b/src/main/java/interactive/RouteState.java @@ -39,6 +39,7 @@ * Interactive routing state. * * @author Alfons Wirtz + * @version $Id: $Id */ public class RouteState extends InteractiveState { @@ -48,7 +49,13 @@ public class RouteState extends InteractiveState * if starting a new route was not possible at p_location. * If p_logfile != null, the creation of the route is stored * in the logfile. - **/ + * + * @param p_location a {@link geometry.planar.FloatPoint} object. + * @param p_parent_state a {@link interactive.InteractiveState} object. + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_logfile a {@link interactive.Logfile} object. + * @return a {@link interactive.RouteState} object. + */ public static RouteState get_instance(FloatPoint p_location, InteractiveState p_parent_state, BoardHandling p_board_handling, Logfile p_logfile) { if (!(p_parent_state instanceof MenuState)) @@ -198,6 +205,10 @@ else if (picked_item instanceof DrillItem) * Creates a new instance of RouteState * If p_logfile != null, the creation of the route is stored * in the logfile. + * + * @param p_parent_state a {@link interactive.InteractiveState} object. + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_logfile a {@link interactive.Logfile} object. */ protected RouteState(InteractiveState p_parent_state, BoardHandling p_board_handling, Logfile p_logfile) { @@ -208,6 +219,10 @@ protected RouteState(InteractiveState p_parent_state, BoardHandling p_board_hand * Checks starting an interactive route at p_location. * Returns the picked start item of the routing at p_location, * or null, if no such item was found. + * + * @param p_location a {@link geometry.planar.IntPoint} object. + * @param p_hdlg a {@link interactive.BoardHandling} object. + * @return a {@link board.Item} object. */ static protected Item start_ok(IntPoint p_location, BoardHandling p_hdlg) { @@ -276,12 +291,15 @@ static private Item pick_routing_item(IntPoint p_location, int p_layer_no, Board return picked_item; } + /** {@inheritDoc} */ public InteractiveState process_logfile_point(FloatPoint p_point) { return add_corner(p_point); } /** + * {@inheritDoc} + * * Action to be taken when a key is pressed (Shortcut). */ public InteractiveState key_typed(char p_key_char) @@ -351,6 +369,9 @@ else if (p_key_char == '-') * Append a line to p_location to the trace routed so far. * Returns from state, if the route is completed by connecting * to a target. + * + * @param p_location a {@link geometry.planar.FloatPoint} object. + * @return a {@link interactive.InteractiveState} object. */ public InteractiveState add_corner(FloatPoint p_location) { @@ -388,6 +409,11 @@ public InteractiveState add_corner(FloatPoint p_location) return result; } + /** + *

cancel.

+ * + * @return a {@link interactive.InteractiveState} object. + */ public InteractiveState cancel() { Trace tail = hdlg.get_routing_board().get_trace_tail(route.get_last_corner(), hdlg.settings.layer, route.net_no_arr); @@ -421,6 +447,7 @@ public InteractiveState cancel() return this.return_state; } + /** {@inheritDoc} */ public boolean change_layer_action(int p_new_layer) { boolean result = true; @@ -549,6 +576,7 @@ static int[] get_route_net_numbers_at_tie_pin(board.Pin p_pin, int p_layer) return result; } + /** {@inheritDoc} */ public void draw(java.awt.Graphics p_graphics) { if (route != null) @@ -557,6 +585,9 @@ public void draw(java.awt.Graphics p_graphics) } } + /** + *

display_default_message.

+ */ public void display_default_message() { if (route != null) diff --git a/interactive/ScreenMessages.java b/src/main/java/interactive/ScreenMessages.java similarity index 81% rename from interactive/ScreenMessages.java rename to src/main/java/interactive/ScreenMessages.java index d3ef389..b76865e 100644 --- a/interactive/ScreenMessages.java +++ b/src/main/java/interactive/ScreenMessages.java @@ -26,11 +26,20 @@ * Text fields to display messages on the screen. * * @author arbeit + * @version $Id: $Id */ public class ScreenMessages { - /** Creates a new instance of ScreenMessageFields */ + /** + * Creates a new instance of ScreenMessageFields + * + * @param p_status_field a {@link javax.swing.JLabel} object. + * @param p_add_field a {@link javax.swing.JLabel} object. + * @param p_layer_field a {@link javax.swing.JLabel} object. + * @param p_mouse_position a {@link javax.swing.JLabel} object. + * @param p_locale a {@link java.util.Locale} object. + */ public ScreenMessages(JLabel p_status_field, JLabel p_add_field, JLabel p_layer_field, JLabel p_mouse_position, java.util.Locale p_locale) { @@ -50,6 +59,8 @@ public ScreenMessages(JLabel p_status_field, JLabel p_add_field, /** * Sets the message in the status field. + * + * @param p_message a {@link java.lang.String} object. */ public void set_status_message(String p_message) { @@ -61,6 +72,8 @@ public void set_status_message(String p_message) /** * Sets the displayed layer number on the screen. + * + * @param p_layer_name a {@link java.lang.String} object. */ public void set_layer(String p_layer_name) { @@ -70,6 +83,13 @@ public void set_layer(String p_layer_name) } } + /** + *

set_interactive_autoroute_info.

+ * + * @param p_found a int. + * @param p_not_found a int. + * @param p_items_to_go a int. + */ public void set_interactive_autoroute_info(int p_found, int p_not_found, int p_items_to_go) { Integer found = p_found; @@ -80,6 +100,14 @@ public void set_interactive_autoroute_info(int p_found, int p_not_found, int p_i + resources.getString("failed") + " " + failed.toString()); } + /** + *

set_batch_autoroute_info.

+ * + * @param p_items_to_go a int. + * @param p_routed a int. + * @param p_ripped a int. + * @param p_failed a int. + */ public void set_batch_autoroute_info(int p_items_to_go, int p_routed, int p_ripped, int p_failed) { Integer ripped = p_ripped; @@ -92,6 +120,12 @@ public void set_batch_autoroute_info(int p_items_to_go, int p_routed, int p_ripp + resources.getString("failed") + " " + failed.toString()); } + /** + *

set_batch_fanout_info.

+ * + * @param p_pass_no a int. + * @param p_components_to_go a int. + */ public void set_batch_fanout_info(int p_pass_no, int p_components_to_go) { Integer components_to_go = p_components_to_go; @@ -101,6 +135,12 @@ public void set_batch_fanout_info(int p_pass_no, int p_components_to_go) + components_to_go.toString() + " " + resources.getString("components")); } + /** + *

set_post_route_info.

+ * + * @param p_via_count a int. + * @param p_trace_length a double. + */ public void set_post_route_info( int p_via_count, double p_trace_length) { Integer via_count = p_via_count; @@ -111,6 +151,8 @@ public void set_post_route_info( int p_via_count, double p_trace_length) /** * Sets the displayed layer of the nearest target item * in interactive routing. + * + * @param p_layer_name a {@link java.lang.String} object. */ public void set_target_layer(String p_layer_name) { @@ -121,6 +163,11 @@ public void set_target_layer(String p_layer_name) } } + /** + *

set_mouse_position.

+ * + * @param p_pos a {@link geometry.planar.FloatPoint} object. + */ public void set_mouse_position(geometry.planar.FloatPoint p_pos) { if (p_pos == null || this.mouse_position == null || this.write_protected) @@ -158,6 +205,8 @@ public void clear() /** * As long as write_protected is set to true, the set functions in this class will do nothing. + * + * @param p_value a boolean. */ public void set_write_protected(boolean p_value) { diff --git a/interactive/SelectItemsInRegionState.java b/src/main/java/interactive/SelectItemsInRegionState.java similarity index 86% rename from interactive/SelectItemsInRegionState.java rename to src/main/java/interactive/SelectItemsInRegionState.java index 4461109..300fd91 100644 --- a/interactive/SelectItemsInRegionState.java +++ b/src/main/java/interactive/SelectItemsInRegionState.java @@ -33,12 +33,18 @@ * Interactive state for selecting all items in a rectangle. * * @author Alfons Wirtz + * @version $Id: $Id */ public class SelectItemsInRegionState extends SelectRegionState { /** * Returns a new instance of this class. + * + * @param p_parent_state a {@link interactive.InteractiveState} object. + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_logfile a {@link interactive.Logfile} object. + * @return a {@link interactive.SelectItemsInRegionState} object. */ public static SelectItemsInRegionState get_instance(InteractiveState p_parent_state, BoardHandling p_board_handling, Logfile p_logfile) @@ -48,6 +54,12 @@ public static SelectItemsInRegionState get_instance(InteractiveState p_parent_st /** * Returns a new instance of this class with first point p_location. + * + * @param p_location a {@link geometry.planar.FloatPoint} object. + * @param p_parent_state a {@link interactive.InteractiveState} object. + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_logfile a {@link interactive.Logfile} object. + * @return a {@link interactive.SelectItemsInRegionState} object. */ public static SelectItemsInRegionState get_instance(FloatPoint p_location, InteractiveState p_parent_state, BoardHandling p_board_handling, Logfile p_logfile) @@ -75,6 +87,11 @@ private SelectItemsInRegionState(InteractiveState p_parent_state, } } + /** + *

complete.

+ * + * @return a {@link interactive.InteractiveState} object. + */ public InteractiveState complete() { if (!hdlg.is_board_read_only()) diff --git a/interactive/SelectMenuState.java b/src/main/java/interactive/SelectMenuState.java similarity index 80% rename from interactive/SelectMenuState.java rename to src/main/java/interactive/SelectMenuState.java index 49d3de0..d6d4c3c 100644 --- a/interactive/SelectMenuState.java +++ b/src/main/java/interactive/SelectMenuState.java @@ -27,10 +27,17 @@ * especially the different behaviour of the mouse button 1. * * @author Alfons Wirtz + * @version $Id: $Id */ public class SelectMenuState extends MenuState { - /** Returns a new instance of SelectMenuState */ + /** + * Returns a new instance of SelectMenuState + * + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_logfile a {@link interactive.Logfile} object. + * @return a {@link interactive.SelectMenuState} object. + */ public static SelectMenuState get_instance(BoardHandling p_board_handling, Logfile p_logfile) { SelectMenuState new_state = new SelectMenuState(p_board_handling, p_logfile); @@ -43,22 +50,32 @@ private SelectMenuState(BoardHandling p_board_handling, Logfile p_logfile) super(p_board_handling, p_logfile); } + /** {@inheritDoc} */ public InteractiveState left_button_clicked(FloatPoint p_location) { InteractiveState result = select_items(p_location); return result; } + /** {@inheritDoc} */ public InteractiveState mouse_dragged(FloatPoint p_point) { return SelectItemsInRegionState.get_instance(hdlg.get_current_mouse_position(), this, hdlg, logfile); } + /** + *

display_default_message.

+ */ public void display_default_message() { hdlg.screen_messages.set_status_message(resources.getString("in_select_menu")); } + /** + *

get_help_id.

+ * + * @return a {@link java.lang.String} object. + */ public String get_help_id() { return "MenuState_SelectMenuState"; diff --git a/interactive/SelectRegionState.java b/src/main/java/interactive/SelectRegionState.java similarity index 81% rename from interactive/SelectRegionState.java rename to src/main/java/interactive/SelectRegionState.java index 45c9f55..017cf50 100644 --- a/interactive/SelectRegionState.java +++ b/src/main/java/interactive/SelectRegionState.java @@ -26,22 +26,35 @@ * Common base class for interactive selection of a rectangle. * * @author Alfons Wirtz + * @version $Id: $Id */ public class SelectRegionState extends InteractiveState { - /** Creates a new instance of SelectRegionState */ + /** + * Creates a new instance of SelectRegionState + * + * @param p_parent_state a {@link interactive.InteractiveState} object. + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_logfile a {@link interactive.Logfile} object. + */ protected SelectRegionState(InteractiveState p_parent_state, BoardHandling p_board_handling, Logfile p_logfile) { super(p_parent_state, p_board_handling, p_logfile); } + /** + *

button_released.

+ * + * @return a {@link interactive.InteractiveState} object. + */ public InteractiveState button_released() { hdlg.screen_messages.set_status_message(""); return complete(); } + /** {@inheritDoc} */ public InteractiveState mouse_dragged(FloatPoint p_point) { if (corner1 == null) @@ -56,6 +69,7 @@ public InteractiveState mouse_dragged(FloatPoint p_point) return this; } + /** {@inheritDoc} */ public void draw(java.awt.Graphics p_graphics) { this.return_state.draw(p_graphics); diff --git a/interactive/SelectedItemState.java b/src/main/java/interactive/SelectedItemState.java similarity index 93% rename from interactive/SelectedItemState.java rename to src/main/java/interactive/SelectedItemState.java index 0bddcff..4806052 100644 --- a/interactive/SelectedItemState.java +++ b/src/main/java/interactive/SelectedItemState.java @@ -54,6 +54,7 @@ * Class implementing actions on the currently selected items. * * @author Alfons Wirtz + * @version $Id: $Id */ public class SelectedItemState extends InteractiveState { @@ -61,6 +62,12 @@ public class SelectedItemState extends InteractiveState /** * Creates a new SelectedItemState with with the items in p_item_list selected. * Returns null, if p_item_list is empty. + * + * @param p_item_list a {@link java.util.Set} object. + * @param p_parent_state a {@link interactive.InteractiveState} object. + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_logfile a {@link interactive.Logfile} object. + * @return a {@link interactive.SelectedItemState} object. */ public static SelectedItemState get_instance(Set p_item_list, InteractiveState p_parent_state, BoardHandling p_board_handling, Logfile p_logfile) { @@ -81,23 +88,29 @@ private SelectedItemState(Set p_item_list, InteractiveState p_parent_state /** * Gets the list of the currently selected items. + * + * @return a {@link java.util.Collection} object. */ public Collection get_item_list() { return item_list; } + /** {@inheritDoc} */ public InteractiveState left_button_clicked(FloatPoint p_location) { return toggle_select(p_location); } + /** {@inheritDoc} */ public InteractiveState mouse_dragged(FloatPoint p_point) { return SelectItemsInRegionState.get_instance(hdlg.get_current_mouse_position(), this, hdlg, logfile); } /** + * {@inheritDoc} + * * Action to be taken when a key is pressed (Shortcut). */ public InteractiveState key_typed(char p_key_char) @@ -212,6 +225,8 @@ public void unfix_items() /** * Makes all items in this selected_set connectable and assigns * them to a new net. + * + * @return a {@link interactive.InteractiveState} object. */ public InteractiveState assign_items_to_new_net() { @@ -260,6 +275,8 @@ else if (curr_item instanceof DrillItem) /** * Assigns all items in this selected_set to a new group( new component for example) + * + * @return a {@link interactive.InteractiveState} object. */ public InteractiveState assign_items_to_new_group() { @@ -328,6 +345,8 @@ public InteractiveState assign_items_to_new_group() /** * Deletes all unfixed items in this selected set and * pulls tight the neighour traces. + * + * @return a {@link interactive.InteractiveState} object. */ public InteractiveState delete_items() { @@ -377,6 +396,8 @@ public InteractiveState delete_items() /** * Deletes all unfixed items in this selected set inside a rectangle + * + * @return a {@link interactive.InteractiveState} object. */ public InteractiveState cutout_items() { @@ -386,6 +407,9 @@ public InteractiveState cutout_items() /** * Autoroutes the selected items. * If p_stoppable_thread != null, the algorithm can be requestet to terminate. + * + * @param p_stoppable_thread a {@link datastructures.Stoppable} object. + * @return a {@link interactive.InteractiveState} object. */ public InteractiveState autoroute(Stoppable p_stoppable_thread) { @@ -496,6 +520,9 @@ else if (autoroute_result != AutorouteEngine.AutorouteResult.ALREADY_CONNECTED) /** * Fanouts the pins contained in the selected items. * If p_stoppable_thread != null, the algorithm can be requestet to terminate. + * + * @param p_stoppable_thread a {@link datastructures.Stoppable} object. + * @return a {@link interactive.InteractiveState} object. */ public InteractiveState fanout(Stoppable p_stoppable_thread) { @@ -583,6 +610,9 @@ else if (autoroute_result != AutorouteEngine.AutorouteResult.ALREADY_CONNECTED) /** * Optimizes the selected items. * If p_stoppable_thread != null, the algorithm can be requestet to terminate. + * + * @param p_stoppable_thread a {@link datastructures.Stoppable} object. + * @return a {@link interactive.InteractiveState} object. */ public InteractiveState pull_tight(Stoppable p_stoppable_thread) { @@ -655,6 +685,9 @@ else if (curr_item instanceof Via) /** * Assigns the input clearance class to the selected items. + * + * @param p_cl_class_index a int. + * @return a {@link interactive.InteractiveState} object. */ public InteractiveState assign_clearance_class(int p_cl_class_index) { @@ -683,6 +716,8 @@ public InteractiveState assign_clearance_class(int p_cl_class_index) /** * Select also all items belonging to any net of the current selected items. + * + * @return a {@link interactive.InteractiveState} object. */ public InteractiveState extent_to_whole_nets() { @@ -724,6 +759,8 @@ public InteractiveState extent_to_whole_nets() /** * Select also all items belonging to any group of the current selected items. + * + * @return a {@link interactive.InteractiveState} object. */ public InteractiveState extent_to_whole_components() { @@ -762,6 +799,8 @@ public InteractiveState extent_to_whole_components() /** * Select also all items belonging to any connected set of the current selected items. + * + * @return a {@link interactive.InteractiveState} object. */ public InteractiveState extent_to_whole_connected_sets() { @@ -791,6 +830,8 @@ public InteractiveState extent_to_whole_connected_sets() /** * Select also all items belonging to any connection of the current selected items. + * + * @return a {@link interactive.InteractiveState} object. */ public InteractiveState extent_to_whole_connections() { @@ -823,6 +864,9 @@ public InteractiveState extent_to_whole_connections() * Removes it from the selected_items list, if it is already in there, * otherwise adds it to the list. * Returns true (to change to the return_state) if nothing was picked. + * + * @param p_point a {@link geometry.planar.FloatPoint} object. + * @return a {@link interactive.InteractiveState} object. */ public InteractiveState toggle_select(FloatPoint p_point) { @@ -883,6 +927,8 @@ public void toggle_clearance_violations() /** * Removes items not selected by the current interactive filter from the selected item list. + * + * @return a {@link interactive.InteractiveState} object. */ public InteractiveState filter() { @@ -898,6 +944,8 @@ public InteractiveState filter() /** * Prints information about the selected item into a graphical text window. + * + * @return a {@link interactive.SelectedItemState} object. */ public SelectedItemState info() { @@ -905,11 +953,17 @@ public SelectedItemState info() return this; } + /** + *

get_help_id.

+ * + * @return a {@link java.lang.String} object. + */ public String get_help_id() { return "SelectedItemState"; } + /** {@inheritDoc} */ public void draw(java.awt.Graphics p_graphics) { if (item_list == null) @@ -928,16 +982,27 @@ public void draw(java.awt.Graphics p_graphics) } } + /** + *

get_popup_menu.

+ * + * @return a {@link javax.swing.JPopupMenu} object. + */ public javax.swing.JPopupMenu get_popup_menu() { return hdlg.get_panel().popup_menu_select; } + /** + *

set_toolbar.

+ */ public void set_toolbar() { hdlg.get_panel().board_frame.set_select_toolbar(); } + /** + *

display_default_message.

+ */ public void display_default_message() { hdlg.screen_messages.set_status_message(resources.getString("in_select_item_mode")); diff --git a/interactive/Settings.java b/src/main/java/interactive/Settings.java similarity index 81% rename from interactive/Settings.java rename to src/main/java/interactive/Settings.java index bdbda15..85eeb1f 100644 --- a/interactive/Settings.java +++ b/src/main/java/interactive/Settings.java @@ -27,10 +27,16 @@ * Contains the values of the interactive settings of the board handling. * * @author Alfons Wirtz + * @version $Id: $Id */ public class Settings implements java.io.Serializable { - /** Creates a new interactive settings variable. */ + /** + * Creates a new interactive settings variable. + * + * @param p_board a {@link board.RoutingBoard} object. + * @param p_logfile a {@link interactive.Logfile} object. + */ public Settings(RoutingBoard p_board, Logfile p_logfile) { this.logfile = p_logfile; @@ -63,6 +69,8 @@ public Settings(RoutingBoard p_board, Logfile p_logfile) /** * Copy constructor + * + * @param p_settings a {@link interactive.Settings} object. */ public Settings(Settings p_settings) { @@ -91,35 +99,60 @@ public Settings(Settings p_settings) this.snapshot_attributes = new SnapShot.Attributes(p_settings.snapshot_attributes); } + /** + *

get_layer.

+ * + * @return a int. + */ public int get_layer() { return this.layer; } - /** allows pushing obstacles aside */ + /** + * allows pushing obstacles aside + * + * @return a boolean. + */ public boolean get_push_enabled() { return this.push_enabled; } - /** Route mode: stitching or dynamic */ + /** + * Route mode: stitching or dynamic + * + * @return a boolean. + */ public boolean get_is_stitch_route() { return this.is_stitch_route; } - /** allows dragging components with the route */ + /** + * allows dragging components with the route + * + * @return a boolean. + */ public boolean get_drag_components_enabled() { return this.drag_components_enabled; } - /** indicates if interactive selections are made on all visible layers or only on the current layer.*/ + /** + * indicates if interactive selections are made on all visible layers or only on the current layer. + * + * @return a boolean. + */ public boolean get_select_on_all_visible_layers() { return this.select_on_all_visible_layers; } - /** Indicates if the routing rule selection is manual by the user or automatic by the net rules. */ + /** + * Indicates if the routing rule selection is manual by the user or automatic by the net rules. + * + * @return a boolean. + */ public boolean get_manual_rule_selection() { return this.manual_rule_selection; @@ -127,13 +160,19 @@ public boolean get_manual_rule_selection() /** * Via snaps to smd center, if attach smd is alllowed. + * + * @return a boolean. */ public boolean get_via_snap_to_smd_center() { return this.via_snap_to_smd_center; } - /** If true, the current routing obstacle is hilightet in dynamic routing. */ + /** + * If true, the current routing obstacle is hilightet in dynamic routing. + * + * @return a boolean. + */ public boolean get_hilight_routing_obstacle() { return this.hilight_routing_obstacle; @@ -142,32 +181,48 @@ public boolean get_hilight_routing_obstacle() /** * If true, the trace width at static pins smaller the the trace width will be lowered * automatically to the pin with, if necessary. + * + * @return a boolean. */ public boolean get_automatic_neckdown() { return this.automatic_neckdown; } - /** If true, the mouse wheel is used for zooming. */ + /** + * If true, the mouse wheel is used for zooming. + * + * @return a boolean. + */ public boolean get_zoom_with_wheel() { return this.zoom_with_wheel; } - /** The filter used in interactive selection of board items. */ + /** + * The filter used in interactive selection of board items. + * + * @return a {@link board.ItemSelectionFilter} object. + */ public ItemSelectionFilter get_item_selection_filter() { return this.item_selection_filter; } - /** The width of the pull tight region of traces around the cursor */ + /** + * The width of the pull tight region of traces around the cursor + * + * @return a int. + */ public int get_trace_pull_tight_region_width() { return this.trace_pull_tight_region_width; } /** - * The horizontal placement grid when moving components, if > 0. + * The horizontal placement grid when moving components, {@code if > 0}. + * + * @return a int. */ public int get_horizontal_component_grid() { @@ -175,7 +230,9 @@ public int get_horizontal_component_grid() } /** - * The vertical placement grid when moving components, if > 0. + * The vertical placement grid when moving components, {@code if > 0}. + * + * @return a int. */ public int get_vertical_component_grid() { @@ -185,6 +242,8 @@ public int get_vertical_component_grid() /** * The index of the clearance class used for traces in interactive routing in the clearance matrix, * if manual_route_selection is on. + * + * @return a int. */ public int get_manual_trace_clearance_class() { @@ -193,25 +252,40 @@ public int get_manual_trace_clearance_class() /** * The index of the via rule used in routing in the board via rules if manual_route_selection is on. + * + * @return a int. */ public int get_manual_via_rule_index() { return this.manual_via_rule_index; } - /** The accuracy of the pull tight algorithm. */ + /** + * The accuracy of the pull tight algorithm. + * + * @return a int. + */ public int get_trace_pull_tight_accuracy() { return this.trace_pull_tight_accuracy; } - /** Defines the data of the snapshot selected for restoring. */ + /** + * Defines the data of the snapshot selected for restoring. + * + * @return a {@link interactive.SnapShot.Attributes} object. + */ public SnapShot.Attributes get_snapshot_attributes() { return this.snapshot_attributes; } - /** Get the trace half width in manual routing mode on layer p_layer_no */ + /** + * Get the trace half width in manual routing mode on layer p_layer_no + * + * @param p_layer_no a int. + * @return a int. + */ public int get_manual_trace_half_width( int p_layer_no) { if (p_layer_no < 0 || p_layer_no >= this.manual_trace_half_width_arr.length) @@ -224,6 +298,8 @@ public int get_manual_trace_half_width( int p_layer_no) /** * The index of the via rule used in routing in the board via rules if manual_route_selection is on. + * + * @param p_value a int. */ public void set_manual_via_rule_index(int p_value) { @@ -235,7 +311,9 @@ public void set_manual_via_rule_index(int p_value) } /** - * The horizontal placement grid when moving components, if > 0. + * The horizontal placement grid when moving components, {@code if > 0}. + * + * @param p_value a int. */ public void set_horizontal_component_grid(int p_value) { @@ -247,7 +325,9 @@ public void set_horizontal_component_grid(int p_value) } /** - * The vertical placement grid when moving components, if > 0. + * The vertical placement grid when moving components, {@code if > 0}. + * + * @param p_value a int. */ public void set_vertical_component_grid(int p_value) { @@ -258,7 +338,11 @@ public void set_vertical_component_grid(int p_value) this.vertical_component_grid = p_value; } - /** If true, the current routing obstacle is hilightet in dynamic routing. */ + /** + * If true, the current routing obstacle is hilightet in dynamic routing. + * + * @param p_value a boolean. + */ public void set_hilight_routing_obstacle(boolean p_value) { if (read_only) @@ -271,6 +355,8 @@ public void set_hilight_routing_obstacle(boolean p_value) /** * If true, the trace width at static pins smaller the the trace width will be lowered * automatically to the pin with, if necessary. + * + * @param p_value a boolean. */ public void set_automatic_neckdown(boolean p_value) { @@ -281,7 +367,11 @@ public void set_automatic_neckdown(boolean p_value) this.automatic_neckdown = p_value; } - /** The filter used in interactive selection of board items. */ + /** + * The filter used in interactive selection of board items. + * + * @param p_value a {@link board.ItemSelectionFilter} object. + */ public void set_item_selection_filter(ItemSelectionFilter p_value) { if (read_only) @@ -293,6 +383,8 @@ public void set_item_selection_filter(ItemSelectionFilter p_value) /** * Enables or disables pushing obstacles in interactive routing + * + * @param p_value a boolean. */ public void set_push_enabled(boolean p_value) { @@ -306,6 +398,8 @@ public void set_push_enabled(boolean p_value) /** * Enables or disables dragging components + * + * @param p_value a boolean. */ public void set_drag_components_enabled(boolean p_value) { @@ -321,6 +415,8 @@ public void set_drag_components_enabled(boolean p_value) /** * Sets, if item selection is on all board layers or only * on the current layer. + * + * @param p_value a boolean. */ public void set_select_on_all_visible_layers(boolean p_value) { @@ -332,7 +428,11 @@ public void set_select_on_all_visible_layers(boolean p_value) logfile.start_scope(LogfileScope.SET_SELECT_ON_ALL_LAYER, p_value); } - /** Route mode: stitching or dynamic */ + /** + * Route mode: stitching or dynamic + * + * @param p_value a boolean. + */ public void set_stitch_route(boolean p_value) { if (read_only) @@ -346,6 +446,8 @@ public void set_stitch_route(boolean p_value) /** * Changes the current width of the tidy region for traces. + * + * @param p_value a int. */ public void set_current_pull_tight_region_width(int p_value) { @@ -359,6 +461,8 @@ public void set_current_pull_tight_region_width(int p_value) /** * Changes the current width of the pull tight accuracy for traces. + * + * @param p_value a int. */ public void set_current_pull_tight_accuracy(int p_value) { @@ -372,6 +476,8 @@ public void set_current_pull_tight_accuracy(int p_value) /** * Changes, if vias snap to smd center, if attach smd is allowed. + * + * @param p_value a boolean. */ public void set_via_snap_to_smd_center(boolean p_value) { @@ -385,6 +491,8 @@ public void set_via_snap_to_smd_center(boolean p_value) /** * Sets the current trace width selection to manual or automatic. + * + * @param p_value a boolean. */ public void set_manual_tracewidth_selection(boolean p_value) { @@ -398,6 +506,9 @@ public void set_manual_tracewidth_selection(boolean p_value) /** * Sets the manual trace half width used in interactive routing. + * + * @param p_layer_no a int. + * @param p_value a int. */ public void set_manual_trace_half_width( int p_layer_no, int p_value) { @@ -414,6 +525,8 @@ public void set_manual_trace_half_width( int p_layer_no, int p_value) /** * The index of the clearance class used for traces in interactive routing in the clearance matrix, * if manual_route_selection is on. + * + * @param p_index a int. */ public void set_manual_trace_clearance_class(int p_index) { @@ -427,6 +540,8 @@ public void set_manual_trace_clearance_class(int p_index) /** * If true, the wheel is used for zooming. + * + * @param p_value a boolean. */ public void set_zoom_with_wheel(boolean p_value) { @@ -446,6 +561,9 @@ public void set_zoom_with_wheel(boolean p_value) /** * Changes the interactive selectability of p_item_type. + * + * @param p_item_type a {@link board.ItemSelectionFilter.SelectableChoices} object. + * @param p_value a boolean. */ public void set_selectable(ItemSelectionFilter.SelectableChoices p_item_type, boolean p_value) { @@ -470,6 +588,8 @@ public void set_selectable(ItemSelectionFilter.SelectableChoices p_item_type, bo /** * Defines, if the setting attributes are allowed to be changed interactively or not. + * + * @param p_value a {@link java.lang.Boolean} object. */ public void set_read_only(Boolean p_value) { @@ -527,12 +647,12 @@ private void readObject(java.io.ObjectInputStream p_stream) boolean via_snap_to_smd_center; /** - * The horizontal placement grid when moving components, if > 0. + * The horizontal placement grid when moving components, {@code if > 0.} */ int horizontal_component_grid; /** - * The vertical placement grid when moving components, if > 0. + * The vertical placement grid when moving components, {@code if > 0.} */ int vertical_component_grid; diff --git a/interactive/SnapShot.java b/src/main/java/interactive/SnapShot.java similarity index 92% rename from interactive/SnapShot.java rename to src/main/java/interactive/SnapShot.java index 926eee4..c1c77f1 100644 --- a/interactive/SnapShot.java +++ b/src/main/java/interactive/SnapShot.java @@ -24,12 +24,17 @@ * Snapshot of the client situation in an interactive session. * * @author Alfons Wirtz + * @version $Id: $Id */ public class SnapShot implements java.io.Serializable { /** * Returns a new snapshot or null, if the current interactive state * is not suitable to generate a snapshot. + * + * @param p_name a {@link java.lang.String} object. + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @return a {@link interactive.SnapShot} object. */ public static SnapShot get_instance(String p_name, BoardHandling p_board_handling) { @@ -52,12 +57,22 @@ private SnapShot(String p_name, BoardHandling p_board_handling) this.subwindow_filters = p_board_handling.get_panel().board_frame.get_snapshot_subwindow_selections(); } + /** + *

toString.

+ * + * @return a {@link java.lang.String} object. + */ public String toString() { return this.name; } + /** + *

copy_viewport_position.

+ * + * @return a {@link java.awt.Point} object. + */ public java.awt.Point copy_viewport_position() { if (this.viewport_position == null) @@ -69,6 +84,8 @@ public java.awt.Point copy_viewport_position() /** * Goes to this shnapshot in interactive board etiting. + * + * @param p_board_handling a {@link interactive.BoardHandling} object. */ public void go_to(interactive.BoardHandling p_board_handling) { @@ -137,6 +154,10 @@ public void go_to(interactive.BoardHandling p_board_handling) /** * Returns a new InterativeState from the data of this instance. + * + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_logfile a {@link interactive.Logfile} object. + * @return a {@link interactive.InteractiveState} object. */ public InteractiveState get_interactive_state(BoardHandling p_board_handling, Logfile p_logfile) { diff --git a/interactive/StitchRouteState.java b/src/main/java/interactive/StitchRouteState.java similarity index 82% rename from interactive/StitchRouteState.java rename to src/main/java/interactive/StitchRouteState.java index 2d49eb2..7ea212f 100644 --- a/interactive/StitchRouteState.java +++ b/src/main/java/interactive/StitchRouteState.java @@ -27,21 +27,30 @@ * State for interactive routing by adding corners with the left mouse button. * * @author Alfons Wirtz + * @version $Id: $Id */ public class StitchRouteState extends RouteState { - /** Creates a new instance of StichRouteState */ + /** + * Creates a new instance of StichRouteState + * + * @param p_parent_state a {@link interactive.InteractiveState} object. + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_logfile a {@link interactive.Logfile} object. + */ protected StitchRouteState(InteractiveState p_parent_state, BoardHandling p_board_handling, Logfile p_logfile) { super(p_parent_state, p_board_handling, p_logfile); } + /** {@inheritDoc} */ public InteractiveState left_button_clicked(FloatPoint p_location) { return add_corner(p_location); } + /** {@inheritDoc} */ public InteractiveState add_corner(FloatPoint p_location) { // make the current situation restorable by undo @@ -49,6 +58,11 @@ public InteractiveState add_corner(FloatPoint p_location) return super.add_corner(p_location); } + /** + *

mouse_moved.

+ * + * @return a {@link interactive.InteractiveState} object. + */ public InteractiveState mouse_moved() { super.mouse_moved(); @@ -57,16 +71,27 @@ public InteractiveState mouse_moved() return this; } + /** + *

get_popup_menu.

+ * + * @return a {@link javax.swing.JPopupMenu} object. + */ public javax.swing.JPopupMenu get_popup_menu() { return hdlg.get_panel().popup_menu_stitch_route; } + /** + *

get_help_id.

+ * + * @return a {@link java.lang.String} object. + */ public String get_help_id() { return "RouteState_StitchingRouteState"; } + /** {@inheritDoc} */ public void draw(java.awt.Graphics p_graphics) { super.draw(p_graphics); diff --git a/interactive/TileConstructionState.java b/src/main/java/interactive/TileConstructionState.java similarity index 93% rename from interactive/TileConstructionState.java rename to src/main/java/interactive/TileConstructionState.java index 3466a38..116a8a0 100644 --- a/interactive/TileConstructionState.java +++ b/src/main/java/interactive/TileConstructionState.java @@ -39,12 +39,19 @@ * Class for interactive construction of a tile shaped obstacle * * @author Alfons Wirtz + * @version $Id: $Id */ public class TileConstructionState extends CornerItemConstructionState { /** * Returns a new instance of this class * If p_logfile != null; the creation of this item is stored in a logfile + * + * @param p_location a {@link geometry.planar.FloatPoint} object. + * @param p_parent_state a {@link interactive.InteractiveState} object. + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_logfile a {@link interactive.Logfile} object. + * @return a {@link interactive.TileConstructionState} object. */ public static TileConstructionState get_instance(FloatPoint p_location, InteractiveState p_parent_state, BoardHandling p_board_handling, Logfile p_logfile) { @@ -63,6 +70,8 @@ private TileConstructionState(FloatPoint p_location, InteractiveState p_parent_s } /** + * {@inheritDoc} + * * adds a corner to the tile under construction */ public InteractiveState left_button_clicked(FloatPoint p_location) @@ -73,11 +82,17 @@ public InteractiveState left_button_clicked(FloatPoint p_location) return this; } + /** {@inheritDoc} */ public InteractiveState process_logfile_point(FloatPoint p_point) { return left_button_clicked(p_point); } + /** + *

complete.

+ * + * @return a {@link interactive.InteractiveState} object. + */ public InteractiveState complete() { remove_concave_corners_at_close(); @@ -244,6 +259,9 @@ private void remove_concave_corners_at_close() } } + /** + *

display_default_message.

+ */ public void display_default_message() { hdlg.screen_messages.set_status_message(resources.getString("creatig_tile")); diff --git a/interactive/ZoomRegionState.java b/src/main/java/interactive/ZoomRegionState.java similarity index 72% rename from interactive/ZoomRegionState.java rename to src/main/java/interactive/ZoomRegionState.java index a541be3..4f3566c 100644 --- a/interactive/ZoomRegionState.java +++ b/src/main/java/interactive/ZoomRegionState.java @@ -28,11 +28,17 @@ * Class for interactive zooming to a rectangle. * * @author Alfons Wirtz + * @version $Id: $Id */ public class ZoomRegionState extends SelectRegionState { /** * Returns a new instance of this class. + * + * @param p_parent_state a {@link interactive.InteractiveState} object. + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_logfile a {@link interactive.Logfile} object. + * @return a {@link interactive.ZoomRegionState} object. */ public static ZoomRegionState get_instance(InteractiveState p_parent_state, BoardHandling p_board_handling, Logfile p_logfile) { @@ -41,6 +47,12 @@ public static ZoomRegionState get_instance(InteractiveState p_parent_state, Boar /** * Returns a new instance of this class with first point p_location. + * + * @param p_location a {@link geometry.planar.FloatPoint} object. + * @param p_parent_state a {@link interactive.InteractiveState} object. + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_logfile a {@link interactive.Logfile} object. + * @return a {@link interactive.ZoomRegionState} object. */ public static ZoomRegionState get_instance(FloatPoint p_location, InteractiveState p_parent_state, BoardHandling p_board_handling, Logfile p_logfile) { @@ -50,7 +62,13 @@ public static ZoomRegionState get_instance(FloatPoint p_location, InteractiveSta return new_instance; } - /** Creates a new instance of ZoomRegionState */ + /** + * Creates a new instance of ZoomRegionState + * + * @param p_parent_state a {@link interactive.InteractiveState} object. + * @param p_board_handling a {@link interactive.BoardHandling} object. + * @param p_logfile a {@link interactive.Logfile} object. + */ public ZoomRegionState(InteractiveState p_parent_state, BoardHandling p_board_handling, Logfile p_logfile) { super(p_parent_state, p_board_handling, p_logfile); @@ -60,6 +78,11 @@ public ZoomRegionState(InteractiveState p_parent_state, BoardHandling p_board_ha } } + /** + *

complete.

+ * + * @return a {@link interactive.InteractiveState} object. + */ public InteractiveState complete() { corner2 = hdlg.get_current_mouse_position(); diff --git a/interactive/package.html b/src/main/java/interactive/package.html similarity index 100% rename from interactive/package.html rename to src/main/java/interactive/package.html diff --git a/library/BoardLibrary.java b/src/main/java/library/BoardLibrary.java similarity index 77% rename from library/BoardLibrary.java rename to src/main/java/library/BoardLibrary.java index 2a2b248..95a3d06 100644 --- a/library/BoardLibrary.java +++ b/src/main/java/library/BoardLibrary.java @@ -27,11 +27,17 @@ * Describes a board library of packages and padstacks. * * @author alfons + * @version $Id: $Id */ public class BoardLibrary implements java.io.Serializable { - /** Creates a new instance of BoardLibrary */ + /** + * Creates a new instance of BoardLibrary + * + * @param p_padstacks a {@link library.Padstacks} object. + * @param p_packages a {@link library.Packages} object. + */ public BoardLibrary(Padstacks p_padstacks, Packages p_packages) { padstacks = p_padstacks; @@ -39,13 +45,19 @@ public BoardLibrary(Padstacks p_padstacks, Packages p_packages) logical_parts = new LogicalParts(); } - /** Creates a new instance of BoardLibrary */ + /** + * Creates a new instance of BoardLibrary + */ public BoardLibrary() { } - /** Sets the subset of padstacks from this.padstacks, which can be used in routing for inserting vias. */ + /** + * Sets the subset of padstacks from this.padstacks, which can be used in routing for inserting vias. + * + * @param p_padstacks an array of {@link library.Padstack} objects. + */ public void set_via_padstacks(Padstack[] p_padstacks) { @@ -56,7 +68,11 @@ public void set_via_padstacks(Padstack[] p_padstacks) } } - /** The count of padstacks from this.padstacks, which can be used in routing */ + /** + * The count of padstacks from this.padstacks, which can be used in routing + * + * @return a int. + */ public int via_padstack_count() { if (this.via_padstacks == null) @@ -66,7 +82,12 @@ public int via_padstack_count() return this.via_padstacks.size(); } - /** Gets the via padstack for routing with index p_no */ + /** + * Gets the via padstack for routing with index p_no + * + * @param p_no a int. + * @return a {@link library.Padstack} object. + */ public Padstack get_via_padstack(int p_no) { if (this.via_padstacks == null || p_no < 0 || p_no >= this.via_padstacks.size()) @@ -76,7 +97,12 @@ public Padstack get_via_padstack(int p_no) return this.via_padstacks.get(p_no); } - /** Gets the via padstack with name p_name, or null, if no such padstack exists. */ + /** + * Gets the via padstack with name p_name, or null, if no such padstack exists. + * + * @param p_name a {@link java.lang.String} object. + * @return a {@link library.Padstack} object. + */ public Padstack get_via_padstack(String p_name) { if (this.via_padstacks == null) @@ -95,6 +121,8 @@ public Padstack get_via_padstack(String p_name) /** * Returns the via padstacks, which can be used for routing. + * + * @return an array of {@link library.Padstack} objects. */ public Padstack[] get_via_padstacks() { @@ -113,6 +141,9 @@ public Padstack[] get_via_padstacks() /** * Apppends p_padstack to the list of via padstacks. * Returns false, if the list contains already a padstack with p_padstack.name. + * + * @param p_padstack a {@link library.Padstack} object. + * @return a boolean. */ public boolean add_via_padstack(Padstack p_padstack) { @@ -124,10 +155,14 @@ public boolean add_via_padstack(Padstack p_padstack) return true; } - /** - * Removes p_padstack from the via padstack list. + /** + * Removes p_padstack from the via padstack list. * Returns false, if p_padstack was not found in the list. - * If the padstack is no more used on the board, it will also be removed from the board padstacks. + * If the padstack is no more used on the board, it will also be removed from the board padstacks. + * + * @param p_padstack a {@link library.Padstack} object. + * @param p_board a {@link board.BasicBoard} object. + * @return a boolean. */ public boolean remove_via_padstack(Padstack p_padstack, board.BasicBoard p_board) { @@ -139,6 +174,9 @@ public boolean remove_via_padstack(Padstack p_padstack, board.BasicBoard p_board /** * Gets the via padstack mirrored to the back side of the board. * Returns null, if no such via padstack exists. + * + * @param p_via_padstack a {@link library.Padstack} object. + * @return a {@link library.Padstack} object. */ public Padstack get_mirrored_via_padstack(Padstack p_via_padstack) { @@ -161,6 +199,10 @@ public Padstack get_mirrored_via_padstack(Padstack p_via_padstack) /** * Looks, if the input padstack is used on p_board in a Package or in drill. + * + * @param p_padstack a {@link library.Padstack} object. + * @param p_board a {@link board.BasicBoard} object. + * @return a boolean. */ public boolean is_used (Padstack p_padstack, board.BasicBoard p_board) { diff --git a/library/LogicalPart.java b/src/main/java/library/LogicalPart.java similarity index 88% rename from library/LogicalPart.java rename to src/main/java/library/LogicalPart.java index 3023a68..66e85fc 100644 --- a/library/LogicalPart.java +++ b/src/main/java/library/LogicalPart.java @@ -24,6 +24,7 @@ * Contains contain information for gate swap and pin swap for a single component. * * @author Alfons Wirtz + * @version $Id: $Id */ public class LogicalPart implements board.ObjectInfoPanel.Printable, java.io.Serializable { @@ -32,6 +33,10 @@ public class LogicalPart implements board.ObjectInfoPanel.Printable, java.io.Ser * Creates a new instance of LogicalPart. * The part pins are sorted by pin_no. * The pin_no's of the part pins must be the same number as in the componnents library package. + * + * @param p_name a {@link java.lang.String} object. + * @param p_no a int. + * @param p_part_pin_arr an array of {@link library.LogicalPart.PartPin} objects. */ public LogicalPart(String p_name, int p_no, PartPin[] p_part_pin_arr) { @@ -40,12 +45,22 @@ public LogicalPart(String p_name, int p_no, PartPin[] p_part_pin_arr) part_pin_arr = p_part_pin_arr; } + /** + *

pin_count.

+ * + * @return a int. + */ public int pin_count() { return part_pin_arr.length; } - /** Returns the pim with index p_no. Pin numbers are from 0 to pin_count - 1 */ + /** + * Returns the pim with index p_no. Pin numbers are from 0 to pin_count - 1 + * + * @param p_no a int. + * @return a {@link library.LogicalPart.PartPin} object. + */ public PartPin get_pin(int p_no) { if (p_no < 0 || p_no >= part_pin_arr.length) @@ -56,6 +71,7 @@ public PartPin get_pin(int p_no) return part_pin_arr[p_no]; } + /** {@inheritDoc} */ public void print_info(board.ObjectInfoPanel p_window, java.util.Locale p_locale) { java.util.ResourceBundle resources = @@ -117,7 +133,7 @@ public int compareTo(PartPin p_other) /** * The gate swap code. Gates with the same gate swap code can be swapped. - * Gates with swap code <= 0 are not swappable. + * Gates with swap {@code code <= 0} are not swappable. */ public final int gate_swap_code; @@ -126,7 +142,7 @@ public int compareTo(PartPin p_other) /** * The pin swap code of the gate. Pins with the same pin swap code can be swapped inside a gate. - * Pins with swap code <= 0 are not swappable. + * Pins with swap {@code code <= 0} are not swappable. */ public final int gate_pin_swap_code; } diff --git a/library/LogicalParts.java b/src/main/java/library/LogicalParts.java similarity index 81% rename from library/LogicalParts.java rename to src/main/java/library/LogicalParts.java index 32301a8..17134f6 100644 --- a/library/LogicalParts.java +++ b/src/main/java/library/LogicalParts.java @@ -26,10 +26,17 @@ * The logical parts contain information for gate swap and pin swap. * * @author Alfons Wirtz + * @version $Id: $Id */ public class LogicalParts implements java.io.Serializable { - /** Adds a logical part to the database. */ + /** + * Adds a logical part to the database. + * + * @param p_name a {@link java.lang.String} object. + * @param p_part_pin_arr an array of {@link library.LogicalPart.PartPin} objects. + * @return a {@link library.LogicalPart} object. + */ public LogicalPart add(String p_name, LogicalPart.PartPin[] p_part_pin_arr) { java.util.Arrays.sort(p_part_pin_arr); @@ -40,6 +47,9 @@ public LogicalPart add(String p_name, LogicalPart.PartPin[] p_part_pin_arr) /** * Returns the logical part with the input name or null, if no such package exists. + * + * @param p_name a {@link java.lang.String} object. + * @return a {@link library.LogicalPart} object. */ public LogicalPart get(String p_name) { @@ -55,6 +65,9 @@ public LogicalPart get(String p_name) /** * Returns the logical part with index p_part_no. Part numbers are from 1 to part count. + * + * @param p_part_no a int. + * @return a {@link library.LogicalPart} object. */ public LogicalPart get(int p_part_no) { @@ -68,6 +81,8 @@ public LogicalPart get(int p_part_no) /** * Returns the count of logical parts. + * + * @return a int. */ public int count() { diff --git a/library/Package.java b/src/main/java/library/Package.java similarity index 85% rename from library/Package.java rename to src/main/java/library/Package.java index fba5274..4d11344 100644 --- a/library/Package.java +++ b/src/main/java/library/Package.java @@ -30,6 +30,7 @@ * and optional other stuff like an outline package keepouts. * * @author alfons + * @version $Id: $Id */ public class Package implements Comparable, board.ObjectInfoPanel.Printable, java.io.Serializable { @@ -37,6 +38,16 @@ public class Package implements Comparable, board.ObjectInfoPanel.Print /** * Creates a new instance of Package. * p_package_list is the list of packages containing this package. + * + * @param p_name a {@link java.lang.String} object. + * @param p_no a int. + * @param p_pin_arr an array of {@link library.Package.Pin} objects. + * @param p_outline an array of {@link geometry.planar.Shape} objects. + * @param p_keepout_arr an array of {@link library.Package.Keepout} objects. + * @param p_via_keepout_arr an array of {@link library.Package.Keepout} objects. + * @param p_place_keepout_arr an array of {@link library.Package.Keepout} objects. + * @param p_is_front a boolean. + * @param p_package_list a {@link library.Packages} object. */ public Package(String p_name, int p_no, Pin[] p_pin_arr, Shape[] p_outline, Keepout[] p_keepout_arr, Keepout[] p_via_keepout_arr, Keepout[] p_place_keepout_arr, boolean p_is_front, Packages p_package_list) @@ -55,6 +66,9 @@ public Package(String p_name, int p_no, Pin[] p_pin_arr, Shape[] p_outline, Keep /** * Compares 2 packages by name. * Useful for example to display packages in alphabetic order. + * + * @param p_other a {@link library.Package} object. + * @return a int. */ public int compareTo(Package p_other) { @@ -63,6 +77,9 @@ public int compareTo(Package p_other) /** * Returns the pin with the input number from this package. + * + * @param p_no a int. + * @return a {@link library.Package.Pin} object. */ public Pin get_pin(int p_no) { @@ -77,6 +94,9 @@ public Pin get_pin(int p_no) /** * Returns the pin number of the pin with the input name from this package, or -1, if no such pin exists * Pin numbers are from 0 to pin_count - 1. + * + * @param p_name a {@link java.lang.String} object. + * @return a int. */ public int get_pin_no(String p_name) { @@ -92,17 +112,25 @@ public int get_pin_no(String p_name) /** * Returns the pin count of this package. + * + * @return a int. */ public int pin_count() { return pin_arr.length; } + /** + *

toString.

+ * + * @return a {@link java.lang.String} object. + */ public String toString() { return this.name; } + /** {@inheritDoc} */ public void print_info(board.ObjectInfoPanel p_window, java.util.Locale p_locale) { java.util.ResourceBundle resources = diff --git a/library/Packages.java b/src/main/java/library/Packages.java similarity index 78% rename from library/Packages.java rename to src/main/java/library/Packages.java index 1fa2ef7..e045e51 100644 --- a/library/Packages.java +++ b/src/main/java/library/Packages.java @@ -29,6 +29,7 @@ * Describes a library of component packages. * * @author Alfons Wirtz + * @version $Id: $Id */ public class Packages implements java.io.Serializable { @@ -36,6 +37,8 @@ public class Packages implements java.io.Serializable * Creates a new instance of Packages. * p_padstack_list is the list of padstacks used for the pins * of the packages in this data structure. + * + * @param p_padstack_list a {@link library.Padstacks} object. */ public Packages(Padstacks p_padstack_list) { @@ -45,6 +48,10 @@ public Packages(Padstacks p_padstack_list) /** * Returns the package with the input name and the input side or null, * if no such package exists. + * + * @param p_name a {@link java.lang.String} object. + * @param p_is_front a boolean. + * @return a {@link library.Package} object. */ public Package get(String p_name, boolean p_is_front) { @@ -68,6 +75,9 @@ public Package get(String p_name, boolean p_is_front) /** * Returns the package with index p_package_no. * Packages numbers are from 1 to package count. + * + * @param p_package_no a int. + * @return a {@link library.Package} object. */ public Package get(int p_package_no) { @@ -81,6 +91,8 @@ public Package get(int p_package_no) /** * Returns the count of packages in this object. + * + * @return a int. */ public int count() { @@ -89,6 +101,15 @@ public int count() /** * Appends a new package with the input data to this object. + * + * @param p_name a {@link java.lang.String} object. + * @param p_pin_arr an array of {@link library.Package.Pin} objects. + * @param p_outline an array of {@link geometry.planar.Shape} objects. + * @param p_keepout_arr an array of {@link library.Package.Keepout} objects. + * @param p_via_keepout_arr an array of {@link library.Package.Keepout} objects. + * @param p_place_keepout_arr an array of {@link library.Package.Keepout} objects. + * @param p_is_front a boolean. + * @return a {@link library.Package} object. */ public Package add(String p_name, Package.Pin [] p_pin_arr, Shape[] p_outline, Package.Keepout [] p_keepout_arr, Package.Keepout [] p_via_keepout_arr, @@ -103,6 +124,9 @@ public Package add(String p_name, Package.Pin [] p_pin_arr, Shape[] p_outline, /** * Appends a new package with pins p_pin_arr to this object. * The package name is generated internally. + * + * @param p_pin_arr an array of {@link library.Package.Pin} objects. + * @return a {@link library.Package} object. */ public Package add(Package.Pin [] p_pin_arr) { diff --git a/library/Padstack.java b/src/main/java/library/Padstack.java similarity index 90% rename from library/Padstack.java rename to src/main/java/library/Padstack.java index 11aea3e..f62fe70 100644 --- a/library/Padstack.java +++ b/src/main/java/library/Padstack.java @@ -29,6 +29,7 @@ * Describes padstack masks for pins or vias located at the origin. * * @author alfons + * @version $Id: $Id */ public class Padstack implements Comparable, board.ObjectInfoPanel.Printable, java.io.Serializable { @@ -53,6 +54,9 @@ public class Padstack implements Comparable, board.ObjectInfoPanel.Pri /** * Compares 2 padstacks by name. * Useful for example to display padstacks in alphabetic order. + * + * @param p_other a {@link library.Padstack} object. + * @return a int. */ public int compareTo(Padstack p_other) { @@ -61,6 +65,9 @@ public int compareTo(Padstack p_other) /** * Gets the shape of this padstack on layer p_layer + * + * @param p_layer a int. + * @return a {@link geometry.planar.ConvexShape} object. */ public ConvexShape get_shape(int p_layer) { @@ -74,6 +81,8 @@ public ConvexShape get_shape(int p_layer) /** * Returns the first layer of this padstack with a shape != null. + * + * @return a int. */ public int from_layer() { @@ -87,6 +96,8 @@ public int from_layer() /** * Returns the last layer of this padstack with a shape != null. + * + * @return a int. */ public int to_layer() { @@ -98,12 +109,21 @@ public int to_layer() return result; } - /** Returns the layer ciount of the board of this padstack. */ + /** + * Returns the layer ciount of the board of this padstack. + * + * @return a int. + */ public int board_layer_count() { return shapes.length; } + /** + *

toString.

+ * + * @return a {@link java.lang.String} object. + */ public String toString() { return this.name; @@ -113,6 +133,10 @@ public String toString() * Calculates the allowed trace exit directions of the shape of this padstack on layer p_layer. * If the length of the pad is smaller than p_factor times the height of the pad, * connection also to the long side is allowed. + * + * @param p_layer a int. + * @param p_factor a double. + * @return a java$util$Collection object. */ public java.util.Collection get_trace_exit_directions(int p_layer, double p_factor) { @@ -152,6 +176,7 @@ public java.util.Collection get_trace_exit_directions(int p_layer, do return result; } + /** {@inheritDoc} */ public void print_info(board.ObjectInfoPanel p_window, java.util.Locale p_locale) { java.util.ResourceBundle resources = diff --git a/library/Padstacks.java b/src/main/java/library/Padstacks.java similarity index 79% rename from library/Padstacks.java rename to src/main/java/library/Padstacks.java index 532fd79..7eabca1 100644 --- a/library/Padstacks.java +++ b/src/main/java/library/Padstacks.java @@ -29,10 +29,15 @@ * Describes a library of padstacks for pins or vias. * * @author alfons + * @version $Id: $Id */ public class Padstacks implements java.io.Serializable { - /** Creates a new instance of Padstacks */ + /** + * Creates a new instance of Padstacks + * + * @param p_layer_structure a {@link board.LayerStructure} object. + */ public Padstacks(board.LayerStructure p_layer_structure) { board_layer_structure = p_layer_structure; @@ -42,6 +47,9 @@ public Padstacks(board.LayerStructure p_layer_structure) /** * Returns the padstack with the input name or null, * if no such padstack exists. + * + * @param p_name a {@link java.lang.String} object. + * @return a {@link library.Padstack} object. */ public Padstack get(String p_name) { @@ -59,6 +67,8 @@ public Padstack get(String p_name) /** * Returns the count of Padstacks in this object. + * + * @return a int. */ public int count() { @@ -66,7 +76,10 @@ public int count() } /** - * Returns the padstack with index p_padstack_no for 1 <= p_padstack_no <= padstack_count + * Returns the padstack with index p_padstack_no for {@code 1 <= p_padstack_no <= padstack_count} + * + * @param p_padstack_no a int. + * @return a {@link library.Padstack} object. */ public Padstack get(int p_padstack_no) { @@ -89,6 +102,12 @@ public Padstack get(int p_padstack_no) * p_shapes is an array of dimension board layer_count. * p_drill_allowed indicates, if vias of the own net are allowed to overlap with this padstack * If p_placed_absolute is false, the layers of the padstack are mirrored, if it is placed on the back side. + * + * @param p_name a {@link java.lang.String} object. + * @param p_shapes an array of {@link geometry.planar.ConvexShape} objects. + * @param p_drill_allowed a boolean. + * @param p_placed_absolute a boolean. + * @return a {@link library.Padstack} object. */ public Padstack add(String p_name, ConvexShape [] p_shapes, boolean p_drill_allowed, boolean p_placed_absolute) { @@ -102,6 +121,9 @@ public Padstack add(String p_name, ConvexShape [] p_shapes, boolean p_drill_allo * Appends a new padstack with the input shapes to this padstacks. * p_shapes is an array of dimension board layer_count. * The padatack name is generated internally. + * + * @param p_shapes an array of {@link geometry.planar.ConvexShape} objects. + * @return a {@link library.Padstack} object. */ public Padstack add(ConvexShape [] p_shapes) { @@ -113,6 +135,11 @@ public Padstack add(ConvexShape [] p_shapes) * Appends a new padstack withe the input shape from p_from_layer to p_to_layer * and null on the other layers. * The padatack name is generated internally. + * + * @param p_shape a {@link geometry.planar.ConvexShape} object. + * @param p_from_layer a int. + * @param p_to_layer a int. + * @return a {@link library.Padstack} object. */ public Padstack add(ConvexShape p_shape, int p_from_layer, int p_to_layer) { diff --git a/library/package.html b/src/main/java/library/package.html similarity index 100% rename from library/package.html rename to src/main/java/library/package.html diff --git a/rules/BoardRules.java b/src/main/java/rules/BoardRules.java similarity index 85% rename from rules/BoardRules.java rename to src/main/java/rules/BoardRules.java index 98250b4..0bbd4e4 100644 --- a/rules/BoardRules.java +++ b/src/main/java/rules/BoardRules.java @@ -27,11 +27,15 @@ * to be inserted into a routing board * * @author Alfons Wirtz + * @version $Id: $Id */ public class BoardRules implements java.io.Serializable { /** * Creates a new instance of this class. + * + * @param p_layer_structure a {@link board.LayerStructure} object. + * @param p_clearance_matrix a {@link rules.ClearanceMatrix} object. */ public BoardRules(board.LayerStructure p_layer_structure, ClearanceMatrix p_clearance_matrix) { @@ -46,6 +50,10 @@ public BoardRules(board.LayerStructure p_layer_structure, ClearanceMatrix p_clea /** * Returns the trace halfwidth used for routing with the input net on the input layer. + * + * @param p_net_no a int. + * @param p_layer a int. + * @return a int. */ public int get_trace_half_width( int p_net_no, int p_layer) { @@ -55,7 +63,10 @@ public int get_trace_half_width( int p_net_no, int p_layer) /** * Returns true, if the trace widths used for routing for the input net are equal on all layers. - * If p_net_no < 0, the default trace widths for all nets are checked. + * {@code If p_net_no < 0, the default trace widths for all nets are checked.} + * + * @param p_net_no a int. + * @return a boolean. */ public boolean trace_widths_are_layer_dependent(int p_net_no) { @@ -70,13 +81,21 @@ public boolean trace_widths_are_layer_dependent(int p_net_no) return false; } - /** Returns he smallest of all default trace half widths*/ + /** + * Returns he smallest of all default trace half widths + * + * @return a int. + */ public int get_min_trace_half_width() { return min_trace_half_width; } - /** Returns he biggest of all default trace half widths*/ + /** + * Returns he biggest of all default trace half widths + * + * @return a int. + */ public int get_max_trace_half_width() { return max_trace_half_width; @@ -84,6 +103,9 @@ public int get_max_trace_half_width() /** * Changes the default trace halfwidth used for routing on the input layer. + * + * @param p_layer a int. + * @param p_value a int. */ public void set_default_trace_half_width(int p_layer, int p_value) { @@ -92,6 +114,12 @@ public void set_default_trace_half_width(int p_layer, int p_value) max_trace_half_width = Math.max(max_trace_half_width, p_value); } + /** + *

get_default_trace_half_width.

+ * + * @param p_layer a int. + * @return a int. + */ public int get_default_trace_half_width (int p_layer) { return this.get_default_net_class().get_trace_half_width(p_layer); @@ -100,6 +128,8 @@ public int get_default_trace_half_width (int p_layer) /** * Changes the default trace halfwidth used for routing on all layers * to the input value. + * + * @param p_value a int. */ public void set_default_trace_half_widths(int p_value) { @@ -115,6 +145,8 @@ public void set_default_trace_half_widths(int p_value) /** * Returns the net rule used for all nets, for whichh no special rrule was set. + * + * @return a {@link rules.NetClass} object. */ public NetClass get_default_net_class() { @@ -126,13 +158,21 @@ public NetClass get_default_net_class() return this.net_classes.get(0); } - /** Gets the default item clearance class */ + /** + * Gets the default item clearance class + * + * @return a int. + */ public static int default_clearance_class() { return 1; } - /** For items with no clearances */ + /** + * For items with no clearances + * + * @return a int. + */ public static int clearance_class_none() { return 0; @@ -140,6 +180,9 @@ public static int clearance_class_none() /** * Returns an empty new net rule with an internally created name. + * + * @param p_locale a {@link java.util.Locale} object. + * @return a {@link rules.NetClass} object. */ public NetClass get_new_net_class(java.util.Locale p_locale) { @@ -152,6 +195,9 @@ public NetClass get_new_net_class(java.util.Locale p_locale) /** * Returns an empty new net rule with an internally created name. + * + * @param p_name a {@link java.lang.String} object. + * @return a {@link rules.NetClass} object. */ public NetClass get_new_net_class(String p_name) { @@ -166,6 +212,9 @@ public NetClass get_new_net_class(String p_name) * Create a default via rule for p_net_class with name p_name. * If more than one via infos with the same layer range are found, * only the via info with the smmallest pad size is inserted. + * + * @param p_net_class a {@link rules.NetClass} object. + * @param p_name a {@link java.lang.String} object. */ public void create_default_via_rule(NetClass p_net_class, String p_name) { @@ -206,6 +255,9 @@ public void create_default_via_rule(NetClass p_net_class, String p_name) p_net_class.set_via_rule(default_rule); } + /** + *

create_default_net_class.

+ */ public void create_default_net_class() { // add the default net rule @@ -217,6 +269,9 @@ public void create_default_net_class() /** * Appends a new net class initialized with default data and a default name. + * + * @param p_locale a {@link java.util.Locale} object. + * @return a {@link rules.NetClass} object. */ public NetClass append_net_class(java.util.Locale p_locale) { @@ -231,6 +286,9 @@ public NetClass append_net_class(java.util.Locale p_locale) /** * Appends a new net class initialized with default data and returns that class. * If a class with p_name exists, this class is returned withoout appending a new class. + * + * @param p_name a {@link java.lang.String} object. + * @return a {@link rules.NetClass} object. */ public NetClass append_net_class(String p_name) { @@ -250,6 +308,8 @@ public NetClass append_net_class(String p_name) /** * Returns the default via rule for routing or null, if no via rule exists. + * + * @return a {@link rules.ViaRule} object. */ public ViaRule get_default_via_rule() { @@ -262,6 +322,9 @@ public ViaRule get_default_via_rule() /** * Returns the via rule wit name p_name, or null, if no such rule exists. + * + * @param p_name a {@link java.lang.String} object. + * @return a {@link rules.ViaRule} object. */ public ViaRule get_via_rule(String p_name) { @@ -278,6 +341,10 @@ public ViaRule get_via_rule(String p_name) /** * Changes the clearance class index of all objects on the board with index p_from_no * to p_to_no. + * + * @param p_from_no a int. + * @param p_to_no a int. + * @param p_board_items a {@link java.util.Collection} object. */ public void change_clearance_class_no(int p_from_no, int p_to_no, java.util.Collection p_board_items) { @@ -319,6 +386,10 @@ public void change_clearance_class_no(int p_from_no, int p_to_no, java.util.Coll /** * Removes the clearance class with number p_index. * Returns false, if that was not possible, because there were still items assigned to this class. + * + * @param p_index a int. + * @param p_board_items a {@link java.util.Collection} object. + * @return a boolean. */ public boolean remove_clearance_class(int p_index, java.util.Collection p_board_items) { @@ -394,7 +465,9 @@ public boolean remove_clearance_class(int p_index, java.util.Collection= 1 + * Sets the value of all clearance classes with {@code number >= 1} * to p_value on all layers. + * + * @param p_value a int. */ public void set_default_value(int p_value) { @@ -100,8 +115,11 @@ public void set_default_value(int p_value) } /** - * Sets the value of all clearance classes with number >= 1 + * Sets the value of all clearance classes with {@code number >= 1} * to p_value on p_layer. + * + * @param p_layer a int. + * @param p_value a int. */ public void set_default_value(int p_layer, int p_value) { @@ -118,6 +136,10 @@ public void set_default_value(int p_layer, int p_value) /** * Sets the value of an entry in the clearance matrix to p_value * on all layers. + * + * @param p_i a int. + * @param p_j a int. + * @param p_value a int. */ public void set_value(int p_i, int p_j, int p_value) { @@ -130,6 +152,10 @@ public void set_value(int p_i, int p_j, int p_value) /** * Sets the value of an entry in the clearance matrix to p_value * on all inner layers. + * + * @param p_i a int. + * @param p_j a int. + * @param p_value a int. */ public void set_inner_value(int p_i, int p_j, int p_value) { @@ -141,6 +167,11 @@ public void set_inner_value(int p_i, int p_j, int p_value) /** * Sets the value of an entry in the clearance matrix to p_value. + * + * @param p_i a int. + * @param p_j a int. + * @param p_layer a int. + * @param p_value a int. */ public void set_value(int p_i, int p_j, int p_layer, int p_value) { @@ -157,6 +188,11 @@ public void set_value(int p_i, int p_j, int p_layer, int p_value) /** * Cets the required spacing of clearance classes with index p_i and p_j * on p_layer. This value will be always an even integer. + * + * @param p_i a int. + * @param p_j a int. + * @param p_layer a int. + * @return a int. */ public int value(int p_i, int p_j, int p_layer) { @@ -171,6 +207,10 @@ public int value(int p_i, int p_j, int p_layer) /** * Returns the maximal required spacing of clearance class with * index p_i to all other clearance classes on layer p_layer. + * + * @param p_i a int. + * @param p_layer a int. + * @return a int. */ public int max_value(int p_i, int p_layer) { @@ -181,6 +221,12 @@ public int max_value(int p_i, int p_layer) return row[i].max_value[layer]; } + /** + *

max_value.

+ * + * @param p_layer a int. + * @return a int. + */ public int max_value(int p_layer) { int layer = Math.max(p_layer, 0); @@ -191,6 +237,10 @@ public int max_value(int p_layer) /** * Returns true, if the values of the clearance matrix * in the p_i-th column and the p_j-th row are not equal on all layers. + * + * @param p_i a int. + * @param p_j a int. + * @return a boolean. */ public boolean is_layer_dependent(int p_i, int p_j) { @@ -208,6 +258,10 @@ public boolean is_layer_dependent(int p_i, int p_j) /** * Returns true, if the values of the clearance matrix * in the p_i-th column and the p_j-th row are not equal on all inner layers. + * + * @param p_i a int. + * @param p_j a int. + * @return a boolean. */ public boolean is_inner_layer_dependent(int p_i, int p_j) { @@ -228,6 +282,9 @@ public boolean is_inner_layer_dependent(int p_i, int p_j) /** * Returns the row with index p_no + * + * @param p_no a int. + * @return a {@link rules.ClearanceMatrix.Row} object. */ public Row get_row(int p_no) { @@ -239,6 +296,11 @@ public Row get_row(int p_no) return this.row[p_no]; } + /** + *

get_class_count.

+ * + * @return a int. + */ public int get_class_count() { return this.class_count; @@ -246,6 +308,8 @@ public int get_class_count() /** * Return the layer count of this clearance matrix;# + * + * @return a int. */ public int get_layer_count() { @@ -254,6 +318,10 @@ public int get_layer_count() /** * Return the clearance compensation value of p_clearance_class_no on layer p_layer. + * + * @param p_clearance_class_no a int. + * @param p_layer a int. + * @return a int. */ public int clearance_compensation_value(int p_clearance_class_no, int p_layer) { @@ -264,6 +332,9 @@ public int clearance_compensation_value(int p_clearance_class_no, int p_layer) * Appends a new clearance class to the clearence matrix and * initializes it with the values of the default class. * Returns false, oif a clearance class with name p_class_name is already existing. + * + * @param p_class_name a {@link java.lang.String} object. + * @return a boolean. */ public boolean append_class(String p_class_name) { @@ -357,6 +428,10 @@ void remove_class(int p_index) /** * Returns true, if all clearance values of the class with index p_1 are equal to * the clearance values of index p_2. + * + * @param p_1 a int. + * @param p_2 a int. + * @return a boolean. */ public boolean is_equal(int p_1, int p_2) { @@ -492,4 +567,4 @@ boolean is_layer_dependent() } int [] layer; } -} \ No newline at end of file +} diff --git a/rules/DefaultItemClearanceClasses.java b/src/main/java/rules/DefaultItemClearanceClasses.java similarity index 79% rename from rules/DefaultItemClearanceClasses.java rename to src/main/java/rules/DefaultItemClearanceClasses.java index 36b87bb..c7ec43d 100644 --- a/rules/DefaultItemClearanceClasses.java +++ b/src/main/java/rules/DefaultItemClearanceClasses.java @@ -22,13 +22,17 @@ package rules; /** + *

DefaultItemClearanceClasses class.

* * @author Alfons Wirtz + * @version $Id: $Id */ public class DefaultItemClearanceClasses implements java.io.Serializable { - /** Creates a new instance of DefaultItemClearancesClasses */ + /** + * Creates a new instance of DefaultItemClearancesClasses + */ public DefaultItemClearanceClasses() { for (int i = 1; i < ItemClass.values().length; ++i) @@ -37,6 +41,11 @@ public DefaultItemClearanceClasses() } } + /** + *

Constructor for DefaultItemClearanceClasses.

+ * + * @param p_classes a {@link rules.DefaultItemClearanceClasses} object. + */ public DefaultItemClearanceClasses(DefaultItemClearanceClasses p_classes) { for (int i = 1; i < ItemClass.values().length; ++i) @@ -56,6 +65,9 @@ public enum ItemClass /** * Returns the number of the default clearance class for the input item class. + * + * @param p_item_class a {@link rules.DefaultItemClearanceClasses.ItemClass} object. + * @return a int. */ public int get(ItemClass p_item_class) { @@ -65,6 +77,9 @@ public int get(ItemClass p_item_class) /** * Sets the index of the default clearance class of the input item class * in the clearance matrix to p_index. + * + * @param p_item_class a {@link rules.DefaultItemClearanceClasses.ItemClass} object. + * @param p_index a int. */ public void set(ItemClass p_item_class, int p_index) { @@ -73,6 +88,8 @@ public void set(ItemClass p_item_class, int p_index) /** * Sets the indices of all default item clearance classes to p_index. + * + * @param p_index a int. */ public void set_all(int p_index) { diff --git a/rules/Net.java b/src/main/java/rules/Net.java similarity index 88% rename from rules/Net.java rename to src/main/java/rules/Net.java index 110c3c8..e4bd2c7 100644 --- a/rules/Net.java +++ b/src/main/java/rules/Net.java @@ -28,6 +28,7 @@ * Describes properties for an individual electrical net. * * @author Alfons Wirtz + * @version $Id: $Id */ public class Net implements Comparable, board.ObjectInfoPanel.Printable, java.io.Serializable { @@ -35,6 +36,12 @@ public class Net implements Comparable, board.ObjectInfoPanel.Printable, ja /** * Creates a new instance of Net. * p_net_list is the net list, where this net belongs to. + * + * @param p_name a {@link java.lang.String} object. + * @param p_subnet_number a int. + * @param p_no a int. + * @param p_net_list a {@link rules.Nets} object. + * @param p_contains_plane a boolean. */ public Net(String p_name, int p_subnet_number, int p_no, Nets p_net_list, boolean p_contains_plane) { @@ -46,6 +53,11 @@ public Net(String p_name, int p_subnet_number, int p_no, Nets p_net_list, boolea net_class = p_net_list.get_board().rules.get_default_net_class(); } + /** + *

toString.

+ * + * @return a {@link java.lang.String} object. + */ public String toString() { return this.name; @@ -54,19 +66,30 @@ public String toString() /** * Compares 2 nets by name. * Useful for example to display nets in alphabetic order. + * + * @param p_other a {@link rules.Net} object. + * @return a int. */ public int compareTo(Net p_other) { return this.name.compareToIgnoreCase(p_other.name); } - /** Returns the class of this net. */ + /** + * Returns the class of this net. + * + * @return a {@link rules.NetClass} object. + */ public NetClass get_class() { return this.net_class; } - /** Sets the class of this net */ + /** + * Sets the class of this net + * + * @param p_rule a {@link rules.NetClass} object. + */ public void set_class(NetClass p_rule) { this.net_class = p_rule; @@ -74,6 +97,8 @@ public void set_class(NetClass p_rule) /** * Returns the pins and conduction areas of this net. + * + * @return a {@link java.util.Collection} object. */ public java.util.Collection get_terminal_items() { @@ -100,6 +125,8 @@ public java.util.Collection get_terminal_items() /** * Returns the pins of this net. + * + * @return a {@link java.util.Collection} object. */ public java.util.Collection get_pins() { @@ -126,6 +153,8 @@ public java.util.Collection get_pins() /** * Returns all items of this net. + * + * @return a {@link java.util.Collection} object. */ public java.util.Collection get_items() { @@ -149,6 +178,8 @@ public java.util.Collection get_items() /** * Returns the cumulative trace length of all traces on the board belonging to this net. + * + * @return a double. */ public double get_trace_length() { @@ -167,6 +198,8 @@ public double get_trace_length() /** * Returns the count of vias on the board belonging to this net. + * + * @return a int. */ public int get_via_count() { @@ -182,22 +215,30 @@ public int get_via_count() return result; } + /** + *

set_contains_plane.

+ * + * @param p_value a boolean. + */ public void set_contains_plane(boolean p_value) { contains_plane = p_value; } - /** + /** * Indicates, if this net contains a power plane. * Used by the autorouter for setting the via costs to the cheap plane via costs. * May also be true, if a layer covered with a conduction_area of this net is * is a signal layer. + * + * @return a boolean. */ public boolean contains_plane() { return contains_plane; } + /** {@inheritDoc} */ public void print_info(board.ObjectInfoPanel p_window, java.util.Locale p_locale) { Integer via_count = this.get_via_count(); diff --git a/rules/NetClass.java b/src/main/java/rules/NetClass.java similarity index 84% rename from rules/NetClass.java rename to src/main/java/rules/NetClass.java index fbf17af..fa9ea19 100644 --- a/rules/NetClass.java +++ b/src/main/java/rules/NetClass.java @@ -23,11 +23,18 @@ * Describes routing rules for individual nets. * * @author Alfons Wirtz + * @version $Id: $Id */ public class NetClass implements java.io.Serializable, board.ObjectInfoPanel.Printable { - /** Creates a new instance of NetClass */ + /** + * Creates a new instance of NetClass + * + * @param p_name a {@link java.lang.String} object. + * @param p_layer_structure a {@link board.LayerStructure} object. + * @param p_clearance_matrix a {@link rules.ClearanceMatrix} object. + */ public NetClass(String p_name, board.LayerStructure p_layer_structure, ClearanceMatrix p_clearance_matrix) { this.name = p_name; @@ -42,6 +49,11 @@ public NetClass(String p_name, board.LayerStructure p_layer_structure, Clearance } + /** + *

toString.

+ * + * @return a {@link java.lang.String} object. + */ public String toString() { return this.name; @@ -49,6 +61,8 @@ public String toString() /** * Changes the name of this net class. + * + * @param p_name a {@link java.lang.String} object. */ public void set_name(String p_name) { @@ -57,6 +71,8 @@ public void set_name(String p_name) /** * Gets the name of this net class. + * + * @return a {@link java.lang.String} object. */ public String get_name() { @@ -65,6 +81,8 @@ public String get_name() /** * Sets the trace half width used for routing to p_value on all layers. + * + * @param p_value a int. */ public void set_trace_half_width(int p_value) { @@ -73,6 +91,8 @@ public void set_trace_half_width(int p_value) /** * Sets the trace half width used for routing to p_value on all inner layers. + * + * @param p_value a int. */ public void set_trace_half_width_on_inner(int p_value) { @@ -84,12 +104,20 @@ public void set_trace_half_width_on_inner(int p_value) /** * Sets the trace half width used for routing to p_value on the input layer. + * + * @param p_layer a int. + * @param p_value a int. */ public void set_trace_half_width(int p_layer, int p_value) { trace_half_width_arr[p_layer] = p_value; } + /** + *

layer_count.

+ * + * @return a int. + */ public int layer_count() { return trace_half_width_arr.length; @@ -97,6 +125,9 @@ public int layer_count() /** * Gets the trace half width used for routing on the input layer. + * + * @param p_layer a int. + * @return a int. */ public int get_trace_half_width(int p_layer) { @@ -110,6 +141,8 @@ public int get_trace_half_width(int p_layer) /** * Sets the clearance class used for routing traces with this net rclass. + * + * @param p_clearance_class_no a int. */ public void set_trace_clearance_class(int p_clearance_class_no) { @@ -118,6 +151,8 @@ public void set_trace_clearance_class(int p_clearance_class_no) /** * Gets the clearance class used for routing traces with this net class. + * + * @return a int. */ public int get_trace_clearance_class() { @@ -126,6 +161,8 @@ public int get_trace_clearance_class() /** * Sets the via rule of this net class. + * + * @param p_via_rule a {@link rules.ViaRule} object. */ public void set_via_rule(ViaRule p_via_rule) { @@ -134,6 +171,8 @@ public void set_via_rule(ViaRule p_via_rule) /** * Gets the via rule of this net rule. + * + * @return a {@link rules.ViaRule} object. */ public ViaRule get_via_rule() { @@ -142,6 +181,8 @@ public ViaRule get_via_rule() /** * Sets, if traces and vias of this net class can be pushed. + * + * @param p_value a boolean. */ public void set_shove_fixed(boolean p_value) { @@ -150,6 +191,8 @@ public void set_shove_fixed(boolean p_value) /** * Returns, if traces and vias of this net class can be pushed. + * + * @return a boolean. */ public boolean is_shove_fixed() { @@ -158,6 +201,8 @@ public boolean is_shove_fixed() /** * Sets, if traces of this nets class are pulled tight. + * + * @param p_value a boolean. */ public void set_pull_tight(boolean p_value) { @@ -166,6 +211,8 @@ public void set_pull_tight(boolean p_value) /** * Returns, if traces of this nets class are pulled tight. + * + * @return a boolean. */ public boolean get_pull_tight() { @@ -174,6 +221,8 @@ public boolean get_pull_tight() /** * Sets, if the cycle remove algorithm ignores cycles, where conduction areas are involved + * + * @param p_value a boolean. */ public void set_ignore_cycles_with_areas(boolean p_value) { @@ -182,6 +231,8 @@ public void set_ignore_cycles_with_areas(boolean p_value) /** * Returns, if the cycle remove algorithm ignores cycles, where conduction areas are involved + * + * @return a boolean. */ public boolean get_ignore_cycles_with_areas() { @@ -190,7 +241,9 @@ public boolean get_ignore_cycles_with_areas() /** * Returns the minimum trace length of this net class. - * If the result is <= 0, there is no minimal trace length restriction. + * {@code If the result is <= 0, there is no minimal trace length restriction.} + * + * @return a double. */ public double get_minimum_trace_length() { @@ -199,7 +252,9 @@ public double get_minimum_trace_length() /** * Sets the minimum trace length of this net class to p_value. - * If p_value is <= 0, there is no minimal trace length restriction. + * {@code If p_value is <= 0, there is no minimal trace length restriction.} + * + * @param p_value a double. */ public void set_minimum_trace_length(double p_value) { @@ -208,7 +263,9 @@ public void set_minimum_trace_length(double p_value) /** * Returns the maximum trace length of this net class. - * If the result is <= 0, there is no maximal trace length restriction. + * {@code If the result is <= 0, there is no maximal trace length restriction.} + * + * @return a double. */ public double get_maximum_trace_length() { @@ -217,7 +274,9 @@ public double get_maximum_trace_length() /** * Sets the maximum trace length of this net class to p_value. - * If p_value is <= 0, there is no maximal trace length restriction. + * {@code If p_value is <= 0, there is no maximal trace length restriction.} + * + * @param p_value a double. */ public void set_maximum_trace_length(double p_value) { @@ -226,6 +285,9 @@ public void set_maximum_trace_length(double p_value) /** * Returns if the layer with index p_layer_no is active for routing + * + * @param p_layer_no a int. + * @return a boolean. */ public boolean is_active_routing_layer(int p_layer_no) { @@ -238,6 +300,9 @@ public boolean is_active_routing_layer(int p_layer_no) /** * Sets the layer with index p_layer_no to p_active. + * + * @param p_layer_no a int. + * @param p_active a boolean. */ public void set_active_routing_layer(int p_layer_no, boolean p_active) { @@ -250,6 +315,8 @@ public void set_active_routing_layer(int p_layer_no, boolean p_active) /** * Activates or deactivates all layers for routing + * + * @param p_value a boolean. */ public void set_all_layers_active(boolean p_value) { @@ -258,6 +325,8 @@ public void set_all_layers_active(boolean p_value) /** * Activates or deactivates all inner layers for routing + * + * @param p_value a boolean. */ public void set_all_inner_layers_active(boolean p_value) { @@ -267,6 +336,7 @@ public void set_all_inner_layers_active(boolean p_value) } } + /** {@inheritDoc} */ public void print_info(board.ObjectInfoPanel p_window, java.util.Locale p_locale) { java.util.ResourceBundle resources = @@ -304,7 +374,10 @@ public void print_info(board.ObjectInfoPanel p_window, java.util.Locale p_locale } /** - * Returns true, if the trace width of this class is not equal on all layers. */ + * Returns true, if the trace width of this class is not equal on all layers. + * + * @return a boolean. + */ public boolean trace_width_is_layer_dependent() { int compare_value = trace_half_width_arr[0]; @@ -323,6 +396,8 @@ public boolean trace_width_is_layer_dependent() /** * Returns true, if the trace width of this class is not equal on all inner layers. + * + * @return a boolean. */ public boolean trace_width_is_inner_layer_dependent() { diff --git a/rules/NetClasses.java b/src/main/java/rules/NetClasses.java similarity index 86% rename from rules/NetClasses.java rename to src/main/java/rules/NetClasses.java index f962d17..09f37b7 100644 --- a/rules/NetClasses.java +++ b/src/main/java/rules/NetClasses.java @@ -25,11 +25,14 @@ * Contains the array of net classes for interactive routing. * * @author Alfons Wirtz + * @version $Id: $Id */ public class NetClasses implements java.io.Serializable { /** * Returns the number of classes in this array. + * + * @return a int. */ public int count() { @@ -38,6 +41,9 @@ public int count() /** * Returns the net class with index p_index. + * + * @param p_index a int. + * @return a {@link rules.NetClass} object. */ public NetClass get(int p_index) { @@ -47,6 +53,9 @@ public NetClass get(int p_index) /** * Returns the net class with name p_name, or null, if no such class exists. + * + * @param p_name a {@link java.lang.String} object. + * @return a {@link rules.NetClass} object. */ public NetClass get(String p_name) { @@ -96,6 +105,11 @@ NetClass append(board.LayerStructure p_layer_structure, ClearanceMatrix p_cleara * Looks, if the list contains a net class with trace half widths all equal to p_trace_half_width, * trace clearance class equal to p_trace_clearance_class and via rule equal to p_cia_rule. * Returns null, if no such net class was found. + * + * @param p_trace_half_width a int. + * @param p_trace_clearance_class a int. + * @param p_via_rule a {@link rules.ViaRule} object. + * @return a {@link rules.NetClass} object. */ public NetClass find(int p_trace_half_width, int p_trace_clearance_class, ViaRule p_via_rule) { @@ -123,8 +137,13 @@ public NetClass find(int p_trace_half_width, int p_trace_clearance_class, ViaRu /** * Looks, if the list contains a net class with trace half width[i] all equal to p_trace_half_width_arr[i] - * for 0 <= i < layer_count, trace clearance class equal to p_trace_clearance_class + * {@code for 0 <= i < layer_count}, trace clearance class equal to p_trace_clearance_class * and via rule equal to p_via_rule. Returns null, if no such net class was found. + * + * @param p_trace_half_width_arr an array of int. + * @param p_trace_clearance_class a int. + * @param p_via_rule a {@link rules.ViaRule} object. + * @return a {@link rules.NetClass} object. */ public NetClass find(int[] p_trace_half_width_arr, int p_trace_clearance_class, ViaRule p_via_rule) { @@ -154,6 +173,9 @@ public NetClass find(int[] p_trace_half_width_arr, int p_trace_clearance_class, /** * Removes p_net_class from this list. * Returns false, if p_net_class was not contained in the list. + * + * @param p_net_class a {@link rules.NetClass} object. + * @return a boolean. */ public boolean remove(NetClass p_net_class) { diff --git a/rules/Nets.java b/src/main/java/rules/Nets.java similarity index 81% rename from rules/Nets.java rename to src/main/java/rules/Nets.java index 7e6432b..53b92fd 100644 --- a/rules/Nets.java +++ b/src/main/java/rules/Nets.java @@ -26,11 +26,14 @@ * Describes the electrical Nets on a board. * * @author alfons + * @version $Id: $Id */ public class Nets implements java.io.Serializable { - /** Creates a new empty net list */ + /** + * Creates a new empty net list + */ public Nets() { net_arr = new Vector(); @@ -38,13 +41,21 @@ public Nets() /** * Returns the biggest net number on the board. + * + * @return a int. */ public int max_net_no() { return net_arr.size(); } - /** Returns the net with the input name and subnet_number , or null, if no such net exists. */ + /** + * Returns the net with the input name and subnet_number , or null, if no such net exists. + * + * @param p_name a {@link java.lang.String} object. + * @param p_subnet_number a int. + * @return a {@link rules.Net} object. + */ public Net get(String p_name, int p_subnet_number) { for (Net curr_net : net_arr) @@ -62,6 +73,9 @@ public Net get(String p_name, int p_subnet_number) /** * Returns all subnets with the input name. + * + * @param p_name a {@link java.lang.String} object. + * @return a {@link java.util.Collection} object. */ public Collection get(String p_name) { @@ -78,6 +92,9 @@ public Collection get(String p_name) /** * Returns the net with the input net number or null, if no such net exists. + * + * @param p_net_no a int. + * @return a {@link rules.Net} object. */ public Net get(int p_net_no) { @@ -95,6 +112,9 @@ public Net get(int p_net_no) /** * Generates a new net number. + * + * @param p_locale a {@link java.util.Locale} object. + * @return a {@link rules.Net} object. */ public Net new_net(java.util.Locale p_locale) { @@ -107,6 +127,11 @@ public Net new_net(java.util.Locale p_locale) * Adds a new net with default properties with the input name. * p_subnet_number is used only if a net is divided internally because of fromto rules for example. * For normal nets it is always 1. + * + * @param p_name a {@link java.lang.String} object. + * @param p_subnet_number a int. + * @param p_contains_plane a boolean. + * @return a {@link rules.Net} object. */ public Net add(String p_name, int p_subnet_number, boolean p_contains_plane) { @@ -123,6 +148,9 @@ public Net add(String p_name, int p_subnet_number, boolean p_contains_plane) /** * Returns false, if p_net_no belongs to a net internally used * for special purposes. + * + * @param p_net_no a int. + * @return a boolean. */ public static boolean is_normal_net_no(int p_net_no) { @@ -132,6 +160,8 @@ public static boolean is_normal_net_no(int p_net_no) /** * Sets the Board of this net list. * Used for example to get access to the Items of the net. + * + * @param p_board a {@link board.BasicBoard} object. */ public void set_board(board.BasicBoard p_board) { @@ -141,6 +171,8 @@ public void set_board(board.BasicBoard p_board) /** * Gets the Board of this net list. * Used for example to get access to the Items of the net. + * + * @return a {@link board.BasicBoard} object. */ public board.BasicBoard get_board() { diff --git a/rules/ViaInfo.java b/src/main/java/rules/ViaInfo.java similarity index 72% rename from rules/ViaInfo.java rename to src/main/java/rules/ViaInfo.java index d6176c4..4b93847 100644 --- a/rules/ViaInfo.java +++ b/src/main/java/rules/ViaInfo.java @@ -26,11 +26,20 @@ * used in interactive and automatic routing. * * @author Alfons Wirtz + * @version $Id: $Id */ public class ViaInfo implements Comparable, board.ObjectInfoPanel.Printable, java.io.Serializable { - /** Creates a new instance of ViaRule */ + /** + * Creates a new instance of ViaRule + * + * @param p_name a {@link java.lang.String} object. + * @param p_padstack a {@link library.Padstack} object. + * @param p_clearance_class a int. + * @param p_drill_to_smd_allowed a boolean. + * @param p_board_rules a {@link rules.BoardRules} object. + */ public ViaInfo(String p_name, Padstack p_padstack, int p_clearance_class, boolean p_drill_to_smd_allowed, BoardRules p_board_rules) { @@ -41,56 +50,108 @@ public ViaInfo(String p_name, Padstack p_padstack, int p_clearance_class, boolea board_rules = p_board_rules; } + /** + *

get_name.

+ * + * @return a {@link java.lang.String} object. + */ public String get_name() { return name; } + /** + *

set_name.

+ * + * @param p_name a {@link java.lang.String} object. + */ public void set_name(String p_name) { name = p_name; } + /** + *

toString.

+ * + * @return a {@link java.lang.String} object. + */ public String toString() { return this.name; } + /** + *

get_padstack.

+ * + * @return a {@link library.Padstack} object. + */ public Padstack get_padstack() { return padstack; } + /** + *

set_padstack.

+ * + * @param p_padstack a {@link library.Padstack} object. + */ public void set_padstack(Padstack p_padstack) { padstack = p_padstack; } + /** + *

get_clearance_class.

+ * + * @return a int. + */ public int get_clearance_class() { return clearance_class; } + /** + *

set_clearance_class.

+ * + * @param p_clearance_class a int. + */ public void set_clearance_class(int p_clearance_class) { clearance_class = p_clearance_class; } + /** + *

attach_smd_allowed.

+ * + * @return a boolean. + */ public boolean attach_smd_allowed() { return attach_smd_allowed; } + /** + *

set_attach_smd_allowed.

+ * + * @param p_attach_smd_allowed a boolean. + */ public void set_attach_smd_allowed(boolean p_attach_smd_allowed) { attach_smd_allowed = p_attach_smd_allowed; } + /** + *

compareTo.

+ * + * @param p_other a {@link rules.ViaInfo} object. + * @return a int. + */ public int compareTo(ViaInfo p_other) { return this.name.compareTo(p_other.name); } + /** {@inheritDoc} */ public void print_info(board.ObjectInfoPanel p_window, java.util.Locale p_locale) { java.util.ResourceBundle resources = diff --git a/rules/ViaInfos.java b/src/main/java/rules/ViaInfos.java similarity index 87% rename from rules/ViaInfos.java rename to src/main/java/rules/ViaInfos.java index a9aa4f2..74c230e 100644 --- a/rules/ViaInfos.java +++ b/src/main/java/rules/ViaInfos.java @@ -27,12 +27,16 @@ * Contains the lists of different ViaInfo's, which can be used in interactive and automatic routing. * * @author Alfons Wirtz + * @version $Id: $Id */ public class ViaInfos implements java.io.Serializable, board.ObjectInfoPanel.Printable { /** * Adds a via info consisting of padstack, clearance class and drill_to_smd_allowed. * Return false, if the insertion failed, for example if the name existed already. + * + * @param p_via_info a {@link rules.ViaInfo} object. + * @return a boolean. */ public boolean add(ViaInfo p_via_info) { @@ -46,6 +50,8 @@ public boolean add(ViaInfo p_via_info) /** * Returns the number of different vias, which can be used for routing. + * + * @return a int. */ public int count() { @@ -54,6 +60,9 @@ public int count() /** * Returns the p_no-th via af the via types, which can be used for routing. + * + * @param p_no a int. + * @return a {@link rules.ViaInfo} object. */ public ViaInfo get(int p_no) { @@ -63,6 +72,9 @@ public ViaInfo get(int p_no) /** * Returns the via info with name p_name, or null, if no such via exists. + * + * @param p_name a {@link java.lang.String} object. + * @return a {@link rules.ViaInfo} object. */ public ViaInfo get(String p_name) { @@ -78,6 +90,9 @@ public ViaInfo get(String p_name) /** * Returns true, if a via info with name p_name is already wyisting in the list. + * + * @param p_name a {@link java.lang.String} object. + * @return a boolean. */ public boolean name_exists(String p_name) { @@ -94,12 +109,16 @@ public boolean name_exists(String p_name) /** * Removes p_via_info from this list. * Returns false, if p_via_info was not contained in the list. + * + * @param p_via_info a {@link rules.ViaInfo} object. + * @return a boolean. */ public boolean remove(ViaInfo p_via_info) { return this.list.remove(p_via_info); } + /** {@inheritDoc} */ public void print_info(board.ObjectInfoPanel p_window, java.util.Locale p_locale) { java.util.ResourceBundle resources = diff --git a/rules/ViaRule.java b/src/main/java/rules/ViaRule.java similarity index 81% rename from rules/ViaRule.java rename to src/main/java/rules/ViaRule.java index 6145e4b..b0b9fea 100644 --- a/rules/ViaRule.java +++ b/src/main/java/rules/ViaRule.java @@ -28,6 +28,7 @@ * Vias at the beginning of the array are preferred to later vias. * * @author Alfons Wirtz + * @version $Id: $Id */ public class ViaRule implements java.io.Serializable, board.ObjectInfoPanel.Printable { @@ -35,11 +36,21 @@ public class ViaRule implements java.io.Serializable, board.ObjectInfoPanel.Prin /** Empty via rule. Must nott be changed. */ public static final ViaRule EMPTY = new ViaRule("empty"); + /** + *

Constructor for ViaRule.

+ * + * @param p_name a {@link java.lang.String} object. + */ public ViaRule (String p_name) { name = p_name; } + /** + *

append_via.

+ * + * @param p_via a {@link rules.ViaInfo} object. + */ public void append_via(ViaInfo p_via) { list.add(p_via); @@ -48,23 +59,42 @@ public void append_via(ViaInfo p_via) /** * Removes p_via from the rule. * Returns false, if p_via was not contained in the rule. + * + * @param p_via a {@link rules.ViaInfo} object. + * @return a boolean. */ public boolean remove_via(ViaInfo p_via) { return list.remove(p_via); } + /** + *

via_count.

+ * + * @return a int. + */ public int via_count() { return list.size(); } + /** + *

get_via.

+ * + * @param p_index a int. + * @return a {@link rules.ViaInfo} object. + */ public ViaInfo get_via(int p_index) { assert p_index >= 0 && p_index < list.size(); return list.get(p_index); } + /** + *

toString.

+ * + * @return a {@link java.lang.String} object. + */ public String toString() { return this.name; @@ -72,6 +102,9 @@ public String toString() /** * Returns true, if p_via_info is contained in the via list of this rule. + * + * @param p_via_info a {@link rules.ViaInfo} object. + * @return a boolean. */ public boolean contains(ViaInfo p_via_info) { @@ -87,6 +120,9 @@ public boolean contains(ViaInfo p_via_info) /** * Returns true, if this rule contains a via with padstack p_padstack + * + * @param p_padstack a {@link library.Padstack} object. + * @return a boolean. */ public boolean contains_padstack(library.Padstack p_padstack) { @@ -103,6 +139,10 @@ public boolean contains_padstack(library.Padstack p_padstack) /** * Searchs a via in this rule with first layer = p_from_layer and last layer = p_to_layer. * Returns null, if no such via exists. + * + * @param p_from_layer a int. + * @param p_to_layer a int. + * @return a {@link rules.ViaInfo} object. */ public ViaInfo get_layer_range(int p_from_layer, int p_to_layer) { @@ -119,6 +159,10 @@ public ViaInfo get_layer_range(int p_from_layer, int p_to_layer) /** * Swaps the locations of p_1 and p_2 in the rule. * Returns false, if p_1 or p_2 were not found in the list. + * + * @param p_1 a {@link rules.ViaInfo} object. + * @param p_2 a {@link rules.ViaInfo} object. + * @return a boolean. */ public boolean swap(ViaInfo p_1, ViaInfo p_2) { @@ -137,6 +181,7 @@ public boolean swap(ViaInfo p_1, ViaInfo p_2) return true; } + /** {@inheritDoc} */ public void print_info(board.ObjectInfoPanel p_window, java.util.Locale p_locale) { java.util.ResourceBundle resources = diff --git a/rules/package.html b/src/main/java/rules/package.html similarity index 100% rename from rules/package.html rename to src/main/java/rules/package.html diff --git a/tests/Validate.java b/src/main/java/tests/Validate.java similarity index 85% rename from tests/Validate.java rename to src/main/java/tests/Validate.java index 5dac01a..fd7dc23 100644 --- a/tests/Validate.java +++ b/src/main/java/tests/Validate.java @@ -38,6 +38,7 @@ * Some consistancy checking on a routing board. * * @author Alfons Wirtz + * @version $Id: $Id */ public class Validate { @@ -45,6 +46,10 @@ public class Validate * Does some consistancy checking on the routing board and may be some * other actions. * Returns false, if problems were detected. + * + * @param p_s a {@link java.lang.String} object. + * @param p_board a {@link board.BasicBoard} object. + * @return a boolean. */ public static boolean check(String p_s, BasicBoard p_board) { @@ -139,6 +144,18 @@ public static boolean check(String p_s, BasicBoard p_board) return result; } + /** + *

check.

+ * + * @param p_s a {@link java.lang.String} object. + * @param p_board a {@link board.BasicBoard} object. + * @param p_polyline a {@link geometry.planar.Polyline} object. + * @param p_layer a int. + * @param p_half_width a int. + * @param p_net_no_arr an array of int. + * @param p_cl_type a int. + * @return a boolean. + */ static public boolean check(String p_s, BasicBoard p_board, Polyline p_polyline, int p_layer, int p_half_width, int[] p_net_no_arr, int p_cl_type) { @@ -166,6 +183,9 @@ static public boolean check(String p_s, BasicBoard p_board, Polyline p_polyline, /** * check, that all traces on p_board are orthogonal + * + * @param p_s a {@link java.lang.String} object. + * @param p_board a {@link board.BasicBoard} object. */ static public void orthogonal(String p_s, BasicBoard p_board) { @@ -188,6 +208,9 @@ static public void orthogonal(String p_s, BasicBoard p_board) /** * check, that all traces on p_board are multiples of 45 degree + * + * @param p_s a {@link java.lang.String} object. + * @param p_board a {@link board.BasicBoard} object. */ static public void multiple_of_45_degree(String p_s, BasicBoard p_board) { @@ -213,6 +236,13 @@ static public void multiple_of_45_degree(String p_s, BasicBoard p_board) } } + /** + *

corners_on_grid.

+ * + * @param p_s a {@link java.lang.String} object. + * @param p_polyline a {@link geometry.planar.Polyline} object. + * @return a boolean. + */ static public boolean corners_on_grid(String p_s, Polyline p_polyline) { for (int i = 0; i < p_polyline.corner_count(); ++i) @@ -227,6 +257,14 @@ static public boolean corners_on_grid(String p_s, Polyline p_polyline) return true; } + /** + *

stub_count.

+ * + * @param p_s a {@link java.lang.String} object. + * @param p_board a {@link board.BasicBoard} object. + * @param p_net_no a int. + * @return a int. + */ static public int stub_count(String p_s, BasicBoard p_board, int p_net_no) { if (first_time) @@ -264,6 +302,13 @@ static public int stub_count(String p_s, BasicBoard p_board, int p_net_no) return result; } + /** + *

has_cycles.

+ * + * @param p_s a {@link java.lang.String} object. + * @param p_board a {@link board.BasicBoard} object. + * @return a boolean. + */ static public boolean has_cycles(String p_s, BasicBoard p_board) { boolean result = false; @@ -285,8 +330,15 @@ static public boolean has_cycles(String p_s, BasicBoard p_board) } return result; } - /** checks, if there are more than p_max_count traces with + /** + * checks, if there are more than p_max_count traces with * net number p_net_no + * + * @param p_s a {@link java.lang.String} object. + * @param p_board a {@link board.BasicBoard} object. + * @param p_net_no a int. + * @param p_max_count a int. + * @return a boolean. */ static public boolean trace_count_exceeded(String p_s, BasicBoard p_board, int p_net_no, int p_max_count) { @@ -316,6 +368,10 @@ static public boolean trace_count_exceeded(String p_s, BasicBoard p_board, int p /** * checks, if there are unconnectedtraces ore vias on the board + * + * @param p_s a {@link java.lang.String} object. + * @param p_board a {@link board.BasicBoard} object. + * @return a boolean. */ static public boolean unconnnected_routing_items(String p_s, BasicBoard p_board) { diff --git a/tests/package.html b/src/main/java/tests/package.html similarity index 100% rename from tests/package.html rename to src/main/java/tests/package.html diff --git a/board/resources/FixedState_de.properties b/src/main/resources/board/resources/FixedState_de.properties similarity index 100% rename from board/resources/FixedState_de.properties rename to src/main/resources/board/resources/FixedState_de.properties diff --git a/board/resources/FixedState_en.properties b/src/main/resources/board/resources/FixedState_en.properties similarity index 100% rename from board/resources/FixedState_en.properties rename to src/main/resources/board/resources/FixedState_en.properties diff --git a/board/resources/ObjectInfoPanel_de.properties b/src/main/resources/board/resources/ObjectInfoPanel_de.properties similarity index 100% rename from board/resources/ObjectInfoPanel_de.properties rename to src/main/resources/board/resources/ObjectInfoPanel_de.properties diff --git a/board/resources/ObjectInfoPanel_en.properties b/src/main/resources/board/resources/ObjectInfoPanel_en.properties similarity index 100% rename from board/resources/ObjectInfoPanel_en.properties rename to src/main/resources/board/resources/ObjectInfoPanel_en.properties diff --git a/boardgraphics/resources/ColorTableModel_de.properties b/src/main/resources/boardgraphics/resources/ColorTableModel_de.properties similarity index 100% rename from boardgraphics/resources/ColorTableModel_de.properties rename to src/main/resources/boardgraphics/resources/ColorTableModel_de.properties diff --git a/boardgraphics/resources/ColorTableModel_en.properties b/src/main/resources/boardgraphics/resources/ColorTableModel_en.properties similarity index 100% rename from boardgraphics/resources/ColorTableModel_en.properties rename to src/main/resources/boardgraphics/resources/ColorTableModel_en.properties diff --git a/gui/resources/BoardFrame_de.properties b/src/main/resources/gui/resources/BoardFrame_de.properties similarity index 100% rename from gui/resources/BoardFrame_de.properties rename to src/main/resources/gui/resources/BoardFrame_de.properties diff --git a/gui/resources/BoardFrame_en.properties b/src/main/resources/gui/resources/BoardFrame_en.properties similarity index 100% rename from gui/resources/BoardFrame_en.properties rename to src/main/resources/gui/resources/BoardFrame_en.properties diff --git a/gui/resources/BoardMenuDisplay_de.properties b/src/main/resources/gui/resources/BoardMenuDisplay_de.properties similarity index 100% rename from gui/resources/BoardMenuDisplay_de.properties rename to src/main/resources/gui/resources/BoardMenuDisplay_de.properties diff --git a/gui/resources/BoardMenuDisplay_en.properties b/src/main/resources/gui/resources/BoardMenuDisplay_en.properties similarity index 100% rename from gui/resources/BoardMenuDisplay_en.properties rename to src/main/resources/gui/resources/BoardMenuDisplay_en.properties diff --git a/gui/resources/BoardMenuFile_de.properties b/src/main/resources/gui/resources/BoardMenuFile_de.properties similarity index 100% rename from gui/resources/BoardMenuFile_de.properties rename to src/main/resources/gui/resources/BoardMenuFile_de.properties diff --git a/gui/resources/BoardMenuFile_en.properties b/src/main/resources/gui/resources/BoardMenuFile_en.properties similarity index 100% rename from gui/resources/BoardMenuFile_en.properties rename to src/main/resources/gui/resources/BoardMenuFile_en.properties diff --git a/gui/resources/BoardMenuHelp_de.properties b/src/main/resources/gui/resources/BoardMenuHelp_de.properties similarity index 100% rename from gui/resources/BoardMenuHelp_de.properties rename to src/main/resources/gui/resources/BoardMenuHelp_de.properties diff --git a/gui/resources/BoardMenuHelp_en.properties b/src/main/resources/gui/resources/BoardMenuHelp_en.properties similarity index 100% rename from gui/resources/BoardMenuHelp_en.properties rename to src/main/resources/gui/resources/BoardMenuHelp_en.properties diff --git a/gui/resources/BoardMenuInfo_de.properties b/src/main/resources/gui/resources/BoardMenuInfo_de.properties similarity index 100% rename from gui/resources/BoardMenuInfo_de.properties rename to src/main/resources/gui/resources/BoardMenuInfo_de.properties diff --git a/gui/resources/BoardMenuInfo_en.properties b/src/main/resources/gui/resources/BoardMenuInfo_en.properties similarity index 100% rename from gui/resources/BoardMenuInfo_en.properties rename to src/main/resources/gui/resources/BoardMenuInfo_en.properties diff --git a/gui/resources/BoardMenuOther_de.properties b/src/main/resources/gui/resources/BoardMenuOther_de.properties similarity index 100% rename from gui/resources/BoardMenuOther_de.properties rename to src/main/resources/gui/resources/BoardMenuOther_de.properties diff --git a/gui/resources/BoardMenuOther_en.properties b/src/main/resources/gui/resources/BoardMenuOther_en.properties similarity index 100% rename from gui/resources/BoardMenuOther_en.properties rename to src/main/resources/gui/resources/BoardMenuOther_en.properties diff --git a/gui/resources/BoardMenuParameter_de.properties b/src/main/resources/gui/resources/BoardMenuParameter_de.properties similarity index 100% rename from gui/resources/BoardMenuParameter_de.properties rename to src/main/resources/gui/resources/BoardMenuParameter_de.properties diff --git a/gui/resources/BoardMenuParameter_en.properties b/src/main/resources/gui/resources/BoardMenuParameter_en.properties similarity index 100% rename from gui/resources/BoardMenuParameter_en.properties rename to src/main/resources/gui/resources/BoardMenuParameter_en.properties diff --git a/gui/resources/BoardMenuRules_de.properties b/src/main/resources/gui/resources/BoardMenuRules_de.properties similarity index 100% rename from gui/resources/BoardMenuRules_de.properties rename to src/main/resources/gui/resources/BoardMenuRules_de.properties diff --git a/gui/resources/BoardMenuRules_en.properties b/src/main/resources/gui/resources/BoardMenuRules_en.properties similarity index 100% rename from gui/resources/BoardMenuRules_en.properties rename to src/main/resources/gui/resources/BoardMenuRules_en.properties diff --git a/gui/resources/BoardPanelStatus_de.properties b/src/main/resources/gui/resources/BoardPanelStatus_de.properties similarity index 100% rename from gui/resources/BoardPanelStatus_de.properties rename to src/main/resources/gui/resources/BoardPanelStatus_de.properties diff --git a/gui/resources/BoardPanelStatus_en.properties b/src/main/resources/gui/resources/BoardPanelStatus_en.properties similarity index 100% rename from gui/resources/BoardPanelStatus_en.properties rename to src/main/resources/gui/resources/BoardPanelStatus_en.properties diff --git a/gui/resources/BoardToolbarSelectedItem_de.properties b/src/main/resources/gui/resources/BoardToolbarSelectedItem_de.properties similarity index 100% rename from gui/resources/BoardToolbarSelectedItem_de.properties rename to src/main/resources/gui/resources/BoardToolbarSelectedItem_de.properties diff --git a/gui/resources/BoardToolbarSelectedItem_en.properties b/src/main/resources/gui/resources/BoardToolbarSelectedItem_en.properties similarity index 100% rename from gui/resources/BoardToolbarSelectedItem_en.properties rename to src/main/resources/gui/resources/BoardToolbarSelectedItem_en.properties diff --git a/gui/resources/BoardToolbar_de.properties b/src/main/resources/gui/resources/BoardToolbar_de.properties similarity index 100% rename from gui/resources/BoardToolbar_de.properties rename to src/main/resources/gui/resources/BoardToolbar_de.properties diff --git a/gui/resources/BoardToolbar_en.properties b/src/main/resources/gui/resources/BoardToolbar_en.properties similarity index 100% rename from gui/resources/BoardToolbar_en.properties rename to src/main/resources/gui/resources/BoardToolbar_en.properties diff --git a/gui/resources/CleanupWindows_de.properties b/src/main/resources/gui/resources/CleanupWindows_de.properties similarity index 100% rename from gui/resources/CleanupWindows_de.properties rename to src/main/resources/gui/resources/CleanupWindows_de.properties diff --git a/gui/resources/CleanupWindows_en.properties b/src/main/resources/gui/resources/CleanupWindows_en.properties similarity index 100% rename from gui/resources/CleanupWindows_en.properties rename to src/main/resources/gui/resources/CleanupWindows_en.properties diff --git a/gui/resources/Default_de.properties b/src/main/resources/gui/resources/Default_de.properties similarity index 100% rename from gui/resources/Default_de.properties rename to src/main/resources/gui/resources/Default_de.properties diff --git a/gui/resources/Default_en.properties b/src/main/resources/gui/resources/Default_en.properties similarity index 100% rename from gui/resources/Default_en.properties rename to src/main/resources/gui/resources/Default_en.properties diff --git a/gui/resources/DisplayMisc_de.properties b/src/main/resources/gui/resources/DisplayMisc_de.properties similarity index 100% rename from gui/resources/DisplayMisc_de.properties rename to src/main/resources/gui/resources/DisplayMisc_de.properties diff --git a/gui/resources/DisplayMisc_en.properties b/src/main/resources/gui/resources/DisplayMisc_en.properties similarity index 100% rename from gui/resources/DisplayMisc_en.properties rename to src/main/resources/gui/resources/DisplayMisc_en.properties diff --git a/gui/resources/MainApplication_de.properties b/src/main/resources/gui/resources/MainApplication_de.properties similarity index 100% rename from gui/resources/MainApplication_de.properties rename to src/main/resources/gui/resources/MainApplication_de.properties diff --git a/gui/resources/MainApplication_en.properties b/src/main/resources/gui/resources/MainApplication_en.properties similarity index 100% rename from gui/resources/MainApplication_en.properties rename to src/main/resources/gui/resources/MainApplication_en.properties diff --git a/gui/resources/PopupMenuMain_de.properties b/src/main/resources/gui/resources/PopupMenuMain_de.properties similarity index 100% rename from gui/resources/PopupMenuMain_de.properties rename to src/main/resources/gui/resources/PopupMenuMain_de.properties diff --git a/gui/resources/PopupMenuMain_en.properties b/src/main/resources/gui/resources/PopupMenuMain_en.properties similarity index 100% rename from gui/resources/PopupMenuMain_en.properties rename to src/main/resources/gui/resources/PopupMenuMain_en.properties diff --git a/gui/resources/PopupMenuMove_de.properties b/src/main/resources/gui/resources/PopupMenuMove_de.properties similarity index 100% rename from gui/resources/PopupMenuMove_de.properties rename to src/main/resources/gui/resources/PopupMenuMove_de.properties diff --git a/gui/resources/PopupMenuMove_en.properties b/src/main/resources/gui/resources/PopupMenuMove_en.properties similarity index 100% rename from gui/resources/PopupMenuMove_en.properties rename to src/main/resources/gui/resources/PopupMenuMove_en.properties diff --git a/gui/resources/WindowAbout_de.properties b/src/main/resources/gui/resources/WindowAbout_de.properties similarity index 100% rename from gui/resources/WindowAbout_de.properties rename to src/main/resources/gui/resources/WindowAbout_de.properties diff --git a/gui/resources/WindowAbout_en.properties b/src/main/resources/gui/resources/WindowAbout_en.properties similarity index 100% rename from gui/resources/WindowAbout_en.properties rename to src/main/resources/gui/resources/WindowAbout_en.properties diff --git a/gui/resources/WindowAssignNetClass_de.properties b/src/main/resources/gui/resources/WindowAssignNetClass_de.properties similarity index 100% rename from gui/resources/WindowAssignNetClass_de.properties rename to src/main/resources/gui/resources/WindowAssignNetClass_de.properties diff --git a/gui/resources/WindowAssignNetClass_en.properties b/src/main/resources/gui/resources/WindowAssignNetClass_en.properties similarity index 100% rename from gui/resources/WindowAssignNetClass_en.properties rename to src/main/resources/gui/resources/WindowAssignNetClass_en.properties diff --git a/gui/resources/WindowAutorouteParameter_de.properties b/src/main/resources/gui/resources/WindowAutorouteParameter_de.properties similarity index 100% rename from gui/resources/WindowAutorouteParameter_de.properties rename to src/main/resources/gui/resources/WindowAutorouteParameter_de.properties diff --git a/gui/resources/WindowAutorouteParameter_en.properties b/src/main/resources/gui/resources/WindowAutorouteParameter_en.properties similarity index 100% rename from gui/resources/WindowAutorouteParameter_en.properties rename to src/main/resources/gui/resources/WindowAutorouteParameter_en.properties diff --git a/gui/resources/WindowClearanceMatrix_de.properties b/src/main/resources/gui/resources/WindowClearanceMatrix_de.properties similarity index 100% rename from gui/resources/WindowClearanceMatrix_de.properties rename to src/main/resources/gui/resources/WindowClearanceMatrix_de.properties diff --git a/gui/resources/WindowClearanceMatrix_en.properties b/src/main/resources/gui/resources/WindowClearanceMatrix_en.properties similarity index 100% rename from gui/resources/WindowClearanceMatrix_en.properties rename to src/main/resources/gui/resources/WindowClearanceMatrix_en.properties diff --git a/gui/resources/WindowClearanceViolations_de.properties b/src/main/resources/gui/resources/WindowClearanceViolations_de.properties similarity index 100% rename from gui/resources/WindowClearanceViolations_de.properties rename to src/main/resources/gui/resources/WindowClearanceViolations_de.properties diff --git a/gui/resources/WindowClearanceViolations_en.properties b/src/main/resources/gui/resources/WindowClearanceViolations_en.properties similarity index 100% rename from gui/resources/WindowClearanceViolations_en.properties rename to src/main/resources/gui/resources/WindowClearanceViolations_en.properties diff --git a/gui/resources/WindowEditVias_de.properties b/src/main/resources/gui/resources/WindowEditVias_de.properties similarity index 100% rename from gui/resources/WindowEditVias_de.properties rename to src/main/resources/gui/resources/WindowEditVias_de.properties diff --git a/gui/resources/WindowEditVias_en.properties b/src/main/resources/gui/resources/WindowEditVias_en.properties similarity index 100% rename from gui/resources/WindowEditVias_en.properties rename to src/main/resources/gui/resources/WindowEditVias_en.properties diff --git a/gui/resources/WindowLengthViolations_de.properties b/src/main/resources/gui/resources/WindowLengthViolations_de.properties similarity index 100% rename from gui/resources/WindowLengthViolations_de.properties rename to src/main/resources/gui/resources/WindowLengthViolations_de.properties diff --git a/gui/resources/WindowLengthViolations_en.properties b/src/main/resources/gui/resources/WindowLengthViolations_en.properties similarity index 100% rename from gui/resources/WindowLengthViolations_en.properties rename to src/main/resources/gui/resources/WindowLengthViolations_en.properties diff --git a/gui/resources/WindowManualRule_de.properties b/src/main/resources/gui/resources/WindowManualRule_de.properties similarity index 100% rename from gui/resources/WindowManualRule_de.properties rename to src/main/resources/gui/resources/WindowManualRule_de.properties diff --git a/gui/resources/WindowManualRule_en.properties b/src/main/resources/gui/resources/WindowManualRule_en.properties similarity index 100% rename from gui/resources/WindowManualRule_en.properties rename to src/main/resources/gui/resources/WindowManualRule_en.properties diff --git a/gui/resources/WindowMoveParameter_de.properties b/src/main/resources/gui/resources/WindowMoveParameter_de.properties similarity index 100% rename from gui/resources/WindowMoveParameter_de.properties rename to src/main/resources/gui/resources/WindowMoveParameter_de.properties diff --git a/gui/resources/WindowMoveParameter_en.properties b/src/main/resources/gui/resources/WindowMoveParameter_en.properties similarity index 100% rename from gui/resources/WindowMoveParameter_en.properties rename to src/main/resources/gui/resources/WindowMoveParameter_en.properties diff --git a/gui/resources/WindowNetClasses_de.properties b/src/main/resources/gui/resources/WindowNetClasses_de.properties similarity index 100% rename from gui/resources/WindowNetClasses_de.properties rename to src/main/resources/gui/resources/WindowNetClasses_de.properties diff --git a/gui/resources/WindowNetClasses_en.properties b/src/main/resources/gui/resources/WindowNetClasses_en.properties similarity index 100% rename from gui/resources/WindowNetClasses_en.properties rename to src/main/resources/gui/resources/WindowNetClasses_en.properties diff --git a/gui/resources/WindowNetSamples_de.properties b/src/main/resources/gui/resources/WindowNetSamples_de.properties similarity index 100% rename from gui/resources/WindowNetSamples_de.properties rename to src/main/resources/gui/resources/WindowNetSamples_de.properties diff --git a/gui/resources/WindowNetSamples_en.properties b/src/main/resources/gui/resources/WindowNetSamples_en.properties similarity index 100% rename from gui/resources/WindowNetSamples_en.properties rename to src/main/resources/gui/resources/WindowNetSamples_en.properties diff --git a/gui/resources/WindowNets_de.properties b/src/main/resources/gui/resources/WindowNets_de.properties similarity index 100% rename from gui/resources/WindowNets_de.properties rename to src/main/resources/gui/resources/WindowNets_de.properties diff --git a/gui/resources/WindowNets_en.properties b/src/main/resources/gui/resources/WindowNets_en.properties similarity index 100% rename from gui/resources/WindowNets_en.properties rename to src/main/resources/gui/resources/WindowNets_en.properties diff --git a/gui/resources/WindowObjectInfo_de.properties b/src/main/resources/gui/resources/WindowObjectInfo_de.properties similarity index 100% rename from gui/resources/WindowObjectInfo_de.properties rename to src/main/resources/gui/resources/WindowObjectInfo_de.properties diff --git a/gui/resources/WindowObjectInfo_en.properties b/src/main/resources/gui/resources/WindowObjectInfo_en.properties similarity index 100% rename from gui/resources/WindowObjectInfo_en.properties rename to src/main/resources/gui/resources/WindowObjectInfo_en.properties diff --git a/gui/resources/WindowObjectList_de.properties b/src/main/resources/gui/resources/WindowObjectList_de.properties similarity index 100% rename from gui/resources/WindowObjectList_de.properties rename to src/main/resources/gui/resources/WindowObjectList_de.properties diff --git a/gui/resources/WindowObjectList_en.properties b/src/main/resources/gui/resources/WindowObjectList_en.properties similarity index 100% rename from gui/resources/WindowObjectList_en.properties rename to src/main/resources/gui/resources/WindowObjectList_en.properties diff --git a/gui/resources/WindowObjectVisibility_de.properties b/src/main/resources/gui/resources/WindowObjectVisibility_de.properties similarity index 100% rename from gui/resources/WindowObjectVisibility_de.properties rename to src/main/resources/gui/resources/WindowObjectVisibility_de.properties diff --git a/gui/resources/WindowObjectVisibility_en.properties b/src/main/resources/gui/resources/WindowObjectVisibility_en.properties similarity index 100% rename from gui/resources/WindowObjectVisibility_en.properties rename to src/main/resources/gui/resources/WindowObjectVisibility_en.properties diff --git a/gui/resources/WindowRouteDetail_de.properties b/src/main/resources/gui/resources/WindowRouteDetail_de.properties similarity index 100% rename from gui/resources/WindowRouteDetail_de.properties rename to src/main/resources/gui/resources/WindowRouteDetail_de.properties diff --git a/gui/resources/WindowRouteDetail_en.properties b/src/main/resources/gui/resources/WindowRouteDetail_en.properties similarity index 100% rename from gui/resources/WindowRouteDetail_en.properties rename to src/main/resources/gui/resources/WindowRouteDetail_en.properties diff --git a/gui/resources/WindowRouteParameter_de.properties b/src/main/resources/gui/resources/WindowRouteParameter_de.properties similarity index 100% rename from gui/resources/WindowRouteParameter_de.properties rename to src/main/resources/gui/resources/WindowRouteParameter_de.properties diff --git a/gui/resources/WindowRouteParameter_en.properties b/src/main/resources/gui/resources/WindowRouteParameter_en.properties similarity index 100% rename from gui/resources/WindowRouteParameter_en.properties rename to src/main/resources/gui/resources/WindowRouteParameter_en.properties diff --git a/gui/resources/WindowSelectParameter_de.properties b/src/main/resources/gui/resources/WindowSelectParameter_de.properties similarity index 100% rename from gui/resources/WindowSelectParameter_de.properties rename to src/main/resources/gui/resources/WindowSelectParameter_de.properties diff --git a/gui/resources/WindowSelectParameter_en.properties b/src/main/resources/gui/resources/WindowSelectParameter_en.properties similarity index 100% rename from gui/resources/WindowSelectParameter_en.properties rename to src/main/resources/gui/resources/WindowSelectParameter_en.properties diff --git a/gui/resources/WindowSnapshotSettings_de.properties b/src/main/resources/gui/resources/WindowSnapshotSettings_de.properties similarity index 100% rename from gui/resources/WindowSnapshotSettings_de.properties rename to src/main/resources/gui/resources/WindowSnapshotSettings_de.properties diff --git a/gui/resources/WindowSnapshotSettings_en.properties b/src/main/resources/gui/resources/WindowSnapshotSettings_en.properties similarity index 100% rename from gui/resources/WindowSnapshotSettings_en.properties rename to src/main/resources/gui/resources/WindowSnapshotSettings_en.properties diff --git a/gui/resources/WindowSnapshot_de.properties b/src/main/resources/gui/resources/WindowSnapshot_de.properties similarity index 100% rename from gui/resources/WindowSnapshot_de.properties rename to src/main/resources/gui/resources/WindowSnapshot_de.properties diff --git a/gui/resources/WindowSnapshot_en.properties b/src/main/resources/gui/resources/WindowSnapshot_en.properties similarity index 100% rename from gui/resources/WindowSnapshot_en.properties rename to src/main/resources/gui/resources/WindowSnapshot_en.properties diff --git a/gui/resources/WindowViaRule_de.properties b/src/main/resources/gui/resources/WindowViaRule_de.properties similarity index 100% rename from gui/resources/WindowViaRule_de.properties rename to src/main/resources/gui/resources/WindowViaRule_de.properties diff --git a/gui/resources/WindowViaRule_en.properties b/src/main/resources/gui/resources/WindowViaRule_en.properties similarity index 100% rename from gui/resources/WindowViaRule_en.properties rename to src/main/resources/gui/resources/WindowViaRule_en.properties diff --git a/gui/resources/WindowVia_de.properties b/src/main/resources/gui/resources/WindowVia_de.properties similarity index 100% rename from gui/resources/WindowVia_de.properties rename to src/main/resources/gui/resources/WindowVia_de.properties diff --git a/gui/resources/WindowVia_en.properties b/src/main/resources/gui/resources/WindowVia_en.properties similarity index 100% rename from gui/resources/WindowVia_en.properties rename to src/main/resources/gui/resources/WindowVia_en.properties diff --git a/interactive/resources/BoardHandling_de.properties b/src/main/resources/interactive/resources/BoardHandling_de.properties similarity index 100% rename from interactive/resources/BoardHandling_de.properties rename to src/main/resources/interactive/resources/BoardHandling_de.properties diff --git a/interactive/resources/BoardHandling_en.properties b/src/main/resources/interactive/resources/BoardHandling_en.properties similarity index 100% rename from interactive/resources/BoardHandling_en.properties rename to src/main/resources/interactive/resources/BoardHandling_en.properties diff --git a/interactive/resources/InteractiveState_de.properties b/src/main/resources/interactive/resources/InteractiveState_de.properties similarity index 100% rename from interactive/resources/InteractiveState_de.properties rename to src/main/resources/interactive/resources/InteractiveState_de.properties diff --git a/interactive/resources/InteractiveState_en.properties b/src/main/resources/interactive/resources/InteractiveState_en.properties similarity index 100% rename from interactive/resources/InteractiveState_en.properties rename to src/main/resources/interactive/resources/InteractiveState_en.properties diff --git a/interactive/resources/RatsNest_de.properties b/src/main/resources/interactive/resources/RatsNest_de.properties similarity index 100% rename from interactive/resources/RatsNest_de.properties rename to src/main/resources/interactive/resources/RatsNest_de.properties diff --git a/interactive/resources/RatsNest_en.properties b/src/main/resources/interactive/resources/RatsNest_en.properties similarity index 100% rename from interactive/resources/RatsNest_en.properties rename to src/main/resources/interactive/resources/RatsNest_en.properties diff --git a/interactive/resources/ScreenMessages_de.properties b/src/main/resources/interactive/resources/ScreenMessages_de.properties similarity index 100% rename from interactive/resources/ScreenMessages_de.properties rename to src/main/resources/interactive/resources/ScreenMessages_de.properties diff --git a/interactive/resources/ScreenMessages_en.properties b/src/main/resources/interactive/resources/ScreenMessages_en.properties similarity index 100% rename from interactive/resources/ScreenMessages_en.properties rename to src/main/resources/interactive/resources/ScreenMessages_en.properties diff --git a/rules/resources/Default_de.properties b/src/main/resources/rules/resources/Default_de.properties similarity index 100% rename from rules/resources/Default_de.properties rename to src/main/resources/rules/resources/Default_de.properties diff --git a/rules/resources/Default_en.properties b/src/main/resources/rules/resources/Default_en.properties similarity index 100% rename from rules/resources/Default_en.properties rename to src/main/resources/rules/resources/Default_en.properties diff --git a/src/main/resources/simplelogger.properties b/src/main/resources/simplelogger.properties new file mode 100644 index 0000000..eb7843b --- /dev/null +++ b/src/main/resources/simplelogger.properties @@ -0,0 +1,34 @@ +# SLF4J's SimpleLogger configuration file +# Simple implementation of Logger that sends all enabled log messages, for all defined loggers, to System.err. + +# Default logging detail level for all instances of SimpleLogger. +# Must be one of ("trace", "debug", "info", "warn", or "error"). +# If not specified, defaults to "info". +org.slf4j.simpleLogger.defaultLogLevel=info + +# Logging detail level for a SimpleLogger instance named "xxxxx". +# Must be one of ("trace", "debug", "info", "warn", or "error"). +# If not specified, the default logging detail level is used. +#org.slf4j.simpleLogger.log.xxxxx= + +# Set to true if you want the current date and time to be included in output messages. +# Default is false, and will output the number of milliseconds elapsed since startup. +#org.slf4j.simpleLogger.showDateTime=false + +# The date and time format to be used in the output messages. +# The pattern describing the date and time format is the same that is used in java.text.SimpleDateFormat. +# If the format is not specified or is invalid, the default format is used. +# The default format is yyyy-MM-dd HH:mm:ss:SSS Z. +#org.slf4j.simpleLogger.dateTimeFormat=yyyy-MM-dd HH:mm:ss:SSS Z + +# Set to true if you want to output the current thread name. +# Defaults to true. +#org.slf4j.simpleLogger.showThreadName=true + +# Set to true if you want the Logger instance name to be included in output messages. +# Defaults to true. +#org.slf4j.simpleLogger.showLogName=true + +# Set to true if you want the last component of the name to be included in output messages. +# Defaults to false. +#org.slf4j.simpleLogger.showShortLogName=false \ No newline at end of file diff --git a/src/main/site/index.html b/src/main/site/index.html new file mode 100644 index 0000000..c9baf98 --- /dev/null +++ b/src/main/site/index.html @@ -0,0 +1,47 @@ + + + + +

FreeRouting

+ +Java Based Printed Circuit Board Routing Software from FreeRouting.net written by Alfons Wirtz. + + + +
+http://www.freerouting.net/fen/viewtopic.php?f=4&t=255 + +by alfons ยป Sat Mar 08, 2014 12:07 pm + +Because I am no more maintaining the Freerouting project since 4 years and future Java versions may block my Freerouting Java Web Start application completely, I finally decided to open the source of the Freerouting project under the GNU public license version 3. + +I have attached the complete source code of the Freerouting project. Please feel free downloading and using the sources according to the GPLv3 license. +
+ + +

Introduction

+

+This software can be used together with all host PCB design software systems containing a standard Specctra or Electra DSN interface. It imports .dsn-files generated by the Specctra interface of the host system and exports Specctra session files.(There exists also an interface to Cadsoft-Eagle.) + +There are three modes for routing traces: 90 degree, 45 degree and free angle. The interactive router is production stable and unsurpassed in its free angle capabilities. An autorouter is currently under development and already stable in the conventional 45 degree mode. + +After launching the router a window appears with buttons to display some router demonstrations, to open a sample design, or to open a design of your own. + +After opening a design you can start the autorouter with the button in the toolbar on top of the board window. + +The board editor has three different interactive states. You can switch between this states with the buttons Select, Route and Drag on the left of the toolbar. + +In the beginning the board editor is in the select state. In this state you can select single board items by picking them with the left mouse button or select items in a rectangle by dragging the left mouse button. Only item types switched on in the select parameter sheet will be selected. After selecting some items the toolbar displays options for showing and manipulating these items. If you push the info button for example a window with text information about the selected items is displayed. After clicking a blue word in this text a new window with further information pops up. To return to the select state push the cancel button or click somewhere in the empty space of the board window. + +By pushing the Route button you get into the state for interactive routing. In this state you can start a new trace by picking an item belonging to a net, for example a pin. Then you can follow the displayed airline with the mouse until you have reached the target item at the other end of the airline. The trace will be connected automatically to the target, if it is on the same layer. If you want to change to a different layer during interactive routing, select "change layer" and then the name of the new layer in the popup menu under the right mouse button. Then a via will be inserted, if that is possible, and a new trace starts on the new layer. You can also change the layer by pressing a number key. + +After pushing the Drag button you get into the state for changing the location of vias, components or traces. In this state you can select vias or components and drag them with the left mouse button to a different location. The connected route is updated automatically. You can also move traces by pushing them from behind out of the empty space with the left mouse button pressed. That works on the current layer, which can be changed in the select parameter sheet. In this way you can make space for example to insert a new component. + +For more information please use the online help in the board editor. From here you can download also a printable version of the online help. + +If you have further questions or want some feedback, please sent an Email to support@ FreeRouting.net or visit our forum. + +

+ + + \ No newline at end of file