Meshfix integration into GUI
This commit is contained in:
parent
a1143ab26e
commit
20c91aa48e
@ -1,6 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(PrusaSlicer-native)
|
||||
|
||||
add_subdirectory(mesh_fix)
|
||||
add_subdirectory(build-utils)
|
||||
add_subdirectory(admesh)
|
||||
add_subdirectory(avrdude)
|
||||
|
36
src/mesh_fix/CMakeLists.txt
Normal file
36
src/mesh_fix/CMakeLists.txt
Normal file
@ -0,0 +1,36 @@
|
||||
################################################################################
|
||||
|
||||
set(SOURCES
|
||||
src/TMesh/edge.cpp
|
||||
src/TMesh/vertex.cpp
|
||||
src/TMesh/io.cpp
|
||||
src/TMesh/triangle.cpp
|
||||
src/TMesh/tin.cpp
|
||||
src/Algorithms/detectIntersections.cpp
|
||||
src/Algorithms/holeFilling.cpp
|
||||
src/Algorithms/marchIntersections.cpp
|
||||
src/Algorithms/checkAndRepair.cpp
|
||||
src/Kernel/heap.cpp
|
||||
src/Kernel/matrix.cpp
|
||||
src/Kernel/orientation.c
|
||||
src/Kernel/list.cpp
|
||||
src/Kernel/coordinates.cpp
|
||||
src/Kernel/tmesh.cpp
|
||||
src/Kernel/graph.cpp
|
||||
src/Kernel/point.cpp
|
||||
src/Kernel/jqsort.cpp
|
||||
src/MeshFix/meshfix.cpp
|
||||
)
|
||||
|
||||
################################################################################
|
||||
|
||||
add_library(meshfix ${SOURCES})
|
||||
|
||||
target_include_directories(meshfix PUBLIC
|
||||
include/TMesh
|
||||
include/Kernel
|
||||
)
|
||||
|
||||
target_compile_options(meshfix PRIVATE -fpermissive)
|
||||
|
||||
################################################################################
|
674
src/mesh_fix/gpl-3.0.txt
Normal file
674
src/mesh_fix/gpl-3.0.txt
Normal file
@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
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:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
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
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
157
src/mesh_fix/include/Kernel/basics.h
Normal file
157
src/mesh_fix/include/Kernel/basics.h
Normal file
@ -0,0 +1,157 @@
|
||||
/****************************************************************************
|
||||
* TMesh *
|
||||
* *
|
||||
* Consiglio Nazionale delle Ricerche *
|
||||
* Istituto di Matematica Applicata e Tecnologie Informatiche *
|
||||
* Sezione di Genova *
|
||||
* IMATI-GE / CNR *
|
||||
* *
|
||||
* Authors: Marco Attene *
|
||||
* Copyright(C) 2012: IMATI-GE / CNR *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is dual-licensed as follows: *
|
||||
* *
|
||||
* (1) You may use TMesh as 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. *
|
||||
* In this case the 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 (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
* (2) You may use TMesh as part of a commercial software. In this case a *
|
||||
* proper agreement must be reached with the Authors and with IMATI-GE/CNR *
|
||||
* based on a proper licensing contract. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef _BASICS_H
|
||||
#define _BASICS_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <limits.h>
|
||||
#include <float.h>
|
||||
#include "coordinates.h"
|
||||
|
||||
namespace T_MESH
|
||||
{
|
||||
|
||||
#ifdef EXTENSIBLE_TMESH
|
||||
#define TMESH_VIRTUAL virtual
|
||||
#else
|
||||
#define TMESH_VIRTUAL
|
||||
#endif
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
#define TMESH_VERSION "2.0"
|
||||
#define TMESH_YEAR 2012
|
||||
|
||||
class TMesh
|
||||
{
|
||||
public:
|
||||
|
||||
static void (*display_message)(const char *, int);
|
||||
static const char *app_name;
|
||||
static const char *app_version;
|
||||
static const char *app_year;
|
||||
static const char *app_authors;
|
||||
static const char *app_url;
|
||||
static const char *app_maillist;
|
||||
|
||||
static const char *filename; // This might be null. If not, it represents the file we are currently working with.
|
||||
|
||||
static bool quiet;
|
||||
|
||||
static void init(void (*)(const char *, int) = NULL);
|
||||
|
||||
static void info(const char *, ...);
|
||||
static void warning(const char *, ...);
|
||||
static void error(const char *, ...);
|
||||
static void begin_progress();
|
||||
static void report_progress(const char *, ...);
|
||||
static void end_progress();
|
||||
|
||||
//! When called with a nonzero argument 'ts', launches a chronometer with a timeout of 'ts' seconds.
|
||||
//! Later calls without arguments check the chronometer, and if it is over 'ts' the program exits.
|
||||
static void exitOnTimeout(clock_t ts = 0);
|
||||
|
||||
//! Appends a line to the file "tmesh.log"
|
||||
static void addMessageToLogFile(const char *msg);
|
||||
|
||||
//! Formats a message headed with date/time/filename, appends it to "tmesh.log", and exits with error
|
||||
static void logToFileAndExit(const char *msg);
|
||||
|
||||
//! When called without arguments prints the elapsed time from the latest reset.
|
||||
static void printElapsedTime(bool reset = false);
|
||||
|
||||
static void useRationals(bool u);
|
||||
static bool isUsingRationals();
|
||||
static void useFiltering(bool u);
|
||||
static bool isUsingFiltering();
|
||||
|
||||
//! Returns the status before the switch
|
||||
static bool useRationals() { bool t = isUsingRationals(); useRationals(true); return t; }
|
||||
|
||||
static void setFilename(const char *fname) { filename = fname; }
|
||||
};
|
||||
|
||||
#define DISPMSG_ACTION_SETWIDGET 1
|
||||
#define DISPMSG_ACTION_PUTNEWLINE 2
|
||||
#define DISPMSG_ACTION_PUTPROGRESS 3
|
||||
#define DISPMSG_ACTION_PUTMESSAGE 4
|
||||
#define DISPMSG_ACTION_ERRORDIALOG 5
|
||||
|
||||
#ifndef _INC_WINDOWS
|
||||
typedef unsigned char UBYTE;
|
||||
typedef signed char BYTE;
|
||||
typedef unsigned short UINT16;
|
||||
typedef signed short INT16;
|
||||
#endif
|
||||
|
||||
#ifdef IS64BITPLATFORM
|
||||
typedef long int j_voidint;
|
||||
#else
|
||||
typedef int j_voidint;
|
||||
#endif
|
||||
|
||||
#define UBYTE_MAX 255
|
||||
|
||||
#ifndef UINT16_MAX
|
||||
#define UINT16_MAX 65535
|
||||
#endif
|
||||
|
||||
#define FABS(a) (((a)<0)?(-(a)):(a))
|
||||
#define LOG2(a) (log(a)/log(2))
|
||||
#define PI2 (M_PI/2.0)
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#endif
|
||||
#ifndef MAX
|
||||
#define MAX(a,b)(((a)>(b))?(a):(b))
|
||||
#endif
|
||||
|
||||
|
||||
//////// Swaps two pointers. ///////////////////////////////
|
||||
|
||||
inline void p_swap(void **a, void **b) {void *t = *a; *a = *b; *b = t;}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class Data {
|
||||
public:
|
||||
virtual ~Data() = default;
|
||||
};
|
||||
|
||||
|
||||
} //namespace T_MESH
|
||||
|
||||
#endif //_BASICS_H
|
||||
|
178
src/mesh_fix/include/Kernel/coordinates.h
Normal file
178
src/mesh_fix/include/Kernel/coordinates.h
Normal file
@ -0,0 +1,178 @@
|
||||
/****************************************************************************
|
||||
* TMesh *
|
||||
* *
|
||||
* Consiglio Nazionale delle Ricerche *
|
||||
* Istituto di Matematica Applicata e Tecnologie Informatiche *
|
||||
* Sezione di Genova *
|
||||
* IMATI-GE / CNR *
|
||||
* *
|
||||
* Authors: Marco Attene *
|
||||
* Copyright(C) 2012: IMATI-GE / CNR *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is dual-licensed as follows: *
|
||||
* *
|
||||
* (1) You may use TMesh as 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. *
|
||||
* In this case the 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 (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
* (2) You may use TMesh as part of a commercial software. In this case a *
|
||||
* proper agreement must be reached with the Authors and with IMATI-GE/CNR *
|
||||
* based on a proper licensing contract. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef _COORDINATES_H
|
||||
#define _COORDINATES_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <limits.h>
|
||||
#include <float.h>
|
||||
|
||||
#ifdef USE_HYBRID_KERNEL
|
||||
|
||||
#ifdef USE_CGAL_LAZYNT
|
||||
#include <CGAL/Gmpq.h>
|
||||
#include <CGAL/Lazy_exact_nt.h>
|
||||
#include <CGAL/number_utils.h>
|
||||
|
||||
typedef CGAL::Lazy_exact_nt<CGAL::Gmpq> EXACT_NT;
|
||||
#define EXACT_NT_TO_DOUBLE(x) (CGAL::to_double(x))
|
||||
#define EXACT_NT_DENOMINATOR(x) ((x)->exact().denominator())
|
||||
#define EXACT_NT_NUMERATOR(x) ((x)->exact().numerator())
|
||||
|
||||
#else
|
||||
#include <mpirxx.h>
|
||||
|
||||
typedef mpq_class EXACT_NT;
|
||||
#define EXACT_NT_TO_DOUBLE(x) ((x).get_d())
|
||||
#define EXACT_NT_DENOMINATOR(x) ((x)->get_den())
|
||||
#define EXACT_NT_NUMERATOR(x) ((x)->get_num())
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef __APPLE__
|
||||
#include <cstdint>
|
||||
#endif
|
||||
|
||||
namespace T_MESH
|
||||
{
|
||||
|
||||
#ifdef USE_HYBRID_KERNEL
|
||||
class PM_Rational
|
||||
{
|
||||
private:
|
||||
// Only one of the following two static members can be true at any time, but both of them can be false
|
||||
// Thus, three configurations are possible:
|
||||
// 1) APPROXIMATED: use_rationals = false, use_filtering = false
|
||||
// 2) FILTERED: use_rationals = false, use_filtering = true
|
||||
// 3) PRECISE: use_rationals = true, use_filtering = false
|
||||
static bool use_rationals; // Kernel_mode uses rational numbers (precise)
|
||||
static bool use_filtering; // Kernel_mode uses filtering
|
||||
|
||||
public:
|
||||
inline static bool isUsingRationals() { return use_rationals; }
|
||||
inline static bool isUsingFiltering() { return use_filtering; }
|
||||
static void useRationals(bool v) { use_rationals = v; use_filtering = !v; }
|
||||
static void useFiltering(bool v) { use_filtering = v; if (v) use_rationals = false; }
|
||||
|
||||
protected:
|
||||
int64_t _val; // value. Might contain either a double or a pointer to mpq_class.
|
||||
bool _whv; // Which value type is stored here. 1=rational, 0=double
|
||||
|
||||
inline bool isOfRationalType() const { return _whv; }
|
||||
inline bool isOfDoubleType() const { return !_whv; }
|
||||
|
||||
inline static int64_t d2int64t(double a) { return *((int64_t *)((void *)(&a))); }
|
||||
inline static double& int64t2d(const int64_t& a) { return *((double *)((void *)(&a))); }
|
||||
|
||||
inline EXACT_NT& getVal() { return *((EXACT_NT *)_val); }
|
||||
inline double& getDVal() { return int64t2d(_val); }
|
||||
|
||||
inline const EXACT_NT& getVal() const { return *((EXACT_NT *)_val); }
|
||||
inline const double& getDVal() const { return int64t2d(_val); }
|
||||
|
||||
void switchToDouble();
|
||||
void switchToRational();
|
||||
|
||||
public:
|
||||
PM_Rational() : _whv(0) {} // Undetermined double
|
||||
PM_Rational(const EXACT_NT& a) { _whv = use_rationals; _val = (_whv) ? ((int64_t)new EXACT_NT(a)) : (d2int64t(EXACT_NT_TO_DOUBLE(a))); }
|
||||
PM_Rational(float a) { _whv = use_rationals; _val = (_whv) ? ((int64_t)new EXACT_NT(a)) : (d2int64t(a)); }
|
||||
PM_Rational(double a) { _whv = use_rationals; _val = (_whv) ? ((int64_t)new EXACT_NT(a)) : (d2int64t(a)); }
|
||||
PM_Rational(int a) { _whv = use_rationals; _val = (_whv) ? ((int64_t)new EXACT_NT(a)) : (d2int64t(a)); }
|
||||
|
||||
PM_Rational(const PM_Rational& a) { _whv = a._whv; _val = (_whv) ? ((int64_t)new EXACT_NT(a.getVal())) : (a._val); }
|
||||
~PM_Rational() { if (_whv) delete ((EXACT_NT *)_val); }
|
||||
|
||||
inline EXACT_NT toRational() const { return (_whv) ? (getVal()) : (EXACT_NT(getDVal())); }
|
||||
|
||||
// The following toSomething() functions may cause rounding. Use with caution !
|
||||
inline double toDouble() const { return ((_whv) ? (EXACT_NT_TO_DOUBLE(getVal())) : (getDVal())); }
|
||||
inline int toInt() const { return int(toDouble()); }
|
||||
inline float toFloat() const { return float(toDouble()); }
|
||||
|
||||
void operator+=(const PM_Rational& a);
|
||||
void operator-=(const PM_Rational& a);
|
||||
void operator*=(const PM_Rational& a);
|
||||
void operator/=(const PM_Rational& a);
|
||||
PM_Rational operator+(const PM_Rational& a) const;
|
||||
PM_Rational operator-(const PM_Rational& a) const;
|
||||
PM_Rational operator*(const PM_Rational& a) const;
|
||||
PM_Rational operator/(const PM_Rational& a) const;
|
||||
bool operator==(const PM_Rational& a) const;
|
||||
bool operator!=(const PM_Rational& a) const;
|
||||
|
||||
PM_Rational& operator=(const PM_Rational& a);
|
||||
void setFromRational(const EXACT_NT& a);
|
||||
|
||||
bool operator<(const PM_Rational& a) const;
|
||||
bool operator>(const PM_Rational& a) const;
|
||||
inline bool operator<=(const PM_Rational& a) const { return (operator==(a) || operator<(a)); }
|
||||
inline bool operator>=(const PM_Rational& a) const { return (operator==(a) || operator>(a)); }
|
||||
|
||||
friend PM_Rational orient2D(const PM_Rational& px, const PM_Rational& py, const PM_Rational& qx, const PM_Rational& qy, const PM_Rational& rx, const PM_Rational& ry);
|
||||
friend PM_Rational orient3D(const class Point *t, const class Point *a, const class Point *b, const class Point *c);
|
||||
};
|
||||
|
||||
PM_Rational operator-(const PM_Rational& a);
|
||||
PM_Rational ceil(const PM_Rational& a);
|
||||
PM_Rational floor(const PM_Rational& a);
|
||||
PM_Rational round(const PM_Rational& a);
|
||||
|
||||
/**************** I/O operators ****************/
|
||||
|
||||
inline std::ostream & operator<<(std::ostream &o, const PM_Rational& c) { return o << c.toRational(); }
|
||||
inline std::istream & operator>>(std::istream &i, PM_Rational& c) { EXACT_NT a; i >> a; c.setFromRational(a); return i; }
|
||||
|
||||
#define TMESH_TO_DOUBLE(x) ((x).toDouble())
|
||||
#define TMESH_TO_FLOAT(x) ((x).toFloat())
|
||||
#define TMESH_TO_INT(x) ((x).toInt())
|
||||
|
||||
#else
|
||||
|
||||
typedef double PM_Rational;
|
||||
|
||||
#define TMESH_TO_DOUBLE(x) (x)
|
||||
#define TMESH_TO_FLOAT(x) ((float)(x))
|
||||
#define TMESH_TO_INT(x) ((int)(x))
|
||||
|
||||
#endif
|
||||
|
||||
typedef PM_Rational coord;
|
||||
|
||||
#define TMESH_DETERMINANT3X3(a11, a12, a13, a21, a22, a23, a31, a32, a33) ((a11)*((a22)*(a33) - (a23)*(a32)) - (a12)*((a21)*(a33) - (a23)*(a31)) + (a13)*((a21)*(a32) - (a22)*(a31)))
|
||||
|
||||
} //namespace T_MESH
|
||||
|
||||
#endif //_COORDINATES_H
|
||||
|
145
src/mesh_fix/include/Kernel/graph.h
Normal file
145
src/mesh_fix/include/Kernel/graph.h
Normal file
@ -0,0 +1,145 @@
|
||||
/****************************************************************************
|
||||
* TMesh *
|
||||
* *
|
||||
* Consiglio Nazionale delle Ricerche *
|
||||
* Istituto di Matematica Applicata e Tecnologie Informatiche *
|
||||
* Sezione di Genova *
|
||||
* IMATI-GE / CNR *
|
||||
* *
|
||||
* Authors: Marco Attene *
|
||||
* Copyright(C) 2012: IMATI-GE / CNR *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is dual-licensed as follows: *
|
||||
* *
|
||||
* (1) You may use TMesh as 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. *
|
||||
* In this case the 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 (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
* (2) You may use TMesh as part of a commercial software. In this case a *
|
||||
* proper agreement must be reached with the Authors and with IMATI-GE/CNR *
|
||||
* based on a proper licensing contract. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef _GRAPH_H
|
||||
#define _GRAPH_H
|
||||
|
||||
#include "list.h"
|
||||
#include "basics.h"
|
||||
|
||||
namespace T_MESH
|
||||
{
|
||||
|
||||
//! Base class type for nodes of non-oriented graphs
|
||||
|
||||
class graphNode : public Data
|
||||
{
|
||||
public:
|
||||
|
||||
//! List of incident edges.
|
||||
List edges;
|
||||
|
||||
//! Generic 8-bit mask for marking purposes.
|
||||
unsigned char mask;
|
||||
|
||||
graphNode() {mask=0;}
|
||||
TMESH_VIRTUAL ~graphNode() {}
|
||||
|
||||
//! Returns TRUE if the node is isolated. O(1).
|
||||
bool isIsolated() {return (edges.numels()==0);}
|
||||
|
||||
//! Returns the edge connecting this with 'n'. NULL if not connected. O(degree).
|
||||
class graphEdge *getEdge(graphNode *n);
|
||||
};
|
||||
|
||||
|
||||
//! Base class type for edges of non-oriented graphs
|
||||
|
||||
class graphEdge : public Data
|
||||
{
|
||||
public:
|
||||
|
||||
//! Edge's end-points
|
||||
graphNode *n1, *n2;
|
||||
|
||||
//! Generic info attached to the edge
|
||||
void *info;
|
||||
|
||||
//! Generic 8-bit mask for marking purposes.
|
||||
unsigned char mask;
|
||||
|
||||
//! Constructor.
|
||||
graphEdge(graphNode *, graphNode *);
|
||||
TMESH_VIRTUAL ~graphEdge() {}
|
||||
|
||||
//! Returns the node oppsite to 'n'. O(1).
|
||||
graphNode *oppositeNode(graphNode *n) {return (n1==n)?(n2):((n2==n)?(n1):(NULL));}
|
||||
|
||||
//! Returns TRUE if this edge does not connect points. O(1).
|
||||
bool isUnlinked() {return (n1==NULL);}
|
||||
|
||||
//! Returns TRUE if 'n' is a node of this edge. O(1).
|
||||
bool hasNode(graphNode *n) {return (n1==n || n2==n);}
|
||||
|
||||
//! Makes this edge as 'unlinked' from the graph. O(1).
|
||||
void makeUnlinked() {n1=NULL; n2=NULL;}
|
||||
|
||||
//! Edge collapse. O(degree of neighbors).
|
||||
|
||||
//! After one (or a series of) collapse, remember to call Graph::deleteUnlinkedElements()
|
||||
//! to make the graph coherent with its node and edge lists.
|
||||
void collapse();
|
||||
|
||||
//! Inverts the edge's orientation
|
||||
void invert();
|
||||
};
|
||||
|
||||
|
||||
//! Base class type for non oriented graphs
|
||||
|
||||
class Graph
|
||||
{
|
||||
public:
|
||||
|
||||
//! Nodes and edges of the graph.
|
||||
List nodes, edges;
|
||||
|
||||
~Graph();
|
||||
|
||||
//! Adds an existing isolated node to the graph. O(1).
|
||||
graphNode *addNode(graphNode *n) {nodes.appendHead(n); return n;}
|
||||
|
||||
//! Creates a new edge out of a pair of nodes. O(degree of nodes).
|
||||
|
||||
//! If the edges already exists, no new edge is created and the
|
||||
//! existing one is returned. Otherwise the newly created edge is returned.
|
||||
graphEdge *createEdge(graphNode *n1, graphNode *n2);
|
||||
|
||||
//! Unlinks the edge and updates the graph connectivity accordingly.
|
||||
void unlinkEdge(graphEdge *e);
|
||||
|
||||
//! Removes and deletes the edge. Updates the graph connectivity accordingly.
|
||||
void destroyEdge(graphEdge *e);
|
||||
|
||||
//! Removes a node and updates the graph connectivity accordingly.
|
||||
//! The unlinked node is returned.
|
||||
graphNode *unlinkNode(graphNode *n);
|
||||
|
||||
//! Eliminates isolated nodes and unlinked edges from the lists. O(N).
|
||||
//! The eliminated elements are deleted too.
|
||||
void deleteUnlinkedElements();
|
||||
|
||||
|
||||
bool isConnected();
|
||||
};
|
||||
|
||||
} //namespace T_MESH
|
||||
|
||||
#endif // _GRAPH_H
|
94
src/mesh_fix/include/Kernel/heap.h
Normal file
94
src/mesh_fix/include/Kernel/heap.h
Normal file
@ -0,0 +1,94 @@
|
||||
/****************************************************************************
|
||||
* TMesh *
|
||||
* *
|
||||
* Consiglio Nazionale delle Ricerche *
|
||||
* Istituto di Matematica Applicata e Tecnologie Informatiche *
|
||||
* Sezione di Genova *
|
||||
* IMATI-GE / CNR *
|
||||
* *
|
||||
* Authors: Marco Attene *
|
||||
* Copyright(C) 2012: IMATI-GE / CNR *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is dual-licensed as follows: *
|
||||
* *
|
||||
* (1) You may use TMesh as 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. *
|
||||
* In this case the 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 (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
* (2) You may use TMesh as part of a commercial software. In this case a *
|
||||
* proper agreement must be reached with the Authors and with IMATI-GE/CNR *
|
||||
* based on a proper licensing contract. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef _HEAP_H
|
||||
#define _HEAP_H
|
||||
|
||||
#include "basics.h"
|
||||
|
||||
namespace T_MESH
|
||||
{
|
||||
|
||||
//! Heap base class type.
|
||||
|
||||
//! abstractHeap is the base class for implementing heaps.
|
||||
//! Each implementation (class extension) must define the method
|
||||
//! compare to be used for sorting the heap. If the objects being
|
||||
//! sorted are non-negative numbers, a special implementation may
|
||||
//! use the field positions to record the index of each element
|
||||
//! within the heap. This feature is useful when there is a need to
|
||||
//! re-sort an element whose cost changes after its insertion into
|
||||
//! the heap. The array 'positions' must be allocated by
|
||||
//! the extended class constructor, and must be able to contain NMAX+1
|
||||
//! integer numbers, where NMAX is the maximum value that can be
|
||||
//! assumed by an object.
|
||||
|
||||
|
||||
class abstractHeap
|
||||
{
|
||||
protected:
|
||||
void **heap; //!< Heap data is stored here
|
||||
int numels; //!< Current number of elements
|
||||
int maxels; //!< Maximum number of elements
|
||||
int *positions; //!< Optional pointer to an array of positions
|
||||
|
||||
int upheap(int i); //!< Moves the i'th object up on the heap
|
||||
int downheap(int i); //!< Moves the i'th object down on the heap
|
||||
|
||||
//! Comparison of two heap elements
|
||||
|
||||
//! This function must be implemented in the extended class.
|
||||
//! The return value must be <0 if a<b, >0 if a>b or 0 if a=b.
|
||||
|
||||
virtual int compare(const void *a, const void *b) = 0;
|
||||
|
||||
public :
|
||||
|
||||
abstractHeap(int n); //!< Creates a heap which can contain up to 'n' elements
|
||||
virtual ~abstractHeap() = 0; //!< Default destructor
|
||||
|
||||
//! Inserts 'e' into the heap
|
||||
|
||||
//! Inserts an element 'e' into the heap in the correct position, according to the
|
||||
//! method compare. If the insertion fails because the heap is full, -1 is
|
||||
//! returned, otherwise the index position of the newly inserted element is
|
||||
//! returned.
|
||||
|
||||
int insert(void *e);
|
||||
|
||||
int isEmpty() const {return (numels == 0);} //!< Returns TRUE if the heap is empty
|
||||
void *getHead() const {return heap[1];} //!< Returns the first element of the heap
|
||||
void *removeHead(); //!< Removes and returns the first element after rearranging the heap
|
||||
void flush() {numels=0;} //!< Removes all the elements
|
||||
};
|
||||
|
||||
} //namespace T_MESH
|
||||
|
||||
#endif // _HEAP_H
|
50
src/mesh_fix/include/Kernel/jqsort.h
Normal file
50
src/mesh_fix/include/Kernel/jqsort.h
Normal file
@ -0,0 +1,50 @@
|
||||
/****************************************************************************
|
||||
* TMesh *
|
||||
* *
|
||||
* Consiglio Nazionale delle Ricerche *
|
||||
* Istituto di Matematica Applicata e Tecnologie Informatiche *
|
||||
* Sezione di Genova *
|
||||
* IMATI-GE / CNR *
|
||||
* *
|
||||
* Authors: Marco Attene *
|
||||
* Copyright(C) 2012: IMATI-GE / CNR *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is dual-licensed as follows: *
|
||||
* *
|
||||
* (1) You may use TMesh as 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. *
|
||||
* In this case the 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 (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
* (2) You may use TMesh as part of a commercial software. In this case a *
|
||||
* proper agreement must be reached with the Authors and with IMATI-GE/CNR *
|
||||
* based on a proper licensing contract. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
//! \file
|
||||
//! \brief Declaration of a generic QuickSort function.
|
||||
//!
|
||||
//! The jqsort() function sorts an array with numels elements.
|
||||
//! The v argument points to the start of the array of elements casted to void *.
|
||||
//! The contents of the array are sorted in ascending order according to a
|
||||
//! comparison function pointed to by comp, which is called with two
|
||||
//! arguments that point to the objects being compared.
|
||||
//! The comparison function must return an integer less than, equal to, or
|
||||
//! greater than zero if the first argument is considered to be respectively
|
||||
//! less than, equal to, or greater than the second. If two members
|
||||
//! compare as equal, their order in the sorted array is undefined.
|
||||
//! See the manpage of the standard library qsort() function for further information.
|
||||
|
||||
namespace T_MESH
|
||||
{
|
||||
|
||||
extern void jqsort(Data *v[], int numels, int (*comp)(const Data *, const Data *));
|
||||
|
||||
} //namespace T_MESH
|
183
src/mesh_fix/include/Kernel/list.h
Normal file
183
src/mesh_fix/include/Kernel/list.h
Normal file
@ -0,0 +1,183 @@
|
||||
/****************************************************************************
|
||||
* TMesh *
|
||||
* *
|
||||
* Consiglio Nazionale delle Ricerche *
|
||||
* Istituto di Matematica Applicata e Tecnologie Informatiche *
|
||||
* Sezione di Genova *
|
||||
* IMATI-GE / CNR *
|
||||
* *
|
||||
* Authors: Marco Attene *
|
||||
* Copyright(C) 2012: IMATI-GE / CNR *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is dual-licensed as follows: *
|
||||
* *
|
||||
* (1) You may use TMesh as 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. *
|
||||
* In this case the 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 (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
* (2) You may use TMesh as part of a commercial software. In this case a *
|
||||
* proper agreement must be reached with the Authors and with IMATI-GE/CNR *
|
||||
* based on a proper licensing contract. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef _JLIST_H
|
||||
#define _JLIST_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include "basics.h"
|
||||
|
||||
namespace T_MESH
|
||||
{
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//! Generic node of a doubly likned list.
|
||||
|
||||
class Node
|
||||
{
|
||||
friend class List; // This is to make methods in 'List' able to modify n_prev and n_next
|
||||
|
||||
public :
|
||||
Data *data; //!< Actual data stored in the node
|
||||
|
||||
//! Creates an isolated node storing 'd'
|
||||
Node(const void *d) {data=(Data *)d; n_prev=n_next=NULL;}
|
||||
|
||||
//! Creates a new node storing 'd' and links it to a previous node 'p' and to a next one 'n'.
|
||||
Node(const Node *p, const Data *d, const Node *n);
|
||||
~Node(); //!< Standard destructor
|
||||
|
||||
inline Node *prev() const {return n_prev;} //!< Returns the previous node in the list, possibly NULL
|
||||
inline Node *next() const {return n_next;} //!< Returns the next node in the list, possibly NULL
|
||||
|
||||
protected:
|
||||
Node *n_prev,*n_next; //!< Previous and next node pointers
|
||||
};
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//! Doubly linked list.
|
||||
|
||||
|
||||
class List : public Data
|
||||
{
|
||||
protected :
|
||||
|
||||
Node *l_head; //!< First node pointer
|
||||
Node *l_tail; //!< Last node pointer
|
||||
int l_numels; //!< Number of elements in the list
|
||||
|
||||
public :
|
||||
|
||||
//! Creates an empty list
|
||||
List() {l_head = l_tail = NULL; l_numels = 0;}
|
||||
|
||||
//! Creates a list containing an element 'd' (singleton)
|
||||
List(const Data *d) {l_head = l_tail = new Node(d); l_numels = 1;}
|
||||
|
||||
//! Creates a list out of an array 'd' made of 'n' elements.
|
||||
List(const Data **d, int n);
|
||||
|
||||
//! Creates a duplicated list.
|
||||
List(List& l) {l_head = l_tail = NULL; l_numels = 0; appendList(&l);}
|
||||
|
||||
//! Creates a duplicated list.
|
||||
List(List* l) {l_head = l_tail = NULL; l_numels = 0; appendList(l);}
|
||||
|
||||
//! Destructor
|
||||
~List();
|
||||
|
||||
Node *head() const {return l_head;} //!< Gets the first node, NULL if empty. \n O(1).
|
||||
Node *tail() const {return l_tail;} //!< Gets the last node, NULL if empty. \n O(1).
|
||||
int numels() const {return l_numels;} //!< Gets the number of elements. \n O(1).
|
||||
|
||||
void appendHead(const Data *d); //!< Appends a new node storing 'd' to the head. \n O(1).
|
||||
void appendTail(const Data *d); //!< Appends a new node storing 'd' to the tail. \n O(1).
|
||||
void insertAfter(Node *n, const Data *d); //! Inserts a new node storing 'd' right after 'n'. \n O(1).
|
||||
|
||||
//! Deletes and removes the node containing 'd'. Returns its position, 0 if 'd' is not in the list. \n O(numels()).
|
||||
int removeNode(const Data *d);
|
||||
|
||||
//! Deletes and i'th node (starting from 0). Returns 0 if the list has less than i+1 nodes. \n O(numels()).
|
||||
int removeNode(int i);
|
||||
|
||||
//! Returns the node at position 'i' (starting from 0). Returns NULL if the list has less than i+1 nodes. \n O(numels()).
|
||||
Node *getNode(int i) const;
|
||||
|
||||
//! Deletes and removes the node 'n' from the list. \n O(1).
|
||||
void removeCell(Node *n);
|
||||
|
||||
//! Appends a list 'l' to the head by duplicating nodes in 'l'. \n O(l->numels()).
|
||||
void appendList(const List *l);
|
||||
|
||||
//! Appends a list 'l' to the tail by linking the first node of 'l' to the last one of this list. 'l' becomes empty. \n O(1).
|
||||
void joinTailList(List *l);
|
||||
|
||||
//! Moves node 'n' from this list to the end of 'l'. \n O(1).
|
||||
void moveNodeTo(Node *n, List *l);
|
||||
|
||||
Data *popHead(); //!< Deletes and removes the first node. Returns its data. \n O(1).
|
||||
Data *popTail(); //!< Deletes and removes the last node. Returns its data. \n O(1).
|
||||
|
||||
//! Deletes and removes the node 'n' from the list and frees data memory. \n O(1).
|
||||
|
||||
// NOTE: The following is not true after refactoring, void* has been replaced with Data*
|
||||
//! Warning. This method uses the free() function to to dispose the memory space
|
||||
//! used by the data stored in the node. This means that such data should have
|
||||
//! been allocated through malloc(), calloc() or realloc(), and not through the
|
||||
//! 'new' operator. On some systems, however, the 'delete' operator simply calls 'free()'
|
||||
//! right after the execution of the proper object destructor so, if the object
|
||||
//! does not need to free internally allocated memory, it is safe to dispose the
|
||||
//! memory trhough free() although the object was allocated by 'new'. This works
|
||||
//! on Linux Fedora Core 2 distributions.
|
||||
void freeCell(Node *n);
|
||||
|
||||
//! Deletes and removes the node storing 'd' and frees the memory occupied by 'd' itself. \n O(numels()).
|
||||
|
||||
//! Warning. Read the comment for the method 'freeCell()'
|
||||
void freeNode(Data *d);
|
||||
|
||||
//! Returns the node storing 'd'. NULL if not found. \n O(numels()).
|
||||
Node *containsNode(const Data *d) const;
|
||||
|
||||
//! Replaces old_n with new_n. The Node containing new_n is returned. \n O(numels()).
|
||||
Node *replaceNode(const Data *old_n, const Data *new_n);
|
||||
|
||||
//! Deletes and removes all the nodes and frees data memory. \n O(numels()).
|
||||
|
||||
//! Warning. Read the comment for the method 'freeCell()'
|
||||
void freeNodes();
|
||||
|
||||
void removeNodes(); //!< Deletes and removes all the nodes. \n O(numels()).
|
||||
|
||||
Data **toArray() const; //!< Creates an array out of the list. \n O(numels()).
|
||||
|
||||
//! Sorts the list using 'comp' as comparison function for two elements. \n O(numels()^2).
|
||||
|
||||
//! This method uses the QuickSort algorithm for sorting, thus the complexity is N^2 in the
|
||||
//! worst case, but it is actually much faster in the average case. If, however, there is
|
||||
//! the need to have a guaranteed O(NlogN) complexity, it is possible to implement a heap
|
||||
//! based on the 'abstractHeap' class. See the documentation of the standard 'qsort' library
|
||||
//! function for details on the prototype of the comparison function 'comp'.
|
||||
int sort(int (*comp)(const Data *, const Data *));
|
||||
};
|
||||
|
||||
//! Convenience macro to scan the nodes of a list.
|
||||
#define FOREACHNODE(l, n) for ((n) = (l).head(); (n) != NULL; (n)=(n)->next())
|
||||
|
||||
//! Convenience macro to circulate around the nodes of a list 'l' starting from node 'm'. Must exit with break or return.
|
||||
#define FOREACHNODECIRCULAR(l, m, n) for ((n) = (m); ; (n)=((n)!=(l).tail())?((n)->next()):((l).head()))
|
||||
|
||||
} //namespace T_MESH
|
||||
|
||||
#endif // _JLIST_H
|
||||
|
301
src/mesh_fix/include/Kernel/matrix.h
Normal file
301
src/mesh_fix/include/Kernel/matrix.h
Normal file
@ -0,0 +1,301 @@
|
||||
/****************************************************************************
|
||||
* TMesh *
|
||||
* *
|
||||
* Consiglio Nazionale delle Ricerche *
|
||||
* Istituto di Matematica Applicata e Tecnologie Informatiche *
|
||||
* Sezione di Genova *
|
||||
* IMATI-GE / CNR *
|
||||
* *
|
||||
* Authors: Marco Attene *
|
||||
* Copyright(C) 2012: IMATI-GE / CNR *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is dual-licensed as follows: *
|
||||
* *
|
||||
* (1) You may use TMesh as 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. *
|
||||
* In this case the 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 (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
* (2) You may use TMesh as part of a commercial software. In this case a *
|
||||
* proper agreement must be reached with the Authors and with IMATI-GE/CNR *
|
||||
* based on a proper licensing contract. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef MATRIX_H
|
||||
#define MATRIX_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <float.h>
|
||||
#include "coordinates.h"
|
||||
#include "list.h"
|
||||
|
||||
namespace T_MESH
|
||||
{
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generic 3x3 matrix
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//! Generic 3x3 matrix.
|
||||
|
||||
//! Elements are stored in a row-dominant order, thus
|
||||
//! for example, M[4] is the first element of the second row.
|
||||
|
||||
class Matrix3x3
|
||||
{
|
||||
public:
|
||||
double M[9]; //!< Actual values of the matrix
|
||||
|
||||
Matrix3x3() {M[0]=M[1]=M[2]=M[3]=M[4]=M[5]=M[6]=M[7]=M[8]=0.0;} //!< Contructs a null matrix
|
||||
|
||||
//! Constructs a fully initialized matrix.
|
||||
Matrix3x3(const double& a11, const double& a12, const double& a13,
|
||||
const double& a21, const double& a22, const double& a23,
|
||||
const double& a31, const double& a32, const double& a33);
|
||||
|
||||
//! Constructs a 3x3 matrix as the product of Transpose(v1,v2,v3) and (w1,w2,w3).
|
||||
Matrix3x3(const double& v1, const double& v2, const double& v3,
|
||||
const double& w1, const double& w2, const double& w3);
|
||||
|
||||
//! Constructs a 3x3 matrix as the product of Transpose(a,b,c) and (a,b,c).
|
||||
Matrix3x3(const double& a, const double& b, const double& c);
|
||||
|
||||
//! Returns TRUE if the matrix is symmetric
|
||||
bool isSymmetric() const {return (M[2]==M[4] && M[3]==M[7] && M[6]==M[8]);}
|
||||
|
||||
|
||||
//! Initializes all elements to 'd'
|
||||
void operator=(const double& d) {M[0]=M[1]=M[2]=M[3]=M[4]=M[5]=M[6]=M[7]=M[8]=d;}
|
||||
|
||||
void operator+=(const Matrix3x3&); //!< Sum another matrix
|
||||
void operator-=(const Matrix3x3&); //!< Subtract another matrix
|
||||
void operator*=(const double&); //!< Multiply by a scalar
|
||||
void operator/=(const double& d) {operator *=(1.0/d);} //!< Divide by a scalar
|
||||
Matrix3x3 operator+(const Matrix3x3&) const; //!< Returns the sum of this and another matrix
|
||||
Matrix3x3 operator*(const double&) const; //!< Returns the product of this matrix with a scalar
|
||||
Matrix3x3 operator*(const Matrix3x3&) const; //!< Returns the product of this and another matrix (rows by columns)
|
||||
Matrix3x3 operator~() const; //!< Returns the transpose of this matrix
|
||||
|
||||
//! Return the matrix transpose
|
||||
Matrix3x3 transpose() const;
|
||||
|
||||
//! Returns Transpose(a,b,c)*M*(a,b,c)
|
||||
|
||||
//! Returns the (scalar) result of multiplying the matrix on
|
||||
//! the left and on the right by the vector (a,b,c).
|
||||
double lrMultiply(const double& a, const double& b, const double& c) const;
|
||||
|
||||
//! Returns the (scalar) result of v*M*w
|
||||
double lrMultiply(const double& v1, const double& v2, const double& v3,
|
||||
const double& w1, const double& w2, const double& w3) const;
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Symmetric 3x3 matrix
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//! Symmetric 3x3 matrix
|
||||
|
||||
//! Compact storage: \n
|
||||
//! M[0] M[1] M[3] \n
|
||||
//! M[1] M[2] M[4] \n
|
||||
//! M[3] M[4] M[5] \n
|
||||
|
||||
class SymMatrix3x3
|
||||
{
|
||||
public:
|
||||
double M[6]; //!< Actual values of the matrix
|
||||
|
||||
SymMatrix3x3() {M[0]=M[1]=M[2]=M[3]=M[4]=M[5]=0.0;} //!< Constructs a null matrix.
|
||||
|
||||
//! Constructs a fully initialized matrix.
|
||||
SymMatrix3x3(const double&a11, const double&a12, const double&a22,
|
||||
const double&a13, const double&a23, const double&a33);
|
||||
|
||||
//! Constructs a symmetric matrix as the product of Transpose(a,b,c) and (a,b,c).
|
||||
SymMatrix3x3(const double& a, const double& b, const double& c);
|
||||
|
||||
//! Constructs a symmetric 3x3 matrix as a copy of an existing 3x3 matrix S.
|
||||
|
||||
//! If 'S' is not symmetric, its upper triangular part is reflected to the lower.
|
||||
|
||||
SymMatrix3x3(const Matrix3x3& S);
|
||||
|
||||
bool operator==(const SymMatrix3x3& s) //!< True iff all entries are equal
|
||||
{return (M[0]==s.M[0] && M[1]==s.M[1] && M[2]==s.M[2] && M[3]==s.M[3] && M[4]==s.M[4] && M[5]==s.M[5]);}
|
||||
bool operator!=(const SymMatrix3x3& s) //!< True iff at least one different entry
|
||||
{return (M[0]!=s.M[0] || M[1]!=s.M[1] || M[2]!=s.M[2] || M[3]!=s.M[3] || M[4]!=s.M[4] || M[5]!=s.M[5]);}
|
||||
|
||||
void operator+=(const SymMatrix3x3&); //!< Sum another matrix
|
||||
void operator-=(const SymMatrix3x3&); //!< Subtract another matrix
|
||||
void operator*=(const double&); //!< Multiply by a scalar
|
||||
void operator/=(const double& d) {operator *=(1.0/d);} //!< Divide by a scalar
|
||||
SymMatrix3x3 operator+(const SymMatrix3x3&) const; //!< Returns the sum of this and another matrix
|
||||
SymMatrix3x3 operator*(const double&) const; //!< Returns the product of this matrix with a scalar
|
||||
|
||||
//! Initializes all elements to 'd'
|
||||
void operator=(const double& d) {M[0]=M[1]=M[2]=M[3]=M[4]=M[5]=d;}
|
||||
|
||||
//! Returns the determinant
|
||||
double determinant() const {return (M[0]*M[2]*M[5])+(2.0*M[1]*M[3]*M[4])-(M[0]*M[4]*M[4])-(M[2]*M[3]*M[3])-(M[5]*M[1]*M[1]);}
|
||||
|
||||
//! Returns TRUE iff the matrix is made of all zeroes.
|
||||
bool isNull() const {return (M[0]==0 && M[1]==0 && M[2]==0 && M[3]==0 && M[4]==0 && M[5]==0);}
|
||||
|
||||
//! Returns Transpose(a,b,c)*M*(a,b,c)
|
||||
|
||||
//! Returns the (scalar) result of multiplying the matrix on
|
||||
//! the left and on the right by the vector (a,b,c).
|
||||
double lrMultiply(const double& a, const double& b, const double& c) const;
|
||||
|
||||
|
||||
//! Returns the (scalar) result of v*M*w
|
||||
double lrMultiply(const double& v1, const double& v2, const double& v3,
|
||||
const double& w1, const double& w2, const double& w3) const;
|
||||
|
||||
bool invert(); //!< Inverts this matrix. Returns FALSE if not invertible, TRUE otherwise
|
||||
|
||||
//! Returns the matrix trace
|
||||
double trace() const {return M[0]+M[2]+M[5];}
|
||||
|
||||
//! Compute eigenvalues and eigenvectors of the matrix (Jacobi method).
|
||||
|
||||
//! The calling function is responsible of verifying that the matrix
|
||||
//! is diagonalizable. Also, eigen_vals and eigen_vecs must be allocated
|
||||
//! prior to calling this method.\n
|
||||
//! eigen_vals are sorted in ascending order (i.e., eigen_vals[0] is the smallest one).\n
|
||||
//! eigen_vecs are sorted accordingly to the order of eigen_vals, that is,
|
||||
//! (eigen_vecs[0], eigen_vecs[1], eigen_vecs[2]) is the eigenvector corresponding to
|
||||
//! eigen_vals[0].
|
||||
void diagonalize(double eigen_vals[3], double eigen_vecs[9]) const;
|
||||
|
||||
//! Compute the eigenvalues l1, l2 and l3.
|
||||
|
||||
//! This method is much faster and precise than 'diagonalize', as it uses
|
||||
//! an analytical direct method instead of an iterative approach.
|
||||
void getEigenvalues(double *l1, double *l2, double *l3) const;
|
||||
|
||||
//! Compute the eigenvector (a,b,c) corresponding to the minimum eigenvalue.
|
||||
|
||||
//! This method is much faster and precise than 'diagonalize', as it uses
|
||||
//! an analytical direct method instead of an iterative approach.
|
||||
//! Returns the corresponding eigenvalue
|
||||
double getMinEigenvector(double *a, double *b, double *c) const;
|
||||
|
||||
//! This method is much faster and precise than 'diagonalize', as it uses
|
||||
//! an analytical direct method instead of an iterative approach.
|
||||
void getMaxEigenvector(double *a, double *b, double *c) const;
|
||||
|
||||
//! Prints the contents of the matrix to the specified FILE id.
|
||||
|
||||
//! If no 'id' is specifyed, results are printed to stdout.
|
||||
|
||||
void print(FILE *id =stdout) const;
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Symmetric 4x4 matrix
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//! Symmetric 4x4 matrix.
|
||||
|
||||
//! Compact storage: \n
|
||||
//! a2 ab ac ad \n
|
||||
//! ab b2 bc bd \n
|
||||
//! ac bc c2 cd \n
|
||||
//! ad bd cd d2 \n
|
||||
|
||||
class SymMatrix4x4
|
||||
{
|
||||
public:
|
||||
coord a2,ab,ac,ad,b2,bc,bd,c2,cd,d2; //!< Actual matrix coeffs.
|
||||
|
||||
SymMatrix4x4() {a2=ab=ac=ad=b2=bc=bd=c2=cd=d2=0;} //!< Constructs a null matrix
|
||||
|
||||
//! Extend a 3x3 symmetric matrix to homogeneous coordinates (ad=bd=cd=0 and d2=1).
|
||||
SymMatrix4x4(const SymMatrix3x3&);
|
||||
|
||||
//! Quadric (a,b,c,d)*Transpose(a,b,c,d)
|
||||
SymMatrix4x4(const coord& a, const coord& b, const coord& c, const coord& d);
|
||||
|
||||
bool operator==(const SymMatrix4x4&); //!< True iff equal
|
||||
bool operator!=(const SymMatrix4x4&); //!< True iff not equal
|
||||
|
||||
void operator+=(const SymMatrix4x4&); //!< Sum another matrix
|
||||
SymMatrix4x4 operator+(const SymMatrix4x4&) const; //!< Returns the sum of this and another matrix
|
||||
SymMatrix4x4 operator*(const coord&) const; //!< Returns the product of this matrix by a scalar
|
||||
|
||||
//! Adds the quadric (a,b,c,d)*Transpose(a,b,c,d)
|
||||
void add(const coord& a, const coord& b, const coord& c, const coord& d);
|
||||
|
||||
//! Returns Transpose(a,b,c,d)*M*(a,b,c,d)
|
||||
|
||||
//! Returns the (scalar) result of multiplying the matrix on
|
||||
//! the left and on the right by the vector (a,b,c,d).
|
||||
coord lrMultiply(const coord& a, const coord& b, const coord& c, const coord& d) const;
|
||||
|
||||
//! \brief Computes the vector (a,b,c) that minimizes the quantity lrMultiply(a,b,c,1).
|
||||
//! Returns FALSE if such a vector is not unique.
|
||||
bool getMinimizer(coord *a, coord *b, coord *c) const;
|
||||
|
||||
bool invert(); //!< Inverts this matrix. Returns FALSE if not invertible, TRUE otherwise
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generic 4x4 matrix
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//! Generic 4x4 matrix.
|
||||
|
||||
class Matrix4x4
|
||||
{
|
||||
public:
|
||||
double matrix[4][4]; //!< Actual matrix coefficients
|
||||
|
||||
//! Constructs an undefined matrix
|
||||
Matrix4x4();
|
||||
|
||||
//! Constructs a diagonal matrix with 'd' values on the diagonal
|
||||
Matrix4x4(const double& d);
|
||||
|
||||
//! Constructs a fully initialized matrix (parameters are in row dominant order M[0][0], M[0][1], ...).
|
||||
Matrix4x4(
|
||||
const double&, const double&, const double&, const double&,
|
||||
const double&, const double&, const double&, const double&,
|
||||
const double&, const double&, const double&, const double&,
|
||||
const double&, const double&, const double&, const double&
|
||||
);
|
||||
|
||||
//! Rotation matrix from a quaternion
|
||||
void setRotation(const double &, const double&, const double&, const double&);
|
||||
|
||||
//! Translation matrix from a vector
|
||||
void setTranslation(const double &, const double&, const double&);
|
||||
|
||||
Matrix4x4 operator*(const Matrix4x4&) const; //!< Returns the product of this and another matrix (rows by columns)
|
||||
|
||||
void transform(double *, double *, double *); //! Transform the vector by left-multiplication with the matrix
|
||||
};
|
||||
|
||||
} //namespace T_MESH
|
||||
|
||||
#endif // MATRIX_H
|
||||
|
299
src/mesh_fix/include/Kernel/point.h
Normal file
299
src/mesh_fix/include/Kernel/point.h
Normal file
@ -0,0 +1,299 @@
|
||||
/****************************************************************************
|
||||
* TMesh *
|
||||
* *
|
||||
* Consiglio Nazionale delle Ricerche *
|
||||
* Istituto di Matematica Applicata e Tecnologie Informatiche *
|
||||
* Sezione di Genova *
|
||||
* IMATI-GE / CNR *
|
||||
* *
|
||||
* Authors: Marco Attene *
|
||||
* Copyright(C) 2012: IMATI-GE / CNR *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is dual-licensed as follows: *
|
||||
* *
|
||||
* (1) You may use TMesh as 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. *
|
||||
* In this case the 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 (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
* (2) You may use TMesh as part of a commercial software. In this case a *
|
||||
* proper agreement must be reached with the Authors and with IMATI-GE/CNR *
|
||||
* based on a proper licensing contract. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef _POINT_H
|
||||
#define _POINT_H
|
||||
|
||||
#include "basics.h"
|
||||
|
||||
namespace T_MESH
|
||||
{
|
||||
|
||||
//! Orientation predicates using filtering on doubles
|
||||
extern "C" double orient2d(double *, double *, double *);
|
||||
extern "C" double orient3d(double *, double *, double *, double *);
|
||||
|
||||
//! Orientation predicates on PM_Rationals
|
||||
|
||||
// orient2D: >0 =0 <0 if (p,q,r) are CCW, aligned, CW respectively
|
||||
PM_Rational orient2D(const PM_Rational& px, const PM_Rational& py, const PM_Rational& qx, const PM_Rational& qy, const PM_Rational& rx, const PM_Rational& ry);
|
||||
|
||||
|
||||
//! Geometric point definition
|
||||
|
||||
//! This class represents a point in the Euclidean 3D space. It can be used
|
||||
//! to represent 3D vectors originating at (0,0,0) and terminating at the
|
||||
//! corresponding point. Several methods of this class are intended to
|
||||
//! manipulate vectors rather than points; for example, a call of the
|
||||
//! method normalize is an actual normalization if the object is a vector,
|
||||
//! but it has to be intended as a projection on the unit sphere if the
|
||||
//! object is intended to be a point. An object of type Point is a triplet
|
||||
//! (x,y,z) of coordinates endowed with a pointer 'info' to possible additional
|
||||
//! information. Each coordinate is a number of type 'coord' which, by
|
||||
//! default, is a standard double. Operations on points include addition,
|
||||
//! subtraction, cross and dot product, and many others. This class implements
|
||||
//! several useful operations using vector arithmethic. For example,
|
||||
//! the simple piece of code "A = B*C;" assignes to A the value of the dot
|
||||
//! product of B and C.
|
||||
//! Nearly zero or nearly flat angles are automatically snapped to
|
||||
//! exactly zero and exactly flat angles if the difference is smaller
|
||||
//! than the global variable _acos_tolerance. This is the very basic application
|
||||
//! of our version of the epsilon geometry for robust computation.
|
||||
|
||||
|
||||
class Point : public Data
|
||||
{
|
||||
public :
|
||||
coord x,y,z; //!< Coordinates
|
||||
void *info; //!< Further information
|
||||
|
||||
//! Creates a new point with coordinates (0,0,0).
|
||||
Point() {x = y = z = 0; info = NULL;}
|
||||
|
||||
//! Creates a new point with the same coordinates as 's'. The info field is not copied.
|
||||
Point(const Point *s) {x = s->x; y = s->y; z = s->z; info = NULL;}
|
||||
|
||||
//! Creates a new point with the same coordinates as 's'. The info field is not copied.
|
||||
Point(const Point& s) {x = s.x; y = s.y; z = s.z; info = NULL;}
|
||||
|
||||
//! Creates a new point with coordinates (a,b,c).
|
||||
Point(const coord& a, const coord& b, const coord& c) {x = a; y = b; z = c; info = NULL;}
|
||||
|
||||
//! Do not remove this. It makes the compiler produce a vtable for this object.
|
||||
TMESH_VIRTUAL bool isPoint() const { return true; }
|
||||
|
||||
//! Set the coordinates to (a,b,c).
|
||||
void setValue(const coord& a, const coord& b, const coord& c) {x = a; y = b; z = c;}
|
||||
|
||||
//! Set the coordinates as those of 'p'
|
||||
void setValue(const Point& p) {x = p.x; y = p.y; z = p.z;}
|
||||
|
||||
//! Set the coordinates as those of '*p'
|
||||
void setValue(const Point *p) {x = p->x; y = p->y; z = p->z;}
|
||||
|
||||
//! Returns the vector difference
|
||||
Point operator-(const Point& p) const {return Point(x-p.x, y-p.y, z-p.z);}
|
||||
|
||||
//! Returns the vector sum
|
||||
Point operator+(const Point& p) const {return Point(x+p.x, y+p.y, z+p.z);}
|
||||
|
||||
//! Sums another point
|
||||
void operator+=(const Point& p) {x+=p.x; y+=p.y; z+=p.z;}
|
||||
|
||||
//! Subtracts another point
|
||||
void operator-=(const Point& p) {x-=p.x; y-=p.y; z-=p.z;}
|
||||
|
||||
//! Returns the Cross Product
|
||||
Point operator&(const Point& p) const {return Point(y*p.z-z*p.y, z*p.x-x*p.z, x*p.y-y*p.x);}
|
||||
|
||||
//! Returns the Dot Product
|
||||
coord operator*(const Point& p) const {return (x*p.x+y*p.y+z*p.z);}
|
||||
|
||||
//! Returns the product with a scalar
|
||||
Point operator*(const coord& d) const {return Point(x*d,y*d,z*d);}
|
||||
|
||||
//! Multiplies by a scalar
|
||||
void operator*=(const coord& m) { x *= m; y *= m; z *= m; }
|
||||
|
||||
//! Divides by a scalar
|
||||
void operator/=(const coord& m) { x /= m; y /= m; z /= m; }
|
||||
|
||||
//! Returns the vector divided by the scalar
|
||||
Point operator/(const coord& d) const { return Point(x / d, y / d, z / d); }
|
||||
|
||||
//! TRUE iff coordinates are equal
|
||||
bool operator==(const Point& p) const {return (x==p.x && y==p.y && z==p.z);}
|
||||
|
||||
//! FALSE iff coordinates are equal
|
||||
bool operator!=(const Point& p) const {return (x!=p.x || y!=p.y || z!=p.z);}
|
||||
|
||||
//! TRUE iff this is lexycographically smaller than s
|
||||
bool operator<(const Point& s) const;
|
||||
|
||||
//! Returns the i'th coordinate
|
||||
inline coord& at(unsigned char i) { return (i == 0) ? (x) : ((i == 1) ? (y) : (z)); }
|
||||
|
||||
//! Returns the i'th coordinate
|
||||
inline coord& operator[](unsigned char i) { return (i == 0) ? (x) : ((i == 1) ? (y) : (z)); }
|
||||
|
||||
//! Returns the inverse vector
|
||||
Point inverse() const {return Point(-x,-y,-z);}
|
||||
|
||||
//! Inverts the vector
|
||||
void invert() {x=-x; y=-y; z=-z;}
|
||||
|
||||
//! TRUE if vector is (0,0,0)
|
||||
bool isNull() const {return (x==0 && y==0 && z==0);}
|
||||
|
||||
//! Squared distance from origin
|
||||
coord squaredLength() const {return (x*x + y*y + z*z);}
|
||||
|
||||
//! Squared distance from '*b'
|
||||
coord squaredDistance(const Point *b) const { return (((*(this)) - (*b)).squaredLength()); }
|
||||
|
||||
//! Returns the solution of the linear system Ax = d, where A is a 3x3 matrix whose rows are row1, row2 and row3, d = this
|
||||
Point linearSystem(const Point& row1, const Point& row2, const Point& row3);
|
||||
|
||||
|
||||
//! Projects the vector on the plane with normal 'n' passing through the origin.
|
||||
void project(const Point *n);
|
||||
|
||||
//! Returns the projection of the point on the straight line though 'a' and 'b'.
|
||||
Point projection(const Point *a, const Point *b) const;
|
||||
|
||||
//! Prints the coordinates of the point to a file handler. stdout is the default.
|
||||
void printPoint(FILE *fp = stdout) const { fprintf(fp, "%f %f %f,\n", TMESH_TO_FLOAT(x), TMESH_TO_FLOAT(y), TMESH_TO_FLOAT(z)); } // Debug
|
||||
|
||||
|
||||
//! Exact orientation test.
|
||||
//! Return value is positive iff the tetrahedron (this,a,b,c) has a positive volume;
|
||||
//! It is negative iff the tetrahedron (this,a,b,c) has a negative volume;
|
||||
//! It is zero iff the tetrahedron (this,a,b,c) has a zero volume.
|
||||
coord exactOrientation(const Point *a, const Point *b, const Point *c) const;
|
||||
coord side3D(const Point *p1, const Point *p2, const Point *p3) const { return exactOrientation(p1, p2, p3); }
|
||||
|
||||
|
||||
//! Exact misalignment test. Returns TRUE iff points are not aligned.
|
||||
bool exactMisalignment(const Point *a, const Point *b) const;
|
||||
bool notAligned(const Point *a, const Point *b) const { return exactMisalignment(a,b); }
|
||||
|
||||
//! Exact planar side test. Returns TRUE iff 'this', Q, A and B are coplanar
|
||||
//! and 'this' and Q are (properly) on the same side of A-B.
|
||||
//! Warning! Coplanarity is not checked, result is undetermined if
|
||||
//! 'this', Q, A and B are not coplanar.
|
||||
bool exactSameSideOnPlane(const Point *Q, const Point *A, const Point *B) const;
|
||||
|
||||
//! Itersection point between lines p-q and r-s. Return INFINITE_POINT if lineas are either parallel or degenerate.
|
||||
static Point lineLineIntersection(const Point& p, const Point& q, const Point& r, const Point& s);
|
||||
|
||||
//! Itersection point between line p-q and plane r-s-t. Return INFINITE_POINT for parallel/degenerate args.
|
||||
static Point linePlaneIntersection(const Point& p, const Point& q, const Point& r, const Point& s, const Point& t);
|
||||
|
||||
//! Squared area of the triangle p-q-r.
|
||||
static coord squaredTriangleArea3D(const Point& p, const Point& q, const Point& r);
|
||||
|
||||
//! true if 'p' is a point of the segment v1-v2 (endpoints excluded)
|
||||
static bool pointInInnerSegment(const Point *p, const Point *v1, const Point *v2);
|
||||
|
||||
//! true if 'p' is a point of the segment v1-v2 (endpoints included)
|
||||
static bool pointInSegment(const Point *p, const Point *v1, const Point *v2);
|
||||
|
||||
//! true if the coplanar point 'p' is in the inner area of v1-v2-v3.
|
||||
//! Undetermined if points are not coplanar.
|
||||
static bool pointInInnerTriangle(const Point *p, const Point *v1, const Point *v2, const Point *v3);
|
||||
|
||||
//! true if the coplanar point 'p' is either in the inner area of v1-v2-v3 or on its border.
|
||||
//! Undetermined if points are not coplanar.
|
||||
static bool pointInTriangle(const Point *p, const Point *v1, const Point *v2, const Point *v3);
|
||||
|
||||
//! true if (p1-p2) properly intersects (sp1-sp2) at any point (endpoints included).
|
||||
//! Collinear overlapping segments are not considered to be properly intersecting.
|
||||
static bool segmentsIntersect(const Point *p1, const Point *p2, const Point *sp1, const Point *sp2);
|
||||
|
||||
//! true if the interior of (p1-p2) properly intersects the interior of (sp1-sp2).
|
||||
//! Collinear overlapping segments are not considered to be properly intersecting.
|
||||
static bool innerSegmentsCross(const Point& p1, const Point& p2, const Point& sp1, const Point& sp2);
|
||||
|
||||
//! true if segment (s1-s2) intersects the triangle v1-v2-v3 (border included).
|
||||
static bool segmentIntersectsTriangle(const Point *s1, const Point *s2, const Point *v1, const Point *v2, const Point *v3);
|
||||
|
||||
//! true if segment (s1-s2) intersects the triangle v1-v2-v3 (border included).
|
||||
//! Accelerated version - relative orientations are passed as parameters.
|
||||
static bool segmentIntersectsTriangle(const Point *s1, const Point *s2, const Point *v1, const Point *v2, const Point *v3, const coord& o1, const coord& o2);
|
||||
|
||||
|
||||
|
||||
|
||||
// FUNCTIONS BELOW THIS LINE MAY RETURN APPROXIMATED/NOT ROBUST RESULTS EVEN WHEN USING RATIONALS
|
||||
|
||||
|
||||
|
||||
//! Distance from origin
|
||||
double length() const { return sqrt(TMESH_TO_DOUBLE((x*x + y*y + z*z))); }
|
||||
|
||||
//! Divides the vector by its length. If isNull() the application exits with an error.
|
||||
void normalize();
|
||||
|
||||
//! Rotates the vector around 'axis' by 'ang' radians ccw.
|
||||
void rotate(const Point& axis, const double& ang);
|
||||
|
||||
//! Distance from 'b'
|
||||
double distance(const Point& b) const {return (((*(this))-(b)).length());}
|
||||
|
||||
//! Distance from '*b'
|
||||
double distance(const Point *b) const { return (((*(this)) - (*b)).length()); }
|
||||
|
||||
//! Distance from straight line through 'a' and 'b'
|
||||
double distanceFromLine(const Point *a, const Point *b) const;
|
||||
|
||||
//! Distance from straight line through 'a' and 'b'. *cc is set to the closest line point.
|
||||
double distanceFromLine(const Point *a, const Point *b, Point *cc) const;
|
||||
|
||||
double distanceFromEdge(const Point *a, const Point *b) const; //!< Distance from segment a-b
|
||||
|
||||
//! Distance from segment a-b. *cc is set to the closest edge point.
|
||||
double distanceFromEdge(const Point *a, const Point *b, Point *cc) const;
|
||||
|
||||
//! Distance between the straight lines through (this) - l1_p2 and l2_p1 - l2_p2.
|
||||
double distanceLineLine(const Point *l1_p2, const Point *l2_p1, const Point *l2_p2) const;
|
||||
|
||||
//!< Angle between this vector and 'v' in radians.
|
||||
double getAngle(const Point& v) const;
|
||||
|
||||
//! Angle defined by <a, *this, b> in radians.
|
||||
double getAngle(const Point& a, const Point& b) const { return (a - (*this)).getAngle(b - (*this)); }
|
||||
|
||||
//! Angle defined by <*a, *this, *b> in radians.
|
||||
double getAngle(const Point *a, const Point *b) const { return ((*a) - (*this)).getAngle((*b) - (*this)); }
|
||||
|
||||
|
||||
//! Line-line closest point computation.
|
||||
//! I SUSPECT THIS CAN BE MADE EXACT...
|
||||
|
||||
//! Computes the closest points of the line passing through this and this2,
|
||||
//! and the line passing through p1 and p2. The computed points are used to
|
||||
//! initialize the coordinates of cpOnThis and cpOnOther. The method
|
||||
//! returns 0 if the lines are parallel, 1 otherwise.
|
||||
int closestPoints(const Point *this2, const Point *p1, const Point *p2, Point *cpOnThis, Point *cpOnOther) const;
|
||||
};
|
||||
|
||||
//! Lexycographic comparison to be used with jqsort() or abstractHeap.
|
||||
int xyzCompare(const Data *p1, const Data *p2);
|
||||
|
||||
//! Static point with DBL_MAX coordinates.
|
||||
extern const Point INFINITE_POINT;
|
||||
|
||||
//! Checks whether a point is INFINITE_POINT.
|
||||
#define IS_FINITE_POINT(p) ((p).x < DBL_MAX)
|
||||
|
||||
} //namespace T_MESH
|
||||
|
||||
#endif // _POINT_H
|
||||
|
39
src/mesh_fix/include/Kernel/tmesh_kernel.h
Normal file
39
src/mesh_fix/include/Kernel/tmesh_kernel.h
Normal file
@ -0,0 +1,39 @@
|
||||
/****************************************************************************
|
||||
* TMesh *
|
||||
* *
|
||||
* Consiglio Nazionale delle Ricerche *
|
||||
* Istituto di Matematica Applicata e Tecnologie Informatiche *
|
||||
* Sezione di Genova *
|
||||
* IMATI-GE / CNR *
|
||||
* *
|
||||
* Authors: Marco Attene *
|
||||
* Copyright(C) 2012: IMATI-GE / CNR *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is dual-licensed as follows: *
|
||||
* *
|
||||
* (1) You may use TMesh as 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. *
|
||||
* In this case the 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 (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
* (2) You may use TMesh as part of a commercial software. In this case a *
|
||||
* proper agreement must be reached with the Authors and with IMATI-GE/CNR *
|
||||
* based on a proper licensing contract. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef _TMESH_KERNEL_H
|
||||
#define _TMESH_KERNEL_H
|
||||
|
||||
#include "basics.h"
|
||||
#include "list.h"
|
||||
#include "point.h"
|
||||
#include "matrix.h"
|
||||
|
||||
#endif //_TMESH_KERNEL_H
|
59
src/mesh_fix/include/TMesh/detectIntersections.h
Normal file
59
src/mesh_fix/include/TMesh/detectIntersections.h
Normal file
@ -0,0 +1,59 @@
|
||||
/****************************************************************************
|
||||
* TMesh *
|
||||
* *
|
||||
* Consiglio Nazionale delle Ricerche *
|
||||
* Istituto di Matematica Applicata e Tecnologie Informatiche *
|
||||
* Sezione di Genova *
|
||||
* IMATI-GE / CNR *
|
||||
* *
|
||||
* Authors: Marco Attene *
|
||||
* Copyright(C) 2013: IMATI-GE / CNR *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is dual-licensed as follows: *
|
||||
* *
|
||||
* (1) You may use TMesh as 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. *
|
||||
* In this case the 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 (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
* (2) You may use TMesh as part of a commercial software. In this case a *
|
||||
* proper agreement must be reached with the Authors and with IMATI-GE/CNR *
|
||||
* based on a proper licensing contract. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef DETECT_INTERSECTIONS_H
|
||||
#define DETECT_INTERSECTIONS_H
|
||||
|
||||
#include "tin.h"
|
||||
|
||||
namespace T_MESH
|
||||
{
|
||||
#define DI_MAX_NUMBER_OF_CELLS 10000
|
||||
#define DI_EPSILON_POINT Point(1.0e-9, 1.0e-9, 1.0e-9)
|
||||
|
||||
class di_cell : public Data
|
||||
{
|
||||
public:
|
||||
Point mp, Mp;
|
||||
List triangles;
|
||||
|
||||
di_cell() {}
|
||||
di_cell(Basic_TMesh *tin, bool useAll = true);
|
||||
|
||||
bool is_triangleBB_in_cell(Triangle *t) const;
|
||||
|
||||
di_cell *fork();
|
||||
void selectIntersections(bool justproper = false);
|
||||
bool doesNotIntersectForSure();
|
||||
};
|
||||
|
||||
} //namespace T_MESH
|
||||
|
||||
#endif // DETECT_INTERSECTIONS_H
|
252
src/mesh_fix/include/TMesh/edge.h
Normal file
252
src/mesh_fix/include/TMesh/edge.h
Normal file
@ -0,0 +1,252 @@
|
||||
/****************************************************************************
|
||||
* TMesh *
|
||||
* *
|
||||
* Consiglio Nazionale delle Ricerche *
|
||||
* Istituto di Matematica Applicata e Tecnologie Informatiche *
|
||||
* Sezione di Genova *
|
||||
* IMATI-GE / CNR *
|
||||
* *
|
||||
* Authors: Marco Attene *
|
||||
* Copyright(C) 2013: IMATI-GE / CNR *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is dual-licensed as follows: *
|
||||
* *
|
||||
* (1) You may use TMesh as 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. *
|
||||
* In this case the 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 (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
* (2) You may use TMesh as part of a commercial software. In this case a *
|
||||
* proper agreement must be reached with the Authors and with IMATI-GE/CNR *
|
||||
* based on a proper licensing contract. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef _EDGE_H
|
||||
#define _EDGE_H
|
||||
|
||||
#include "basics.h"
|
||||
#include "vertex.h"
|
||||
|
||||
namespace T_MESH
|
||||
{
|
||||
|
||||
//! Edge of a Basic_TMesh.
|
||||
|
||||
//! This class represents an edge of a triangulation. An Edge is the main
|
||||
//! part of the Basic_TMesh data structure. Each edge has an orientation
|
||||
//! (i.e. from v1 to v2) which forces the order in which incident triangles
|
||||
//! (t1 and t2) are stored in the class. When looking the edge so that it
|
||||
//! points "upwards", if the normal of t1 points towards the observer then
|
||||
//! t1 must be on the left of the edge. The field mask is useful for
|
||||
//! assigning up to 256 different states to the edge.
|
||||
|
||||
|
||||
class Edge : public Data
|
||||
{
|
||||
public :
|
||||
|
||||
Vertex *v1,*v2; //!< End-points
|
||||
class Triangle *t1,*t2; //!< Incident triangles
|
||||
unsigned char mask; //!< bit-mask for marking purposes
|
||||
void *info; //!< Further information
|
||||
|
||||
|
||||
Edge(); //!< AMF_ADD 1.1-2 >
|
||||
Edge(Vertex *s, Vertex *d); //!< Constructor
|
||||
~Edge(); //!< Destructor
|
||||
|
||||
//! Returns true only if object is a basic Edge. All the reimplementations must return false.
|
||||
TMESH_VIRTUAL bool isBaseType() const { return true; }
|
||||
|
||||
//! TRUE iff edge is properly linked to a Basic_TMesh.
|
||||
bool isLinked() const {return (v1 != NULL);}
|
||||
|
||||
//! TRUE iff 'v' is an end-point of the edge.
|
||||
bool hasVertex(const Vertex *v) const {return (v1==v || v2==v);}
|
||||
|
||||
//! TRUE iff 't' is incident to the edge.
|
||||
bool hasTriangle(const Triangle *t) const {return (t1==t || t2==t);}
|
||||
|
||||
//! TRUE if both 'va' and 'vb' are vertices of the edge.
|
||||
bool hasVertices(const Vertex *va, const Vertex *vb) const {return ((v1==va && v2==vb) || (v2==va && v1==vb));}
|
||||
|
||||
//! Squared length of the edge.
|
||||
coord squaredLength() const {return v1->squaredDistance(v2);}
|
||||
|
||||
//! Convert to vector v2-v1.
|
||||
Point toVector() const {return (*v2)-(*v1);}
|
||||
|
||||
//! Return the edge's mid-point.
|
||||
Point getMidPoint() const {return ((*v1)+(*v2))/2.0;}
|
||||
|
||||
//! Invert the edge's orientation.
|
||||
TMESH_VIRTUAL void invert() {p_swap((void **)(&v1), (void **)(&v2)); p_swap((void **)(&t1), (void **)(&t2));} //!< AMF_CHANGE 1.1-2>
|
||||
|
||||
//! Triangle on the left of the edge when looking from 'v'. NULL if 'v' is not a vertex of the edge.
|
||||
Triangle *leftTriangle(const Vertex *v) const {return ((v1 == v)?(t1):((v2 == v)?(t2):(NULL)));}
|
||||
|
||||
//! Triangle on the right of the edge when looking from 'v'. NULL if 'v' is not a vertex of the edge.
|
||||
Triangle *rightTriangle(const Vertex *v) const {return ((v1 == v)?(t2):((v2 == v)?(t1):(NULL)));}
|
||||
|
||||
//! Vertex opposite to 'v'. NULL if 'v' is not a vertex of the edge.
|
||||
Vertex *oppositeVertex(const Vertex *v) const {return ((v1 == v)?(v2):((v2 == v)?(v1):(NULL)));}
|
||||
|
||||
//! Incident triangle opposite to 't'. NULL if 't' is not incident to the edge.
|
||||
Triangle *oppositeTriangle(const Triangle *t) const {return ((t1 == t)?(t2):((t2 == t)?(t1):(NULL)));}
|
||||
|
||||
//! Replace vertex 'a' with vertex 'b' in the edge and return TRUE. If 'a' is not a vertex of the edge return FALSE.
|
||||
bool replaceVertex(const Vertex *a, Vertex *b) {if (v1==a) v1=b; else if (v2==a) v2=b; else return 0; return 1;}
|
||||
|
||||
//! Replace incident triangle 'a' with 'b' and return TRUE. If 'a' is not incident to the edge return FALSE.
|
||||
bool replaceTriangle(const Triangle *a, Triangle *b) {if (t1==a) t1=b; else if (t2==a) t2=b; else return 0; return 1;}
|
||||
|
||||
//! Vertex shared with edge 'b'. NULL if this and 'b' do not share any vertex.
|
||||
Vertex *commonVertex(const Edge *b) const {return ((v1 == b->v1 || v1 == b->v2)?(v1):((v2 == b->v1 || v2 == b->v2)?(v2):(NULL)));}
|
||||
|
||||
//! TRUE iff edge is on the boundary (i.e., one of the two incident triangles is NULL).
|
||||
bool isOnBoundary() const {return (t1 == NULL || t2 == NULL);}
|
||||
|
||||
//! TRUE iff edge is isolated (i.e., both the two incident triangles are NULL).
|
||||
bool isIsolated() const {return (t1 == NULL && t2 == NULL);}
|
||||
|
||||
//! TRUE iff the two endpoints coincide exactly
|
||||
bool isDegenerate() const {return ((*v1)==(*v2));}
|
||||
|
||||
//! If the edge is on boundary return its only incident triangle. NULL otherwise.
|
||||
Triangle *getBoundaryTriangle() const {return (t2 == NULL)?(t1):((t1 == NULL)?(t2):(NULL));}
|
||||
|
||||
//! Print the coordinates of the end-ponts to the file handler pointed to by 'f' (stdout by default).
|
||||
void printEdge(FILE *f =stdout) const {v1->printPoint(f); v2->printPoint(f);}
|
||||
|
||||
//! Combinatorial edge-swap.
|
||||
|
||||
//! Vertices of the edge are replaced with vertices of the two incident triangles which are opposite to this edge.
|
||||
//! Connectivity information is updated properly.
|
||||
//! If the edge is on boundary or if the edge after the swap already exists return FALSE and do not change anything.
|
||||
//! Return TRUE on success.
|
||||
//! If 'fast' is set, no topological check is performed.
|
||||
TMESH_VIRTUAL bool swap(const bool fast=0);
|
||||
|
||||
//! Edge collapse.
|
||||
|
||||
//! This method collapses the edge and updates the connectivity of the
|
||||
//! neighboring elements consistently. The edge will be contracted into its
|
||||
//! first vertex v1 (or v2, for collapseOnV2()).
|
||||
//! This method returns v1 (or v2) on success, NULL otherwise.
|
||||
//! Failure occurs when the collapse would produce an invalid connectivity graph.
|
||||
//! Caution! If the collapse succeeds the
|
||||
//! edge, its incident triangles and the second vertex are unlinked, but
|
||||
//! they are still present in the lists of the Basic_TMesh.
|
||||
//! The calling function is responsible of removing them from the lists using
|
||||
//! the method removeUnlinkedElements().
|
||||
Vertex *collapseOnV1();
|
||||
Vertex *collapseOnV2();
|
||||
|
||||
//! This method collapses the edge and updates the connectivity of the
|
||||
//! neighboring elements consistently. The edge will be transformed into a
|
||||
//! vertex with the coordinates of 'p'.
|
||||
//! This method returns TRUE on success, FALSE otherwise.
|
||||
//! Failure occurs when the collapse would produce an invalid connectivity graph.
|
||||
//! Caution! If the collapse succeeds the
|
||||
//! edge, its incident triangles and the second vertex are unlinked, but
|
||||
//! they are still present in the lists of the Basic_TMesh.
|
||||
//! The calling function is responsible of removing them from the lists using
|
||||
//! the method removeUnlinkedElements().
|
||||
bool collapse(const Point& p);
|
||||
|
||||
//! Edge collapse.
|
||||
|
||||
//! This method collapses the edge and updates the connectivity of the
|
||||
//! neighboring elements consistently. The edge will be transformed into a
|
||||
//! vertex placed at the edge's mid-point.
|
||||
//! This method returns TRUE on success, FALSE otherwise.
|
||||
//! Failure occurs when the collapse would produce an invalid connectivity graph.
|
||||
//! Caution! If the collapse succeeds the
|
||||
//! edge, its incident triangles and the second vertex are unlinked, but
|
||||
//! they are still present in the lists of the Basic_TMesh.
|
||||
//! The calling function is responsible of removing them from the lists using
|
||||
//! the method removeUnlinkedElements().
|
||||
bool collapse();
|
||||
|
||||
//! Merge with another boundary edge.
|
||||
|
||||
//! If both this and 'e' are boundary edges, the edge 'e' is identified with
|
||||
//! this one, and the connectivity of the neighboring elements is updated consistently.
|
||||
//! This method returns TRUE on success, FALSE otherwise.
|
||||
//! Failure occurs when the merge would produce an invalid connectivity graph (i.e., non orientable).
|
||||
//! Caution! If the merge succeeds the edge 'e' and its two end-points
|
||||
//! are unlinked, but they are still present in the lists of the
|
||||
//! Basic_TMesh. It's responsibility of the calling function to remove
|
||||
//! them from the lists using the method removeUnlinkedElements().
|
||||
bool merge(Edge *e);
|
||||
|
||||
//! Stitching primitive.
|
||||
|
||||
//! If there is a copy of this edge incident to one of the end-points,
|
||||
//! identify it with this edge, and update the connectivity properly.
|
||||
//! This method returns TRUE on success, FALSE otherwise.
|
||||
//! Caution! If the stitch succeeds, the duplicated edge
|
||||
//! is unlinked, but it is still present in the lists of the
|
||||
//! Basic_TMesh. It's responsibility of the calling function to remove
|
||||
//! it from the lists using the method removeEdges().
|
||||
bool stitch();
|
||||
|
||||
//! Returns TRUE if edge is not on boundary and its two incident triangles overlap
|
||||
bool overlaps() const;
|
||||
|
||||
//! true if this edge itersects 't' other than on common subsimplexes
|
||||
bool intersects(const Triangle *t) const;
|
||||
|
||||
//! Returns a positive value if dihedral angle is less than flat (convex), 0 if flat,
|
||||
//! negative if more than flat (concave). Returns DBL_MAX if edge is on boundary.
|
||||
coord getConvexity() const;
|
||||
|
||||
// FUNCTIONS BELOW THIS LINE MAY RETURN APPROXIMATED/NOT ROBUST RESULTS EVEN WHEN USING RATIONALS
|
||||
|
||||
|
||||
|
||||
//! Euclidean length of the edge.
|
||||
double length() const { return v1->distance(v2); }
|
||||
|
||||
//! Convert to normalized vector (v2-v1)/|v2-v1|.
|
||||
Point toUnitVector() const;
|
||||
|
||||
//! Return the normal at the edge as the average of the normals of the two incident triangles.
|
||||
//! A null (0,0,0) vector is returned if the edge is on boundary.
|
||||
Point getNormal() const;
|
||||
|
||||
//! Return the minimum among the six angles of the two incident triangles.2PI if on boundary.
|
||||
double delaunayMinAngle() const;
|
||||
|
||||
//! Dihedral angle at the edge.
|
||||
double dihedralAngle() const;
|
||||
|
||||
//! Angle between the normals of the two incident triangles.
|
||||
|
||||
//! Angle between the normals of the two incident triangles. If
|
||||
//! the edge is on boundary or one or both the incident triangles are
|
||||
//! degenerate, return -1.
|
||||
double curvature() const;
|
||||
};
|
||||
|
||||
//! Edge comparison based on length to be used with jqsort() or abstractHeap.
|
||||
int edgeCompare(const Data *a, const Data *b);
|
||||
|
||||
//! Lexycographic edge comparison to be used with jqsort() or abstractHeap.
|
||||
int lexEdgeCompare(const Data *a, const Data *b);
|
||||
|
||||
//! Vertex-based edge comparison for qsort.
|
||||
//! Duplicated edges are contiguous in this sorting.
|
||||
int vtxEdgeCompare(const Data *a, const Data *b);
|
||||
|
||||
} //namespace T_MESH
|
||||
|
||||
#endif //_EDGE_H
|
||||
|
133
src/mesh_fix/include/TMesh/marchIntersections.h
Normal file
133
src/mesh_fix/include/TMesh/marchIntersections.h
Normal file
@ -0,0 +1,133 @@
|
||||
/****************************************************************************
|
||||
* TMesh *
|
||||
* *
|
||||
* Consiglio Nazionale delle Ricerche *
|
||||
* Istituto di Matematica Applicata e Tecnologie Informatiche *
|
||||
* Sezione di Genova *
|
||||
* IMATI-GE / CNR *
|
||||
* *
|
||||
* Authors: Marco Attene *
|
||||
* Copyright(C) 2013: IMATI-GE / CNR *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is dual-licensed as follows: *
|
||||
* *
|
||||
* (1) You may use TMesh as 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. *
|
||||
* In this case the 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 (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
* (2) You may use TMesh as part of a commercial software. In this case a *
|
||||
* proper agreement must be reached with the Authors and with IMATI-GE/CNR *
|
||||
* based on a proper licensing contract. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef MARCHING_INTS_H
|
||||
#define MARCHING_INTS_H
|
||||
|
||||
#include "tmesh.h"
|
||||
|
||||
namespace T_MESH
|
||||
{
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
//
|
||||
// A ray-mesh intersection.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////
|
||||
|
||||
class mc_ints : public Data
|
||||
{
|
||||
public:
|
||||
|
||||
coord ic; // Distance from ray source
|
||||
unsigned char sg; // 1 if ray enters mesh, 0 if it exits
|
||||
ExtVertex *v; // Used to support polygonization
|
||||
Triangle *source; // The triangle that generates this intersection
|
||||
|
||||
mc_ints(coord a, unsigned char b, Triangle *s) { ic = a; sg = b; v = NULL; source = s; }
|
||||
~mc_ints() { if (v) delete(v); }
|
||||
|
||||
static int compare(const Data *e1, const Data *e2);
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
//
|
||||
// A cubical cell to be polygonized
|
||||
//
|
||||
///////////////////////////////////////////////////////////////
|
||||
|
||||
class mc_cell : public Data
|
||||
{
|
||||
public:
|
||||
int x,y,z; // Coordinates (i.e. cell's position)
|
||||
mc_ints *ints[12]; // Intersection at each voxel edge
|
||||
|
||||
mc_cell(int a, int b, int c) {x=a; y=b; z=c;}
|
||||
mc_cell(int a, int b, int c, mc_ints *m, int i) : x(a), y(b), z(c)
|
||||
{
|
||||
for (int n=0; n<12; n++) ints[n] = (n==i)?(m):(NULL);
|
||||
}
|
||||
|
||||
void polygonize(Basic_TMesh *tin);
|
||||
static int compare(const void *e1, const void *e2);
|
||||
|
||||
void merge(mc_cell *m);
|
||||
|
||||
private:
|
||||
unsigned char lookup() const; // The polygonization to be used
|
||||
unsigned char lookdown(); // The other polygonization to be used
|
||||
void purgeIntersections(); // TRUE if intersections are consistent in the cell
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
//
|
||||
// The marching intersections grid
|
||||
//
|
||||
///////////////////////////////////////////////////////////////
|
||||
|
||||
class mc_grid : public Data
|
||||
{
|
||||
Point origin; // Origin for normalization
|
||||
coord norm; // Normalization factor
|
||||
protected: //! < AMF_CHANGE - since T_MESH 2.4-2 >
|
||||
Basic_TMesh *tin; // Triangulation to remesh //! < AMF_CHANGE - since T_MESH 2.4-2 >
|
||||
List *xy, *xz, *zy; // Axis-parallel rays //! < AMF_CHANGE - since T_MESH 2.4-2 >
|
||||
int numrays; // Number of rays per axis //! < AMF_CHANGE - since T_MESH 2.4-2 >
|
||||
|
||||
public:
|
||||
mc_grid(Basic_TMesh *_tin, int n);
|
||||
~mc_grid() {delete [] xy; delete [] xz; delete [] zy;}
|
||||
|
||||
TMESH_VIRTUAL mc_ints * newMcInts(coord a, unsigned char b, Triangle *s){ return new mc_ints(a,b,s); } //! < AMF_CHANGE - since T_MESH 2.4-2 >
|
||||
|
||||
void remesh(bool simplify_result =false);
|
||||
void simplify();
|
||||
|
||||
static bool segmentIntersectsTriangle(Point& ev1, Point& ev2, Triangle *t, Point& op);
|
||||
|
||||
protected: //! < AMF_CHANGE - since T_MESH 2.4-2 >
|
||||
TMESH_VIRTUAL void sample_triangle(Triangle *t); //! < AMF_CHANGE - since T_MESH 2.4-2 >
|
||||
TMESH_VIRTUAL void createVertices(List *l, int i, int j, int k); //! < AMF_CHANGE - since T_MESH 2.4-2 >
|
||||
private:
|
||||
void sort();
|
||||
void purge();
|
||||
void createVertices();
|
||||
List *createCells();
|
||||
void trackOuterHull();
|
||||
|
||||
static inline coord oceil(const coord& d) { coord c; return ((c = ceil(d)) == d) ? (c + 1) : (c); }
|
||||
void purgeList(List *l);
|
||||
};
|
||||
|
||||
} //namespace T_MESH
|
||||
|
||||
#endif // MARCHING_INTS_H
|
804
src/mesh_fix/include/TMesh/tin.h
Normal file
804
src/mesh_fix/include/TMesh/tin.h
Normal file
@ -0,0 +1,804 @@
|
||||
/****************************************************************************
|
||||
* TMesh *
|
||||
* *
|
||||
* Consiglio Nazionale delle Ricerche *
|
||||
* Istituto di Matematica Applicata e Tecnologie Informatiche *
|
||||
* Sezione di Genova *
|
||||
* IMATI-GE / CNR *
|
||||
* *
|
||||
* Authors: Marco Attene *
|
||||
* Copyright(C) 2013: IMATI-GE / CNR *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is dual-licensed as follows: *
|
||||
* *
|
||||
* (1) You may use TMesh as 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. *
|
||||
* In this case the 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 (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
* (2) You may use TMesh as part of a commercial software. In this case a *
|
||||
* proper agreement must be reached with the Authors and with IMATI-GE/CNR *
|
||||
* based on a proper licensing contract. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef _TIN_H
|
||||
#define _TIN_H
|
||||
|
||||
#include "tmesh.h"
|
||||
|
||||
namespace T_MESH
|
||||
{
|
||||
|
||||
//! Basic_TMesh
|
||||
|
||||
//! This class represents a manifold and oriented triangle mesh.
|
||||
//! Vertices, Edges and Triangles are stored in the Lists V, E and T
|
||||
//! respectively. Methods boundaries(), handles() and shells() may
|
||||
//! be used to retrieve the respective topological entities.
|
||||
//! Navigation of the mesh is based on the topological relationships
|
||||
//! stored in each Vertex, Edge and Triangle.
|
||||
//! Some methods would require a global update only to maintain
|
||||
//! consistent values of the protected fields n_boundaries, n_handles
|
||||
//! and n_shells. On the other hand, the same methods would work in
|
||||
//! constant time if these values would not need to be updated.
|
||||
//! To keep complexity as low as possible,
|
||||
//! we make use of the 'dirty bits' d_boundaries, d_handles and
|
||||
//! d_shells to mark that the respective entities must be updated.
|
||||
//! The access functions boundaries(), handles() and shells()
|
||||
//! check the status of the respective dirty bit and do a global
|
||||
//! update (i.e., eulerUpdate()) only if necessary.
|
||||
//! The complexity of the methods is provided as a function of a
|
||||
//! generic 'N', which is O(V.numels()) = O(E.numels()) = O(T.numels()).
|
||||
|
||||
class Basic_TMesh
|
||||
{
|
||||
protected:
|
||||
|
||||
int n_boundaries; //!< Number of boundary loops
|
||||
int n_handles; //!< Number of handles
|
||||
int n_shells; //!< Number of connected components
|
||||
|
||||
bool d_boundaries; //!< Dirty bit for n_boundaries
|
||||
bool d_handles; //!< Dirty bit for n_handles
|
||||
bool d_shells; //!< Dirty bit for n_shells
|
||||
|
||||
public:
|
||||
|
||||
List V; //!< Vertex set
|
||||
List E; //!< Edge set
|
||||
List T; //!< Triangle set
|
||||
|
||||
void *info; //! Generic information attached to this mesh
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Constructors/Destructor (Implemented in "MESH_STRUCTURE/io.cpp")
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//! Empty triangulation. Should be used only prior to a call to load().
|
||||
Basic_TMesh();
|
||||
|
||||
//! Pre-defined triangulation. Currently, only "triangle" and "tetrahedron"
|
||||
//! are recognized.
|
||||
Basic_TMesh(const char *);
|
||||
void init(const char *);
|
||||
|
||||
//! Clones an existing Trianglation.
|
||||
Basic_TMesh(const Basic_TMesh *, const bool clone_info = false);
|
||||
void init(const Basic_TMesh *, const bool clone_info = false);
|
||||
|
||||
//! Clones an existing connected component.
|
||||
|
||||
//! Creates a new Basic_TMesh out of a connected component of an existing
|
||||
//! Basic_TMesh. 't' is a triangle of the connected component that must
|
||||
//! be copied. If 'keep_ref' is TRUE, each element of the existing mesh
|
||||
//! keeps a pointer to the corresponding new element in the 'info' field.
|
||||
Basic_TMesh(const Triangle *t, const bool keep_ref = false);
|
||||
void init(const Triangle *t, const bool keep_ref = false);
|
||||
|
||||
//FIXED:
|
||||
//! Destructor. Frees the memory allocated for all the mesh elements.
|
||||
//! Warning! This method uses the freeNodes() method of the class List,
|
||||
//! which is not guaranteed to work correctly on systems other than
|
||||
//! Linux (see the documentation of List for details).
|
||||
//! Assuming that the method works correctly, however, the calling
|
||||
//! function is responsible of freeing the memory that was possibly
|
||||
//! allocated for objects pointed to by the 'info' field of mesh
|
||||
//! elements. Clearly, this must be done before calling the destructor.
|
||||
~Basic_TMesh();
|
||||
|
||||
//! Returns true only if object is a basic Basic_TMesh. All the reimplementations must return false.
|
||||
// TMESH_VIRTUAL bool isBaseType() const { return true; }
|
||||
|
||||
//! Get the number of boundary loops of the triangle mesh. O(1) or O(N).
|
||||
int boundaries() { if (d_boundaries) eulerUpdate(); return n_boundaries; }
|
||||
|
||||
//! Get the number of handles of the triangle mesh. O(1) or O(N).
|
||||
int handles() { if (d_handles) eulerUpdate(); return n_handles; }
|
||||
|
||||
//! Get the number of connected components of the triangle mesh. O(1) or O(N).
|
||||
int shells() { if (d_shells) eulerUpdate(); return n_shells; }
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Input/Output methods (Implemented in "MESH_STRUCTURE/io.cpp")
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//! Initialize the triangle mesh from the file 'filename'.
|
||||
|
||||
//! The file format is automatically deduced from the magic number
|
||||
//! or the filename extension. If 'doupdate' is FALSE, the
|
||||
//! global update for the topological entities is prevented.
|
||||
//! Currently, the following file formats are supported:
|
||||
//! Open Inventor (IV), VRML 1.0 and 2.0 (WRL), Object File Format (OFF),
|
||||
//! IMATI Ver-Tri (VER, TRI), PLY, OBJ, STL.
|
||||
//! A non-zero value is returned in case of error. Specifically,
|
||||
//! IO_CANTOPEN means that the file couldn't be opened for reading.
|
||||
//! IO_FORMAT means that the file format was not recognized by the loader.
|
||||
//! IO_UNKNOWN represents all the other errors.
|
||||
//! The calling function is responsible of verifying that the mesh is
|
||||
//! empty before calling this method.
|
||||
|
||||
int load(const char *filename, const bool update = 1);
|
||||
int loadIV(const char *); //!< Loads IV
|
||||
int loadVRML1(const char *); //!< Loads VRML 1.0
|
||||
int loadOFF(const char *); //!< Loads OFF
|
||||
int loadEFF(const char *); //!< Loads EFF
|
||||
int loadPLY(const char *); //!< Loads PLY
|
||||
int loadVerTri(const char *); //!< Loads VER-TRI
|
||||
int loadVRML2(const char *); //!< Loads VRML 2.0
|
||||
int loadOBJ(const char *); //!< Loads OBJ
|
||||
int loadSTL(const char *); //!< Loads STL
|
||||
|
||||
int cutAndStitch(); //!< Convert to manifold
|
||||
Triangle * CreateIndexedTriangle(ExtVertex **, int, int, int);
|
||||
TMESH_VIRTUAL Triangle * CreateTriangleFromVertices(ExtVertex *, ExtVertex *, ExtVertex *);
|
||||
|
||||
//! This function approximates the vertex coordinates with the values
|
||||
//! that can be represented in an ASCII file.
|
||||
void coordBackApproximation();
|
||||
|
||||
protected:
|
||||
void closeLoadingSession(FILE *, int, ExtVertex **, bool);
|
||||
bool pinch(Edge *e, bool wcv);
|
||||
//! If the 'e' is internal, creates a copy of the edge and associates e->t2
|
||||
//! to this copy. After this operation, 'e' and its copy are boundary edges
|
||||
//! with the same vertices. If 'e' is already on boundary, nothing is done
|
||||
//! and NULL is returned. Otherwise the newly created copy is returned.
|
||||
TMESH_VIRTUAL Edge *duplicateEdge(Edge *e);
|
||||
|
||||
public:
|
||||
TMESH_VIRTUAL Vertex * newVertex();
|
||||
TMESH_VIRTUAL Vertex * newVertex(const coord &, const coord &, const coord &);
|
||||
TMESH_VIRTUAL Vertex * newVertex(Point *);
|
||||
TMESH_VIRTUAL Vertex * newVertex(Point &);
|
||||
TMESH_VIRTUAL Vertex * newVertex(Vertex *);
|
||||
TMESH_VIRTUAL Edge * newEdge(Vertex *, Vertex *);
|
||||
TMESH_VIRTUAL Edge * newEdge(Edge *);
|
||||
TMESH_VIRTUAL Triangle * newTriangle();
|
||||
TMESH_VIRTUAL Triangle * newTriangle(Edge *, Edge *, Edge *);
|
||||
TMESH_VIRTUAL Basic_TMesh * newObject() const { return new Basic_TMesh(); }
|
||||
TMESH_VIRTUAL Basic_TMesh * newObject(const Basic_TMesh *tm, const bool ci = false) const { return new Basic_TMesh(tm, ci); }
|
||||
TMESH_VIRTUAL Basic_TMesh * newObject(const char *s) const { return new Basic_TMesh(s); }
|
||||
|
||||
//! Save the triangle mesh to file 'filename'.
|
||||
|
||||
//! The file format is deduced from the filename extension
|
||||
//! (wrl = vrml 1.0), (iv = OpenInventor), (off = Object
|
||||
//! file format), (ply = PLY format), (tri = IMATI Ver-Tri).
|
||||
//! If 'back_approx' is set, vertex coordinates are approximated
|
||||
//! to reflect the limited precision of floating point
|
||||
//! representation in ASCII files. This should be used when
|
||||
//! coherence is necessary between in-memory and saved data.
|
||||
//! A non-zero return value is returned if errors occur.
|
||||
|
||||
int save(const char *filename, bool back_approx = 0);
|
||||
|
||||
int saveIV(const char *); //!< Saves IV
|
||||
int saveOFF(const char *); //!< Saves OFF 1.0
|
||||
int saveEFF(const char *); //!< Saves EFF
|
||||
int saveOBJ(const char *); //!< Saves OBJ
|
||||
int saveSTL(const char *); //!< Saves STL
|
||||
int savePLY(const char *, bool ascii = 1); //!< Saves PLY 1.0 (ascii or binary)
|
||||
int saveVerTri(const char *); //!< Saves Ver-Tri
|
||||
|
||||
//! Saves the triangle mesh to a VRML 1.0 file.
|
||||
//! The value of 'mode' specifies whether to use additional
|
||||
//! information attached to mesh elements in order to assign
|
||||
//! them a proper color.
|
||||
//! IO_CSAVE_OVERALL assigns a unique color for the entire mesh (default).
|
||||
//! IO_CSAVE_PERFACE assigns a color to each triangle depending on the value
|
||||
//! of its 'info' field.
|
||||
//! IO_CSAVE_PERVERTEX assigns a color to each vertex depending on the value
|
||||
//! of its 'info' field.
|
||||
//! IO_CSAVE_PERFACE_INDEXED assigns one of five base colors to each triangle
|
||||
//! depending on the value of its 'mask' field.
|
||||
//! IO_CSAVE_PERVERTEX_INDEXED assigns one of five base colors to each vertex
|
||||
//! depending on the value of its 'mask' field.
|
||||
int saveVRML1(const char *, const int mode = 0);
|
||||
|
||||
|
||||
//! Append another triangle mesh to the existing one.
|
||||
|
||||
//! This method works exactly as the 'load()' method, except for the fact
|
||||
//! that it does not assume that the mesh is empty.
|
||||
int append(const char *filename, const bool doupdate = 1);
|
||||
|
||||
|
||||
// Move all the elements of 't' to this mesh and delete 't' itself.
|
||||
TMESH_VIRTUAL void moveMeshElements(Basic_TMesh *t, bool delInput = true);
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Primitive Construction (Implemented in "MESH_STRUCTURE/tin.cpp")
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//! Creates an Edge connecting two existing mesh vertices.
|
||||
|
||||
//! Returns the newly created edge. If an edge connecting the two vertices
|
||||
//! already exists in the mesh, then no new edge is created and the old one
|
||||
//! is returned.
|
||||
Edge *CreateEdge(Vertex *v1, Vertex *v2);
|
||||
|
||||
|
||||
//! Creates an Edge connecting two existing mesh Extended vertices.
|
||||
|
||||
//! Returns the newly created edge. If an edge connecting the two vertices
|
||||
//! already exists in the mesh, then no new edge is created and the old one
|
||||
//! is returned.
|
||||
//! If 'check' is FALSE, the check for previously existing edges is skipped.
|
||||
Edge *CreateEdge(ExtVertex *v1, ExtVertex *v2, const bool check = 1);
|
||||
|
||||
|
||||
//! Creates a properly oriented Triangle bounded by three existing mesh edges.
|
||||
|
||||
//! Returns the newly created Triangle. If e1, e2 and e3
|
||||
//! are not suitable for creating a properly oriented and
|
||||
//! manifold triangle, the creation fails and NULL is returned.
|
||||
TMESH_VIRTUAL Triangle * CreateTriangle(Edge *e1, Edge *e2, Edge *e3);
|
||||
|
||||
|
||||
//! Creates an arbitrarily oriented Triangle bounded by three existing mesh edges.
|
||||
|
||||
//! Returns the newly created Triangle. If either e1, e2 or e3
|
||||
//! has already two incident triangles, the creation fails and NULL is returned.
|
||||
//! This method assumes that e1, e2 and e3 are incident to exactly three vertices.
|
||||
TMESH_VIRTUAL Triangle * CreateUnorientedTriangle(Edge *, Edge *, Edge *);
|
||||
|
||||
|
||||
//! Creates a newEdge 'e' and an oriented Triangle bounded by 'e', 'e1' and 'e2'.
|
||||
|
||||
//! The newly created triangle is returned, unless 'e1' and 'e2' do not share a
|
||||
//! vertex or they are not boundary edges. In this cases, NULL is returned.
|
||||
TMESH_VIRTUAL Triangle *EulerEdgeTriangle(Edge *e1, Edge *e2);
|
||||
|
||||
|
||||
//! Splits and edge at a given point and returns the newly created Vertex.
|
||||
//! If the boolean parameter is set to true, the 'mask' fields of edges and
|
||||
//! triangles are propagated to the new elements.
|
||||
TMESH_VIRTUAL Vertex *splitEdge(Edge *, Point *, bool = 0);
|
||||
|
||||
|
||||
//! Splits a triangle at a given point and returns the newly created Vertex.
|
||||
//! If the boolean parameter is set to true, the 'mask' field of the
|
||||
//! triangle is propagated to the new triangle.
|
||||
TMESH_VIRTUAL Vertex *splitTriangle(Triangle *, Point *, bool = 0);
|
||||
|
||||
//! Creates two new triangles connecting the boundary edges e1 and e2
|
||||
//! and returns their common edge.
|
||||
//! If e1 and e2 share a vertex, then only one triangle is created and
|
||||
//! e1 is returned.
|
||||
//! Returns NULL if either e1 or e2 are not boundary edges.
|
||||
TMESH_VIRTUAL Edge *bridgeBoundaries(Edge *e1, Edge *e2);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Primitive Destruction (Implemented in "MESH_STRUCTURE/tin.cpp")
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
//! Unlinks a triangle from the mesh. O(1).
|
||||
|
||||
//! Resulting isolated vertices and edges are unlinked too.
|
||||
//! If necessary, this method duplicates non-manifold vertices that can
|
||||
//! occur due to the removal of the triangle.
|
||||
//! The unlinked triangle, along with the other possible unlinked elements,
|
||||
//! must be removed from the List T through removeUnlinkedElements().
|
||||
void unlinkTriangle(Triangle *);
|
||||
|
||||
|
||||
//! Unlinks a triangle from the mesh. O(1).
|
||||
|
||||
//! No check is performed on the resulting topology, which may be inconsistent.
|
||||
//! The unlinked triangle, along with the other possible unlinked elements,
|
||||
//! must be removed from the List T through removeUnlinkedElements().
|
||||
void unlinkTriangleNoManifold(Triangle *);
|
||||
|
||||
|
||||
//! Removes a triangle from the mesh. O(N).
|
||||
|
||||
//! This is equivalent to an unlinkTriangle(t) followed by a
|
||||
//! removeUnlinkedElements().
|
||||
void removeTriangle(Triangle *t) { unlinkTriangle(t); removeUnlinkedElements(); }
|
||||
|
||||
//! Removes all the unlinked triangles from List T. Returns the number of removed triangles. O(N).
|
||||
int removeTriangles();
|
||||
|
||||
//! Removes all the unlinked edges from List E. Returns the number of removed edges. O(N).
|
||||
int removeEdges();
|
||||
|
||||
//! Removes all the unlinked vertices from List V. Returns the number of removed vertices. O(N).
|
||||
int removeVertices();
|
||||
|
||||
//! Removes all the unlinked elements from the lists. Returns the number of removed elements. O(N).
|
||||
int removeUnlinkedElements() { return removeTriangles() + removeEdges() + removeVertices(); }
|
||||
|
||||
//! Removes all the vertices that can be deleted without changing the geometric realization. O(N).
|
||||
int removeRedundantVertices();
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Methods acting on selections (Implemented in "MESH_STRUCTURE/tin.cpp")
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//! Deselects all the triangles. O(N).
|
||||
void deselectTriangles();
|
||||
|
||||
//! Removes all the selected triangles. O(N).
|
||||
void removeSelectedTriangles();
|
||||
|
||||
//! Selects all the triangles having at least one boundary vertex. O(N).
|
||||
//! Returns the number of selected triangles.
|
||||
int selectBoundaryTriangles();
|
||||
|
||||
//! Enlarges the current selection of one triangle in width. O(N).
|
||||
|
||||
//! Each triangle sharing at least one vertex with a currently selected
|
||||
//! triangle becomes selected.
|
||||
//! Returns the number of newly selected triangles.
|
||||
int growSelection();
|
||||
|
||||
//! Shrinks the current selection of one triangle in width. O(N).
|
||||
|
||||
//! Each triangle sharing at least one vertex with a currently unselected
|
||||
//! triangle becomes unselected.
|
||||
void shrinkSelection();
|
||||
|
||||
//! Inverts the selection status of all the triangles. O(N).
|
||||
|
||||
//! If 't0' is not NULL, then only the connected component containing 't0'
|
||||
//! is inverted.
|
||||
void invertSelection(Triangle *t0 = NULL);
|
||||
|
||||
//! If 't0' is selected, deselect everything but the selected triangles connected to 't0'
|
||||
void reselectSelection(Triangle *t0);
|
||||
|
||||
//! Creates a new Basic_TMesh out of an existing selection containing 't0'. O(output).
|
||||
|
||||
//! If necessary, non-manifold vertices are properly duplicated.
|
||||
//! If 'keep_ref' is set to TRUE, then elements of the original mesh point
|
||||
//! (through their info field) to corresponding elements of the newly created copy.
|
||||
|
||||
TMESH_VIRTUAL Basic_TMesh *createSubMeshFromSelection(Triangle *t0 = NULL, bool keep_ref = 0);
|
||||
|
||||
//! Creates a new Basic_TMesh out of an existing triangle 't0'. O(output).
|
||||
|
||||
TMESH_VIRTUAL Basic_TMesh *createSubMeshFromTriangle(Triangle *t0);
|
||||
|
||||
//! Marks all the triangles within distance L from 'p' as selected. O(output).
|
||||
|
||||
//! A triangle is considered to be within distance L from 'p' only if all
|
||||
//! its three vertices are so.
|
||||
//! Point 'p' is assumed to belong to triangle 't0', which is required to
|
||||
//! limit the complexity to the size of the selected region.
|
||||
//! Returns the number of selected triangles.
|
||||
int selectSphericalRegion(Triangle *t0, const double L, const Point *p);
|
||||
|
||||
|
||||
//! Marks all the triangles within distance L from 'p' as deselected. O(output).
|
||||
|
||||
//! A triangle is considered to be within distance L from 'p' only if all
|
||||
//! its three vertices are so.
|
||||
//! Point 'p' is assumed to belong to triangle 't0', which is required to
|
||||
//! limit the complexity to the size of the selected region.
|
||||
//! Returns the number of deselected triangles.
|
||||
int deselectSphericalRegion(Triangle *t0, const double L, const Point *p);
|
||||
|
||||
|
||||
//! Deselects all the triangles farther than L from 'p'. O(N).
|
||||
|
||||
//! A triangle is considered to be farther than L from 'p' if at least
|
||||
//! one of its three vertices is so.
|
||||
//! Point 'p' is assumed to belong to triangle 't0'. Passing 't0' avoids
|
||||
//! the non robust and expensive computation of point-in-triangle.
|
||||
void reselectSphericalRegion(Triangle *t0, const double L, const Point *p);
|
||||
|
||||
//! Re-triangulates the currently selected region using a Delaunay-like approach. O(SlogS).
|
||||
|
||||
//! A common plane is computed as the average of the planes of the triangles selected;
|
||||
//! then, the vertices of the region are projected on the plane and edges are iteratively
|
||||
//! swapped up to convergence (which is guaranteed on planar and simple domains).
|
||||
//! Finally, the vertices are moved back to their original positions. This operation is
|
||||
//! particularly useful to improve the quality of nearly flat regions. The selection must
|
||||
//! be simple and its Gauss map must be entirely contained in a semi-sphere.
|
||||
//! Returns TRUE on success, FALSE otherwise.
|
||||
bool retriangulateSelectedRegion();
|
||||
|
||||
|
||||
//! TRUE iff the set of selected triangles in 'l' is simply connected. O(l->numels()).
|
||||
bool isSelectionSimple(List *l);
|
||||
|
||||
//! Unmarks all the elements but leaves the selection status of triangles as is. O(N).
|
||||
void unmarkEverythingButSelections();
|
||||
|
||||
|
||||
//! Selects all the triangles of the connected component containing t0. O(N).
|
||||
|
||||
//! If 'stop_on_sharp', expansion from 't0' brakes at tagged sharp edges.
|
||||
//! Returns the number of selected triangles.
|
||||
int selectConnectedComponent(Triangle *t0, bool stop_on_sharp = 0);
|
||||
|
||||
|
||||
//! Deselects all the triangles of the connected component containing t0. O(N).
|
||||
|
||||
//! If 'stop_on_sharp', expansion from 't0' brakes at tagged sharp edges.
|
||||
//! Returns the number of deselected triangles.
|
||||
int deselectConnectedComponent(Triangle *t0, bool stop_on_sharp = 0);
|
||||
|
||||
|
||||
//! Append to the current mesh a copy of all the elements of 't'.
|
||||
//! The newly created elements form a new selection.
|
||||
TMESH_VIRTUAL void append(Basic_TMesh *t);
|
||||
|
||||
//! This method removes one connected component from the mesh and creates
|
||||
//! a separate new mesh out of it. The components to be removed is the one
|
||||
//! containing the first triangle in the list T.
|
||||
//! Possible selection flags are deleted by this method.
|
||||
TMESH_VIRTUAL Basic_TMesh *split();
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Region manipulation (Implemented in "MESH_STRUCTURE/tin.cpp")
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//! Make a list of triangles within distance L from 'p'. O(output).
|
||||
|
||||
//! Starting from 't0', which is assumed to contain 'p', add a triangle at a
|
||||
//! time to the list as long as all the vertices stay within distance L from 'p'.
|
||||
List *getRegion(Triangle *t0, const double L, const Point *p);
|
||||
|
||||
//! Removes triangles within distance L from 'p'. O(N).
|
||||
|
||||
//! Starting from 't0', which is assumed to contain 'p', remove a triangle at a
|
||||
//! time as long as all its vertices stay within distance L from 'p'.
|
||||
void removeRegion(Triangle *t0, const double L, const Point *p);
|
||||
|
||||
//! Get the vertex next to 'v' on the boundary of the region. O(1).
|
||||
Vertex *nextVertexOnRegionBoundary(Vertex *v) const;
|
||||
|
||||
//! Retrieve internal vertices of a region. O(l->numels()).
|
||||
|
||||
//! This method returns a list containing an edge of the region's boundary
|
||||
//! as its first element, and all the internal vertices as the remaining elements.
|
||||
List *getRegionInternalVertices(List *l);
|
||||
|
||||
//! Transform the vertices of the shell containing 't0' using the matrix m. O(S).
|
||||
void transformShell(Triangle *t0, const Matrix4x4& m);
|
||||
|
||||
//! Translate the mesh by a vector
|
||||
void translate(const Point& t_vec);
|
||||
|
||||
//! Return the center of mass of the mesh
|
||||
Point getCenter() const;
|
||||
|
||||
//! Remove all the triangles belonging to the shell containing 't0'. O(N).
|
||||
void removeShell(Triangle *t0);
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Global Operations (Implemented in "MESH_STRUCTURE/tin.cpp")
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//! Tag sharp edges based on threshold angle. O(N).
|
||||
|
||||
//! Tag as sharp all the edges in which the normals of the two incident
|
||||
//! triangles form an angle greater than 't'.
|
||||
void sharpEdgeTagging(const double t);
|
||||
|
||||
//! Unmark all the elements. O(N).
|
||||
void unmarkEverything();
|
||||
|
||||
//! Bounding box longest edge. 'b' and 't' are set as the longest diagonal end-points. O(N).
|
||||
coord getBoundingBox(Point& b, Point& t) const;
|
||||
|
||||
//! Bounding box longest diagonal. O(N).
|
||||
double bboxLongestDiagonal() { Point a, b; getBoundingBox(a, b); return a.distance(b); }
|
||||
|
||||
//! Approximate bounding ball radius. O(N).
|
||||
double getBoundingBallRadius() const;
|
||||
|
||||
//! Total area of the mesh. O(N).
|
||||
double area() const;
|
||||
|
||||
//! Total volume of the mesh assuming that boundaries() = 0. O(N).
|
||||
double volume() const;
|
||||
|
||||
//! Scale the mesh to make it fit within a cube [0,0,0]-[s,s,s]. O(N).
|
||||
void normalize(const coord s = 1.0);
|
||||
|
||||
//! Scale the mesh to make it fit within a cube [0,0,0]-[s,s,s] and snap coordinates on grid points O(N).
|
||||
void quantize(const int s = 65536);
|
||||
|
||||
//! Transform the mesh geometry using the transformation matrix m. O(N).
|
||||
void transform(const Matrix4x4& m);
|
||||
|
||||
//! Randomly move vertices along their normals. O(N).
|
||||
//! Displacement is bounded by 'p'% of the bounding ball radius.
|
||||
void addNormalNoise(const double p);
|
||||
|
||||
//! Iteratively swaps edges to minimize the Delaunay minimum angle. O(N).
|
||||
|
||||
//! Edges tagged as sharp are constrained not to swap.
|
||||
//! On generically curved manifolds this process is not guaranteed to converge.
|
||||
//! This method returns TRUE if convergence is reached, FALSE otherwise.
|
||||
bool iterativeEdgeSwaps();
|
||||
|
||||
//! True if the mesh properly contains 'p' (exact when using rationals).
|
||||
//! The mesh is assumed to be a well-defined polyhedron (i.e. no boundary,
|
||||
//! no degenerate triangles, no self-intersections) and to have a correct orientation:
|
||||
//! result is undetermined otherwise.
|
||||
bool isInnerPoint(Point& p) const;
|
||||
|
||||
//! Performs one step of Loop subdivision. If 'midpoint' is set, only the connectivity
|
||||
//! is subdivided, whereas the surface shape is kept unchanged.
|
||||
void loopSubdivision(bool midpoint =false);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Surface topology manipulation (Implemented in "MESH_STRUCTURE/tin.cpp")
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//! Invert all the triangle and edge orientations. O(N).
|
||||
void flipNormals();
|
||||
|
||||
//! Invert the orientation of triangles and edges belonging to the shell containing 't0'. O(S).
|
||||
void flipNormals(Triangle *t0);
|
||||
|
||||
//! Return the triangle with the maximum 'z' coordinate in the shell containing 't0'. O(N).
|
||||
|
||||
//! Useful for orienting meshes bounding solids.
|
||||
Triangle *topTriangle(Triangle *t0);
|
||||
|
||||
//! Updates the values of n_boundaries, n_handles and n_shells. O(N).
|
||||
|
||||
//! The relative dirty bits are set to zero.
|
||||
void eulerUpdate();
|
||||
|
||||
//! Duplicates edges and vertices to make the mesh homeomorphic to a disk. O(N).
|
||||
void openToDisk();
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Topological fixes (Implemented in "MESH_STRUCTURE/checkAndRepair.cpp")
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//! Removes all connected components but the one having most triangles.
|
||||
//! Returns the number of components removed.
|
||||
int removeSmallestComponents();
|
||||
|
||||
//! Checks that triangles are consistently oriented and, if they are not,
|
||||
//! invert some of them to achieve an overall consistency. If the mesh is
|
||||
//! not orientable cut it. Returns: 0 if mesh was already oriented; 1 if
|
||||
//! the mesh could be oriented without cuts; >1 if cuts were necessary.
|
||||
int forceNormalConsistence();
|
||||
|
||||
//! Same as above, but acts on a single connected component and uses one
|
||||
//! specific triangle from which the orientation is propagated.
|
||||
int forceNormalConsistence(Triangle *);
|
||||
|
||||
//! Detect singular vertices and duplicte them. Return number of singular
|
||||
//! vertices being duplicated.
|
||||
int duplicateNonManifoldVertices();
|
||||
|
||||
//! Remove redundant triangles (i.e. having the same vertices as others)
|
||||
//! and return their number.
|
||||
int removeDuplicatedTriangles();
|
||||
|
||||
//! Check the mesh connectivity. If everything is fine NULL is returned,
|
||||
//! otherwise an error string is returned.
|
||||
const char *checkConnectivity();
|
||||
|
||||
//! If called in rebuildConnectivity(bool) fix the connectivity between
|
||||
//! geometric elements
|
||||
bool fixConnectivity(); //!< AMF_ADD 1.1>
|
||||
|
||||
//! Considers triangles as purely geometric entities and recomputes their
|
||||
//! connectivity based on vertex correspondence.
|
||||
//! Returns false if mesh was not an oriented manifold.
|
||||
TMESH_VIRTUAL bool rebuildConnectivity(bool = true); //!< AMF_CHANGE 1.1>
|
||||
|
||||
//! Looks for topologically different edges having the same geometry
|
||||
//! (i.e. coincident vertices) and unify them. Return their number.
|
||||
int mergeCoincidentEdges();
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Geometrical fixes (Implemented in "MESH_STRUCTURE/checkAndRepair.cpp")
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//! Looks for zero-area triangles and resolve them by splits and collapses.
|
||||
//! If, for any reason, some degeneracies cannot be removed
|
||||
//! a warning is issued and the degenerate triangles that could not
|
||||
//! be resolved are selected.
|
||||
//! The absolute value of the integer returned is the number of
|
||||
//! collapses performed; the return value is negative if some
|
||||
//! degenerate triangles could not be resolved.
|
||||
int removeDegenerateTriangles();
|
||||
|
||||
//! Calls 'removeDegenerateTriangles()' and, if some degeneracies remain,
|
||||
//! removes them and fills the resulting holes. Then tries again and, if
|
||||
//! some degeneracies still remain, removes them and their neighbors and
|
||||
//! fills the resulting holes, and so on, until the neighborhood growth
|
||||
//! reaches max-iters. If even in this case some degeneracies remain,
|
||||
//! returns false, otherwise returns true.
|
||||
bool strongDegeneracyRemoval(int max_iters);
|
||||
|
||||
//! Removes all the intersecting triangles and patches the resulting holes.
|
||||
//! If the patches still produce intersections, iterates again on a larger
|
||||
//! neighborhood. Tries up to max_iters times before giving up. Returns
|
||||
//! true only if all the intersections could be removed.
|
||||
bool strongIntersectionRemoval(int max_iters);
|
||||
|
||||
//! Iteratively call strongDegeneracyRemoval and strongIntersectionRemoval
|
||||
//! to produce an eventually clean mesh without degeneracies and intersections.
|
||||
//! The two aforementioned methods are called up to max_iter times and
|
||||
//! each of them is called using 'inner_loops' as a parameter.
|
||||
//! Returns true only if the mesh could be completely cleaned.
|
||||
bool meshclean(int max_iters = 10, int inner_loops = 3);
|
||||
|
||||
//! Removes overlapping triangles and return their number.
|
||||
int removeOverlappingTriangles();
|
||||
|
||||
//! Checks the mesh for degeneracies, concident vertices and overlaps.
|
||||
//! If such a flaw is found returns its closest vertex.
|
||||
Vertex *checkGeometry();
|
||||
|
||||
//! Selects all the triangles that unproperly intersect other parts of
|
||||
//! the mesh and return their number. The parameter 'tris_per_cell'
|
||||
//! determines the depth of the recursive space subdivision used to keep
|
||||
//! the complexity under a resonable threchold. The default value is safe
|
||||
//! in most cases.
|
||||
//! if 'justproper' is true, coincident edges and vertices are not regarded
|
||||
//! as intersections even if they are not common subsimplexes.
|
||||
int selectIntersectingTriangles(UINT16 tris_per_cell = 50, bool justproper = false);
|
||||
|
||||
|
||||
//! This is as coordBackApproximation() but it also checks for
|
||||
//! intersections and, if any, it tries different approximations.
|
||||
//! Returns true if no intersections remain.
|
||||
bool safeCoordBackApproximation();
|
||||
|
||||
//! Removes all the connected components whose area is less than 'epsilon'.
|
||||
//! Returns the number of components removed.
|
||||
int removeSmallestComponents(double epsilon);
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Hole triangulation (Implemented in "MESH_STRUCTURE/holeFilling.cpp")
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//! Computes the barycenter of the boundary loop and connects it with
|
||||
//! all the edges of the loop. Returns the number of triangles
|
||||
//! created.
|
||||
TMESH_VIRTUAL int StarTriangulateHole(Edge *);
|
||||
|
||||
//! Creates a triangulation whose projection on the plane with normal 'nor'
|
||||
//! is Delaunay. Returns the number of triangles created.
|
||||
int TriangulateHole(Edge *, Point *nor);
|
||||
|
||||
//! Creates a triangulation of the hole based on heuristics.
|
||||
//! Returns the number of triangles created.
|
||||
int TriangulateHole(Edge *);
|
||||
|
||||
//! Creates a triangulation of the hole based on the assumption that it is flat.
|
||||
//! Returns the number of triangles created.
|
||||
// int TriangulateFlatHole(Edge *);
|
||||
|
||||
//! Creates a triangulation and inserts the additional points in the List.
|
||||
//! Returns the number of triangles created.
|
||||
TMESH_VIRTUAL int TriangulateHole(Edge *, List *);
|
||||
|
||||
//! Hole filling algorithm. Performs a triangulation based on heuristics and,
|
||||
//! if 'refine' is set to true, adds inner vertices to reproduce the sampling
|
||||
//! density of the surroundings.
|
||||
void FillHole(Edge *, bool refine = true);
|
||||
|
||||
//! Fills all the holes having at least 'nbe' boundary edges. If 'refine'
|
||||
//! is true, adds inner vertices to reproduce the sampling density
|
||||
//! of the surroundings. Returns number of holes patched.
|
||||
//! If 'nbe' is 0 (default), all the holes are patched.
|
||||
int fillSmallBoundaries(int nbe = 0, bool refine = true);
|
||||
|
||||
//! Takes a selected region and inserts inner vertices to reproduce the
|
||||
//! sampling density of the surroundings. If 't0' is not NULL, only the
|
||||
//! selected region containing 't0' is refined. Returns the number of
|
||||
//! vertices inserted.
|
||||
TMESH_VIRTUAL int refineSelectedHolePatches(Triangle *t0 =NULL);
|
||||
|
||||
//! Retriangulates the vertex neghborhood based on heuristics.
|
||||
int retriangulateVT(Vertex *);
|
||||
|
||||
//! Joins the two boundary vertices gv and gw through an edge. A pair of triangles is
|
||||
//! added to properly change the topology of the mesh.
|
||||
Edge *joinBoundaryLoops(Vertex *, Vertex *, bool = 0, bool = 1);
|
||||
|
||||
// Debug and work-in-progress
|
||||
|
||||
void printReport();
|
||||
|
||||
protected:
|
||||
Vertex *watsonInsert(Point *, List *, int);
|
||||
};
|
||||
|
||||
#define FOREACHTRIANGLE(Tt, n) for (n = T.head(), Tt = (n)?((Triangle *)n->data):NULL; n != NULL; n=n->next(), Tt = (n)?((Triangle *)n->data):NULL)
|
||||
#define FOREACHEDGE(Tt, n) for (n = E.head(), Tt = (n)?((Edge *)n->data):NULL; n != NULL; n=n->next(), Tt = (n)?((Edge *)n->data):NULL)
|
||||
#define FOREACHVERTEX(Tt, n) for (n = V.head(), Tt = (n)?((Vertex *)n->data):NULL; n != NULL; n=n->next(), Tt = (n)?((Vertex *)n->data):NULL)
|
||||
|
||||
#define MARK_VISIT(a) ((a)->mask |= ((unsigned char)1))
|
||||
#define IS_VISITED(a) ((a)->mask & ((unsigned char)1))
|
||||
#define UNMARK_VISIT(a) ((a)->mask &= (~((unsigned char)1)))
|
||||
|
||||
#define MARK_VISIT2(a) ((a)->mask |= ((unsigned char)2))
|
||||
#define IS_VISITED2(a) ((a)->mask & ((unsigned char)2))
|
||||
#define UNMARK_VISIT2(a) ((a)->mask &= (~((unsigned char)2)))
|
||||
|
||||
#define MARK_BIT(a,b) ((a)->mask |= ((unsigned char)(1<<b)))
|
||||
#define IS_BIT(a,b) ((a)->mask & ((unsigned char)(1<<b)))
|
||||
#define UNMARK_BIT(a,b) ((a)->mask &= (~((unsigned char)(1<<b))))
|
||||
|
||||
#define TAG_SHARPEDGE(a) (MARK_BIT((a),7))
|
||||
#define IS_SHARPEDGE(a) (IS_BIT((a),7))
|
||||
#define UNTAG_SHARPEDGE(a) (UNMARK_BIT((a),7))
|
||||
|
||||
|
||||
// Errors from loading
|
||||
|
||||
#define IO_CANTOPEN 10
|
||||
#define IO_FORMAT 20
|
||||
#define IO_UNKNOWN 30
|
||||
|
||||
#define IO_CSAVE_OVERALL 0
|
||||
#define IO_CSAVE_PERFACE 1
|
||||
#define IO_CSAVE_PERVERTEX 2
|
||||
#define IO_CSAVE_PERFACE_INDEXED 3
|
||||
#define IO_CSAVE_PERVERTEX_INDEXED 4
|
||||
|
||||
} //namespace T_MESH
|
||||
|
||||
#endif //_TIN_H
|
||||
|
40
src/mesh_fix/include/TMesh/tmesh.h
Normal file
40
src/mesh_fix/include/TMesh/tmesh.h
Normal file
@ -0,0 +1,40 @@
|
||||
/****************************************************************************
|
||||
* TMesh *
|
||||
* *
|
||||
* Consiglio Nazionale delle Ricerche *
|
||||
* Istituto di Matematica Applicata e Tecnologie Informatiche *
|
||||
* Sezione di Genova *
|
||||
* IMATI-GE / CNR *
|
||||
* *
|
||||
* Authors: Marco Attene *
|
||||
* Copyright(C) 2012: IMATI-GE / CNR *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is dual-licensed as follows: *
|
||||
* *
|
||||
* (1) You may use TMesh as 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. *
|
||||
* In this case the 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 (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
* (2) You may use TMesh as part of a commercial software. In this case a *
|
||||
* proper agreement must be reached with the Authors and with IMATI-GE/CNR *
|
||||
* based on a proper licensing contract. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef _TMESH_H
|
||||
#define _TMESH_H
|
||||
|
||||
#include "tmesh_kernel.h"
|
||||
#include "vertex.h"
|
||||
#include "edge.h"
|
||||
#include "triangle.h"
|
||||
#include "tin.h"
|
||||
|
||||
#endif //_TMESH_H
|
218
src/mesh_fix/include/TMesh/triangle.h
Normal file
218
src/mesh_fix/include/TMesh/triangle.h
Normal file
@ -0,0 +1,218 @@
|
||||
/****************************************************************************
|
||||
* TMesh *
|
||||
* *
|
||||
* Consiglio Nazionale delle Ricerche *
|
||||
* Istituto di Matematica Applicata e Tecnologie Informatiche *
|
||||
* Sezione di Genova *
|
||||
* IMATI-GE / CNR *
|
||||
* *
|
||||
* Authors: Marco Attene *
|
||||
* Copyright(C) 2013: IMATI-GE / CNR *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is dual-licensed as follows: *
|
||||
* *
|
||||
* (1) You may use TMesh as 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. *
|
||||
* In this case the 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 (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
* (2) You may use TMesh as part of a commercial software. In this case a *
|
||||
* proper agreement must be reached with the Authors and with IMATI-GE/CNR *
|
||||
* based on a proper licensing contract. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef _TRIANGLE_H
|
||||
#define _TRIANGLE_H
|
||||
|
||||
#include "tmesh.h"
|
||||
|
||||
namespace T_MESH
|
||||
{
|
||||
|
||||
//! Triangle of a Basic_TMesh.
|
||||
|
||||
//! This class represents a triangle of a triangulation. Each Triangle has
|
||||
//! an orientation (clockwise or counter-clockwise) due to the order in
|
||||
//! which its edges are stored in the class. When looking at the triangle
|
||||
//! so that (e1, e2, e3) are sorted counter-clockwise, the normal at the
|
||||
//! triangle points towards the observer. The field mask is useful for
|
||||
//! assigning up to 256 different states to the edge.
|
||||
|
||||
|
||||
class Triangle : public Data
|
||||
{
|
||||
public :
|
||||
|
||||
Edge *e1, *e2, *e3; //!< Edges of the triangle
|
||||
void *info; //!< Further information
|
||||
unsigned char mask; //!< bit-mask for marking purposes
|
||||
|
||||
Triangle();
|
||||
Triangle(Edge *, Edge *, Edge *); //!< Constructor
|
||||
|
||||
//! Returns true only if object is a basic Triangle. All the reimplementations must return false.
|
||||
TMESH_VIRTUAL bool isBaseType() const { return true; }
|
||||
|
||||
bool isLinked() const {return (e1!=NULL);} //!< TRUE if properly linked
|
||||
|
||||
//! Inverts the orientation of the triangle
|
||||
|
||||
TMESH_VIRTUAL void invert() { p_swap((void **)(&e2), (void **)(&e3)); }
|
||||
|
||||
Vertex *v1() const {return e1->commonVertex(e2);} //!< First vertex
|
||||
Vertex *v2() const {return e2->commonVertex(e3);} //!< Second vertex
|
||||
Vertex *v3() const {return e3->commonVertex(e1);} //!< Third vertex
|
||||
|
||||
//! First adjacent triangle. NULL if boundary.
|
||||
Triangle *t1() const {return e1->oppositeTriangle(this);}
|
||||
|
||||
//! Second adjacent triangle. NULL if boundary.
|
||||
Triangle *t2() const {return e2->oppositeTriangle(this);}
|
||||
|
||||
//! Third adjacent triangle. NULL if boundary.
|
||||
Triangle *t3() const {return e3->oppositeTriangle(this);}
|
||||
|
||||
//! TRUE iff 'e' is an edge of the triangle.
|
||||
bool hasEdge(const Edge *e) const {return (e==e1 || e==e2 || e==e3);}
|
||||
|
||||
//! TRUE iff 'v' is a vertex of the triangle.
|
||||
bool hasVertex(const Vertex *v) const {return (e1->hasVertex(v) || e2->hasVertex(v) || e3->hasVertex(v));}
|
||||
|
||||
//! Triangle's edge opposite to 'v'. NULL if 'v' is not a vertex of the triangle.
|
||||
Edge *oppositeEdge(const Vertex *v) const
|
||||
{return ((!e1->hasVertex(v))?(e1):((!e2->hasVertex(v))?(e2):((!e3->hasVertex(v))?(e3):(NULL))));}
|
||||
|
||||
//! Adjacent triangle opposite to 'v'. NULL if 'v' is not a vertex of the triangle.
|
||||
Triangle *oppositeTriangle(const Vertex *v) const
|
||||
{return ((!e1->hasVertex(v))?(t1()):((!e2->hasVertex(v))?(t2()):((!e3->hasVertex(v))?(t3()):(NULL))));}
|
||||
|
||||
//! Triangle's vertex opposite to 'e'. NULL if 'e' is not an edge of the triangle.
|
||||
Vertex *oppositeVertex(const Edge *e) const
|
||||
{return (e==e1)?(v2()):((e==e2)?(v3()):((e==e3)?(v1()):(NULL)));}
|
||||
|
||||
//! Triangle adjacent to the next edge of 'e'. NULL if 'e' is not an edge of the triangle.
|
||||
Triangle *rightTriangle(const Edge *e) const
|
||||
{return (e==e1)?(t2()):((e==e2)?(t3()):((e==e3)?(t1()):(NULL)));}
|
||||
|
||||
//! Triangle adjacent to the previous edge of 'e'. NULL if 'e' is not an edge of the triangle.
|
||||
Triangle *leftTriangle(const Edge *e) const
|
||||
{return (e==e1)?(t3()):((e==e2)?(t1()):((e==e3)?(t2()):(NULL)));}
|
||||
|
||||
//! Edge next to 'e' in the ordering or the triangle. NULL if 'e' is not an edge of the triangle.
|
||||
Edge *nextEdge(const Edge *e) const {return ((e==e1)?(e2):((e==e2)?(e3):((e==e3)?(e1):(NULL))));}
|
||||
|
||||
//! Edge preceeding 'e' in the ordering or the triangle. NULL if 'e' is not an edge of the triangle.
|
||||
Edge *prevEdge(const Edge *e) const {return ((e==e1)?(e3):((e==e2)?(e1):((e==e3)?(e2):(NULL))));}
|
||||
|
||||
//! Vertex next to 'v' in the ordering or the triangle. NULL if 'v' is not a vertex of the triangle.
|
||||
Vertex *nextVertex(const Vertex *v) const
|
||||
{return (!e1->hasVertex(v))?(v3()):((!e2->hasVertex(v))?(v1()):((!e3->hasVertex(v))?(v2()):(NULL)));}
|
||||
|
||||
//! Vertex preceeding 'v' in the ordering or the triangle. NULL if 'v' is not a vertex of the triangle.
|
||||
Vertex *prevVertex(const Vertex *v) const
|
||||
{return (!e1->hasVertex(v))?(v1()):((!e2->hasVertex(v))?(v2()):((!e3->hasVertex(v))?(v3()):(NULL)));}
|
||||
|
||||
//! Edge next to 'e' in the ordering or the triangle. NULL if 'e' is not an edge of the triangle.
|
||||
Edge *nextEdge(const Vertex *v) const { return (v == v1()) ? (e2) : ((v == v2()) ? (e3) : ((v == v3()) ? (e1) : (NULL))); }
|
||||
|
||||
|
||||
//! If this triangle shares an edge with 'b', then such an edge is returned. NULL otherwise.
|
||||
Edge *commonEdge(const Triangle *b) const
|
||||
{return ((e1 == b->e1 || e1 == b->e2 || e1 == b->e3)?(e1):\
|
||||
(((e2 == b->e1 || e2 == b->e2 || e2 == b->e3)?(e2):\
|
||||
(((e3 == b->e1 || e3 == b->e2 || e3 == b->e3)?(e3):(NULL))))));}
|
||||
|
||||
//! If this triangle shares a vertex with 'b', then such a vertex is returned. NULL otherwise.
|
||||
Vertex *commonVertex(const Triangle *b) const;
|
||||
|
||||
//! Replace edge 'a' with edge 'b' in the triangle and return TRUE. If 'a' is not an edge of the triangle return FALSE.
|
||||
bool replaceEdge(const Edge *a, Edge *b)
|
||||
{if (e1==a) e1=b; else if (e2==a) e2=b; else if (e3==a) e3=b; else return 0; return 1;}
|
||||
|
||||
//! TRUE if the oriantation is consistent with the one of 't' OR if this and 't' do not share any edge.
|
||||
bool checkAdjNor(const Triangle *t) const;
|
||||
|
||||
//! Return a vector orthogonal to the plane of the triangle. If triangle is degenerate return a null vector.
|
||||
Point getVector() const;
|
||||
|
||||
//! Return the triangle's barycenter.
|
||||
Point getCenter() const;
|
||||
|
||||
//! Return the center of the triangle's bounding sphere.
|
||||
Point getCircleCenter() const;
|
||||
|
||||
//! TRUE iff 'p' is inside the triangle's bounding sphere.
|
||||
bool inSphere(const Point *p) const;
|
||||
|
||||
//! Squared distance of 'p' from the plane of the triangle. Return -1 if triangle is degenerate.
|
||||
coord squaredDistanceFromPoint(const Point *p) const;
|
||||
|
||||
//! Squared distance of 'p' from the closest point of the triangle. Return -1 if triangle is degenerate.
|
||||
//! If closest point is in the interior of the triangle, *closest_edge and *closest_vertex are set to NULL.
|
||||
//! If the closest point is in the interior of an edge, *closest_edge is initialized with that edge.
|
||||
//! If the closest point is a vertex, *closest_vertex is initialized with it.
|
||||
coord pointTriangleSquaredDistance(const Point *p, Edge **closest_edge =NULL, Vertex **closest_vertex =NULL) const;
|
||||
|
||||
//! Projection of 'p' on the plane of the triangle. Return INFINITE_POINT if triangle is degenerate.
|
||||
Point project(const Point *p) const;
|
||||
|
||||
//! Returns the longest edge of the triangle.
|
||||
Edge *getLongestEdge() const;
|
||||
|
||||
//! Degeneracy check using exact predicates. Return TRUE iff triangle has zero area.
|
||||
bool isExactlyDegenerate() const;
|
||||
|
||||
//! Returns the edge opposite to a 'cap' vertex
|
||||
Edge *getCapEdge() const;
|
||||
|
||||
//! Print the coordinates of the three vertices to the file handler pointed to by 'f' (stdout by default).
|
||||
void printTriangle(FILE *f =stdout) const;
|
||||
|
||||
//! true if this triangle itersects 't' other than on common subsimplexes
|
||||
//! if 'justproper' is true, coincident edges and vertices are not regarded
|
||||
//! as intersections even if they are not common subsimplexes.
|
||||
bool intersects(const Triangle *t, bool justproper =false) const;
|
||||
|
||||
// FUNCTIONS BELOW THIS LINE MAY RETURN APPROXIMATED/NOT ROBUST RESULTS EVEN WHEN USING RATIONALS
|
||||
|
||||
|
||||
|
||||
//! Return a normal vector with direction (v1-v2) cross (v2-v3). If triangle is degenerate return a null vector.
|
||||
Point getNormal() const;
|
||||
|
||||
//! Area of the triangle (Heron's formula).
|
||||
double area() const;
|
||||
|
||||
//! Perimeter of the triangle.
|
||||
double perimeter() const;
|
||||
|
||||
//! Angle at vertex 'v'. Return -1 if 'v' is not a vertex of the triangle.
|
||||
double getAngle(const Vertex *v) const;
|
||||
|
||||
//! Angle between the normal vector of this and the one of 't'. Return -1 if one or both the triangles are degenerate.
|
||||
double getDAngle(const Triangle *t) const;
|
||||
|
||||
//! Distance of 'p' from the plane of the triangle. Return -1 if triangle is degenerate.
|
||||
double distanceFromPoint(const Point *p) const;
|
||||
|
||||
//! Distance of 'p' from the closest point of the triangle. Return -1 if triangle is degenerate.
|
||||
//! If 'c' is not NULL, its coordinates are set to the ones of the closest point.
|
||||
double pointTriangleDistance(const Point *p, Point *c = NULL) const;
|
||||
|
||||
//! Return TRUE iff one of the adjacent triangles overlaps with this one
|
||||
bool overlaps() const;
|
||||
};
|
||||
|
||||
#define FOREACHTRIANGLEEDGE(t, e) for ((e) = (t)->e1; (e) != NULL; (e)=((e)==(t)->e3)?(NULL):((t)->nextEdge(e)))
|
||||
|
||||
} //namespace T_MESH
|
||||
|
||||
#endif // _TRIANGLE_H
|
||||
|
223
src/mesh_fix/include/TMesh/vertex.h
Normal file
223
src/mesh_fix/include/TMesh/vertex.h
Normal file
@ -0,0 +1,223 @@
|
||||
/****************************************************************************
|
||||
* TMesh *
|
||||
* *
|
||||
* Consiglio Nazionale delle Ricerche *
|
||||
* Istituto di Matematica Applicata e Tecnologie Informatiche *
|
||||
* Sezione di Genova *
|
||||
* IMATI-GE / CNR *
|
||||
* *
|
||||
* Authors: Marco Attene *
|
||||
* Copyright(C) 2013: IMATI-GE / CNR *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is dual-licensed as follows: *
|
||||
* *
|
||||
* (1) You may use TMesh as 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. *
|
||||
* In this case the 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 (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
* (2) You may use TMesh as part of a commercial software. In this case a *
|
||||
* proper agreement must be reached with the Authors and with IMATI-GE/CNR *
|
||||
* based on a proper licensing contract. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef _VERTEX_H
|
||||
#define _VERTEX_H
|
||||
|
||||
#include "basics.h"
|
||||
#include "list.h"
|
||||
#include "point.h"
|
||||
|
||||
namespace T_MESH
|
||||
{
|
||||
|
||||
//! Vertex of a Basic_TMesh
|
||||
|
||||
//! This class represents a vertex of a manifold and oriented triangulation.
|
||||
//! The base-class Point
|
||||
//! describes geometrical and additional attributes of the vertex. The
|
||||
//! field 'e0' is sufficient to retrieve all the neighboring elements in
|
||||
//! optimal time, while the field 'mask' is useful for assigning up to 256
|
||||
//! different states to the vertex.
|
||||
|
||||
|
||||
class Vertex : public Point
|
||||
{
|
||||
public :
|
||||
class Edge *e0; //!< One of the incident edges
|
||||
unsigned char mask; //!< bit-mask for marking purposes
|
||||
|
||||
//! Creates a new vertex with coordinates (0,0,0).
|
||||
Vertex();
|
||||
|
||||
//! Creates a new vertex with the same coordinates (x,y,z).
|
||||
Vertex(const coord& x, const coord& y, const coord& z);
|
||||
|
||||
//! Creates a new vertex with the same coordinates as 'p'. The info field is not copied.
|
||||
Vertex(const Point *p);
|
||||
|
||||
//! Creates a new vertex with the same coordinates as 'p'. The info field is not copied.
|
||||
Vertex(const Point& p);
|
||||
~Vertex(); //!< Destructor
|
||||
|
||||
//! Returns true only if object is a basic Vertex. All the reimplementations must return false.
|
||||
TMESH_VIRTUAL bool isBaseType() const { return true; }
|
||||
|
||||
bool isLinked() const {return (e0!=0);} //!< TRUE iff vertex is not isolated
|
||||
|
||||
//! List of adjacent vertices.
|
||||
|
||||
//! Returns the list of vertices which are linked to this through an edge.
|
||||
//! The list is counter-clockwise ordered. In the case of an internal ver-
|
||||
//! tex the list starts from the opposite vertex of e0. If the vertex is on
|
||||
//! the boundary, the list starts from the opposite vertex of the clock-
|
||||
//! wise-most boundary edge.
|
||||
List *VV() const;
|
||||
|
||||
//! List of incident edges.
|
||||
|
||||
//! Returns the list of edges incident at this vertex. The list is counter-clockwise
|
||||
//! ordered. In the case of an internal vertex the list starts from 'e0'
|
||||
//! If the vertex is on the boundary, the list starts from its clockwise-most
|
||||
//! incident boundary edge.
|
||||
List *VE() const;
|
||||
|
||||
//! List of incident triangles.
|
||||
|
||||
//! Returns the list of triangles incident at this. The list is counter-
|
||||
//! clockwise ordered. In the case of an internal vertex the list starts
|
||||
//! from the triangle on the left of e0, when looking from this. If the
|
||||
//! vertex is on the boundary, the list starts from the clockwise-most
|
||||
//! boundary triangle.
|
||||
List *VT() const;
|
||||
|
||||
//! Returns the edge connecting this vertex to 'v'. NULL if such an edge does not exist.
|
||||
class Edge *getEdge(const Vertex *v) const;
|
||||
int valence() const; //!< Returns the number of incident edges
|
||||
int isOnBoundary() const; //!< TRUE iff vertex is on boundary
|
||||
|
||||
//! Returns the edge following this vertex on the boundary.
|
||||
|
||||
//! This edge is the counterclockwise-most incident edge.
|
||||
//! Returns NULL if this vertex is not on the boundary.
|
||||
Edge *nextBoundaryEdge() const;
|
||||
|
||||
//! Returns the edge preceeding this vertex on the boundary.
|
||||
|
||||
//! This edge is the clockwise-most incident edge.
|
||||
//! Returns NULL if this vertex is not on the boundary.
|
||||
Edge *prevBoundaryEdge() const;
|
||||
|
||||
//! Returns the vertex following this one on the boundary.
|
||||
|
||||
//! If the vertex is on the boundary, this is equivalent to nextBoundaryEdge()->oppositeVertex(v)
|
||||
//! otherwise returns NULL.
|
||||
Vertex *nextOnBoundary() const;
|
||||
|
||||
//! Returns the vertex preceeding this one on the boundary.
|
||||
|
||||
//! If the vertex is on the boundary, this is equivalent to prevBoundaryEdge()->oppositeVertex(v)
|
||||
//! otherwise returns NULL.
|
||||
Vertex *prevOnBoundary() const;
|
||||
|
||||
//! TRUE iff vertex neighborhood is a flat disk. Always FALSE for boundary vertices.
|
||||
bool isFlat() const;
|
||||
|
||||
//! TRUE iff vertex neighborhood is made of either two flat halfdisks or one flat halfdisk on a rectilinear boundary.
|
||||
//! When TRUE, the two edges may be initialized with the two non-flat incident edges.
|
||||
//! If the two halfdisks are also coplanar, returns TRUE and e1 and e2 are set to NULL.
|
||||
bool isDoubleFlat(Edge **e1, Edge **e2) const;
|
||||
|
||||
//! Unlinks the vertex if it is either Flat() or DoubleFlat(). On success, the function returns TRUE,
|
||||
//! the vertex neighborhood is retriangulated, and the geometric realization does not change.
|
||||
//! If 'check_neighborhood' is 'false', incident triangles are assumed to be neither degenerate nor
|
||||
//! overlapping.
|
||||
//! Attention! The method unlinks the vertex but does not remove it from the Basic_TMesh list. The
|
||||
//! calling function must clear the lists through Basic_TMesh::removeUnlinkedElements().
|
||||
bool removeIfRedundant(bool check_neighborhood = true);
|
||||
|
||||
//! Normal at the vertex computed as the sum of incident triangle normals weighted on their incidence angle.
|
||||
Point getNormal() const;
|
||||
|
||||
//! Returns the angle between the two incident boundary edges. If the vertex is not on the boundary, returns -1.
|
||||
double getBoundaryAngle() const;
|
||||
|
||||
//! Discriminant Angle for triangulating 3D polygons.
|
||||
|
||||
//! This method is useful when patching holes, and represents a heuristic
|
||||
//! for choosing which vertex of the hole's boundary must be patched first.
|
||||
//! Several cases are considered, including degenerate ones. Let 'v1' and 'v2'
|
||||
//! be the two boundary vertices which are linked to this one through a boundary
|
||||
//! edge. If 'v1' and 'v2' coincide, the method returns a negative number.
|
||||
//! If 'v1' , 'this' , 'v2' form a flat angle, the method returns 3PI (270
|
||||
//! degrees). If the angle formed by 'v1' , 'this' , 'v2' is 0, the method
|
||||
//! returns 0. If the vertex is not on the boundary, the method returns the
|
||||
//! limit number DBL_MAX. In all the other cases the method returns the sum
|
||||
//! of three angles A + D1 + D2, where A is the angle formed by v1 , this ,
|
||||
//! v2 , while D1 is the angle between the normal of the clockwise-most
|
||||
//! incident boundary triangle and the normal of the triangle v1 , this ,
|
||||
//! v2; D2 is the analogous for the counterclockwise-most incident boundary
|
||||
//! triangle.
|
||||
double getAngleForTriangulation() const;
|
||||
|
||||
//! Discriminant Angle for triangulating flat (or nearly flat) polygons.
|
||||
|
||||
//! This method returns the angle between the two incident boundary edges
|
||||
//! when projected onto the plane whose normal is 'n'. This angle
|
||||
//! may be more than PI, because it represents the aperture of the non-tri-
|
||||
//! angulated region around the vertex when projected on the plane. If the
|
||||
//! vertex is not on the boundary, the method returns the limit value
|
||||
//! DBL_MAX.
|
||||
double getAngleOnAveragePlane(Point *n) const;
|
||||
|
||||
double totalAngle() const; //!< Sum of incident angles. Returns -1 if on boundary.
|
||||
|
||||
//! Excess angle. Returns DBL_MAX if on boundary.
|
||||
double gaussianCurvature() const {double t=totalAngle(); return (t>=0)?(t):(DBL_MAX);}
|
||||
|
||||
double totalDihedralAngle() const; //!< Sum of signed dihedral angles. Returns DBL_MAX if on boundary.
|
||||
double voronoiArea() const; //!< A third of the total area of incident triangles.
|
||||
|
||||
//! Zips the gap starting from here.
|
||||
int zip(const bool =1);
|
||||
|
||||
// Edge *inverseCollapse(Vertex *, Vertex *, Vertex *);
|
||||
Edge *inverseCollapse(Vertex *, Edge *, Edge *, Edge *, Edge *, Edge *, class Triangle *, class Triangle *);
|
||||
};
|
||||
|
||||
//! Scans the nodes 'n' of a list 'l' of vertices 'v'.
|
||||
#define FOREACHVVVERTEX(l, v, n) for (n = l->head(), v = (n)?((Vertex *)n->data):NULL; n != NULL; n=n->next(), v = (n)?((Vertex *)n->data):NULL)
|
||||
|
||||
//! Scans the nodes 'n' of a list 'l' of edges 'e'.
|
||||
#define FOREACHVEEDGE(l, e, n) for (n = l->head(), e = (n)?((Edge *)n->data):NULL; n != NULL; n=n->next(), e = (n)?((Edge *)n->data):NULL)
|
||||
|
||||
//! Scans the nodes 'n' of a list 'l' of triangles 't'.
|
||||
#define FOREACHVTTRIANGLE(l, t, n) for (n = l->head(), t = (n)?((T_MESH::Triangle *)n->data):NULL; n != NULL; n=n->next(), t = (n)?((T_MESH::Triangle *)n->data):NULL)
|
||||
|
||||
|
||||
//! Extended vertex for temporary use during connectivity creation.
|
||||
|
||||
//! This class is used to allow the reconstruction of the connectivity
|
||||
//! in linear time (average case) and to handle badly oriented input files.
|
||||
//! It provides a complete VE relation.
|
||||
|
||||
class ExtVertex
|
||||
{
|
||||
public :
|
||||
Vertex *v;
|
||||
List VE;
|
||||
|
||||
ExtVertex(Vertex *a) {v=a;}
|
||||
};
|
||||
|
||||
} //namespace T_MESH
|
||||
|
||||
#endif //_VERTEX_H
|
||||
|
1058
src/mesh_fix/src/Algorithms/checkAndRepair.cpp
Normal file
1058
src/mesh_fix/src/Algorithms/checkAndRepair.cpp
Normal file
File diff suppressed because it is too large
Load Diff
395
src/mesh_fix/src/Algorithms/detectIntersections.cpp
Normal file
395
src/mesh_fix/src/Algorithms/detectIntersections.cpp
Normal file
@ -0,0 +1,395 @@
|
||||
/****************************************************************************
|
||||
* TMesh *
|
||||
* *
|
||||
* Consiglio Nazionale delle Ricerche *
|
||||
* Istituto di Matematica Applicata e Tecnologie Informatiche *
|
||||
* Sezione di Genova *
|
||||
* IMATI-GE / CNR *
|
||||
* *
|
||||
* Authors: Marco Attene *
|
||||
* Copyright(C) 2013: IMATI-GE / CNR *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is dual-licensed as follows: *
|
||||
* *
|
||||
* (1) You may use TMesh as 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. *
|
||||
* In this case the 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 (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
* (2) You may use TMesh as part of a commercial software. In this case a *
|
||||
* proper agreement must be reached with the Authors and with IMATI-GE/CNR *
|
||||
* based on a proper licensing contract. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#include "detectIntersections.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "jqsort.h"
|
||||
|
||||
namespace T_MESH
|
||||
{
|
||||
di_cell::di_cell(Basic_TMesh *tin, bool useAll)
|
||||
{
|
||||
Node *n;
|
||||
Vertex *v;
|
||||
Triangle *t;
|
||||
Mp.x = -DBL_MAX, mp.x = DBL_MAX;
|
||||
Mp.y = -DBL_MAX, mp.y = DBL_MAX;
|
||||
Mp.z = -DBL_MAX, mp.z = DBL_MAX;
|
||||
FOREACHVVVERTEX((&(tin->V)), v, n) if (useAll || IS_BIT(v,5))
|
||||
{
|
||||
if (v->x < mp.x) mp.x = v->x;
|
||||
if (v->x > Mp.x) Mp.x = v->x;
|
||||
if (v->y < mp.y) mp.y = v->y;
|
||||
if (v->y > Mp.y) Mp.y = v->y;
|
||||
if (v->z < mp.z) mp.z = v->z;
|
||||
if (v->z > Mp.z) Mp.z = v->z;
|
||||
}
|
||||
|
||||
mp -= DI_EPSILON_POINT;
|
||||
Mp += DI_EPSILON_POINT;
|
||||
|
||||
FOREACHVTTRIANGLE((&(tin->T)), t, n) if (useAll || IS_VISITED(t)) triangles.appendTail(t);
|
||||
}
|
||||
|
||||
bool di_cell::is_triangleBB_in_cell(Triangle *t) const
|
||||
{
|
||||
Vertex *v1 = t->v1(), *v2 = t->v2(), *v3 = t->v3();
|
||||
coord mx = MIN(v1->x, MIN(v2->x, v3->x));
|
||||
coord Mx = MAX(v1->x, MAX(v2->x, v3->x));
|
||||
coord my = MIN(v1->y, MIN(v2->y, v3->y));
|
||||
coord My = MAX(v1->y, MAX(v2->y, v3->y));
|
||||
coord mz = MIN(v1->z, MIN(v2->z, v3->z));
|
||||
coord Mz = MAX(v1->z, MAX(v2->z, v3->z));
|
||||
|
||||
// Triangle BB is not entirely out of cell
|
||||
if (!(Mx<mp.x || mx>Mp.x || My<mp.y || my>Mp.y || Mz<mp.z || mz>Mp.z)) return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
di_cell *di_cell::fork()
|
||||
{
|
||||
Node *n;
|
||||
Triangle *t;
|
||||
Point e = Mp - mp;
|
||||
di_cell *nc = new di_cell;
|
||||
char which_coord = 2;
|
||||
|
||||
if (e.x >= e.y && e.x >= e.z) which_coord = 0;
|
||||
else if (e.y >= e.x && e.y >= e.z) which_coord = 1;
|
||||
nc->mp = mp; nc->Mp = Mp;
|
||||
nc->Mp[which_coord] -= (e[which_coord] / 2); mp[which_coord] = nc->Mp[which_coord];
|
||||
|
||||
n = triangles.head();
|
||||
while (n != NULL)
|
||||
{
|
||||
t = (Triangle *)n->data;
|
||||
n = n->next();
|
||||
if (!is_triangleBB_in_cell(t))
|
||||
{
|
||||
triangles.moveNodeTo((n != NULL) ? (n->prev()) : triangles.tail(), &(nc->triangles));
|
||||
}
|
||||
else if (nc->is_triangleBB_in_cell(t)) nc->triangles.appendHead(t);
|
||||
}
|
||||
|
||||
return nc;
|
||||
}
|
||||
|
||||
|
||||
// Brute force all-with-all intersection test of the triangles in 'triangles'.
|
||||
void di_cell::selectIntersections(bool justproper)
|
||||
{
|
||||
Triangle *t, *y;
|
||||
Node *n, *m;
|
||||
List *ts;
|
||||
|
||||
for (n = triangles.head(); n != NULL; n = n->next())
|
||||
for (m = n->next(); m != NULL; m = m->next())
|
||||
{
|
||||
t = (Triangle *)n->data;
|
||||
y = (Triangle *)m->data; // For any pair (t,y) of triangles in the cell
|
||||
// The same triangle pair can be in different cells. The following avoids redoing the check.
|
||||
if (t->info == NULL || y->info == NULL || (((List *)t->info)->containsNode(y) == NULL))
|
||||
{
|
||||
if (t->intersects(y, justproper))
|
||||
{
|
||||
MARK_VISIT(t); MARK_VISIT(y);
|
||||
ts = ((t->info != NULL) ? ((List *)t->info) : (new List)); ts->appendTail(y); t->info = ts;
|
||||
ts = ((y->info != NULL) ? ((List *)y->info) : (new List)); ts->appendTail(t); y->info = ts;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// ||
|
||||
////////////////////// Select Intersections ///////////////////////////
|
||||
// ||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int Basic_TMesh::selectIntersectingTriangles(UINT16 tris_per_cell, bool justproper)
|
||||
{
|
||||
Triangle *t;
|
||||
Vertex *v;
|
||||
Node *n;
|
||||
bool isSelection=0;
|
||||
List *selT = new List, *selV = new List;
|
||||
|
||||
TMesh::begin_progress();
|
||||
TMesh::report_progress(NULL);
|
||||
|
||||
FOREACHTRIANGLE(t, n) if (IS_VISITED(t))
|
||||
{
|
||||
isSelection=1;
|
||||
selT->appendTail(t);
|
||||
v=t->v1(); if (!IS_BIT(v,5)) {MARK_BIT(v,5); selV->appendTail(v);}
|
||||
v=t->v2(); if (!IS_BIT(v,5)) {MARK_BIT(v,5); selV->appendTail(v);}
|
||||
v=t->v3(); if (!IS_BIT(v,5)) {MARK_BIT(v,5); selV->appendTail(v);}
|
||||
}
|
||||
TMesh::report_progress(NULL);
|
||||
|
||||
if (!isSelection) {delete(selT); delete(selV); selT=&T; selV=&V;}
|
||||
|
||||
di_cell *c2, *c = new di_cell(this, !isSelection);
|
||||
List cells, todo(c);
|
||||
int i=0;
|
||||
|
||||
while ((c = (di_cell *)todo.popHead()) != NULL)
|
||||
{
|
||||
if (i>DI_MAX_NUMBER_OF_CELLS || c->triangles.numels() <= tris_per_cell) cells.appendHead(c);
|
||||
else
|
||||
{
|
||||
if (!(i % 1000)) TMesh::report_progress(NULL);
|
||||
i++;
|
||||
c2 = c->fork();
|
||||
todo.appendTail(c);
|
||||
todo.appendTail(c2);
|
||||
}
|
||||
}
|
||||
|
||||
// Deselect everything and select only intersecting triangles
|
||||
deselectTriangles();
|
||||
FOREACHTRIANGLE(t, n) t->info = NULL;
|
||||
i=0; FOREACHNODE(cells, n)
|
||||
{
|
||||
(((di_cell *)n->data)->selectIntersections(justproper));
|
||||
if (!(i % 100)) TMesh::report_progress("%d %% done ", ((i)* 100) / cells.numels());
|
||||
i++;
|
||||
}
|
||||
TMesh::end_progress();
|
||||
|
||||
// Dispose memory allocated for cells
|
||||
FOREACHVTTRIANGLE(selT, t, n) { if (t->info!=NULL) delete((List *)t->info); t->info = NULL; }
|
||||
while (cells.numels()) delete((di_cell *)cells.popHead());
|
||||
|
||||
// Count selected triangles for final report and delete stored normals
|
||||
int its=0;
|
||||
FOREACHVTTRIANGLE(selT, t, n) { if (IS_VISITED(t)) its++;}
|
||||
|
||||
if (its) TMesh::info("%d intersecting triangles have been selected.\n",its);
|
||||
else TMesh::info("No intersections detected.\n");
|
||||
|
||||
FOREACHVVVERTEX(selV, v, n) UNMARK_BIT(v,5);
|
||||
if (isSelection) {delete(selT); delete(selV);}
|
||||
|
||||
return its;
|
||||
}
|
||||
|
||||
void jitterIncrease(char *f)
|
||||
{
|
||||
bool isnegative = (f[0] == '-');
|
||||
int l = strlen(f);
|
||||
|
||||
if (isnegative)
|
||||
{
|
||||
for (int i = l - 1; i >= 1; i--)
|
||||
if (f[i] == '0') f[i] = '9';
|
||||
else if (f[i] == '.') continue;
|
||||
else { f[i]--; break; }
|
||||
} else
|
||||
{
|
||||
for (int i = l - 1; i >= 0; i--)
|
||||
if (f[i] == '9') f[i] = '0';
|
||||
else if (f[i] == '.') continue;
|
||||
else { f[i]++; break; }
|
||||
}
|
||||
}
|
||||
|
||||
void jitterDecrease(char *f)
|
||||
{
|
||||
bool isnegative = (f[0] == '-');
|
||||
int l = strlen(f);
|
||||
|
||||
if (isnegative)
|
||||
{
|
||||
for (int i = l - 1; i >= 1; i--)
|
||||
if (f[i] == '9') f[i] = '0';
|
||||
else if (f[i] == '.') continue;
|
||||
else { f[i]++; break; }
|
||||
} else
|
||||
{
|
||||
for (int i = l - 1; i >= 0; i--)
|
||||
if (f[i] == '0') f[i] = '9';
|
||||
else if (f[i] == '.') continue;
|
||||
else { f[i]--; break; }
|
||||
}
|
||||
}
|
||||
|
||||
void jitterCoordinate(coord& c, int j)
|
||||
{
|
||||
char floatver[32];
|
||||
float x;
|
||||
|
||||
sprintf(floatver, "%f", TMESH_TO_FLOAT(c));
|
||||
if (j > 0) jitterIncrease(floatver);
|
||||
else if (j<0) jitterDecrease(floatver);
|
||||
sscanf(floatver, "%f", &x); c = x;
|
||||
}
|
||||
|
||||
bool Basic_TMesh::safeCoordBackApproximation()
|
||||
{
|
||||
Node *n;
|
||||
Vertex *v;
|
||||
|
||||
deselectTriangles();
|
||||
|
||||
FOREACHVERTEX(v, n)
|
||||
{
|
||||
jitterCoordinate(v->x, 0);
|
||||
jitterCoordinate(v->y, 0);
|
||||
jitterCoordinate(v->z, 0);
|
||||
}
|
||||
|
||||
Edge *e;
|
||||
Vertex *ov1, *ov2;
|
||||
|
||||
int pnos = 0, nos;
|
||||
nos = 0; FOREACHEDGE(e, n) if (e->overlaps()) nos++;
|
||||
|
||||
do
|
||||
{
|
||||
pnos = nos;
|
||||
FOREACHEDGE(e, n) if (e->overlaps())
|
||||
{
|
||||
ov1 = e->t1->oppositeVertex(e);
|
||||
ov2 = e->t2->oppositeVertex(e);
|
||||
v = (Point::squaredTriangleArea3D(e->v1, e->v2, ov1) < Point::squaredTriangleArea3D(e->v1, e->v2, ov2)) ? (ov1) : (ov2);
|
||||
for (int a = -1; a <= 1; a++) for (int b = -1; b <= 1; b++) for (int c = -1; c <= 1; c++)
|
||||
{
|
||||
jitterCoordinate(v->x, a); jitterCoordinate(v->y, b); jitterCoordinate(v->z, c);
|
||||
if (e->overlaps())
|
||||
{
|
||||
jitterCoordinate(v->x, -a); jitterCoordinate(v->y, -b); jitterCoordinate(v->z, -c);
|
||||
} else a = b = c = 2;
|
||||
}
|
||||
}
|
||||
nos = 0; FOREACHEDGE(e, n) if (e->overlaps()) nos++;
|
||||
} while (nos < pnos);
|
||||
|
||||
// if (nos) TMesh::warning("%d overlaps could not be removed.\n", nos);
|
||||
return (nos == 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool remints_appendCubeToList(Triangle *t0, List& l)
|
||||
{
|
||||
if (!IS_VISITED(t0) || IS_BIT(t0, 6)) return false;
|
||||
|
||||
Triangle *t, *s;
|
||||
Vertex *v;
|
||||
List triList(t0);
|
||||
MARK_BIT(t0,6);
|
||||
coord minx = DBL_MAX, maxx = -DBL_MAX, miny = DBL_MAX, maxy = -DBL_MAX, minz = DBL_MAX, maxz = -DBL_MAX;
|
||||
|
||||
while(triList.numels())
|
||||
{
|
||||
t = (Triangle *)triList.popHead();
|
||||
v = t->v1();
|
||||
minx=MIN(minx,v->x); miny=MIN(miny,v->y); minz=MIN(minz,v->z);
|
||||
maxx=MAX(maxx,v->x); maxy=MAX(maxy,v->y); maxz=MAX(maxz,v->z);
|
||||
v = t->v2();
|
||||
minx=MIN(minx,v->x); miny=MIN(miny,v->y); minz=MIN(minz,v->z);
|
||||
maxx=MAX(maxx,v->x); maxy=MAX(maxy,v->y); maxz=MAX(maxz,v->z);
|
||||
v = t->v3();
|
||||
minx=MIN(minx,v->x); miny=MIN(miny,v->y); minz=MIN(minz,v->z);
|
||||
maxx=MAX(maxx,v->x); maxy=MAX(maxy,v->y); maxz=MAX(maxz,v->z);
|
||||
if ((s = t->t1()) != NULL && !IS_BIT(s, 6) && IS_VISITED(s)) {triList.appendHead(s); MARK_BIT(s,6);}
|
||||
if ((s = t->t2()) != NULL && !IS_BIT(s, 6) && IS_VISITED(s)) {triList.appendHead(s); MARK_BIT(s,6);}
|
||||
if ((s = t->t3()) != NULL && !IS_BIT(s, 6) && IS_VISITED(s)) {triList.appendHead(s); MARK_BIT(s,6);}
|
||||
}
|
||||
|
||||
l.appendTail(new Point(minx, miny, minz));
|
||||
l.appendTail(new Point(maxx, maxy, maxz));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool remints_isVertexInCube(Vertex *v, List& loc)
|
||||
{
|
||||
Node *n;
|
||||
Point *p1, *p2;
|
||||
FOREACHNODE(loc, n)
|
||||
{
|
||||
p1 = (Point *)n->data; n=n->next(); p2 = (Point *)n->data;
|
||||
if (!(v->x < p1->x || v->y < p1->y || v->z < p1->z ||
|
||||
v->x > p2->x || v->y > p2->y || v->z > p2->z)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void remints_selectTrianglesInCubes(Basic_TMesh *tin)
|
||||
{
|
||||
Triangle *t;
|
||||
Vertex *v;
|
||||
Node *n;
|
||||
List loc;
|
||||
FOREACHVTTRIANGLE((&(tin->T)), t, n) remints_appendCubeToList(t, loc);
|
||||
FOREACHVVVERTEX((&(tin->V)), v, n) if (remints_isVertexInCube(v, loc)) MARK_BIT(v, 5);
|
||||
FOREACHVTTRIANGLE((&(tin->T)), t, n)
|
||||
{
|
||||
UNMARK_BIT(t, 6);
|
||||
if (IS_BIT(t->v1(), 5) || IS_BIT(t->v2(), 5) || IS_BIT(t->v3(), 5)) MARK_VISIT(t);
|
||||
}
|
||||
FOREACHVVVERTEX((&(tin->V)), v, n) UNMARK_BIT(v, 5);
|
||||
loc.freeNodes();
|
||||
}
|
||||
|
||||
|
||||
// returns true on success
|
||||
|
||||
bool Basic_TMesh::strongIntersectionRemoval(int max_iters)
|
||||
{
|
||||
int n, iter_count = 0;
|
||||
bool qstatus = TMesh::quiet;
|
||||
|
||||
TMesh::info("Removing self-intersections...\n");
|
||||
|
||||
while ((++iter_count) <= max_iters && selectIntersectingTriangles())
|
||||
{
|
||||
for (n=1; n<iter_count; n++) growSelection();
|
||||
removeSelectedTriangles();
|
||||
removeSmallestComponents();
|
||||
TMesh::quiet = true; fillSmallBoundaries(E.numels(), false); TMesh::quiet = qstatus;
|
||||
coordBackApproximation();
|
||||
remints_selectTrianglesInCubes(this);
|
||||
}
|
||||
|
||||
if (iter_count > max_iters) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
} //namespace T_MESH
|
797
src/mesh_fix/src/Algorithms/holeFilling.cpp
Normal file
797
src/mesh_fix/src/Algorithms/holeFilling.cpp
Normal file
@ -0,0 +1,797 @@
|
||||
/****************************************************************************
|
||||
* TMesh *
|
||||
* *
|
||||
* Consiglio Nazionale delle Ricerche *
|
||||
* Istituto di Matematica Applicata e Tecnologie Informatiche *
|
||||
* Sezione di Genova *
|
||||
* IMATI-GE / CNR *
|
||||
* *
|
||||
* Authors: Marco Attene *
|
||||
* Copyright(C) 2013: IMATI-GE / CNR *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is dual-licensed as follows: *
|
||||
* *
|
||||
* (1) You may use TMesh as 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. *
|
||||
* In this case the 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 (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
* (2) You may use TMesh as part of a commercial software. In this case a *
|
||||
* proper agreement must be reached with the Authors and with IMATI-GE/CNR *
|
||||
* based on a proper licensing contract. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#include "tin.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace T_MESH
|
||||
{
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// T R I A N G U L A T I O N M E T H O D S //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/////// Computes the center of mass of the hole and star-patches ////////
|
||||
|
||||
int Basic_TMesh::StarTriangulateHole(Edge *e)
|
||||
{
|
||||
if (!e->isOnBoundary()) return 0;
|
||||
|
||||
List bvs;
|
||||
Node *n;
|
||||
Edge *e1, *e2, *e3;
|
||||
Point np;
|
||||
Vertex *v, *nv, *v1, *v2;
|
||||
int nt=0;
|
||||
|
||||
v = e->v1;
|
||||
|
||||
do
|
||||
{
|
||||
bvs.appendHead(v);
|
||||
v = v->nextOnBoundary();
|
||||
//MARK_BIT(v,5); // < AMF_ADD - since IMAT-STL 2.4-1 >
|
||||
} while (v != e->v1);
|
||||
|
||||
FOREACHVVVERTEX((&(bvs)), v, n) np = np+(*v);
|
||||
|
||||
np = np/bvs.numels();
|
||||
nv = newVertex(&np);
|
||||
V.appendHead(nv);
|
||||
|
||||
v1 = ((Vertex *)bvs.head()->data);
|
||||
Edge *ep = v1->e0; // AMF_ADD - since IMAT-STL 2.4-2
|
||||
e1 = CreateEdge(nv, v1);
|
||||
v1->e0 = ep; // AMF_ADD - since IMAT-STL 2.4-2
|
||||
for (n=bvs.head()->next(); n!=NULL; n=n->next())
|
||||
{
|
||||
v2 = ((Vertex *)n->data);
|
||||
e2 = CreateEdge(nv, v2);
|
||||
e3 = v1->getEdge(v2);
|
||||
CreateTriangle(e1, e2, e3);
|
||||
nt++;
|
||||
v1 = v2;
|
||||
e1 = e2;
|
||||
}
|
||||
v2 = ((Vertex *)bvs.head()->data);
|
||||
e2 = nv->getEdge(v2);
|
||||
e3 = v1->getEdge(v2);
|
||||
CreateTriangle(e1, e2, e3);
|
||||
nt++;
|
||||
|
||||
return nt;
|
||||
}
|
||||
|
||||
|
||||
///// Patch holes using 2D Delaunay triangulation on the plane 'nor' /////
|
||||
|
||||
int Basic_TMesh::TriangulateHole(Edge *e, Point *nor)
|
||||
{
|
||||
if (!e->isOnBoundary()) return 0;
|
||||
|
||||
List bvs;
|
||||
Node *n, *gn = NULL;
|
||||
Edge *e1, *e2;
|
||||
Vertex *v, *v1, *v2;
|
||||
double ang, gang;
|
||||
int nt = 0;
|
||||
|
||||
v = e->v1;
|
||||
do
|
||||
{
|
||||
bvs.appendHead(v);
|
||||
v = v->nextOnBoundary();
|
||||
} while (v != e->v1);
|
||||
|
||||
while (bvs.numels() > 2)
|
||||
{
|
||||
gang = DBL_MAX;
|
||||
FOREACHVVVERTEX((&(bvs)), v, n)
|
||||
if (!IS_BIT(v, 5) && v->e0 && (ang = v->getAngleOnAveragePlane(nor)) < gang)
|
||||
{gang = ang; gn = n;}
|
||||
if (gang == DBL_MAX)
|
||||
{
|
||||
TMesh::warning("TriangulateHole: Can't complete the triangulation.\n");
|
||||
FOREACHVVVERTEX((&(bvs)), v, n) UNMARK_BIT(v, 5);
|
||||
return 0;
|
||||
}
|
||||
v = ((Vertex *)gn->data);
|
||||
v1 = (Vertex *)((gn->next() != NULL)?(gn->next()):(bvs.head()))->data;
|
||||
v2 = (Vertex *)((gn->prev() != NULL)?(gn->prev()):(bvs.tail()))->data;
|
||||
e1 = v->getEdge(v1);
|
||||
e2 = v->getEdge(v2);
|
||||
if (!EulerEdgeTriangle(e1, e2)) MARK_BIT(v, 5);
|
||||
else { bvs.removeCell(gn); UNMARK_BIT(v1, 5); UNMARK_BIT(v2, 5); nt++; }
|
||||
}
|
||||
|
||||
int i, skips;
|
||||
do
|
||||
{
|
||||
skips = 0;
|
||||
for (n=E.head(), i=2*nt*nt; i<nt; n=n->next(), i--)
|
||||
{
|
||||
e = ((Edge *)n->data);
|
||||
ang = e->delaunayMinAngle();
|
||||
if (e->swap())
|
||||
{if (e->delaunayMinAngle() <= ang) e->swap(1); else skips++;}
|
||||
}
|
||||
if (i < 0) {TMesh::warning("Optimization is taking too long. I give up.\n"); break;}
|
||||
} while (skips);
|
||||
|
||||
return nt;
|
||||
}
|
||||
|
||||
|
||||
///// Triangulates a hole using the additional vertices in 'vl' /////
|
||||
|
||||
int Basic_TMesh::TriangulateHole(Edge *e, List *vl)
|
||||
{
|
||||
if (!e->isOnBoundary()) return 0;
|
||||
|
||||
List bvs, ovbs, nedg;
|
||||
Node *n, *gn = NULL;
|
||||
Edge *e1, *e2;
|
||||
Vertex *v, *v1, *v2;
|
||||
double ang, gang;
|
||||
int nt = 0, neb;
|
||||
|
||||
v = e->v1;
|
||||
|
||||
do
|
||||
{
|
||||
bvs.appendHead(v);
|
||||
v = v->nextOnBoundary();
|
||||
} while (v != e->v1);
|
||||
ovbs.appendList(&bvs);
|
||||
|
||||
while (bvs.numels() > 2) // While there are more than two boundary vertices
|
||||
{
|
||||
gang = DBL_MAX;
|
||||
FOREACHVVVERTEX((&(bvs)), v, n)
|
||||
if (!IS_BIT(v, 5) && v->e0 && (ang = v->getAngleForTriangulation()) < gang)
|
||||
{gang = ang; gn = n;}
|
||||
if (gang == DBL_MAX)
|
||||
{
|
||||
TMesh::warning("TriangulateHole: Can't complete the triangulation.\n");
|
||||
FOREACHVVVERTEX((&(bvs)), v, n) UNMARK_BIT(v, 5);
|
||||
return 0;
|
||||
}
|
||||
v = ((Vertex *)gn->data);
|
||||
v1 = (Vertex *)((gn->next() != NULL)?(gn->next()):(bvs.head()))->data;
|
||||
v2 = (Vertex *)((gn->prev() != NULL)?(gn->prev()):(bvs.tail()))->data;
|
||||
e1 = v->getEdge(v1);
|
||||
e2 = v->getEdge(v2);
|
||||
neb = E.numels();
|
||||
if (!EulerEdgeTriangle(e1, e2)) MARK_BIT(v, 5);
|
||||
else
|
||||
{
|
||||
bvs.removeCell(gn);
|
||||
UNMARK_BIT(v1, 5);
|
||||
UNMARK_BIT(v2, 5);
|
||||
nt++;
|
||||
if (E.numels() > neb) nedg.appendHead(E.head()->data);
|
||||
}
|
||||
}
|
||||
|
||||
// if (nt < 2) return nt;
|
||||
|
||||
// Calcolo una normale per il buco come media dei nuovi triangoli
|
||||
int i;
|
||||
Point nor;
|
||||
|
||||
for (i=0, n=T.head(); i<nt; i++, n=n->next()) nor = nor+((Triangle *)n->data)->getNormal();
|
||||
if (nor.isNull())
|
||||
{
|
||||
TMesh::warning("TriangulateHole: Unable to compute an average normal. Can't optimize.\n");
|
||||
return nt;
|
||||
}
|
||||
nor.normalize();
|
||||
|
||||
// Memorizzo da qualche parte la posizione originale dei vertici
|
||||
// e Proietto il boundary sul piano con normale quella appena calcolata
|
||||
//coord *ovps = (coord *)malloc((ovbs.numels())*3*sizeof(coord)); // AMF_CHANGE - since IMAT-STL 2.4-2
|
||||
coord *ovps = new coord[3*(ovbs.numels())]; // AMF_CHANGE - since IMAT-STL 2.4-2
|
||||
int j = 0;
|
||||
FOREACHVVVERTEX((&(ovbs)), v, n)
|
||||
{
|
||||
ovps[j++] = v->x;
|
||||
ovps[j++] = v->y;
|
||||
ovps[j++] = v->z;
|
||||
v->project(&nor);
|
||||
}
|
||||
|
||||
// Proietto i punti interni sul piano d'appoggio
|
||||
Point *p;
|
||||
//coord *ovpsi = (coord *)malloc((vl->numels())*3*sizeof(coord)); // AMF_CHANGE - since IMAT-STL 2.4-2
|
||||
coord *ovpsi = new coord[3*(vl->numels())]; // AMF_CHANGE - since IMAT-STL 2.4-2
|
||||
j = 0;
|
||||
FOREACHNODE((*vl), n)
|
||||
{
|
||||
p = ((Point *)n->data);
|
||||
ovpsi[j++] = p->x; ovpsi[j++] = p->y; ovpsi[j++] = p->z;
|
||||
}
|
||||
FOREACHNODE((*vl), n)
|
||||
{
|
||||
p = ((Point *)n->data);
|
||||
p->project(&nor);
|
||||
}
|
||||
|
||||
// Ottimizzo secondo Delaunay vincolato al boundary la nuova regione
|
||||
|
||||
int sw;
|
||||
do
|
||||
{
|
||||
sw = 0;
|
||||
FOREACHVEEDGE((&(nedg)), e1, n)
|
||||
{
|
||||
ang = e1->delaunayMinAngle();
|
||||
if (e1->swap())
|
||||
{if (e1->delaunayMinAngle() <= ang) e1->swap(1); else sw++;}
|
||||
}
|
||||
} while (sw);
|
||||
|
||||
// Inserisco i punti interni
|
||||
int ntt = T.numels()-nt;
|
||||
List ivs;
|
||||
|
||||
FOREACHNODE((*vl), n)
|
||||
{
|
||||
p = ((Point *)n->data);
|
||||
ivs.appendTail(watsonInsert(p, &T, T.numels()-ntt));
|
||||
}
|
||||
nt = (T.numels() - ntt);
|
||||
|
||||
// Riporto i vertici interni al loro posto
|
||||
j=0; FOREACHVVVERTEX((&(ivs)), v, n)
|
||||
{
|
||||
if (v != NULL)
|
||||
{
|
||||
v->x = ovpsi[j++]; v->y = ovpsi[j++]; v->z = ovpsi[j++];
|
||||
} else j+=3;
|
||||
}
|
||||
delete [] ovpsi; //free(ovpsi); // AMF_CHANGE - since IMAT-STL 2.4-2
|
||||
|
||||
// Riporto i vertici del boundary al loro posto
|
||||
j=0; FOREACHVVVERTEX((&(ovbs)), v, n)
|
||||
{
|
||||
v->x = ovps[j++]; v->y = ovps[j++]; v->z = ovps[j++];
|
||||
}
|
||||
delete [] ovps; //free(ovps); // AMF_CHANGE - since IMAT-STL 2.4-2
|
||||
|
||||
return nt;
|
||||
}
|
||||
|
||||
|
||||
////// Inserts the point 'p' in the Delaunay triangulation 'tR' with 'nt' triangles ////
|
||||
|
||||
Vertex *Basic_TMesh::watsonInsert(Point *p, List *tR, int nt)
|
||||
{
|
||||
Node *n, *m;
|
||||
Edge *e;
|
||||
Triangle *t;
|
||||
List bdr, bdrs, todo, *ve;
|
||||
Vertex *v1, *v2, *v3;
|
||||
int i;
|
||||
|
||||
for (i=0, n = T.head(); i<nt; n=n->next(), i++)
|
||||
{
|
||||
t = ((Triangle *)n->data);
|
||||
if (t->e1 != NULL && t->inSphere(p))
|
||||
{
|
||||
v1 = t->v1(); v2 = t->v2(); v3 = t->v3();
|
||||
if (!IS_BIT(v1, 5)) bdr.appendHead(v1);
|
||||
if (!IS_BIT(v2, 5)) bdr.appendHead(v2);
|
||||
if (!IS_BIT(v3, 5)) bdr.appendHead(v3);
|
||||
MARK_BIT(v1, 5); MARK_BIT(v2, 5); MARK_BIT(v3, 5);
|
||||
MARK_BIT(t, 6);
|
||||
todo.appendHead(t);
|
||||
}
|
||||
}
|
||||
if (bdr.numels() == 0) return NULL;
|
||||
|
||||
FOREACHVVVERTEX((&(bdr)), v1, n)
|
||||
{
|
||||
ve = v1->VE();
|
||||
FOREACHVEEDGE(ve, e, m) if (!IS_BIT(e->t1, 6) || !IS_BIT(e->t2, 6)) v1->e0 = e;
|
||||
delete(ve);
|
||||
}
|
||||
|
||||
while (todo.numels())
|
||||
{
|
||||
t = ((Triangle *)todo.head()->data);
|
||||
todo.removeCell(todo.head());
|
||||
unlinkTriangleNoManifold(t);
|
||||
}
|
||||
|
||||
Node *tmp;
|
||||
for (i=0, n = T.head(); i<nt; i++)
|
||||
{
|
||||
t = ((Triangle *)n->data);
|
||||
if (t->e1 == NULL) {tmp = n; n=n->next(); T.freeCell(tmp);}
|
||||
else n=n->next();
|
||||
}
|
||||
|
||||
for (n = bdr.head(); n!=NULL;)
|
||||
{
|
||||
v1 = ((Vertex *)n->data);
|
||||
if (v1->e0 == NULL) {tmp = n; n=n->next(); bdr.removeCell(tmp);}
|
||||
else n=n->next();
|
||||
}
|
||||
|
||||
v1 = v2 = ((Vertex *)bdr.head()->data);
|
||||
do
|
||||
{
|
||||
bdrs.appendHead(v1);
|
||||
v1 = v1->nextOnBoundary();
|
||||
} while (v1 != v2);
|
||||
|
||||
Vertex *v = newVertex(p->x, p->y, p->z);
|
||||
V.appendHead(v);
|
||||
|
||||
v1 = ((Vertex *)bdrs.head()->data);
|
||||
v->e0 = e = newEdge(v, v1);
|
||||
UNMARK_BIT(v1, 5);
|
||||
E.appendHead(e);
|
||||
|
||||
for (n = bdrs.head()->next(); n!=NULL; n=n->next())
|
||||
{
|
||||
v1 = ((Vertex *)n->data);
|
||||
UNMARK_BIT(v1, 5);
|
||||
v2 = ((Vertex *)n->prev()->data);
|
||||
e = newEdge(v, v1);
|
||||
CreateTriangle(e, v1->getEdge(v2), (Edge *)E.head()->data);
|
||||
E.appendHead(e);
|
||||
}
|
||||
EulerEdgeTriangle(v->e0, (Edge *)E.head()->data);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
//// Removes a vertex and retriangulates its VT ////
|
||||
|
||||
int Basic_TMesh::retriangulateVT(Vertex *v)
|
||||
{
|
||||
Point nor;
|
||||
Edge *e, *e0 = v->e0->t1->oppositeEdge(v);
|
||||
List *vt = v->VT();
|
||||
List oe;
|
||||
Triangle *t;
|
||||
Node *m, *n;
|
||||
int i, nt;
|
||||
|
||||
FOREACHVTTRIANGLE(vt, t, m)
|
||||
{
|
||||
e = t->oppositeEdge(v);
|
||||
oe.appendTail(t->prevEdge(e));
|
||||
oe.appendTail(e);
|
||||
oe.appendTail(t->nextEdge(e));
|
||||
nor = nor+t->getNormal();
|
||||
unlinkTriangle(t);
|
||||
}
|
||||
removeUnlinkedElements(); // AMF_CHANGE - since IMAT-STL 2.4-2
|
||||
nor.normalize();
|
||||
nt = TriangulateHole(e0, &nor);
|
||||
|
||||
for (m=T.head(), i=0; i<nt; i++, m=m->next())
|
||||
{
|
||||
t = ((Triangle *)m->data);
|
||||
if (t->overlaps() || t->isExactlyDegenerate()) break;
|
||||
}
|
||||
if (i<nt)
|
||||
{
|
||||
TMesh::warning("Re-triangulation failed. Restoring..\n");
|
||||
for (m=T.head(), i=0; i<nt; i++, m=m->next())
|
||||
unlinkTriangle(((Triangle *)m->data));
|
||||
n = oe.head();
|
||||
FOREACHVTTRIANGLE(vt, t, m)
|
||||
{
|
||||
t->e1 = ((Edge *)n->data); n=n->next();
|
||||
t->e2 = ((Edge *)n->data); n=n->next();
|
||||
t->e3 = ((Edge *)n->data); n=n->next();
|
||||
t->e1->v1 = v; t->e1->v2 = (t->e2->t1 == NULL)?(t->e2->v1):(t->e2->v2);
|
||||
t->e3->v1 = v; t->e3->v2 = (t->e2->t1 == NULL)?(t->e2->v2):(t->e2->v1);
|
||||
((t->e2->t1 == NULL)?(t->e2->t1):(t->e2->t2)) = t;
|
||||
t->e1->t1 = t;
|
||||
t->e3->t2 = t;
|
||||
}
|
||||
v->e0 = ((Triangle *)vt->head()->data)->e1;
|
||||
}
|
||||
delete(vt);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
////////// Generic method for patching holes. Heuristic. /////////////
|
||||
////////// Small angles are patched first, if possible. /////////////
|
||||
|
||||
int Basic_TMesh::TriangulateHole(Edge *e)
|
||||
{
|
||||
if (!e->isOnBoundary()) return 0;
|
||||
|
||||
List bvs;
|
||||
Node *n, *gn = NULL;
|
||||
Edge *e1, *e2;
|
||||
Vertex *v, *v1, *v2;
|
||||
double ang, gang;
|
||||
int nt = 0;
|
||||
Triangle *t;
|
||||
v = e->v1;
|
||||
|
||||
t = (e->t1!=NULL)?(e->t1):(e->t2);
|
||||
if (t->nextEdge(e)->isOnBoundary() && t->prevEdge(e)->isOnBoundary()) return 0;
|
||||
|
||||
do
|
||||
{
|
||||
bvs.appendHead(v);
|
||||
v = v->nextOnBoundary();
|
||||
} while (v != e->v1);
|
||||
|
||||
while (bvs.numels() > 2)
|
||||
{
|
||||
gang = DBL_MAX;
|
||||
FOREACHVVVERTEX((&bvs), v, n)
|
||||
if (!IS_BIT(v, 5) && v->e0 && (ang = v->getAngleForTriangulation()) < gang)
|
||||
{gang = ang; gn = n;}
|
||||
if (gang == DBL_MAX)
|
||||
{
|
||||
TMesh::warning("TriangulateHole: Can't complete the triangulation.\n");
|
||||
FOREACHVVVERTEX((&bvs), v, n) UNMARK_BIT(v, 5);
|
||||
int i=0; FOREACHTRIANGLE(t, n) if (i++==nt) break; else unlinkTriangle(t);
|
||||
removeUnlinkedElements();
|
||||
return 0;
|
||||
}
|
||||
v = ((Vertex *)gn->data);
|
||||
v1 = (Vertex *)((gn->next() != NULL)?(gn->next()):(bvs.head()))->data;
|
||||
v2 = (Vertex *)((gn->prev() != NULL)?(gn->prev()):(bvs.tail()))->data;
|
||||
e1 = v->getEdge(v1);
|
||||
e2 = v->getEdge(v2);
|
||||
if ((t=EulerEdgeTriangle(e1,e2))==NULL) MARK_BIT(v, 5);
|
||||
else { bvs.removeCell(gn); UNMARK_BIT(v1, 5); UNMARK_BIT(v2, 5); MARK_VISIT(t); nt++; }
|
||||
}
|
||||
|
||||
return nt;
|
||||
}
|
||||
|
||||
|
||||
// Fills the hole identified by 'e' and leaves the new triangle selected.
|
||||
// 'refine' is for internal vertex insertion.
|
||||
|
||||
void Basic_TMesh::FillHole(Edge *e, bool refine)
|
||||
{
|
||||
int i, nt;
|
||||
Node *n;
|
||||
Triangle *t;
|
||||
Vertex *v;
|
||||
|
||||
deselectTriangles();
|
||||
FOREACHVERTEX(v, n) UNMARK_BIT(v, 5);
|
||||
nt = TriangulateHole(e);
|
||||
if (!nt) return;
|
||||
|
||||
i=0; FOREACHTRIANGLE(t, n) if (i++==nt) break; else MARK_VISIT(t);
|
||||
|
||||
if (refine)
|
||||
refineSelectedHolePatches((Triangle *)T.head()->data);
|
||||
}
|
||||
|
||||
//// Triangulate Small Boundaries (with less than 'nbe' edges) /////
|
||||
|
||||
int Basic_TMesh::fillSmallBoundaries(int nbe, bool refine_patches)
|
||||
{
|
||||
if (nbe == 0) nbe = E.numels();
|
||||
Vertex *v,*w;
|
||||
Triangle *t;
|
||||
Node *n;
|
||||
int grd, is_selection=0, tbds = 0, pct = 100;
|
||||
List bdrs;
|
||||
|
||||
TMesh::begin_progress();
|
||||
TMesh::report_progress("0%% done ");
|
||||
|
||||
FOREACHTRIANGLE(t, n) if (IS_VISITED(t)) {is_selection=1; break;}
|
||||
|
||||
if (is_selection) {
|
||||
FOREACHTRIANGLE(t, n) if (!IS_VISITED(t))
|
||||
{
|
||||
MARK_BIT(t->v1(), 6); MARK_BIT(t->v2(), 6); MARK_BIT(t->v3(), 6);
|
||||
}
|
||||
}
|
||||
else FOREACHVERTEX(v, n) UNMARK_BIT(v, 6);
|
||||
|
||||
FOREACHVERTEX(v, n)
|
||||
{
|
||||
grd = 0;
|
||||
if (!IS_BIT(v, 6) && v->isOnBoundary())
|
||||
{
|
||||
tbds++;
|
||||
w = v;
|
||||
do
|
||||
{
|
||||
if (IS_BIT(w, 6)) grd=nbe+1;
|
||||
MARK_BIT(w, 6);
|
||||
grd++;
|
||||
w = w->nextOnBoundary();
|
||||
} while (w != v);
|
||||
if (grd <= nbe) bdrs.appendHead(w->nextBoundaryEdge());
|
||||
}
|
||||
}
|
||||
FOREACHVERTEX(v, n) { UNMARK_BIT(v, 5); UNMARK_BIT(v, 6); }
|
||||
|
||||
deselectTriangles();
|
||||
|
||||
pct=0; FOREACHNODE(bdrs, n)
|
||||
{
|
||||
if (TriangulateHole((Edge *)n->data) && refine_patches)
|
||||
{
|
||||
t = (Triangle *)T.head()->data;
|
||||
refineSelectedHolePatches(t);
|
||||
}
|
||||
TMesh::report_progress("%d%% done ",((++pct)*100)/bdrs.numels());
|
||||
}
|
||||
|
||||
grd = bdrs.numels();
|
||||
|
||||
TMesh::end_progress();
|
||||
|
||||
return grd;
|
||||
}
|
||||
|
||||
|
||||
// Inserts new vertices in the current selection so as
|
||||
// to reflect the density of the surrounding mesh.
|
||||
// This method assumes that the selection has no internal vertices.
|
||||
|
||||
int Basic_TMesh::refineSelectedHolePatches(Triangle *t0)
|
||||
{
|
||||
Node *n, *m;
|
||||
Triangle *t, *t1, *t2;
|
||||
Edge *e, *f;
|
||||
Vertex *v;
|
||||
List *ve, toswap, reg, all_edges, interior_edges, boundary_edges, boundary_vertices, interior_vertices;
|
||||
coord sigma, l, sv1, sv2, sv3, dv1, dv2, dv3;
|
||||
int swaps, totits, nee, ntb, nnt=-1, pnnt, gits=0;
|
||||
const double alpha = sqrt(2.0);
|
||||
Point vc;
|
||||
|
||||
if (t0 != NULL)
|
||||
{
|
||||
if (!IS_VISITED(t0)) TMesh::error("refineSelectedHolePatches: unexpected unselected t0 !");
|
||||
UNMARK_VISIT(t0); toswap.appendHead(t0);
|
||||
while ((t=(Triangle *)toswap.popHead()) != NULL)
|
||||
{
|
||||
reg.appendHead(t);
|
||||
t1=t->t1(); if (IS_VISITED(t1)) {UNMARK_VISIT(t1); toswap.appendHead(t1);}
|
||||
t1=t->t2(); if (IS_VISITED(t1)) {UNMARK_VISIT(t1); toswap.appendHead(t1);}
|
||||
t1=t->t3(); if (IS_VISITED(t1)) {UNMARK_VISIT(t1); toswap.appendHead(t1);}
|
||||
}
|
||||
FOREACHVTTRIANGLE((®), t, n) MARK_VISIT(t);
|
||||
}
|
||||
else FOREACHTRIANGLE(t, n) if (IS_VISITED(t)) reg.appendHead(t);
|
||||
|
||||
printf("%d\n",reg.numels());
|
||||
|
||||
FOREACHVTTRIANGLE((®), t, n)
|
||||
{
|
||||
e = t->e1; if (!IS_BIT(e, 5)) {MARK_BIT(e, 5); all_edges.appendHead(e);} else UNMARK_BIT(e, 5);
|
||||
e = t->e2; if (!IS_BIT(e, 5)) {MARK_BIT(e, 5); all_edges.appendHead(e);} else UNMARK_BIT(e, 5);
|
||||
e = t->e3; if (!IS_BIT(e, 5)) {MARK_BIT(e, 5); all_edges.appendHead(e);} else UNMARK_BIT(e, 5);
|
||||
}
|
||||
|
||||
while (all_edges.numels())
|
||||
{
|
||||
e = (Edge *)all_edges.popHead();
|
||||
if (IS_BIT(e, 5)) { boundary_edges.appendHead(e); UNMARK_BIT(e, 5); }
|
||||
else { interior_edges.appendHead(e); MARK_BIT(e, 5); }
|
||||
}
|
||||
|
||||
FOREACHVEEDGE((&boundary_edges), e, n)
|
||||
{
|
||||
v = e->v1; if (!IS_BIT(v, 5)) { MARK_BIT(v, 5); boundary_vertices.appendHead(v);}
|
||||
v = e->v2; if (!IS_BIT(v, 5)) { MARK_BIT(v, 5); boundary_vertices.appendHead(v);}
|
||||
}
|
||||
|
||||
FOREACHVVVERTEX((&boundary_vertices), v, n) UNMARK_BIT(v, 5);
|
||||
|
||||
// Due to the above definitions, interior edges are BIT
|
||||
|
||||
FOREACHVVVERTEX((&boundary_vertices), v, n)
|
||||
{
|
||||
ve = v->VE();
|
||||
sigma=0; nee=0; FOREACHVEEDGE(ve, e, m) if (!IS_BIT(e, 5)) {nee++; sigma += e->length();}
|
||||
sigma /= nee; v->info = new coord(sigma);
|
||||
delete(ve);
|
||||
}
|
||||
|
||||
FOREACHVEEDGE((&interior_edges), e, n) UNMARK_BIT(e, 5);
|
||||
FOREACHVEEDGE((&boundary_edges), e, n) MARK_BIT(e, 6);
|
||||
|
||||
do
|
||||
{
|
||||
pnnt=nnt;
|
||||
nnt=0;
|
||||
FOREACHVTTRIANGLE((®), t, n)
|
||||
{
|
||||
vc = t->getCenter();
|
||||
sv1 = (*(coord *)t->v1()->info);
|
||||
sv2 = (*(coord *)t->v2()->info);
|
||||
sv3 = (*(coord *)t->v3()->info);
|
||||
sigma = (sv1+sv2+sv3)/3.0;
|
||||
dv1 = alpha*(t->v1()->distance(&vc));
|
||||
dv2 = alpha*(t->v2()->distance(&vc));
|
||||
dv3 = alpha*(t->v3()->distance(&vc));
|
||||
if (dv1>sigma && dv1>sv1 && dv2>sigma && dv2>sv2 && dv3>sigma && dv3>sv3)
|
||||
{
|
||||
ntb = T.numels();
|
||||
v = splitTriangle(t,&vc,1);
|
||||
nnt += (T.numels()-ntb);
|
||||
if (T.numels() == ntb+2)
|
||||
{
|
||||
v->info = new coord(sigma);
|
||||
interior_vertices.appendHead(v);
|
||||
interior_edges.appendHead(v->e0);
|
||||
interior_edges.appendHead(v->e0->leftTriangle(v)->prevEdge(v->e0));
|
||||
interior_edges.appendHead(v->e0->rightTriangle(v)->nextEdge(v->e0));
|
||||
t1 = ((Triangle *)T.head()->data);
|
||||
t2 = ((Triangle *)T.head()->next()->data);
|
||||
t1->mask = t2->mask = t->mask;
|
||||
reg.appendHead(t1); reg.appendHead(t2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FOREACHVEEDGE((&interior_edges), e, n) {MARK_BIT(e, 5); toswap.appendHead(e);}
|
||||
totits=0; swaps=1;
|
||||
while (swaps && totits++ < 10)
|
||||
{
|
||||
swaps = 0;
|
||||
while ((e=(Edge *)toswap.popHead())!=NULL)
|
||||
{
|
||||
UNMARK_BIT(e, 5);
|
||||
l = e->squaredLength();
|
||||
if (e->swap())
|
||||
{
|
||||
if (e->squaredLength() >= l*0.999999) e->swap(1);
|
||||
else
|
||||
{
|
||||
swaps++;
|
||||
toswap.appendTail(e);
|
||||
f = e->t1->nextEdge(e); if (!IS_BIT(f, 5) && !IS_BIT(f, 6)) { MARK_BIT(f, 5); toswap.appendTail(f); }
|
||||
f = e->t1->prevEdge(e); if (!IS_BIT(f, 5) && !IS_BIT(f, 6)) { MARK_BIT(f, 5); toswap.appendTail(f); }
|
||||
f = e->t2->nextEdge(e); if (!IS_BIT(f, 5) && !IS_BIT(f, 6)) { MARK_BIT(f, 5); toswap.appendTail(f); }
|
||||
f = e->t2->prevEdge(e); if (!IS_BIT(f, 5) && !IS_BIT(f, 6)) { MARK_BIT(f, 5); toswap.appendTail(f); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pnnt==nnt) gits++;
|
||||
} while (nnt && gits<10);
|
||||
|
||||
//FOREACHVEEDGE((&boundary_edges), e, n) UNMARK_BIT(e, 6);
|
||||
FOREACHVVVERTEX((&boundary_vertices), v, n) { delete((coord *)v->info); v->info = NULL; MARK_BIT(v, 5);}
|
||||
FOREACHVVVERTEX((&interior_vertices), v, n) { delete((coord *)v->info); v->info = NULL; MARK_BIT(v, 6);}
|
||||
|
||||
if (gits>=10) {TMesh::warning("Fill holes: Refinement stage failed to converge. Breaking.\n"); return 1;}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Joins the two boundary vertices gv and gw through an edge. A pair of triangles is
|
||||
// added to properly change the topology of the mesh.
|
||||
// On success, the return value is the new edge connecting the two vertices.
|
||||
// NULL is returned on failure.
|
||||
// Failure occurs if gv and gw are not both on boundary.
|
||||
// If 'justconnect' is false, the remaining hole is filled with new triangles, unless
|
||||
// gv and gw are contiguous on the boundary loop (failure).
|
||||
// If 'justconnect' is true, gv and gw must not belong to the same boundary loop (failure).
|
||||
// If 'refine', the patching triangles are refined to reproduce neighboring density.
|
||||
|
||||
Edge *Basic_TMesh::joinBoundaryLoops(Vertex *gv, Vertex *gw, bool justconnect, bool refine)
|
||||
{
|
||||
Vertex *v, *gvn, *gwn;
|
||||
Edge *e, *gve, *gwe;
|
||||
Triangle *t;
|
||||
Node *n;
|
||||
double tl1 = 0.0, tl2 = 0.0, pl1, pl2;
|
||||
|
||||
if (gv == NULL || gw == NULL || !gv->isOnBoundary() || !gw->isOnBoundary()) return NULL;
|
||||
|
||||
FOREACHVERTEX(v, n) UNMARK_VISIT(v);
|
||||
deselectTriangles();
|
||||
|
||||
v = gv;
|
||||
if (!justconnect)
|
||||
{
|
||||
do { v = v->nextOnBoundary(); if (v == gw) return NULL; } while (v != gv);
|
||||
} else
|
||||
{
|
||||
gvn = gv->nextOnBoundary(); gwn = gv->prevOnBoundary();
|
||||
if (gw == gvn || gw == gwn) return NULL;
|
||||
if (gw == gvn->nextOnBoundary())
|
||||
{
|
||||
t = EulerEdgeTriangle(gvn->prevBoundaryEdge(), gvn->nextBoundaryEdge()); MARK_VISIT(t); return t->oppositeEdge(gvn);
|
||||
}
|
||||
if (gw == gwn->prevOnBoundary())
|
||||
{
|
||||
t = EulerEdgeTriangle(gwn->prevBoundaryEdge(), gwn->nextBoundaryEdge()); MARK_VISIT(t); return t->oppositeEdge(gwn);
|
||||
}
|
||||
}
|
||||
|
||||
gve = gv->prevBoundaryEdge();
|
||||
gvn = gve->oppositeVertex(gv);
|
||||
gwe = gw->nextBoundaryEdge();
|
||||
gwn = gwe->oppositeVertex(gw);
|
||||
|
||||
Edge *je = CreateEdge(gv, gw);
|
||||
Edge *je1 = CreateEdge(gv, gwn);
|
||||
Edge *je2 = CreateEdge(gwn, gvn);
|
||||
|
||||
t = CreateTriangle(je, gwe, je1); MARK_VISIT(t);
|
||||
t = CreateTriangle(je1, je2, gve); MARK_VISIT(t);
|
||||
|
||||
if (justconnect) return je;
|
||||
|
||||
v = gv; do { e = v->nextBoundaryEdge(); v = e->oppositeVertex(v); tl1 += e->length(); } while (v != gv);
|
||||
v = gw; do { e = v->nextBoundaryEdge(); v = e->oppositeVertex(v); tl2 += e->length(); } while (v != gw);
|
||||
pl1 = tl1; pl2 = tl2;
|
||||
|
||||
double c1, c2;
|
||||
|
||||
e = je;
|
||||
while (e->isOnBoundary())
|
||||
{
|
||||
gv = (e->t2 != NULL) ? (e->v2) : (e->v1); gve = gv->nextBoundaryEdge();
|
||||
gw = (e->t1 != NULL) ? (e->v2) : (e->v1); gwe = gw->prevBoundaryEdge();
|
||||
c1 = fabs((pl1 - gve->length())*tl2 - pl2*tl1);
|
||||
c2 = fabs((pl2 - gwe->length())*tl1 - pl1*tl2);
|
||||
if (c1<c2)
|
||||
{
|
||||
t = EulerEdgeTriangle(e, gve); MARK_VISIT(t);
|
||||
pl1 -= gve->length();
|
||||
e = t->nextEdge(gve);
|
||||
} else
|
||||
{
|
||||
t = EulerEdgeTriangle(gwe, e); MARK_VISIT(t);
|
||||
pl2 -= gwe->length();
|
||||
e = t->prevEdge(gwe);
|
||||
}
|
||||
}
|
||||
|
||||
if (refine) refineSelectedHolePatches();
|
||||
|
||||
return je;
|
||||
}
|
||||
|
||||
} //namespace T_MESH
|
1039
src/mesh_fix/src/Algorithms/marchIntersections.cpp
Normal file
1039
src/mesh_fix/src/Algorithms/marchIntersections.cpp
Normal file
File diff suppressed because it is too large
Load Diff
168
src/mesh_fix/src/Algorithms/subdivision.cpp
Normal file
168
src/mesh_fix/src/Algorithms/subdivision.cpp
Normal file
@ -0,0 +1,168 @@
|
||||
/****************************************************************************
|
||||
* TMesh *
|
||||
* *
|
||||
* Consiglio Nazionale delle Ricerche *
|
||||
* Istituto di Matematica Applicata e Tecnologie Informatiche *
|
||||
* Sezione di Genova *
|
||||
* IMATI-GE / CNR *
|
||||
* *
|
||||
* Authors: Marco Attene *
|
||||
* Copyright(C) 2012: IMATI-GE / CNR *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is dual-licensed as follows: *
|
||||
* *
|
||||
* (1) You may use TMesh as 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. *
|
||||
* In this case the 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 (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
* (2) You may use TMesh as part of a commercial software. In this case a *
|
||||
* proper agreement must be reached with the Authors and with IMATI-GE/CNR *
|
||||
* based on a proper licensing contract. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#include "tmesh.h"
|
||||
|
||||
using namespace T_MESH;
|
||||
|
||||
//////////////////// Loop's Subdivision Scheme //////////////////
|
||||
|
||||
class loopSplit
|
||||
{
|
||||
public:
|
||||
Edge *e;
|
||||
Point p;
|
||||
|
||||
loopSplit(Edge *_e, int md)
|
||||
{
|
||||
e = _e;
|
||||
if (e->t1 == NULL || e->t2 == NULL || md) p = ((*e->v1)+(*e->v2))/2.0;
|
||||
else
|
||||
{
|
||||
Vertex *ov1 = e->t1->oppositeVertex(e);
|
||||
Vertex *ov2 = e->t2->oppositeVertex(e);
|
||||
p = ((((*e->v1)+(*e->v2))*3.0)+((*ov1)+(*ov2)))/8.0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
double subsurfbeta_loop(int k)
|
||||
{
|
||||
double beta = (cos((2.0*M_PI)/((double)k))/4.0)+(3.0/8.0);
|
||||
return ((5.0/8.0)-(beta*beta))/((double)k);
|
||||
}
|
||||
|
||||
|
||||
void loopRelaxOriginal(Vertex *v)
|
||||
{
|
||||
Node *n;
|
||||
Edge *e;
|
||||
List *ve;
|
||||
Point np;
|
||||
int k;
|
||||
double beta;
|
||||
|
||||
if (v->isOnBoundary())
|
||||
{
|
||||
ve = v->VE();
|
||||
np = (*(((Edge *)ve->head()->data)->oppositeVertex(v)));
|
||||
np += (*(((Edge *)ve->tail()->data)->oppositeVertex(v)));
|
||||
np = (((*v)*6.0)+np)/8.0;
|
||||
delete(ve);
|
||||
}
|
||||
else
|
||||
{
|
||||
ve = v->VE();
|
||||
k = ve->numels();
|
||||
beta = subsurfbeta_loop(k);
|
||||
FOREACHVEEDGE(ve, e, n) np += (*(e->oppositeVertex(v)));
|
||||
np = ((*v)*(1.0-k*beta))+(np*beta);
|
||||
delete(ve);
|
||||
}
|
||||
|
||||
v->info = new Point(&np);
|
||||
}
|
||||
|
||||
|
||||
//// Performs one subdivision step using Loop's scheme ////
|
||||
//// If 'md' is set the method does not alter the geometry ////
|
||||
|
||||
void Basic_TMesh::loopSubdivision(bool midpoint)
|
||||
{
|
||||
List nvs;
|
||||
Edge *e, *e1, *e2;
|
||||
Node *n;
|
||||
Vertex *v;
|
||||
Triangle *t;
|
||||
loopSplit *ls;
|
||||
int k, detected_sharp=0, is_selection=0;
|
||||
if (!midpoint) FOREACHVERTEX(v, n) loopRelaxOriginal(v);
|
||||
|
||||
FOREACHTRIANGLE(t, n) if (IS_VISITED(t)) {is_selection=1; break;}
|
||||
if (is_selection) {FOREACHTRIANGLE(t, n) if (IS_VISITED(t)) {MARK_BIT(t->e1, 3); MARK_BIT(t->e2, 3); MARK_BIT(t->e3, 3);}}
|
||||
else FOREACHEDGE(e, n) MARK_BIT(e, 3);
|
||||
|
||||
FOREACHEDGE(e, n) if (IS_BIT(e, 3))
|
||||
{
|
||||
MARK_BIT(e->v1, 3); MARK_BIT(e->v2, 3);
|
||||
if (!midpoint && IS_SHARPEDGE(e)) detected_sharp = 1;
|
||||
nvs.appendHead(new loopSplit(e, midpoint));
|
||||
}
|
||||
|
||||
if (detected_sharp)
|
||||
TMesh::warning("loopSubdivision: Crease-preservation is not supported.\n");
|
||||
|
||||
FOREACHNODE(nvs, n)
|
||||
{
|
||||
ls = ((loopSplit *)n->data);
|
||||
k = ls->e->isOnBoundary();
|
||||
v = splitEdge(ls->e, &(ls->p));
|
||||
e1 = (Edge *)E.head()->data;
|
||||
e2 = (Edge *)E.head()->next()->data;
|
||||
MARK_VISIT2(v); MARK_VISIT2(e1); if (!k) MARK_VISIT2(e2);
|
||||
|
||||
if (ls->e->t2)
|
||||
{
|
||||
if (IS_VISITED(ls->e->t2)) {t=(Triangle *)T.head()->data; MARK_VISIT(t);}
|
||||
if (ls->e->t1 && IS_VISITED(ls->e->t1)) {t=(Triangle *)T.head()->next()->data; MARK_VISIT(t);}
|
||||
}
|
||||
else if (IS_VISITED(ls->e->t1)) {t=(Triangle *)T.head()->data; MARK_VISIT(t);}
|
||||
|
||||
if (IS_SHARPEDGE(ls->e))
|
||||
{
|
||||
if (k) TAG_SHARPEDGE(e2);
|
||||
else TAG_SHARPEDGE((Edge *)E.head()->next()->next()->data);
|
||||
}
|
||||
}
|
||||
|
||||
nvs.freeNodes();
|
||||
|
||||
FOREACHEDGE(e, n)
|
||||
if (IS_VISITED2(e))
|
||||
{
|
||||
UNMARK_VISIT2(e);
|
||||
if ((IS_VISITED2(e->v1) && !IS_VISITED2(e->v2)) ||
|
||||
(!IS_VISITED2(e->v1) && IS_VISITED2(e->v2)))
|
||||
if (e->swap(1) && (!IS_VISITED2(e->v1) || !IS_VISITED2(e->v2))) e->swap(1);
|
||||
}
|
||||
|
||||
FOREACHVERTEX(v, n) if (!IS_VISITED2(v) && !midpoint && IS_BIT(v, 3))
|
||||
{
|
||||
v->setValue((Point *)v->info);
|
||||
delete((Point *)v->info);
|
||||
v->info = NULL;
|
||||
}
|
||||
FOREACHVERTEX(v, n) {UNMARK_VISIT2(v); UNMARK_BIT(v, 3);}
|
||||
|
||||
if (detected_sharp)
|
||||
TMesh::warning("loopSubdivision: Tagged sharp edges have been smoothed.\n");
|
||||
|
||||
FOREACHEDGE(e, n) UNMARK_BIT(e, 3);
|
||||
}
|
241
src/mesh_fix/src/Kernel/coordinates.cpp
Normal file
241
src/mesh_fix/src/Kernel/coordinates.cpp
Normal file
@ -0,0 +1,241 @@
|
||||
/****************************************************************************
|
||||
* TMesh *
|
||||
* *
|
||||
* Consiglio Nazionale delle Ricerche *
|
||||
* Istituto di Matematica Applicata e Tecnologie Informatiche *
|
||||
* Sezione di Genova *
|
||||
* IMATI-GE / CNR *
|
||||
* *
|
||||
* Authors: Marco Attene *
|
||||
* Copyright(C) 2012: IMATI-GE / CNR *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is dual-licensed as follows: *
|
||||
* *
|
||||
* (1) You may use TMesh as 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. *
|
||||
* In this case the 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 (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
* (2) You may use TMesh as part of a commercial software. In this case a *
|
||||
* proper agreement must be reached with the Authors and with IMATI-GE/CNR *
|
||||
* based on a proper licensing contract. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#include "coordinates.h"
|
||||
#include <limits>
|
||||
#include <cmath>
|
||||
|
||||
|
||||
namespace T_MESH
|
||||
{
|
||||
#ifndef NAN
|
||||
#define NAN std::numeric_limits<double>::quiet_NaN()
|
||||
#endif
|
||||
|
||||
#ifdef USE_HYBRID_KERNEL
|
||||
|
||||
// Default behaviour = FILTERED KERNEL
|
||||
bool PM_Rational::use_rationals = false;
|
||||
bool PM_Rational::use_filtering = true;
|
||||
|
||||
void PM_Rational::switchToDouble()
|
||||
{
|
||||
if (_whv)
|
||||
{
|
||||
EXACT_NT * ov = (EXACT_NT *)_val;
|
||||
double d = (double)((EXACT_NT_DENOMINATOR(ov) != 0) ? (EXACT_NT_TO_DOUBLE((*ov))) : (NAN));
|
||||
_val = d2int64t(d);
|
||||
delete ov;
|
||||
_whv = false;
|
||||
}
|
||||
}
|
||||
|
||||
void PM_Rational::switchToRational()
|
||||
{
|
||||
if (!_whv)
|
||||
{
|
||||
double od = int64t2d(_val);
|
||||
if (od == NAN) _val = (int64_t)new EXACT_NT(0, 0);
|
||||
else _val = (int64_t)new EXACT_NT(od);
|
||||
_whv = true;
|
||||
}
|
||||
}
|
||||
|
||||
void PM_Rational::operator+=(const PM_Rational& a)
|
||||
{
|
||||
if (use_rationals) { switchToRational(); getVal() += a.toRational(); }
|
||||
else { switchToDouble(); getDVal() += a.toDouble(); }
|
||||
}
|
||||
|
||||
void PM_Rational::operator-=(const PM_Rational& a)
|
||||
{
|
||||
if (use_rationals) { switchToRational(); getVal() -= a.toRational(); }
|
||||
else { switchToDouble(); getDVal() -= a.toDouble(); }
|
||||
}
|
||||
|
||||
void PM_Rational::operator*=(const PM_Rational& a)
|
||||
{
|
||||
if (use_rationals) { switchToRational(); getVal() *= a.toRational(); }
|
||||
else { switchToDouble(); getDVal() *= a.toDouble(); }
|
||||
}
|
||||
|
||||
void PM_Rational::operator/=(const PM_Rational& a)
|
||||
{
|
||||
if (use_rationals) { switchToRational(); getVal() /= a.toRational(); }
|
||||
else { switchToDouble(); getDVal() /= a.toDouble(); }
|
||||
}
|
||||
|
||||
PM_Rational PM_Rational::operator+(const PM_Rational& a) const
|
||||
{
|
||||
if (use_rationals) return PM_Rational(toRational() + a.toRational());
|
||||
else return PM_Rational(toDouble() + a.toDouble());
|
||||
}
|
||||
|
||||
PM_Rational PM_Rational::operator-(const PM_Rational& a) const
|
||||
{
|
||||
if (use_rationals) return PM_Rational(toRational() - a.toRational());
|
||||
else return PM_Rational(toDouble() - a.toDouble());
|
||||
}
|
||||
|
||||
PM_Rational PM_Rational::operator*(const PM_Rational& a) const
|
||||
{
|
||||
if (use_rationals) return PM_Rational(toRational() * a.toRational());
|
||||
else return PM_Rational(toDouble() * a.toDouble());
|
||||
}
|
||||
|
||||
PM_Rational PM_Rational::operator/(const PM_Rational& a) const
|
||||
{
|
||||
if (use_rationals) return PM_Rational(toRational() / a.toRational());
|
||||
else return PM_Rational(toDouble() / a.toDouble());
|
||||
}
|
||||
|
||||
bool PM_Rational::operator==(const PM_Rational& a) const
|
||||
{
|
||||
if (_whv || a._whv /*use_rationals*/) return (toRational() == a.toRational());
|
||||
else return (toDouble() == a.toDouble());
|
||||
}
|
||||
|
||||
bool PM_Rational::operator!=(const PM_Rational& a) const
|
||||
{
|
||||
if (_whv || a._whv /*use_rationals*/) return (toRational() != a.toRational());
|
||||
else return (toDouble() != a.toDouble());
|
||||
}
|
||||
|
||||
PM_Rational& PM_Rational::operator=(const PM_Rational& a)
|
||||
{
|
||||
if (_whv) delete ((EXACT_NT *)_val);
|
||||
_whv = a._whv; _val = (_whv) ? ((int64_t)new EXACT_NT(a.getVal())) : (a._val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void PM_Rational::setFromRational(const EXACT_NT& a)
|
||||
{
|
||||
if (_whv) delete ((EXACT_NT *)_val);
|
||||
_whv = 1; _val = (int64_t)new EXACT_NT(a);
|
||||
}
|
||||
|
||||
bool PM_Rational::operator<(const PM_Rational& a) const
|
||||
{
|
||||
if (_whv || a._whv) return (toRational() < a.toRational());
|
||||
else return (toDouble() < a.toDouble());
|
||||
}
|
||||
|
||||
bool PM_Rational::operator>(const PM_Rational& a) const
|
||||
{
|
||||
if (_whv || a._whv) return (toRational() > a.toRational());
|
||||
else return (toDouble() > a.toDouble());
|
||||
}
|
||||
|
||||
PM_Rational operator-(const PM_Rational& a) // This might be probably changed... do not understand why to switch..
|
||||
{
|
||||
if (PM_Rational::isUsingRationals()) return PM_Rational(-(a.toRational()));
|
||||
else return PM_Rational(-(a.toDouble()));
|
||||
}
|
||||
|
||||
PM_Rational ceil(const PM_Rational& a)
|
||||
{
|
||||
if (PM_Rational::isUsingRationals())
|
||||
{
|
||||
mpz_t n, d, f;
|
||||
mpz_init(n); mpz_init(d); mpz_init(f);
|
||||
#ifdef USE_CGAL_LAZYNT
|
||||
mpz_set(n, a.toRational().exact().numerator().mpz());
|
||||
mpz_set(d, a.toRational().exact().denominator().mpz());
|
||||
mpz_cdiv_q(f, n, d);
|
||||
mpz_clear(n); mpz_clear(d);
|
||||
return PM_Rational(EXACT_NT(CGAL::Gmpz(f)));
|
||||
#else
|
||||
mpz_set(n, a.toRational().get_num_mpz_t());
|
||||
mpz_set(d, a.toRational().get_den_mpz_t());
|
||||
mpz_cdiv_q(f, n, d);
|
||||
mpz_clear(n); mpz_clear(d);
|
||||
return PM_Rational(mpq_class(mpz_class(f)));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
return PM_Rational(::ceil(a.toDouble()));
|
||||
}
|
||||
|
||||
PM_Rational floor(const PM_Rational& a)
|
||||
{
|
||||
if (PM_Rational::isUsingRationals())
|
||||
{
|
||||
mpz_t n, d, f;
|
||||
mpz_init(n); mpz_init(d); mpz_init(f);
|
||||
#ifdef USE_CGAL_LAZYNT
|
||||
mpz_set(n, a.toRational().exact().numerator().mpz());
|
||||
mpz_set(d, a.toRational().exact().denominator().mpz());
|
||||
mpz_fdiv_q(f, n, d);
|
||||
mpz_clear(n); mpz_clear(d);
|
||||
return PM_Rational(EXACT_NT(CGAL::Gmpz(f)));
|
||||
#else
|
||||
mpz_set(n, a.toRational().get_num_mpz_t());
|
||||
mpz_set(d, a.toRational().get_den_mpz_t());
|
||||
mpz_fdiv_q(f, n, d);
|
||||
mpz_clear(n); mpz_clear(d);
|
||||
return PM_Rational(mpq_class(mpz_class(f)));
|
||||
#endif
|
||||
} else
|
||||
return PM_Rational(::floor(a.toDouble()));
|
||||
}
|
||||
|
||||
PM_Rational round(const PM_Rational& a)
|
||||
{
|
||||
if (PM_Rational::isUsingRationals())
|
||||
{
|
||||
mpz_t n, d, f, c;
|
||||
mpz_init(n); mpz_init(d); mpz_init(f); mpz_init(c);
|
||||
#ifdef USE_CGAL_LAZYNT
|
||||
mpz_set(n, a.toRational().exact().numerator().mpz());
|
||||
mpz_set(d, a.toRational().exact().denominator().mpz());
|
||||
mpz_fdiv_q(f, n, d);
|
||||
mpz_cdiv_q(c, n, d);
|
||||
mpz_clear(n); mpz_clear(d);
|
||||
PM_Rational fr = PM_Rational(EXACT_NT(CGAL::Gmpz(f)));
|
||||
PM_Rational cr = PM_Rational(EXACT_NT(CGAL::Gmpz(c)));
|
||||
mpz_clear(f); mpz_clear(c);
|
||||
return ((a - fr) < (cr - a)) ? (fr) : (cr);
|
||||
#else
|
||||
mpz_set(n, a.toRational().get_num_mpz_t());
|
||||
mpz_set(d, a.toRational().get_den_mpz_t());
|
||||
mpz_fdiv_q(f, n, d);
|
||||
mpz_cdiv_q(c, n, d);
|
||||
mpz_clear(n); mpz_clear(d);
|
||||
PM_Rational fr = PM_Rational(mpq_class(mpz_class(f)));
|
||||
PM_Rational cr = PM_Rational(mpq_class(mpz_class(c)));
|
||||
mpz_clear(f); mpz_clear(c);
|
||||
return ((a - fr) < (cr - a)) ? (fr) : (cr);
|
||||
#endif
|
||||
} else
|
||||
return PM_Rational(::round(a.toDouble()));
|
||||
}
|
||||
|
||||
#endif
|
||||
} //namespace T_MESH
|
219
src/mesh_fix/src/Kernel/graph.cpp
Normal file
219
src/mesh_fix/src/Kernel/graph.cpp
Normal file
@ -0,0 +1,219 @@
|
||||
/****************************************************************************
|
||||
* TMesh *
|
||||
* *
|
||||
* Consiglio Nazionale delle Ricerche *
|
||||
* Istituto di Matematica Applicata e Tecnologie Informatiche *
|
||||
* Sezione di Genova *
|
||||
* IMATI-GE / CNR *
|
||||
* *
|
||||
* Authors: Marco Attene *
|
||||
* Copyright(C) 2012: IMATI-GE / CNR *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is dual-licensed as follows: *
|
||||
* *
|
||||
* (1) You may use TMesh as 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. *
|
||||
* In this case the 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 (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
* (2) You may use TMesh as part of a commercial software. In this case a *
|
||||
* proper agreement must be reached with the Authors and with IMATI-GE/CNR *
|
||||
* based on a proper licensing contract. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#include "graph.h"
|
||||
|
||||
namespace T_MESH
|
||||
{
|
||||
|
||||
graphEdge *graphNode::getEdge(graphNode *gn)
|
||||
{
|
||||
graphEdge *ge;
|
||||
Node *n = edges.head();
|
||||
while (n!=NULL)
|
||||
if ((ge=((graphEdge *)n->data))->oppositeNode(this)==gn) return ge;
|
||||
else n=n->next();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
graphEdge::graphEdge(graphNode *a, graphNode *b)
|
||||
{
|
||||
n1=a; n2=b;
|
||||
n1->edges.appendHead(this);
|
||||
n2->edges.appendHead(this);
|
||||
}
|
||||
|
||||
|
||||
graphEdge *Graph::createEdge(graphNode *n1, graphNode *n2)
|
||||
{
|
||||
Node *n;
|
||||
FOREACHNODE(n1->edges, n)
|
||||
if (((graphEdge *)n->data)->hasNode(n2))
|
||||
return (graphEdge *)n->data;
|
||||
|
||||
edges.appendHead(new graphEdge(n1, n2));
|
||||
return (graphEdge *)edges.head()->data;
|
||||
}
|
||||
|
||||
|
||||
void graphEdge::collapse()
|
||||
{
|
||||
Node *n;
|
||||
graphEdge *e;
|
||||
graphNode *nx;
|
||||
|
||||
while ((e = (graphEdge *)n2->edges.popHead()) != NULL)
|
||||
if (e != this)
|
||||
{
|
||||
((e->n1 == n2)?(e->n1):(e->n2)) = n1;
|
||||
n1->edges.appendHead(e);
|
||||
}
|
||||
|
||||
FOREACHNODE(n1->edges, n)
|
||||
{
|
||||
e = (graphEdge *)n->data;
|
||||
if (!e->isUnlinked()) e->oppositeNode(n1)->mask = 0;
|
||||
}
|
||||
|
||||
n2->mask = 1;
|
||||
FOREACHNODE(n1->edges, n)
|
||||
{
|
||||
e = (graphEdge *)n->data;
|
||||
if (e != this)
|
||||
{
|
||||
nx = e->oppositeNode(n1);
|
||||
if (nx->mask) {nx->edges.removeNode(e); e->makeUnlinked();}
|
||||
nx->mask = 1;
|
||||
}
|
||||
}
|
||||
|
||||
n = n1->edges.head();
|
||||
while (n != NULL)
|
||||
{
|
||||
e = (graphEdge *)n->data;
|
||||
n = n->next();
|
||||
if (e->isUnlinked()) n1->edges.removeCell((n!=NULL)?(n->prev()):n1->edges.tail());
|
||||
}
|
||||
|
||||
FOREACHNODE(n1->edges, n)
|
||||
((graphEdge *)n->data)->oppositeNode(n1)->mask = 0;
|
||||
|
||||
n1->edges.removeNode(this);
|
||||
|
||||
makeUnlinked();
|
||||
}
|
||||
|
||||
|
||||
Graph::~Graph()
|
||||
{
|
||||
graphNode *gn;
|
||||
graphEdge *ge;
|
||||
while ((gn=(graphNode *)nodes.popHead())!=NULL) delete gn;
|
||||
while ((ge=(graphEdge *)edges.popHead())!=NULL) delete ge;
|
||||
}
|
||||
|
||||
void Graph::deleteUnlinkedElements()
|
||||
{
|
||||
Node *n;
|
||||
graphNode *gn;
|
||||
graphEdge *ge;
|
||||
|
||||
n = nodes.head();
|
||||
while (n != NULL)
|
||||
{
|
||||
gn = (graphNode *)n->data;
|
||||
n = n->next();
|
||||
if (gn->isIsolated())
|
||||
{
|
||||
nodes.removeCell((n!=NULL)?(n->prev()):nodes.tail());
|
||||
delete(gn);
|
||||
}
|
||||
}
|
||||
|
||||
n = edges.head();
|
||||
while (n != NULL)
|
||||
{
|
||||
ge = (graphEdge *)n->data;
|
||||
n = n->next();
|
||||
if (ge->isUnlinked())
|
||||
{
|
||||
edges.removeCell((n!=NULL)?(n->prev()):edges.tail());
|
||||
delete(ge);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Graph::unlinkEdge(graphEdge *e)
|
||||
{
|
||||
e->n1->edges.removeNode(e);
|
||||
e->n2->edges.removeNode(e);
|
||||
e->makeUnlinked();
|
||||
}
|
||||
|
||||
void Graph::destroyEdge(graphEdge *e)
|
||||
{
|
||||
unlinkEdge(e);
|
||||
edges.removeNode(e);
|
||||
delete e;
|
||||
}
|
||||
|
||||
graphNode *Graph::unlinkNode(graphNode *a)
|
||||
{
|
||||
graphEdge *e;
|
||||
while ((e = (graphEdge *)a->edges.popHead())!=NULL) unlinkEdge(e);
|
||||
return a;
|
||||
}
|
||||
|
||||
void graphEdge::invert()
|
||||
{
|
||||
graphNode *tmp = n1;
|
||||
n1 = n2;
|
||||
n2 = tmp;
|
||||
}
|
||||
|
||||
bool Graph::isConnected()
|
||||
{
|
||||
if (nodes.numels() < 2) return true;
|
||||
|
||||
unsigned char *nmask = new unsigned char[nodes.numels()];
|
||||
Node *n;
|
||||
graphNode *p, *q;
|
||||
int i;
|
||||
|
||||
for (i=0, n=nodes.head(); n!=NULL; n=n->next(), i++)
|
||||
{
|
||||
p = (graphNode *)n->data;
|
||||
nmask[i]=p->mask;
|
||||
p->mask=0;
|
||||
}
|
||||
|
||||
p = (graphNode *)nodes.head()->data;
|
||||
List todo(p); p->mask = 1;
|
||||
while ((p = (graphNode *)todo.popHead())!=NULL)
|
||||
{
|
||||
for (n=p->edges.head(); n!=NULL; n=n->next())
|
||||
{
|
||||
q = ((graphEdge *)n->data)->oppositeNode(p);
|
||||
if (q->mask==0) {todo.appendTail(q); q->mask=1;}
|
||||
}
|
||||
}
|
||||
|
||||
bool is_connected = true;
|
||||
for (i=0, n=nodes.head(); n!=NULL; n=n->next(), i++)
|
||||
{
|
||||
p = (graphNode *)n->data;
|
||||
if (p->mask==0) is_connected=false;
|
||||
p->mask = nmask[i];
|
||||
}
|
||||
|
||||
return is_connected;
|
||||
}
|
||||
|
||||
} //namespace T_MESH
|
122
src/mesh_fix/src/Kernel/heap.cpp
Normal file
122
src/mesh_fix/src/Kernel/heap.cpp
Normal file
@ -0,0 +1,122 @@
|
||||
/****************************************************************************
|
||||
* TMesh *
|
||||
* *
|
||||
* Consiglio Nazionale delle Ricerche *
|
||||
* Istituto di Matematica Applicata e Tecnologie Informatiche *
|
||||
* Sezione di Genova *
|
||||
* IMATI-GE / CNR *
|
||||
* *
|
||||
* Authors: Marco Attene *
|
||||
* Copyright(C) 2012: IMATI-GE / CNR *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is dual-licensed as follows: *
|
||||
* *
|
||||
* (1) You may use TMesh as 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. *
|
||||
* In this case the 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 (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
* (2) You may use TMesh as part of a commercial software. In this case a *
|
||||
* proper agreement must be reached with the Authors and with IMATI-GE/CNR *
|
||||
* based on a proper licensing contract. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "heap.h"
|
||||
|
||||
namespace T_MESH
|
||||
{
|
||||
|
||||
abstractHeap::abstractHeap(int size)
|
||||
{
|
||||
heap = new void *[size+1];
|
||||
numels = 0;
|
||||
maxels = size;
|
||||
positions = NULL;
|
||||
}
|
||||
|
||||
abstractHeap::~abstractHeap()
|
||||
{
|
||||
delete(heap);
|
||||
}
|
||||
|
||||
int abstractHeap::upheap(int k)
|
||||
{
|
||||
if (k < 2) return k;
|
||||
|
||||
void *t = heap[k];
|
||||
int fk = (k%2)?((k-1)/2):(k/2);
|
||||
void *f = heap[fk];
|
||||
|
||||
if (compare(t, f) <= 0)
|
||||
{
|
||||
heap[k] = f;
|
||||
heap[fk] = t;
|
||||
if (positions != NULL)
|
||||
{
|
||||
positions[(j_voidint)f] = k;
|
||||
positions[(j_voidint)t] = fk;
|
||||
}
|
||||
return upheap(fk);
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
int abstractHeap::downheap(int k)
|
||||
{
|
||||
int j;
|
||||
|
||||
void *t = heap[k];
|
||||
int fk = (numels%2)?((numels-1)/2):(numels/2);
|
||||
if (k > fk) return k;
|
||||
|
||||
j = k+k;
|
||||
if (j < numels && compare(heap[j], heap[j+1]) >= 0) j++;
|
||||
void *f = heap[j];
|
||||
if (compare(t, f) >= 0)
|
||||
{
|
||||
heap[k] = f;
|
||||
heap[j] = t;
|
||||
if (positions != NULL)
|
||||
{
|
||||
positions[(j_voidint)f] = k;
|
||||
positions[(j_voidint)t] = j;
|
||||
}
|
||||
return downheap(j);
|
||||
}
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
int abstractHeap::insert(void *t)
|
||||
{
|
||||
if (numels == maxels) return -1;
|
||||
|
||||
heap[++numels] = t;
|
||||
if (positions != NULL) positions[(j_voidint)t] = numels;
|
||||
return upheap(numels);
|
||||
}
|
||||
|
||||
void *abstractHeap::removeHead()
|
||||
{
|
||||
void *t = heap[1];
|
||||
if (positions != NULL) positions[(j_voidint)t] = 0;
|
||||
heap[1] = heap[numels--];
|
||||
if (numels)
|
||||
{
|
||||
if (positions != NULL) positions[(j_voidint)heap[1]] = 1;
|
||||
downheap(1);
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
} //namespace T_MESH
|
89
src/mesh_fix/src/Kernel/jqsort.cpp
Normal file
89
src/mesh_fix/src/Kernel/jqsort.cpp
Normal file
@ -0,0 +1,89 @@
|
||||
/****************************************************************************
|
||||
* TMesh *
|
||||
* *
|
||||
* Consiglio Nazionale delle Ricerche *
|
||||
* Istituto di Matematica Applicata e Tecnologie Informatiche *
|
||||
* Sezione di Genova *
|
||||
* IMATI-GE / CNR *
|
||||
* *
|
||||
* Authors: Marco Attene *
|
||||
* Copyright(C) 2012: IMATI-GE / CNR *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is dual-licensed as follows: *
|
||||
* *
|
||||
* (1) You may use TMesh as 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. *
|
||||
* In this case the 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 (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
* (2) You may use TMesh as part of a commercial software. In this case a *
|
||||
* proper agreement must be reached with the Authors and with IMATI-GE/CNR *
|
||||
* based on a proper licensing contract. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#define USE_STD_SORT
|
||||
|
||||
#ifdef USE_STD_SORT
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#endif
|
||||
|
||||
#include "basics.h"
|
||||
|
||||
namespace T_MESH
|
||||
{
|
||||
|
||||
#ifndef USE_STD_SORT
|
||||
inline void jswap(void *v[], int i, int j)
|
||||
{
|
||||
void *temp = v[i];
|
||||
v[i] = v[j];
|
||||
v[j] = temp;
|
||||
}
|
||||
|
||||
void jqsort_prv(void *v[], int left, int right, int (*comp)(const void *, const void *))
|
||||
{
|
||||
register int i, last;
|
||||
|
||||
if (left >= right) return;
|
||||
jswap(v, left, (left+right)/2);
|
||||
last = left;
|
||||
for (i = left+1; i <= right; i++)
|
||||
if ((*comp)(v[i], v[left]) < 0) jswap(v, ++last, i);
|
||||
jswap(v, left, last);
|
||||
jqsort_prv(v, left, last-1, comp);
|
||||
jqsort_prv(v, last+1, right, comp);
|
||||
}
|
||||
|
||||
void jqsort(void *v[], int numels, int(*comp)(const void *, const void *))
|
||||
{
|
||||
jqsort_prv(v, 0, numels-1, comp);
|
||||
}
|
||||
#else
|
||||
|
||||
class compobj
|
||||
{
|
||||
int(*comp)(const Data *, const Data *);
|
||||
|
||||
public:
|
||||
compobj(int(*c)(const Data *, const Data *)) { comp = c; }
|
||||
|
||||
bool operator()(Data *a, Data *b) { return (comp(a, b) < 0); }
|
||||
};
|
||||
|
||||
void jqsort(Data *v[], int numels, int(*comp)(const Data *, const Data *))
|
||||
{
|
||||
compobj a(comp);
|
||||
std::sort(v, v + numels, a);
|
||||
}
|
||||
#endif
|
||||
|
||||
} //namespace T_MESH
|
||||
|
301
src/mesh_fix/src/Kernel/list.cpp
Normal file
301
src/mesh_fix/src/Kernel/list.cpp
Normal file
@ -0,0 +1,301 @@
|
||||
/****************************************************************************
|
||||
* TMesh *
|
||||
* *
|
||||
* Consiglio Nazionale delle Ricerche *
|
||||
* Istituto di Matematica Applicata e Tecnologie Informatiche *
|
||||
* Sezione di Genova *
|
||||
* IMATI-GE / CNR *
|
||||
* *
|
||||
* Authors: Marco Attene *
|
||||
* Copyright(C) 2012: IMATI-GE / CNR *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is dual-licensed as follows: *
|
||||
* *
|
||||
* (1) You may use TMesh as 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. *
|
||||
* In this case the 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 (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
* (2) You may use TMesh as part of a commercial software. In this case a *
|
||||
* proper agreement must be reached with the Authors and with IMATI-GE/CNR *
|
||||
* based on a proper licensing contract. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "list.h"
|
||||
#include "jqsort.h"
|
||||
|
||||
namespace T_MESH
|
||||
{
|
||||
|
||||
// Create a new node containing 'd', and link it to //
|
||||
// 'p' on the left (prev) and to 'n' on the right (next). //
|
||||
|
||||
Node::Node(const Node *p, const Data *d, const Node *n)
|
||||
{
|
||||
data=(Data *)d;
|
||||
if ((n_prev=(Node *)p) != NULL) n_prev->n_next = this;
|
||||
if ((n_next=(Node *)n) != NULL) n_next->n_prev = this;
|
||||
}
|
||||
|
||||
|
||||
// Destroy and unlink the node
|
||||
|
||||
Node::~Node()
|
||||
{
|
||||
if (n_prev != NULL) n_prev->n_next = n_next;
|
||||
if (n_next != NULL) n_next->n_prev = n_prev;
|
||||
}
|
||||
|
||||
|
||||
/////////// Constructor from list ///////////////////
|
||||
|
||||
List::List(const Data **d, int n)
|
||||
{
|
||||
l_head = l_tail = NULL; l_numels = 0;
|
||||
for (int i=0; i<n; i++) appendTail(d[i]);
|
||||
}
|
||||
|
||||
///////////////////////// Destructor //////////////////////////
|
||||
|
||||
List::~List()
|
||||
{
|
||||
while (l_head != NULL) removeCell(l_head);
|
||||
}
|
||||
|
||||
////////////////// Append an element //////////////////
|
||||
|
||||
void List::appendHead(const Data *d)
|
||||
{
|
||||
l_head = new Node(NULL, d, l_head);
|
||||
if (l_tail == NULL) l_tail = l_head;
|
||||
l_numels++;
|
||||
}
|
||||
|
||||
void List::appendTail(const Data *d)
|
||||
{
|
||||
l_tail = new Node(l_tail, d, NULL);
|
||||
if (l_head == NULL) l_head = l_tail;
|
||||
l_numels++;
|
||||
}
|
||||
|
||||
void List::insertAfter(Node *b, const Data *d)
|
||||
{
|
||||
Node *nn = new Node(b, d, b->next());
|
||||
if (b == l_tail) l_tail = nn;
|
||||
l_numels++;
|
||||
}
|
||||
|
||||
////////////////// Appends a list //////////////////
|
||||
|
||||
void List::appendList(const List *l)
|
||||
{
|
||||
Node *n = l->l_tail;
|
||||
|
||||
while (n != NULL)
|
||||
{
|
||||
appendHead(n->data);
|
||||
n=n->prev();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////// Joins a list to the l_tail //////////////////
|
||||
|
||||
void List::joinTailList(List *l)
|
||||
{
|
||||
if (l->l_numels == 0) return;
|
||||
if (l_tail != NULL)
|
||||
{
|
||||
l_tail->n_next = l->l_head; l->l_head->n_prev = l_tail; l_tail = l->l_tail;
|
||||
l_numels += l->l_numels;
|
||||
}
|
||||
else
|
||||
{
|
||||
l_head = l->l_head; l_tail = l->l_tail; l_numels = l->l_numels;
|
||||
}
|
||||
l->l_head = l->l_tail = NULL; l->l_numels = 0;
|
||||
}
|
||||
|
||||
//// Moves node 'n' from this list to the end of 'l'. \n O(1).
|
||||
void List::moveNodeTo(Node *n, List *l)
|
||||
{
|
||||
Node *pn = n->n_prev, *nn = n->n_next;
|
||||
n->n_prev = l->l_tail; n->n_next = NULL;
|
||||
|
||||
if (l->l_numels) l->l_tail->n_next = n; else l->l_head = n;
|
||||
l->l_tail = n;
|
||||
l->l_numels++;
|
||||
|
||||
l_numels--;
|
||||
if (pn != NULL) pn->n_next = nn; else l_head = nn;
|
||||
if (nn != NULL) nn->n_prev = pn; else l_tail = pn;
|
||||
}
|
||||
|
||||
//// Removes the first node and returns the corresponding data /////
|
||||
|
||||
Data *List::popHead()
|
||||
{
|
||||
Data *data = (l_head != NULL)?(l_head->data):(NULL);
|
||||
if (l_head != NULL) removeCell(l_head);
|
||||
return data;
|
||||
}
|
||||
|
||||
//// Removes the last node and returns the corresponding data /////
|
||||
|
||||
Data *List::popTail()
|
||||
{
|
||||
Data *data = (l_tail != NULL)?(l_tail->data):(NULL);
|
||||
if (l_tail != NULL) removeCell(l_tail);
|
||||
return data;
|
||||
}
|
||||
|
||||
//////////////////// Removes an element //////////////////
|
||||
|
||||
int List::removeNode(const Data *d)
|
||||
{
|
||||
Node *tmp = l_head;
|
||||
int i=1;
|
||||
|
||||
while (tmp != NULL)
|
||||
if (tmp->data == d)
|
||||
{
|
||||
removeCell(tmp);
|
||||
return i;
|
||||
}
|
||||
else {tmp=tmp->n_next; i++;}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//////////////////// Removes an element //////////////////
|
||||
|
||||
int List::removeNode(int i)
|
||||
{
|
||||
Node *tmp = l_head;
|
||||
|
||||
while (tmp!=NULL && i--) tmp=tmp->n_next;
|
||||
if (tmp==NULL) return 0;
|
||||
|
||||
removeCell(tmp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
//////////////////// Gets a node //////////////////
|
||||
|
||||
Node *List::getNode(int i) const
|
||||
{
|
||||
Node *tmp = l_head;
|
||||
|
||||
while (tmp!=NULL && i--) tmp=tmp->n_next;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
||||
//////////////////// Removes a node //////////////////
|
||||
|
||||
void List::removeCell(Node *n)
|
||||
{
|
||||
if (n==l_head) l_head = n->n_next;
|
||||
if (n==l_tail) l_tail = n->n_prev;
|
||||
delete(n);
|
||||
l_numels--;
|
||||
}
|
||||
|
||||
|
||||
////////////////// Garbage collection //////////////
|
||||
|
||||
void List::freeCell(Node *n)
|
||||
{
|
||||
delete(n->data);
|
||||
removeCell(n);
|
||||
}
|
||||
|
||||
void List::freeNode(Data *d)
|
||||
{
|
||||
delete(d);
|
||||
removeNode(d);
|
||||
}
|
||||
|
||||
//////////////////// Belonging check /////////////////
|
||||
|
||||
Node *List::containsNode(const Data *d) const
|
||||
{
|
||||
Node *tmp = l_head;
|
||||
|
||||
while (tmp != NULL)
|
||||
if (tmp->data == d) return tmp;
|
||||
else tmp=tmp->n_next;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//////////////////// Replaces a node /////////////////
|
||||
|
||||
Node *List::replaceNode(const Data *od, const Data *nd)
|
||||
{
|
||||
Node *tmp = containsNode(od);
|
||||
if (tmp != NULL) { tmp->data = (Data *)nd; return tmp;}
|
||||
appendTail(nd);
|
||||
return l_tail;
|
||||
}
|
||||
|
||||
//////////////////////// Garbage collector /////////////////////
|
||||
|
||||
void List::freeNodes()
|
||||
{
|
||||
while (l_head != NULL) freeCell(l_head);
|
||||
}
|
||||
|
||||
//////////////////////// Garbage collector /////////////////////
|
||||
|
||||
void List::removeNodes()
|
||||
{
|
||||
while (l_head != NULL) removeCell(l_head);
|
||||
}
|
||||
|
||||
|
||||
///// Conversion to array ///////
|
||||
|
||||
Data **List::toArray() const
|
||||
{
|
||||
Node *n = l_head;
|
||||
int i;
|
||||
Data **array;
|
||||
|
||||
if (l_numels == 0) return NULL;
|
||||
array = (Data **)malloc(sizeof(Data *)*l_numels);
|
||||
if (array == NULL) return NULL;
|
||||
for (i=0; i<l_numels; i++, n=n->n_next) array[i] = n->data;
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
///// Sorts the list /////////
|
||||
|
||||
int List::sort(int (*comp)(const Data *, const Data *))
|
||||
{
|
||||
Data **array;
|
||||
int ne = l_numels-1;
|
||||
|
||||
if (l_numels < 2) return 0;
|
||||
if ((array = toArray()) == NULL) return 1;
|
||||
|
||||
jqsort(array, l_numels, comp);
|
||||
removeNodes();
|
||||
for (; ne >= 0; ne--) appendHead(array[ne]);
|
||||
free(array);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} //namespace T_MESH
|
794
src/mesh_fix/src/Kernel/matrix.cpp
Normal file
794
src/mesh_fix/src/Kernel/matrix.cpp
Normal file
@ -0,0 +1,794 @@
|
||||
/****************************************************************************
|
||||
* TMesh *
|
||||
* *
|
||||
* Consiglio Nazionale delle Ricerche *
|
||||
* Istituto di Matematica Applicata e Tecnologie Informatiche *
|
||||
* Sezione di Genova *
|
||||
* IMATI-GE / CNR *
|
||||
* *
|
||||
* Authors: Marco Attene *
|
||||
* Copyright(C) 2012: IMATI-GE / CNR *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is dual-licensed as follows: *
|
||||
* *
|
||||
* (1) You may use TMesh as 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. *
|
||||
* In this case the 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 (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
* (2) You may use TMesh as part of a commercial software. In this case a *
|
||||
* proper agreement must be reached with the Authors and with IMATI-GE/CNR *
|
||||
* based on a proper licensing contract. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#include <math.h>
|
||||
#include "matrix.h"
|
||||
|
||||
namespace T_MESH
|
||||
{
|
||||
|
||||
#define FABS(a) (((a)<0)?(-(a)):((a)))
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generic 3x3 matrix
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Plain constructor
|
||||
|
||||
Matrix3x3::Matrix3x3(const double& a11, const double& a12, const double& a13,
|
||||
const double& a21, const double& a22, const double& a23,
|
||||
const double& a31, const double& a32, const double& a33)
|
||||
{
|
||||
M[0] = a11; M[1] = a12; M[2] = a13;
|
||||
M[3] = a21; M[4] = a22; M[5] = a23;
|
||||
M[6] = a31; M[7] = a32; M[8] = a33;
|
||||
}
|
||||
|
||||
|
||||
// Matrix T(v1,v2,v3)*(w1,w2,w3).
|
||||
|
||||
Matrix3x3::Matrix3x3(const double& v1, const double& v2, const double& v3,
|
||||
const double& w1, const double& w2, const double& w3)
|
||||
{
|
||||
M[0] = v1*w1; M[1] = v1*w2; M[2] = v1*w3;
|
||||
M[3] = v2*w1; M[4] = v2*w2; M[5] = v2*w3;
|
||||
M[6] = v3*w1; M[7] = v3*w2; M[8] = v3*w3;
|
||||
}
|
||||
|
||||
|
||||
// Symmetric matrix T(x,y,z)*(x,y,z)
|
||||
|
||||
Matrix3x3::Matrix3x3(const double& x, const double& y, const double& z)
|
||||
{
|
||||
M[0] = x*x; M[1] = x*y; M[2] = x*z;
|
||||
M[3] = M[1]; M[4] = y*y; M[5] = y*z;
|
||||
M[6] = M[2]; M[7] = M[5]; M[8] = z*z;
|
||||
}
|
||||
|
||||
|
||||
// Self-sum
|
||||
|
||||
void Matrix3x3::operator+=(const Matrix3x3& s)
|
||||
{
|
||||
M[0] += s.M[0]; M[1] += s.M[1]; M[2] += s.M[2];
|
||||
M[3] += s.M[3]; M[4] += s.M[4]; M[5] += s.M[5];
|
||||
M[6] += s.M[6]; M[7] += s.M[7]; M[8] += s.M[8];
|
||||
}
|
||||
|
||||
|
||||
// Self-subtraction
|
||||
|
||||
void Matrix3x3::operator-=(const Matrix3x3& s)
|
||||
{
|
||||
M[0] -= s.M[0]; M[1] -= s.M[1]; M[2] -= s.M[2];
|
||||
M[3] -= s.M[3]; M[4] -= s.M[4]; M[5] -= s.M[5];
|
||||
M[6] -= s.M[6]; M[7] -= s.M[7]; M[8] -= s.M[8];
|
||||
}
|
||||
|
||||
|
||||
// Self-multiplication
|
||||
|
||||
void Matrix3x3::operator*=(const double& d)
|
||||
{
|
||||
M[0] *= d; M[1] *= d; M[2] *= d;
|
||||
M[3] *= d; M[4] *= d; M[5] *= d;
|
||||
M[6] *= d; M[7] *= d; M[8] *= d;
|
||||
}
|
||||
|
||||
|
||||
// Sum
|
||||
|
||||
Matrix3x3 Matrix3x3::operator+(const Matrix3x3& s) const
|
||||
{
|
||||
return Matrix3x3(M[0]+s.M[0], M[1]+s.M[1], M[2]+s.M[2],
|
||||
M[3]+s.M[3], M[4]+s.M[4], M[5]+s.M[5],
|
||||
M[6]+s.M[6], M[7]+s.M[7], M[8]+s.M[8]);
|
||||
}
|
||||
|
||||
|
||||
// Scalar Multiplication
|
||||
|
||||
Matrix3x3 Matrix3x3::operator*(const double& d) const
|
||||
{
|
||||
return Matrix3x3(M[0]*d, M[1]*d, M[2]*d,
|
||||
M[3]*d, M[4]*d, M[5]*d,
|
||||
M[6]*d, M[7]*d, M[8]*d);
|
||||
}
|
||||
|
||||
|
||||
// Matrix multiplication
|
||||
|
||||
Matrix3x3 Matrix3x3::operator*(const Matrix3x3& q) const
|
||||
{
|
||||
return Matrix3x3(
|
||||
M[0]*q.M[0]+M[1]*q.M[3]+M[2]*q.M[6], M[0]*q.M[1]+M[1]*q.M[4]+M[2]*q.M[7], M[0]*q.M[2]+M[1]*q.M[5]+M[2]*q.M[8],
|
||||
M[3]*q.M[0]+M[4]*q.M[3]+M[5]*q.M[6], M[3]*q.M[1]+M[4]*q.M[4]+M[5]*q.M[7], M[3]*q.M[2]+M[4]*q.M[5]+M[5]*q.M[8],
|
||||
M[6]*q.M[0]+M[7]*q.M[3]+M[8]*q.M[6], M[6]*q.M[1]+M[7]*q.M[4]+M[8]*q.M[7], M[6]*q.M[2]+M[7]*q.M[5]+M[8]*q.M[8]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// Matrix transpose
|
||||
|
||||
Matrix3x3 Matrix3x3::operator~() const
|
||||
{
|
||||
return Matrix3x3(M[0],M[3],M[6],M[1],M[4],M[7],M[2],M[5],M[8]);
|
||||
}
|
||||
|
||||
|
||||
// Computes (x,y,z)*M*(x,y,z)
|
||||
|
||||
double Matrix3x3::lrMultiply(const double& x, const double& y, const double& z) const
|
||||
{
|
||||
return (x*(x*M[0] + y*M[3] + z*M[6]) + y*(x*M[1] + y*M[4] + z*M[7]) + z*(x*M[2] + y*M[5] + z*M[8]));
|
||||
}
|
||||
|
||||
|
||||
// Computes v*M*w
|
||||
double Matrix3x3::lrMultiply(const double& v1, const double& v2, const double& v3,
|
||||
const double& w1, const double& w2, const double& w3) const
|
||||
{
|
||||
return (w1*(v1*M[0] + v2*M[3] + v3*M[6]) + w2*(v1*M[1] + v2*M[4] + v3*M[7]) + w3*(v1*M[2] + v2*M[5] + v3*M[8]));
|
||||
}
|
||||
|
||||
Matrix3x3 Matrix3x3::transpose() const
|
||||
{
|
||||
return Matrix3x3(M[0], M[3], M[6],
|
||||
M[1], M[4], M[7],
|
||||
M[2], M[5], M[8]);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Symmetric 3x3 matrix
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Plain constructor
|
||||
|
||||
SymMatrix3x3::SymMatrix3x3(const double&a11, const double&a12, const double&a22,
|
||||
const double&a13, const double&a23, const double&a33)
|
||||
{
|
||||
M[0] = a11; M[1] = a12; M[3] = a13;
|
||||
M[2] = a22; M[4] = a23;
|
||||
M[5] = a33;
|
||||
}
|
||||
|
||||
|
||||
// Symmetric matrix T(x,y,z)*(x,y,z)
|
||||
|
||||
SymMatrix3x3::SymMatrix3x3(const double& x, const double& y, const double& z)
|
||||
{
|
||||
M[0] = x*x; M[1] = x*y; M[3] = x*z;
|
||||
M[2] = y*y; M[4] = y*z;
|
||||
M[5] = z*z;
|
||||
}
|
||||
|
||||
|
||||
// Constructor from generic matrix
|
||||
|
||||
SymMatrix3x3::SymMatrix3x3(const Matrix3x3& q)
|
||||
{
|
||||
M[0] = q.M[0]; M[1] = q.M[1]; M[3] = q.M[2];
|
||||
M[2] = q.M[4]; M[4] = q.M[5];
|
||||
M[5] = q.M[8];
|
||||
}
|
||||
|
||||
|
||||
// Self-sum
|
||||
|
||||
void SymMatrix3x3::operator+=(const SymMatrix3x3& s)
|
||||
{
|
||||
M[0] += s.M[0]; M[1] += s.M[1]; M[2] += s.M[2];
|
||||
M[3] += s.M[3]; M[4] += s.M[4]; M[5] += s.M[5];
|
||||
}
|
||||
|
||||
|
||||
// Self-subtraction
|
||||
|
||||
void SymMatrix3x3::operator-=(const SymMatrix3x3& s)
|
||||
{
|
||||
M[0] -= s.M[0]; M[1] -= s.M[1]; M[2] -= s.M[2];
|
||||
M[3] -= s.M[3]; M[4] -= s.M[4]; M[5] -= s.M[5];
|
||||
}
|
||||
|
||||
|
||||
// Self-multiplication
|
||||
|
||||
void SymMatrix3x3::operator*=(const double& d)
|
||||
{
|
||||
M[0] *= d; M[1] *= d; M[2] *= d;
|
||||
M[3] *= d; M[4] *= d; M[5] *= d;
|
||||
}
|
||||
|
||||
|
||||
// Sum
|
||||
|
||||
SymMatrix3x3 SymMatrix3x3::operator+(const SymMatrix3x3& s) const
|
||||
{
|
||||
return SymMatrix3x3(M[0]+s.M[0], M[1]+s.M[1], M[2]+s.M[2],
|
||||
M[3]+s.M[3], M[4]+s.M[4], M[5]+s.M[5]);
|
||||
}
|
||||
|
||||
|
||||
// Multiplication
|
||||
|
||||
SymMatrix3x3 SymMatrix3x3::operator*(const double& d) const
|
||||
{
|
||||
return SymMatrix3x3(M[0]*d, M[1]*d, M[2]*d, M[3]*d, M[4]*d, M[5]*d);
|
||||
}
|
||||
|
||||
|
||||
// Computes (x,y,z)*M*(x,y,z)
|
||||
|
||||
double SymMatrix3x3::lrMultiply(const double& x, const double& y, const double& z) const
|
||||
{
|
||||
double a,b,c;
|
||||
a = x*M[0] + y*M[1] + z*M[3];
|
||||
b = x*M[1] + y*M[2] + z*M[4];
|
||||
c = x*M[3] + y*M[4] + z*M[5];
|
||||
return (x*a + y*b + z*c);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Computes v*M*w
|
||||
double SymMatrix3x3::lrMultiply(const double& v1, const double& v2, const double& v3,
|
||||
const double& w1, const double& w2, const double& w3) const
|
||||
{
|
||||
return (w1*(v1*M[0] + v2*M[1] + v3*M[3]) + w2*(v1*M[1] + v2*M[2] + v3*M[4]) + w3*(v1*M[3] + v2*M[4] + v3*M[5]));
|
||||
}
|
||||
|
||||
// Invert the matrix. If singular return FALSE
|
||||
|
||||
bool SymMatrix3x3::invert()
|
||||
{
|
||||
double det, pos, neg, t, out[6];
|
||||
|
||||
pos = neg = 0.0;
|
||||
t = M[0]*M[2]*M[5]; ((t >= 0.0)?(pos):(neg)) += t;
|
||||
t = M[1]*M[4]*M[3]; ((t >= 0.0)?(pos):(neg)) += t;
|
||||
t = M[3]*M[1]*M[4]; ((t >= 0.0)?(pos):(neg)) += t;
|
||||
t = -M[3]*M[2]*M[3]; ((t >= 0.0)?(pos):(neg)) += t;
|
||||
t = -M[1]*M[1]*M[5]; ((t >= 0.0)?(pos):(neg)) += t;
|
||||
t = -M[0]*M[4]*M[4]; ((t >= 0.0)?(pos):(neg)) += t;
|
||||
det = pos+neg;
|
||||
|
||||
t = det/(pos-neg);
|
||||
if (FABS(t) >= 1.0e-15)
|
||||
{
|
||||
out[0] = (M[2] * M[5] - M[4] * M[4]) /det;
|
||||
out[1] = -(M[1] * M[5] - M[4] * M[3]) /det;
|
||||
out[2] = (M[0] * M[5] - M[3] * M[3]) /det;
|
||||
out[3] = (M[1] * M[4] - M[2] * M[3]) /det;
|
||||
out[4] = -(M[0] * M[4] - M[1] * M[3]) /det;
|
||||
out[5] = (M[0] * M[2] - M[1] * M[1]) /det;
|
||||
M[0] = out[0]; M[1] = out[1]; M[2] = out[2];
|
||||
M[3] = out[3]; M[4] = out[4]; M[5] = out[5];
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Compute eigenvalues and eigenvectors of the matrix (JACOBI method).
|
||||
// The calling function is responsible of verifying that the matrix
|
||||
// is diagonalizable.
|
||||
//
|
||||
// This routine was inspired from a software to estimate curvature
|
||||
// tensors developed at INRIA. Visit the following link for details:
|
||||
// http://www-sop.inria.fr/geometrica/team/Pierre.Alliez/demos/curvature/
|
||||
//
|
||||
// This version has been slightly optimized.
|
||||
//
|
||||
|
||||
void SymMatrix3x3::diagonalize(double *eigen_val, double *eigen_vec) const
|
||||
{
|
||||
static const double EPS = 0.00001;
|
||||
static const double cos_pi_4 = 0.70710678;
|
||||
static const int MAX_ITER = 100;
|
||||
double a_P[6], v_P[9];
|
||||
double *a = a_P, *v = v_P;
|
||||
double a_norm,a_normEPS,thr,thr_nn;
|
||||
int nb_iter = 0;
|
||||
int i,j,k,ij,jj,ik,l,m,lm,mq,lq,ll,mm,imv,im,iq,ilv,il;
|
||||
int index_P[3];
|
||||
int *index = index_P;
|
||||
double a_ij,a_lm,a_ll,a_mm,a_im,a_il,a_lm_2,v_ilv,v_imv,x;
|
||||
double sinx,sinx_2,cosx,cosx_2,sincos,delta;
|
||||
|
||||
a[0] = M[0]; a[1] = M[1]; a[2] = M[2];
|
||||
a[3] = M[3]; a[4] = M[4]; a[5] = M[5];
|
||||
a--;
|
||||
|
||||
// Step 2 : Init diagonalization matrix as the unit matrix
|
||||
|
||||
for (ij=0, i=0; i<3; i++) for (j=0; j<3; j++) v[ij++] = (i==j)?(1.0):(0.0);
|
||||
v--;
|
||||
|
||||
// Step 3 : compute the weight of the non diagonal terms
|
||||
|
||||
a_norm = 0.0;
|
||||
for (i=1, ij=1; i<=3; i++) for (j=1; j<=i; j++, ij++) if( i!=j ) {a_ij = a[ij]; a_norm += a_ij*a_ij;}
|
||||
|
||||
if( a_norm != 0.0 )
|
||||
{
|
||||
a_normEPS = a_norm*EPS;
|
||||
thr = a_norm ;
|
||||
|
||||
// Step 4 : rotations
|
||||
while (thr > a_normEPS && nb_iter < MAX_ITER)
|
||||
{
|
||||
nb_iter++;
|
||||
thr_nn = thr / 6;
|
||||
|
||||
for (l=1; l<3; l++)
|
||||
for (m=l+1; m<=3; m++)
|
||||
{
|
||||
// compute sinx and cosx
|
||||
|
||||
lq = (l*l-l)/2; mq = (m*m-m)/2;
|
||||
lm = l+mq; a_lm = a[lm];
|
||||
a_lm_2 = a_lm*a_lm;
|
||||
|
||||
if( a_lm_2 < thr_nn ) continue;
|
||||
|
||||
ll = l+lq; mm = m+mq;
|
||||
a_ll = a[ll]; a_mm = a[mm];
|
||||
delta = a_ll - a_mm;
|
||||
|
||||
if (delta==0.0) {sinx = -cos_pi_4; cosx = cos_pi_4;}
|
||||
else {x = -atan( (a_lm+a_lm) / delta )/2.0; sinx=sin(x); cosx=cos(x);}
|
||||
|
||||
sinx_2 = sinx*sinx;
|
||||
cosx_2 = cosx*cosx;
|
||||
sincos = sinx*cosx;
|
||||
|
||||
// rotate L and M columns
|
||||
|
||||
ilv = 3*(l-1); imv = 3*(m-1);
|
||||
|
||||
for( i=1; i<=3;i++ )
|
||||
{
|
||||
if( (i!=l) && (i!=m) )
|
||||
{
|
||||
iq = (i*i-i)/2;
|
||||
im = (i<m)?(i+mq):(m+iq);
|
||||
a_im = a[im];
|
||||
il = (i<l)?(i+lq):(l+iq);
|
||||
a_il = a[il];
|
||||
a[il] = a_il*cosx - a_im*sinx;
|
||||
a[im] = a_il*sinx + a_im*cosx;
|
||||
}
|
||||
|
||||
ilv++; imv++;
|
||||
v_ilv = v[ilv]; v_imv = v[imv];
|
||||
v[ilv] = cosx*v_ilv - sinx*v_imv;
|
||||
v[imv] = sinx*v_ilv + cosx*v_imv;
|
||||
}
|
||||
|
||||
x = a_lm*sincos; x+=x;
|
||||
|
||||
a[ll] = a_ll*cosx_2 + a_mm*sinx_2 - x;
|
||||
a[mm] = a_ll*sinx_2 + a_mm*cosx_2 + x;
|
||||
a[lm] = 0.0;
|
||||
thr = FABS( thr - a_lm_2 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Step 5: index conversion and copy eigen values
|
||||
|
||||
// back from Fortran to C++
|
||||
a++;
|
||||
|
||||
for( i=0; i<3; i++ ) { k = i + (i*(i+1))/2; eigen_val[i] = a[k];}
|
||||
|
||||
// Step 6: sort the eigen values and eigen vectors
|
||||
|
||||
for( i=0; i<3; i++ ) index[i] = i;
|
||||
|
||||
for( i=0; i<(3-1); i++ ) {
|
||||
x = eigen_val[i];
|
||||
k = i;
|
||||
|
||||
for( j=i+1; j<3; j++ ) if( x < eigen_val[j] ) { k = j; x = eigen_val[j];}
|
||||
|
||||
eigen_val[k] = eigen_val[i];
|
||||
eigen_val[i] = x;
|
||||
|
||||
jj = index[k];
|
||||
index[k] = index[i];
|
||||
index[i] = jj;
|
||||
}
|
||||
|
||||
// Step 7: save the eigen vectors
|
||||
|
||||
v++; // back from Fortran to to C++
|
||||
|
||||
ij = 0;
|
||||
for( k=0; k<3; k++ ) for(ik = index[k]*3, i=0; i<3; i++ ) eigen_vec[ij++] = v[ik++];
|
||||
}
|
||||
|
||||
|
||||
// Computes the eigenvalues of the matrix
|
||||
|
||||
void SymMatrix3x3::getEigenvalues(double *L1, double *L2, double *L3) const
|
||||
{
|
||||
double a11 = M[0], a12 = M[1], a22 = M[2], a13 = M[3], a23 = M[4], a33 = M[5];
|
||||
double c0 = (a11*a22*a33)+(2.0*a12*a13*a23)-(a11*a23*a23)-(a22*a13*a13)-(a33*a12*a12); // Mat. Determinant
|
||||
double c1 = a11*a22-a12*a12+a11*a33-a13*a13+a22*a33-a23*a23;
|
||||
double c2 = a11+a22+a33;
|
||||
double a = (3*c1-c2*c2)/3.0;
|
||||
double b = (9*c1*c2-2*c2*c2*c2-27*c0)/27.0;
|
||||
double Q = ((b*b)/4.0)+((a*a*a)/27.0);
|
||||
|
||||
if (Q>1.0e-12) {*L1 = *L2 = *L3 = a11; return;} // Evecs = (1,0,0), (0,1,0), (0,0,1)
|
||||
|
||||
double l1, l2, l3; // Eigenvalues to be computed
|
||||
|
||||
if (Q>=0) {double p=(b>0)?(pow(b/2, 1.0/3.0)):(0); l1=l2=((c2/3.0)+p); l3=((c2/3.0)-2.0*p);}
|
||||
else
|
||||
{
|
||||
double t = atan2(sqrt(-Q), -b/2.0)/3.0, r = pow(((b*b)/4.0)-Q, 1.0/6.0);
|
||||
double cos_t = cos(t), sin_t = sin(t);
|
||||
const double sq3 = sqrt(3.0);
|
||||
l1 = l2 = l3 = (c2/3.0);
|
||||
l1 += (2*r*cos_t);
|
||||
l2 -= r*(cos_t+sq3*sin_t);
|
||||
l3 -= r*(cos_t-sq3*sin_t);
|
||||
}
|
||||
|
||||
if (l1<=l2 && l1<=l3) {*L1=l1; *L2=(l2<l3)?(l2):(l3); *L3=(l2<l3)?(l3):(l2);}
|
||||
else if (l2<=l1 && l2<=l3) {*L1=l2; *L2=(l1<l3)?(l1):(l3); *L3=(l1<l3)?(l3):(l1);}
|
||||
else {*L1=l3; *L2=(l1<l2)?(l1):(l2); *L3=(l1<l2)?(l2):(l1);}
|
||||
}
|
||||
|
||||
|
||||
// Computes the eigenvector corresp. to the minimum eigenvalue
|
||||
|
||||
double SymMatrix3x3::getMinEigenvector(double *x, double *y, double *z) const
|
||||
{
|
||||
double a11 = M[0], a12 = M[1], a22 = M[2], a13 = M[3], a23 = M[4], a33 = M[5];
|
||||
double l, l1, l2, l3, c0, c1, c2;
|
||||
getEigenvalues(&l, &l2, &l3);
|
||||
|
||||
if (l==l3 && l==l2) {*x = 1; *y = *z = 0; return l;}
|
||||
|
||||
a11-=l; a22-=l; a33-=l;
|
||||
double u11 = a22*a33-a23*a23, u12 = a13*a23-a12*a33, u13 = a12*a23-a13*a22;
|
||||
double u22 = a11*a33-a13*a13, u23 = a12*a13-a23*a11, u33 = a11*a22-a12*a12;
|
||||
l1 = u11*u11+u12*u12+u13*u13;
|
||||
l2 = u12*u12+u22*u22+u23*u23;
|
||||
l3 = u13*u13+u23*u23+u33*u33;
|
||||
|
||||
if (l1>=l2 && l1>=l3) {c0=u11; c1=u12; c2=u13; l=l1;}
|
||||
else if (l2>=l1 && l2>=l3) {c0=u12; c1=u22; c2=u23; l=l2;}
|
||||
else {c0=u13; c1=u23; c2=u33; l=l3;}
|
||||
|
||||
l1 = sqrt(l); *x = c0/l1; *y = c1/l1; *z = c2/l1;
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
// Computes the eigenvector corresp. to the maximum eigenvalue
|
||||
|
||||
void SymMatrix3x3::getMaxEigenvector(double *x, double *y, double *z) const
|
||||
{
|
||||
SymMatrix3x3(-M[0], -M[1], -M[2], -M[3], -M[4], -M[5]).getMinEigenvector(x, y, z);
|
||||
}
|
||||
|
||||
// Prints the matrix values
|
||||
|
||||
void SymMatrix3x3::print(FILE *fp) const
|
||||
{
|
||||
fprintf(fp,"%e %e %e\n",M[0],M[1],M[3]);
|
||||
fprintf(fp,"%e %e %e\n",M[1],M[2],M[4]);
|
||||
fprintf(fp,"%e %e %e\n",M[3],M[4],M[5]);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Symmetric 4x4 matrix
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Extend a 3x3 matrix
|
||||
|
||||
SymMatrix4x4::SymMatrix4x4(const SymMatrix3x3& q)
|
||||
{
|
||||
a2 = q.M[0]; ab = q.M[1]; ac = q.M[3]; ad = 0;
|
||||
b2 = q.M[2]; bc = q.M[4]; bd = 0;
|
||||
c2 = q.M[5]; cd = 0; d2 = 1;
|
||||
}
|
||||
|
||||
|
||||
// Build a quadric
|
||||
|
||||
SymMatrix4x4::SymMatrix4x4(const coord& a, const coord& b, const coord& c, const coord& d)
|
||||
{
|
||||
a2 = a*a; ab = a*b; ac = a*c; ad = a*d;
|
||||
b2 = b*b; bc = b*c; bd = b*d;
|
||||
c2 = c*c; cd = c*d; d2 = d*d;
|
||||
}
|
||||
|
||||
// True iff equal
|
||||
|
||||
bool SymMatrix4x4::operator==(const SymMatrix4x4& q)
|
||||
{
|
||||
return (
|
||||
a2 == q.a2 && ab == q.ab && ac == q.ac && ad == q.ad &&\
|
||||
b2 == q.b2 && bc == q.bc && bd == q.bd &&\
|
||||
c2 == q.c2 && cd == q.cd && d2 == q.d2);
|
||||
}
|
||||
|
||||
// True iff different
|
||||
|
||||
bool SymMatrix4x4::operator!=(const SymMatrix4x4& q)
|
||||
{
|
||||
return (
|
||||
a2 != q.a2 || ab != q.ab || ac != q.ac || ad != q.ad ||\
|
||||
b2 != q.b2 || bc != q.bc || bd != q.bd ||\
|
||||
c2 != q.c2 || cd != q.cd || d2 != q.d2);
|
||||
}
|
||||
|
||||
// Sum the matrix 'q' to the current matrix
|
||||
|
||||
void SymMatrix4x4::operator+=(const SymMatrix4x4& q)
|
||||
{
|
||||
a2 += q.a2; ab += q.ab; ac += q.ac; ad += q.ad;
|
||||
b2 += q.b2; bc += q.bc; bd += q.bd;
|
||||
c2 += q.c2; cd += q.cd; d2 += q.d2;
|
||||
}
|
||||
|
||||
// Returns the sum of the matrix with another matrix 'q'
|
||||
|
||||
SymMatrix4x4 SymMatrix4x4::operator+(const SymMatrix4x4& q) const
|
||||
{
|
||||
SymMatrix4x4 n;
|
||||
|
||||
n.a2=a2+q.a2; n.ab=ab+q.ab; n.ac=ac+q.ac; n.ad=ad+q.ad;
|
||||
n.b2=b2+q.b2; n.bc=bc+q.bc; n.bd=bd+q.bd;
|
||||
n.c2=c2+q.c2; n.cd=cd+q.cd; n.d2=d2+q.d2;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
// Returns the product of the matrix with a scalar
|
||||
|
||||
SymMatrix4x4 SymMatrix4x4::operator*(const coord& d) const
|
||||
{
|
||||
SymMatrix4x4 n;
|
||||
|
||||
n.a2=a2*d; n.ab=ab*d; n.ac=ac*d; n.ad=ad*d;
|
||||
n.b2=b2*d; n.bc=bc*d; n.bd=bd*d;
|
||||
n.c2=c2*d; n.cd=cd*d; n.d2=d2*d;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void SymMatrix4x4::add(const coord& a, const coord& b, const coord& c, const coord& d)
|
||||
{
|
||||
a2 += a*a; ab += a*b; ac += a*c; ad += a*d;
|
||||
b2 += b*b; bc += b*c; bd += b*d;
|
||||
c2 += c*c; cd += c*d; d2 += d*d;
|
||||
}
|
||||
|
||||
|
||||
// Computes (a,b,c,w)*M*(a,b,c,w)
|
||||
|
||||
coord SymMatrix4x4::lrMultiply(const coord& x, const coord& y, const coord& z, const coord& w) const
|
||||
{
|
||||
coord a,b,c,d;
|
||||
a = x*a2 + y*ab + z*ac + w*ad;
|
||||
b = x*ab + y*b2 + z*bc + w*bd;
|
||||
c = x*ac + y*bc + z*c2 + w*cd;
|
||||
d = x*ad + y*bd + z*cd + w*d2;
|
||||
return (x*a + y*b + z*c + w*d);
|
||||
}
|
||||
|
||||
// Computes (a,b,c) s.t. (a,b,c,1)*M*(a,b,c,1) is minimized
|
||||
// Returns FALSE if the minimizer is not unique
|
||||
|
||||
bool SymMatrix4x4::getMinimizer(coord *a, coord *b, coord *c) const
|
||||
{
|
||||
coord det, pos, neg, t;
|
||||
|
||||
pos = neg = 0.0;
|
||||
t = a2*b2*c2; ((t >= 0.0)?(pos):(neg)) += t;
|
||||
t = ab*bc*ac; ((t >= 0.0)?(pos):(neg)) += t;
|
||||
t = ac*ab*bc; ((t >= 0.0)?(pos):(neg)) += t;
|
||||
t = -ac*b2*ac; ((t >= 0.0)?(pos):(neg)) += t;
|
||||
t = -ab*ab*c2; ((t >= 0.0)?(pos):(neg)) += t;
|
||||
t = -a2*bc*bc; ((t >= 0.0)?(pos):(neg)) += t;
|
||||
det = pos+neg;
|
||||
|
||||
if (pos == neg) return 0;
|
||||
|
||||
t = det/(pos-neg);
|
||||
if (
|
||||
#ifdef USE_HYBRID_KERNEL
|
||||
(coord::isUsingRationals() && t!=0) ||
|
||||
#endif
|
||||
(FABS(t) >= 1.0e-15))
|
||||
{
|
||||
*a = -(ad*( (b2*c2 - bc*bc)) + bd*(-(ab*c2 - bc*ac)) + cd*( (ab*bc - b2*ac)))/det;
|
||||
*b = -(ad*(-(ab*c2 - ac*bc)) + bd*( (a2*c2 - ac*ac)) + cd*(-(a2*bc - ab*ac)))/det;
|
||||
*c = -(ad*( (ab*bc - ac*b2)) + bd*(-(a2*bc - ac*ab)) + cd*( (a2*b2 - ab*ab)))/det;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Invert a symmetric 4x4 matrix using L*D*L^T decomposition.
|
||||
// The calling function is responsible of verifying that the matrix
|
||||
// is positive definite.
|
||||
//
|
||||
|
||||
bool SymMatrix4x4::invert()
|
||||
{
|
||||
if (a2 <= 0) return false;
|
||||
|
||||
coord d00 = coord(1.0) / a2;
|
||||
coord L10 = ab;
|
||||
coord l10 = ab*d00;
|
||||
coord L20 = ac;
|
||||
coord l20 = ac*d00;
|
||||
coord L30 = ad;
|
||||
coord l30 = ad*d00;
|
||||
coord d11 = b2-(L10*l10);
|
||||
|
||||
if (d11 <= 0) return false; else d11 = coord(1.0)/d11;
|
||||
|
||||
coord L21 = (bc-(L10*l20));
|
||||
coord l21 = L21*d11;
|
||||
coord L31 = (bd-(L10*l30));
|
||||
coord l31 = L31*d11;
|
||||
coord d22 = c2-(L20*l20)-(L21*l21);
|
||||
|
||||
if (d22 <= 0) return false; else d22 = coord(1.0) / d22;
|
||||
|
||||
coord L32 = (cd-(L20*l30)-(L21*l31));
|
||||
coord l32 = L32*d22;
|
||||
coord d33 = d2-(L30*l30)-(L31*l31)-(L32*l32);
|
||||
|
||||
if (d33 <= 0) return false; else d33 = coord(1.0) / d33;
|
||||
|
||||
L20 = l10*l21-l20;
|
||||
L31 = l21*l32-l31;
|
||||
L30 = l32*l20-L31*l10-l30;
|
||||
|
||||
a2 = d00+(-l10)*((-l10)*d11)+L20*(L20*d22)+L30*(L30*d33);
|
||||
ab = ((-l10)*d11)+L20*((-l21)*d22)+L30*(L31*d33);
|
||||
b2 = d11+(-l21)*((-l21)*d22)+L31*(L31*d33);
|
||||
ac = (L20*d22)+L30*((-l32)*d33);
|
||||
bc = ((-l21)*d22)+L31*((-l32)*d33);
|
||||
c2 = d22+(-l32)*((-l32)*d33);
|
||||
ad = (L30*d33);
|
||||
bd = (L31*d33);
|
||||
cd = ((-l32)*d33);
|
||||
d2 = d33;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generic 4x4 matrix
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Matrix4x4::Matrix4x4() {}
|
||||
|
||||
Matrix4x4::Matrix4x4(const double& d)
|
||||
{
|
||||
matrix[0][0] = matrix[1][1] = matrix[2][2] = matrix[3][3] = d;
|
||||
matrix[1][0] = matrix[0][1] = matrix[1][2] = matrix[1][3] = 0;
|
||||
matrix[2][0] = matrix[2][1] = matrix[0][2] = matrix[2][3] = 0;
|
||||
matrix[3][0] = matrix[3][1] = matrix[3][2] = matrix[0][3] = 0;
|
||||
}
|
||||
|
||||
Matrix4x4::Matrix4x4(const double& a11, const double& a12, const double& a13, const double& a14,
|
||||
const double& a21, const double& a22, const double& a23, const double& a24,
|
||||
const double& a31, const double& a32, const double& a33, const double& a34,
|
||||
const double& a41, const double& a42, const double& a43, const double& a44)
|
||||
{
|
||||
matrix[0][0] = a11; matrix[0][1] = a12; matrix[0][2] = a13; matrix[0][3] = a14;
|
||||
matrix[1][0] = a21; matrix[1][1] = a22; matrix[1][2] = a23; matrix[1][3] = a24;
|
||||
matrix[2][0] = a31; matrix[2][1] = a32; matrix[2][2] = a33; matrix[2][3] = a34;
|
||||
matrix[3][0] = a41; matrix[3][1] = a42; matrix[3][2] = a43; matrix[3][3] = a44;
|
||||
}
|
||||
|
||||
void Matrix4x4::setRotation(const double& rx, const double& ry, const double& rz, const double& rw)
|
||||
{
|
||||
matrix[0][0] = rw*rw + rx*rx - ry*ry - rz*rz;
|
||||
matrix[0][1] = 2*rx*ry + 2*rw*rz;
|
||||
matrix[0][2] = 2*rx*rz - 2*rw*ry;
|
||||
matrix[0][3] = 0.0;
|
||||
|
||||
matrix[1][0] = 2*rx*ry-2*rw*rz;
|
||||
matrix[1][1] = rw*rw - rx*rx + ry*ry - rz*rz;
|
||||
matrix[1][2] = 2*ry*rz + 2*rw*rx;
|
||||
matrix[1][3] = 0.0;
|
||||
|
||||
matrix[2][0] = 2*rx*rz + 2*rw*ry;
|
||||
matrix[2][1] = 2*ry*rz - 2*rw*rx;
|
||||
matrix[2][2] = rw*rw - rx*rx - ry*ry + rz*rz;
|
||||
matrix[2][3] = 0.0;
|
||||
|
||||
matrix[3][0] = 0.0;
|
||||
matrix[3][1] = 0.0;
|
||||
matrix[3][2] = 0.0;
|
||||
matrix[3][3] = rw*rw + rx*rx + ry*ry + rz*rz;
|
||||
}
|
||||
|
||||
void Matrix4x4::setTranslation(const double& x, const double& y, const double& z)
|
||||
{
|
||||
matrix[0][0] = matrix[1][1] = matrix[2][2] = matrix[3][3] = 1;
|
||||
matrix[1][0] = matrix[0][1] = matrix[1][2] = 0;
|
||||
matrix[2][0] = matrix[2][1] = matrix[0][2] = 0;
|
||||
matrix[3][0] = matrix[3][1] = matrix[3][2] = 0;
|
||||
matrix[0][3] = x;
|
||||
matrix[1][3] = y;
|
||||
matrix[2][3] = z;
|
||||
}
|
||||
|
||||
Matrix4x4 Matrix4x4::operator*(const Matrix4x4& q) const
|
||||
{
|
||||
int i, j;
|
||||
Matrix4x4 m;
|
||||
|
||||
for (i=0; i<4; i++) for (j=0; j<4; j++)
|
||||
m.matrix[i][j] = matrix[i][0]*q.matrix[0][j] + matrix[i][1]*q.matrix[1][j] + matrix[i][2]*q.matrix[2][j] + matrix[i][3]*q.matrix[3][j];
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
void Matrix4x4::transform(double *x, double *y, double *z)
|
||||
{
|
||||
double w, a = *x, b = *y, c = *z;
|
||||
|
||||
*x = matrix[0][0]*a + matrix[0][1]*b + matrix[0][2]*c + matrix[0][3];
|
||||
*y = matrix[1][0]*a + matrix[1][1]*b + matrix[1][2]*c + matrix[1][3];
|
||||
*z = matrix[2][0]*a + matrix[2][1]*b + matrix[2][2]*c + matrix[2][3];
|
||||
w = matrix[3][0]*a + matrix[3][1]*b + matrix[3][2]*c + matrix[3][3];
|
||||
|
||||
(*x) /= w; (*y) /= w; (*z) /= w;
|
||||
}
|
||||
|
||||
} //namespace T_MESH
|
700
src/mesh_fix/src/Kernel/orientation.c
Normal file
700
src/mesh_fix/src/Kernel/orientation.c
Normal file
@ -0,0 +1,700 @@
|
||||
/****************************************************************************
|
||||
* TMesh *
|
||||
* *
|
||||
* Consiglio Nazionale delle Ricerche *
|
||||
* Istituto di Matematica Applicata e Tecnologie Informatiche *
|
||||
* Sezione di Genova *
|
||||
* IMATI-GE / CNR *
|
||||
* *
|
||||
* Authors: Marco Attene *
|
||||
* Copyright(C) 2012: IMATI-GE / CNR *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is dual-licensed as follows: *
|
||||
* *
|
||||
* (1) You may use TMesh as 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. *
|
||||
* In this case the 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 (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
* (2) You may use TMesh as part of a commercial software. In this case a *
|
||||
* proper agreement must be reached with the Authors and with IMATI-GE/CNR *
|
||||
* based on a proper licensing contract. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
// This code is inspired on ideas first published in the following paper:
|
||||
// Jonathan Richard Shewchuk. Adaptive Precision Floating-Point Arithmetic
|
||||
// and Fast Robust Geometric Predicates, Discrete & Computational Geometry
|
||||
// 18(3):305–363, October 1997.
|
||||
//
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#ifdef SPECIFY_FP_PRECISION
|
||||
#include <float.h>
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* This section contains private macros and functions. */
|
||||
/* These are not part of the public interface. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
#define FABS(a) (((a)>=0.0)?(a):(-(a)))
|
||||
#define FTST(a,b,x,y) _bvr=x-a; y=b-_bvr
|
||||
#define FTS(a,b,x,y) x=(double)(a+b); FTST(a,b,x,y)
|
||||
#define TST(a,b,x,y) _bvr=(double)(x-a); _avr=x-_bvr; _brn=b-_bvr; _arn=a-_avr; y=_arn+_brn
|
||||
#define TWS(a,b,x,y) x=(double)(a+b); TST(a,b,x,y)
|
||||
#define TDT(a,b,x,y) _bvr=(double)(a-x); _avr=x+_bvr; _brn=_bvr-b; _arn=a-_avr; y=_arn+_brn
|
||||
#define TWD(a,b,x,y) x=(double)(a-b); TDT(a,b,x,y)
|
||||
#define SPLT(a,ahi,alo) c=(double)(_spl*a); abig=(double)(c-a); ahi=c-abig; alo=a-ahi
|
||||
#define TPT(a,b,x,y) SPLT(a,ahi,alo); SPLT(b,bhi,blo); err1=x-(ahi*bhi); err2=err1-(alo*bhi); err3=err2-(ahi*blo); y=(alo*blo)-err3
|
||||
#define TWP(a,b,x,y) x=(double)(a*b); TPT(a,b,x,y)
|
||||
#define TPP(a,b,bhi,blo,x,y) x=(double)(a*b); SPLT(a,ahi,alo); err1=x-(ahi*bhi); err2=err1-(alo*bhi); err3=err2-(ahi*blo); y=(alo*blo)-err3
|
||||
#define TOD(a1,a0,b,x2,x1,x0) TWD(a0,b,_i,x0); TWS(a1,_i,x2,x1)
|
||||
#define TTD(a1,a0,b1,b0,x3,x2,x1,x0) TOD(a1,a0,b0,_j,_0,x0); TOD(_j,_0,b1,x3,x2,x1)
|
||||
#define TOP(a1,a0,b,x3,x2,x1,x0) SPLT(b,bhi,blo); TPP(a0,b,bhi,blo,_i,x0); TPP(a1,b,bhi,blo,_j,_0); TWS(_i,_0,_k,x1); FTS(_j,_k,x3,x2)
|
||||
|
||||
double _spl, _eps, _reb, _ccwebA, _ccwebB, _ccwebC, _o3ebA, _o3ebB, _o3ebC;
|
||||
double _iccebA, _iccebB, _iccebC, _ispebA, _ispebB, _ispebC;
|
||||
|
||||
int _fesze(int elen, double *e, int flen, double *f, double *h)
|
||||
{
|
||||
double Q, Qnew, hh, _bvr, _avr, _brn, _arn, enow, fnow;
|
||||
int eindex, findex, hindex;
|
||||
|
||||
enow = e[0];
|
||||
fnow = f[0];
|
||||
eindex = findex = 0;
|
||||
if ((fnow > enow) == (fnow > -enow)) {
|
||||
Q = enow;
|
||||
enow = e[++eindex];
|
||||
} else {
|
||||
Q = fnow;
|
||||
fnow = f[++findex];
|
||||
}
|
||||
hindex = 0;
|
||||
if ((eindex < elen) && (findex < flen)) {
|
||||
if ((fnow > enow) == (fnow > -enow)) {
|
||||
FTS(enow, Q, Qnew, hh);
|
||||
enow = e[++eindex];
|
||||
} else {
|
||||
FTS(fnow, Q, Qnew, hh);
|
||||
fnow = f[++findex];
|
||||
}
|
||||
Q = Qnew;
|
||||
if (hh != 0.0) {
|
||||
h[hindex++] = hh;
|
||||
}
|
||||
while ((eindex < elen) && (findex < flen)) {
|
||||
if ((fnow > enow) == (fnow > -enow)) {
|
||||
TWS(Q, enow, Qnew, hh);
|
||||
enow = e[++eindex];
|
||||
} else {
|
||||
TWS(Q, fnow, Qnew, hh);
|
||||
fnow = f[++findex];
|
||||
}
|
||||
Q = Qnew;
|
||||
if (hh != 0.0) {
|
||||
h[hindex++] = hh;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (eindex < elen) {
|
||||
TWS(Q, enow, Qnew, hh);
|
||||
enow = e[++eindex];
|
||||
Q = Qnew;
|
||||
if (hh != 0.0) {
|
||||
h[hindex++] = hh;
|
||||
}
|
||||
}
|
||||
while (findex < flen) {
|
||||
TWS(Q, fnow, Qnew, hh);
|
||||
fnow = f[++findex];
|
||||
Q = Qnew;
|
||||
if (hh != 0.0) {
|
||||
h[hindex++] = hh;
|
||||
}
|
||||
}
|
||||
if ((Q != 0.0) || (hindex == 0)) {
|
||||
h[hindex++] = Q;
|
||||
}
|
||||
return hindex;
|
||||
}
|
||||
|
||||
int _seze(int elen, double *e, double b, double *h)
|
||||
{
|
||||
double Q, sum, hh, product1, product0, enow, _bvr, _avr, _brn, _arn, c;
|
||||
double abig, ahi, alo, bhi, blo, err1, err2, err3;
|
||||
int eindex, hindex;
|
||||
|
||||
SPLT(b, bhi, blo);
|
||||
TPP(e[0], b, bhi, blo, Q, hh);
|
||||
hindex = 0;
|
||||
if (hh != 0) {
|
||||
h[hindex++] = hh;
|
||||
}
|
||||
for (eindex = 1; eindex < elen; eindex++) {
|
||||
enow = e[eindex];
|
||||
TPP(enow, b, bhi, blo, product1, product0);
|
||||
TWS(Q, product0, sum, hh);
|
||||
if (hh != 0) {
|
||||
h[hindex++] = hh;
|
||||
}
|
||||
FTS(product1, sum, Q, hh);
|
||||
if (hh != 0) {
|
||||
h[hindex++] = hh;
|
||||
}
|
||||
}
|
||||
if ((Q != 0.0) || (hindex == 0)) {
|
||||
h[hindex++] = Q;
|
||||
}
|
||||
return hindex;
|
||||
}
|
||||
|
||||
double _estm(int elen, double *e)
|
||||
{
|
||||
int eindex;
|
||||
double Q = e[0];
|
||||
for (eindex = 1; eindex < elen; eindex++) Q += e[eindex];
|
||||
return Q;
|
||||
}
|
||||
|
||||
|
||||
double _adaptive2dorientation(double *pa, double *pb, double *pc, double detsum)
|
||||
{
|
||||
double acx, acy, bcx, bcy,acxtail, acytail, bcxtail, bcytail, detleft, detright;
|
||||
double detlefttail, detrighttail, det, errbound, B[4], C1[8], C2[12], D[16];
|
||||
double B3, u[4], u3, s1, t1, s0, t0, _bvr, _avr, _brn, _arn, c;
|
||||
double abig, ahi, alo, bhi, blo, err1, err2, err3, _i, _j, _0;
|
||||
int C1length, C2length, Dlength;
|
||||
|
||||
acx = (double) (pa[0] - pc[0]);
|
||||
bcx = (double) (pb[0] - pc[0]);
|
||||
acy = (double) (pa[1] - pc[1]);
|
||||
bcy = (double) (pb[1] - pc[1]);
|
||||
|
||||
TWP(acx, bcy, detleft, detlefttail);
|
||||
TWP(acy, bcx, detright, detrighttail);
|
||||
|
||||
TTD(detleft, detlefttail, detright, detrighttail,
|
||||
B3, B[2], B[1], B[0]);
|
||||
B[3] = B3;
|
||||
|
||||
det = _estm(4, B);
|
||||
errbound = _ccwebB * detsum;
|
||||
if ((det >= errbound) || (-det >= errbound)) {
|
||||
return det;
|
||||
}
|
||||
|
||||
TDT(pa[0], pc[0], acx, acxtail);
|
||||
TDT(pb[0], pc[0], bcx, bcxtail);
|
||||
TDT(pa[1], pc[1], acy, acytail);
|
||||
TDT(pb[1], pc[1], bcy, bcytail);
|
||||
|
||||
if ((acxtail == 0.0) && (acytail == 0.0)
|
||||
&& (bcxtail == 0.0) && (bcytail == 0.0)) {
|
||||
return det;
|
||||
}
|
||||
|
||||
errbound = _ccwebC * detsum + _reb * FABS(det);
|
||||
det += (acx * bcytail + bcy * acxtail)
|
||||
- (acy * bcxtail + bcx * acytail);
|
||||
if ((det >= errbound) || (-det >= errbound)) {
|
||||
return det;
|
||||
}
|
||||
|
||||
TWP(acxtail, bcy, s1, s0);
|
||||
TWP(acytail, bcx, t1, t0);
|
||||
TTD(s1, s0, t1, t0, u3, u[2], u[1], u[0]);
|
||||
u[3] = u3;
|
||||
C1length = _fesze(4, B, 4, u, C1);
|
||||
|
||||
TWP(acx, bcytail, s1, s0);
|
||||
TWP(acy, bcxtail, t1, t0);
|
||||
TTD(s1, s0, t1, t0, u3, u[2], u[1], u[0]);
|
||||
u[3] = u3;
|
||||
C2length = _fesze(C1length, C1, 4, u, C2);
|
||||
|
||||
TWP(acxtail, bcytail, s1, s0);
|
||||
TWP(acytail, bcxtail, t1, t0);
|
||||
TTD(s1, s0, t1, t0, u3, u[2], u[1], u[0]);
|
||||
u[3] = u3;
|
||||
Dlength = _fesze(C2length, C2, 4, u, D);
|
||||
|
||||
return(D[Dlength - 1]);
|
||||
}
|
||||
|
||||
double _adaptive3dorientation(double *pa, double *pb, double *pc, double *pd, double permanent)
|
||||
{
|
||||
double adx, bdx, cdx, ady, bdy, cdy, adz, bdz, cdz, det, errbound;
|
||||
double bdxcdy1, cdxbdy1, cdxady1, adxcdy1, adxbdy1, bdxady1;
|
||||
double bdxcdy0, cdxbdy0, cdxady0, adxcdy0, adxbdy0, bdxady0, bc[4], ca[4], ab[4];
|
||||
double bc3, ca3, ab3, adet[8], bdet[8], cdet[8];
|
||||
double abdet[16], *finnow, *finother, *finswap, fin1[192], fin2[192];
|
||||
double adxtail, bdxtail, cdxtail, adytail, bdytail, cdytail, adztail, bdztail, cdztail;
|
||||
double at_blarge, at_clarge, bt_clarge, bt_alarge, ct_alarge, ct_blarge;
|
||||
double at_b[4], at_c[4], bt_c[4], bt_a[4], ct_a[4], ct_b[4];
|
||||
double bdxt_cdy1, cdxt_bdy1, cdxt_ady1, adxt_cdy1, adxt_bdy1, bdxt_ady1;
|
||||
double bdxt_cdy0, cdxt_bdy0, cdxt_ady0, adxt_cdy0, adxt_bdy0, bdxt_ady0;
|
||||
double bdyt_cdx1, cdyt_bdx1, cdyt_adx1, adyt_cdx1, adyt_bdx1, bdyt_adx1;
|
||||
double bdyt_cdx0, cdyt_bdx0, cdyt_adx0, adyt_cdx0, adyt_bdx0, bdyt_adx0;
|
||||
double bct[8], cat[8], abt[8], bdxt_cdyt1, cdxt_bdyt1, cdxt_adyt1;
|
||||
double adxt_cdyt1, adxt_bdyt1, bdxt_adyt1, bdxt_cdyt0, cdxt_bdyt0, cdxt_adyt0;
|
||||
double adxt_cdyt0, adxt_bdyt0, bdxt_adyt0, u[4], v[12], w[16], u3, negate;
|
||||
double _bvr, _avr, _brn, _arn, c, abig, ahi, alo, bhi, blo;
|
||||
double err1, err2, err3, _i, _j, _k, _0;
|
||||
int at_blen, at_clen, bt_clen, bt_alen, ct_alen, ct_blen, finlength;
|
||||
int vlength, wlength, alen, blen, clen, ablen, bctlen, catlen, abtlen;
|
||||
|
||||
adx = (double) (pa[0] - pd[0]);
|
||||
bdx = (double) (pb[0] - pd[0]);
|
||||
cdx = (double) (pc[0] - pd[0]);
|
||||
ady = (double) (pa[1] - pd[1]);
|
||||
bdy = (double) (pb[1] - pd[1]);
|
||||
cdy = (double) (pc[1] - pd[1]);
|
||||
adz = (double) (pa[2] - pd[2]);
|
||||
bdz = (double) (pb[2] - pd[2]);
|
||||
cdz = (double) (pc[2] - pd[2]);
|
||||
|
||||
TWP(bdx, cdy, bdxcdy1, bdxcdy0);
|
||||
TWP(cdx, bdy, cdxbdy1, cdxbdy0);
|
||||
TTD(bdxcdy1, bdxcdy0, cdxbdy1, cdxbdy0, bc3, bc[2], bc[1], bc[0]);
|
||||
bc[3] = bc3;
|
||||
alen = _seze(4, bc, adz, adet);
|
||||
|
||||
TWP(cdx, ady, cdxady1, cdxady0);
|
||||
TWP(adx, cdy, adxcdy1, adxcdy0);
|
||||
TTD(cdxady1, cdxady0, adxcdy1, adxcdy0, ca3, ca[2], ca[1], ca[0]);
|
||||
ca[3] = ca3;
|
||||
blen = _seze(4, ca, bdz, bdet);
|
||||
|
||||
TWP(adx, bdy, adxbdy1, adxbdy0);
|
||||
TWP(bdx, ady, bdxady1, bdxady0);
|
||||
TTD(adxbdy1, adxbdy0, bdxady1, bdxady0, ab3, ab[2], ab[1], ab[0]);
|
||||
ab[3] = ab3;
|
||||
clen = _seze(4, ab, cdz, cdet);
|
||||
|
||||
ablen = _fesze(alen, adet, blen, bdet, abdet);
|
||||
finlength = _fesze(ablen, abdet, clen, cdet, fin1);
|
||||
|
||||
det = _estm(finlength, fin1);
|
||||
errbound = _o3ebB * permanent;
|
||||
if ((det >= errbound) || (-det >= errbound)) {
|
||||
return det;
|
||||
}
|
||||
|
||||
TDT(pa[0], pd[0], adx, adxtail);
|
||||
TDT(pb[0], pd[0], bdx, bdxtail);
|
||||
TDT(pc[0], pd[0], cdx, cdxtail);
|
||||
TDT(pa[1], pd[1], ady, adytail);
|
||||
TDT(pb[1], pd[1], bdy, bdytail);
|
||||
TDT(pc[1], pd[1], cdy, cdytail);
|
||||
TDT(pa[2], pd[2], adz, adztail);
|
||||
TDT(pb[2], pd[2], bdz, bdztail);
|
||||
TDT(pc[2], pd[2], cdz, cdztail);
|
||||
|
||||
if ((adxtail == 0.0) && (bdxtail == 0.0) && (cdxtail == 0.0)
|
||||
&& (adytail == 0.0) && (bdytail == 0.0) && (cdytail == 0.0)
|
||||
&& (adztail == 0.0) && (bdztail == 0.0) && (cdztail == 0.0)) {
|
||||
return det;
|
||||
}
|
||||
|
||||
errbound = _o3ebC * permanent + _reb * FABS(det);
|
||||
det += (adz * ((bdx * cdytail + cdy * bdxtail)
|
||||
- (bdy * cdxtail + cdx * bdytail))
|
||||
+ adztail * (bdx * cdy - bdy * cdx))
|
||||
+ (bdz * ((cdx * adytail + ady * cdxtail)
|
||||
- (cdy * adxtail + adx * cdytail))
|
||||
+ bdztail * (cdx * ady - cdy * adx))
|
||||
+ (cdz * ((adx * bdytail + bdy * adxtail)
|
||||
- (ady * bdxtail + bdx * adytail))
|
||||
+ cdztail * (adx * bdy - ady * bdx));
|
||||
if ((det >= errbound) || (-det >= errbound)) {
|
||||
return det;
|
||||
}
|
||||
|
||||
finnow = fin1;
|
||||
finother = fin2;
|
||||
|
||||
if (adxtail == 0.0) {
|
||||
if (adytail == 0.0) {
|
||||
at_b[0] = 0.0;
|
||||
at_blen = 1;
|
||||
at_c[0] = 0.0;
|
||||
at_clen = 1;
|
||||
} else {
|
||||
negate = -adytail;
|
||||
TWP(negate, bdx, at_blarge, at_b[0]);
|
||||
at_b[1] = at_blarge;
|
||||
at_blen = 2;
|
||||
TWP(adytail, cdx, at_clarge, at_c[0]);
|
||||
at_c[1] = at_clarge;
|
||||
at_clen = 2;
|
||||
}
|
||||
} else {
|
||||
if (adytail == 0.0) {
|
||||
TWP(adxtail, bdy, at_blarge, at_b[0]);
|
||||
at_b[1] = at_blarge;
|
||||
at_blen = 2;
|
||||
negate = -adxtail;
|
||||
TWP(negate, cdy, at_clarge, at_c[0]);
|
||||
at_c[1] = at_clarge;
|
||||
at_clen = 2;
|
||||
} else {
|
||||
TWP(adxtail, bdy, adxt_bdy1, adxt_bdy0);
|
||||
TWP(adytail, bdx, adyt_bdx1, adyt_bdx0);
|
||||
TTD(adxt_bdy1, adxt_bdy0, adyt_bdx1, adyt_bdx0,
|
||||
at_blarge, at_b[2], at_b[1], at_b[0]);
|
||||
at_b[3] = at_blarge;
|
||||
at_blen = 4;
|
||||
TWP(adytail, cdx, adyt_cdx1, adyt_cdx0);
|
||||
TWP(adxtail, cdy, adxt_cdy1, adxt_cdy0);
|
||||
TTD(adyt_cdx1, adyt_cdx0, adxt_cdy1, adxt_cdy0,
|
||||
at_clarge, at_c[2], at_c[1], at_c[0]);
|
||||
at_c[3] = at_clarge;
|
||||
at_clen = 4;
|
||||
}
|
||||
}
|
||||
if (bdxtail == 0.0) {
|
||||
if (bdytail == 0.0) {
|
||||
bt_c[0] = 0.0;
|
||||
bt_clen = 1;
|
||||
bt_a[0] = 0.0;
|
||||
bt_alen = 1;
|
||||
} else {
|
||||
negate = -bdytail;
|
||||
TWP(negate, cdx, bt_clarge, bt_c[0]);
|
||||
bt_c[1] = bt_clarge;
|
||||
bt_clen = 2;
|
||||
TWP(bdytail, adx, bt_alarge, bt_a[0]);
|
||||
bt_a[1] = bt_alarge;
|
||||
bt_alen = 2;
|
||||
}
|
||||
} else {
|
||||
if (bdytail == 0.0) {
|
||||
TWP(bdxtail, cdy, bt_clarge, bt_c[0]);
|
||||
bt_c[1] = bt_clarge;
|
||||
bt_clen = 2;
|
||||
negate = -bdxtail;
|
||||
TWP(negate, ady, bt_alarge, bt_a[0]);
|
||||
bt_a[1] = bt_alarge;
|
||||
bt_alen = 2;
|
||||
} else {
|
||||
TWP(bdxtail, cdy, bdxt_cdy1, bdxt_cdy0);
|
||||
TWP(bdytail, cdx, bdyt_cdx1, bdyt_cdx0);
|
||||
TTD(bdxt_cdy1, bdxt_cdy0, bdyt_cdx1, bdyt_cdx0,
|
||||
bt_clarge, bt_c[2], bt_c[1], bt_c[0]);
|
||||
bt_c[3] = bt_clarge;
|
||||
bt_clen = 4;
|
||||
TWP(bdytail, adx, bdyt_adx1, bdyt_adx0);
|
||||
TWP(bdxtail, ady, bdxt_ady1, bdxt_ady0);
|
||||
TTD(bdyt_adx1, bdyt_adx0, bdxt_ady1, bdxt_ady0,
|
||||
bt_alarge, bt_a[2], bt_a[1], bt_a[0]);
|
||||
bt_a[3] = bt_alarge;
|
||||
bt_alen = 4;
|
||||
}
|
||||
}
|
||||
if (cdxtail == 0.0) {
|
||||
if (cdytail == 0.0) {
|
||||
ct_a[0] = 0.0;
|
||||
ct_alen = 1;
|
||||
ct_b[0] = 0.0;
|
||||
ct_blen = 1;
|
||||
} else {
|
||||
negate = -cdytail;
|
||||
TWP(negate, adx, ct_alarge, ct_a[0]);
|
||||
ct_a[1] = ct_alarge;
|
||||
ct_alen = 2;
|
||||
TWP(cdytail, bdx, ct_blarge, ct_b[0]);
|
||||
ct_b[1] = ct_blarge;
|
||||
ct_blen = 2;
|
||||
}
|
||||
} else {
|
||||
if (cdytail == 0.0) {
|
||||
TWP(cdxtail, ady, ct_alarge, ct_a[0]);
|
||||
ct_a[1] = ct_alarge;
|
||||
ct_alen = 2;
|
||||
negate = -cdxtail;
|
||||
TWP(negate, bdy, ct_blarge, ct_b[0]);
|
||||
ct_b[1] = ct_blarge;
|
||||
ct_blen = 2;
|
||||
} else {
|
||||
TWP(cdxtail, ady, cdxt_ady1, cdxt_ady0);
|
||||
TWP(cdytail, adx, cdyt_adx1, cdyt_adx0);
|
||||
TTD(cdxt_ady1, cdxt_ady0, cdyt_adx1, cdyt_adx0,
|
||||
ct_alarge, ct_a[2], ct_a[1], ct_a[0]);
|
||||
ct_a[3] = ct_alarge;
|
||||
ct_alen = 4;
|
||||
TWP(cdytail, bdx, cdyt_bdx1, cdyt_bdx0);
|
||||
TWP(cdxtail, bdy, cdxt_bdy1, cdxt_bdy0);
|
||||
TTD(cdyt_bdx1, cdyt_bdx0, cdxt_bdy1, cdxt_bdy0,
|
||||
ct_blarge, ct_b[2], ct_b[1], ct_b[0]);
|
||||
ct_b[3] = ct_blarge;
|
||||
ct_blen = 4;
|
||||
}
|
||||
}
|
||||
|
||||
bctlen = _fesze(bt_clen, bt_c, ct_blen, ct_b, bct);
|
||||
wlength = _seze(bctlen, bct, adz, w);
|
||||
finlength = _fesze(finlength, finnow, wlength, w,
|
||||
finother);
|
||||
finswap = finnow; finnow = finother; finother = finswap;
|
||||
|
||||
catlen = _fesze(ct_alen, ct_a, at_clen, at_c, cat);
|
||||
wlength = _seze(catlen, cat, bdz, w);
|
||||
finlength = _fesze(finlength, finnow, wlength, w,
|
||||
finother);
|
||||
finswap = finnow; finnow = finother; finother = finswap;
|
||||
|
||||
abtlen = _fesze(at_blen, at_b, bt_alen, bt_a, abt);
|
||||
wlength = _seze(abtlen, abt, cdz, w);
|
||||
finlength = _fesze(finlength, finnow, wlength, w,
|
||||
finother);
|
||||
finswap = finnow; finnow = finother; finother = finswap;
|
||||
|
||||
if (adztail != 0.0) {
|
||||
vlength = _seze(4, bc, adztail, v);
|
||||
finlength = _fesze(finlength, finnow, vlength, v,
|
||||
finother);
|
||||
finswap = finnow; finnow = finother; finother = finswap;
|
||||
}
|
||||
if (bdztail != 0.0) {
|
||||
vlength = _seze(4, ca, bdztail, v);
|
||||
finlength = _fesze(finlength, finnow, vlength, v,
|
||||
finother);
|
||||
finswap = finnow; finnow = finother; finother = finswap;
|
||||
}
|
||||
if (cdztail != 0.0) {
|
||||
vlength = _seze(4, ab, cdztail, v);
|
||||
finlength = _fesze(finlength, finnow, vlength, v,
|
||||
finother);
|
||||
finswap = finnow; finnow = finother; finother = finswap;
|
||||
}
|
||||
|
||||
if (adxtail != 0.0) {
|
||||
if (bdytail != 0.0) {
|
||||
TWP(adxtail, bdytail, adxt_bdyt1, adxt_bdyt0);
|
||||
TOP(adxt_bdyt1, adxt_bdyt0, cdz, u3, u[2], u[1], u[0]);
|
||||
u[3] = u3;
|
||||
finlength = _fesze(finlength, finnow, 4, u,
|
||||
finother);
|
||||
finswap = finnow; finnow = finother; finother = finswap;
|
||||
if (cdztail != 0.0) {
|
||||
TOP(adxt_bdyt1, adxt_bdyt0, cdztail, u3, u[2], u[1], u[0]);
|
||||
u[3] = u3;
|
||||
finlength = _fesze(finlength, finnow, 4, u,
|
||||
finother);
|
||||
finswap = finnow; finnow = finother; finother = finswap;
|
||||
}
|
||||
}
|
||||
if (cdytail != 0.0) {
|
||||
negate = -adxtail;
|
||||
TWP(negate, cdytail, adxt_cdyt1, adxt_cdyt0);
|
||||
TOP(adxt_cdyt1, adxt_cdyt0, bdz, u3, u[2], u[1], u[0]);
|
||||
u[3] = u3;
|
||||
finlength = _fesze(finlength, finnow, 4, u,
|
||||
finother);
|
||||
finswap = finnow; finnow = finother; finother = finswap;
|
||||
if (bdztail != 0.0) {
|
||||
TOP(adxt_cdyt1, adxt_cdyt0, bdztail, u3, u[2], u[1], u[0]);
|
||||
u[3] = u3;
|
||||
finlength = _fesze(finlength, finnow, 4, u,
|
||||
finother);
|
||||
finswap = finnow; finnow = finother; finother = finswap;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bdxtail != 0.0) {
|
||||
if (cdytail != 0.0) {
|
||||
TWP(bdxtail, cdytail, bdxt_cdyt1, bdxt_cdyt0);
|
||||
TOP(bdxt_cdyt1, bdxt_cdyt0, adz, u3, u[2], u[1], u[0]);
|
||||
u[3] = u3;
|
||||
finlength = _fesze(finlength, finnow, 4, u,
|
||||
finother);
|
||||
finswap = finnow; finnow = finother; finother = finswap;
|
||||
if (adztail != 0.0) {
|
||||
TOP(bdxt_cdyt1, bdxt_cdyt0, adztail, u3, u[2], u[1], u[0]);
|
||||
u[3] = u3;
|
||||
finlength = _fesze(finlength, finnow, 4, u,
|
||||
finother);
|
||||
finswap = finnow; finnow = finother; finother = finswap;
|
||||
}
|
||||
}
|
||||
if (adytail != 0.0) {
|
||||
negate = -bdxtail;
|
||||
TWP(negate, adytail, bdxt_adyt1, bdxt_adyt0);
|
||||
TOP(bdxt_adyt1, bdxt_adyt0, cdz, u3, u[2], u[1], u[0]);
|
||||
u[3] = u3;
|
||||
finlength = _fesze(finlength, finnow, 4, u,
|
||||
finother);
|
||||
finswap = finnow; finnow = finother; finother = finswap;
|
||||
if (cdztail != 0.0) {
|
||||
TOP(bdxt_adyt1, bdxt_adyt0, cdztail, u3, u[2], u[1], u[0]);
|
||||
u[3] = u3;
|
||||
finlength = _fesze(finlength, finnow, 4, u,
|
||||
finother);
|
||||
finswap = finnow; finnow = finother; finother = finswap;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cdxtail != 0.0) {
|
||||
if (adytail != 0.0) {
|
||||
TWP(cdxtail, adytail, cdxt_adyt1, cdxt_adyt0);
|
||||
TOP(cdxt_adyt1, cdxt_adyt0, bdz, u3, u[2], u[1], u[0]);
|
||||
u[3] = u3;
|
||||
finlength = _fesze(finlength, finnow, 4, u,
|
||||
finother);
|
||||
finswap = finnow; finnow = finother; finother = finswap;
|
||||
if (bdztail != 0.0) {
|
||||
TOP(cdxt_adyt1, cdxt_adyt0, bdztail, u3, u[2], u[1], u[0]);
|
||||
u[3] = u3;
|
||||
finlength = _fesze(finlength, finnow, 4, u,
|
||||
finother);
|
||||
finswap = finnow; finnow = finother; finother = finswap;
|
||||
}
|
||||
}
|
||||
if (bdytail != 0.0) {
|
||||
negate = -cdxtail;
|
||||
TWP(negate, bdytail, cdxt_bdyt1, cdxt_bdyt0);
|
||||
TOP(cdxt_bdyt1, cdxt_bdyt0, adz, u3, u[2], u[1], u[0]);
|
||||
u[3] = u3;
|
||||
finlength = _fesze(finlength, finnow, 4, u,
|
||||
finother);
|
||||
finswap = finnow; finnow = finother; finother = finswap;
|
||||
if (adztail != 0.0) {
|
||||
TOP(cdxt_bdyt1, cdxt_bdyt0, adztail, u3, u[2], u[1], u[0]);
|
||||
u[3] = u3;
|
||||
finlength = _fesze(finlength, finnow, 4, u,
|
||||
finother);
|
||||
finswap = finnow; finnow = finother; finother = finswap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (adztail != 0.0) {
|
||||
wlength = _seze(bctlen, bct, adztail, w);
|
||||
finlength = _fesze(finlength, finnow, wlength, w,
|
||||
finother);
|
||||
finswap = finnow; finnow = finother; finother = finswap;
|
||||
}
|
||||
if (bdztail != 0.0) {
|
||||
wlength = _seze(catlen, cat, bdztail, w);
|
||||
finlength = _fesze(finlength, finnow, wlength, w,
|
||||
finother);
|
||||
finswap = finnow; finnow = finother; finother = finswap;
|
||||
}
|
||||
if (cdztail != 0.0) {
|
||||
wlength = _seze(abtlen, abt, cdztail, w);
|
||||
finlength = _fesze(finlength, finnow, wlength, w,
|
||||
finother);
|
||||
finswap = finnow; finnow = finother; finother = finswap;
|
||||
}
|
||||
|
||||
return finnow[finlength - 1];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* PUBLIC FUNCTIONS */
|
||||
/* initPredicates() Sets the variables used for exact arithmetic. This */
|
||||
/* must be called once before using the other two functions. */
|
||||
/* orient2d() Computes the orientation of three 2D points. */
|
||||
/* orient3d() Computes the orientation of four 3D points. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
void initPredicates()
|
||||
{
|
||||
static char a_c=0;
|
||||
double hf, ck, lc;
|
||||
int e_o;
|
||||
|
||||
if (a_c) return; else a_c = 1;
|
||||
|
||||
#ifdef SPECIFY_FP_PRECISION
|
||||
unsigned int old_cfp;
|
||||
_controlfp_s(&old_cfp, _PC_53, MCW_PC);
|
||||
#endif
|
||||
|
||||
e_o = 1;
|
||||
_eps = _spl = ck = 1.0;
|
||||
hf = 0.5;
|
||||
|
||||
do
|
||||
{
|
||||
lc=ck;
|
||||
_eps *= hf;
|
||||
if (e_o) _spl *= 2.0;
|
||||
e_o = !e_o;
|
||||
ck = 1.0 + _eps;
|
||||
} while ((ck != 1.0) && (ck != lc));
|
||||
_spl += 1.0;
|
||||
|
||||
_reb = (3.0 + 8.0 * _eps) * _eps;
|
||||
_ccwebA = (3.0 + 16.0 * _eps) * _eps;
|
||||
_ccwebB = (2.0 + 12.0 * _eps) * _eps;
|
||||
_ccwebC = (9.0 + 64.0 * _eps) * _eps * _eps;
|
||||
_o3ebA = (7.0 + 56.0 * _eps) * _eps;
|
||||
_o3ebB = (3.0 + 28.0 * _eps) * _eps;
|
||||
_o3ebC = (26.0 + 288.0 * _eps) * _eps * _eps;
|
||||
_iccebA = (10.0 + 96.0 * _eps) * _eps;
|
||||
_iccebB = (4.0 + 48.0 * _eps) * _eps;
|
||||
_iccebC = (44.0 + 576.0 * _eps) * _eps * _eps;
|
||||
_ispebA = (16.0 + 224.0 * _eps) * _eps;
|
||||
_ispebB = (5.0 + 72.0 * _eps) * _eps;
|
||||
_ispebC = (71.0 + 1408.0 * _eps) * _eps * _eps;
|
||||
|
||||
#ifdef SPECIFY_FP_PRECISION
|
||||
_controlfp_s(&old_cfp, _CW_DEFAULT, MCW_PC);
|
||||
#endif
|
||||
}
|
||||
|
||||
double orient2d(double *pa, double *pb, double *pc)
|
||||
{
|
||||
double dlf, drg, det, dsm, eb;
|
||||
|
||||
dlf = (pa[0]-pc[0])*(pb[1]-pc[1]);
|
||||
drg = (pa[1]-pc[1])*(pb[0]-pc[0]);
|
||||
det = dlf - drg;
|
||||
|
||||
if (dlf > 0.0) {if (drg <= 0.0) return det; else dsm = dlf + drg;}
|
||||
else if (dlf < 0.0) {if (drg >= 0.0) return det; else dsm = -dlf - drg;}
|
||||
else return det;
|
||||
|
||||
eb = _ccwebA*dsm;
|
||||
if ((det>=eb) || (-det>=eb)) return det;
|
||||
|
||||
return _adaptive2dorientation(pa, pb, pc, dsm);
|
||||
}
|
||||
|
||||
double orient3d(double *pa, double *pb, double *pc, double *pd)
|
||||
{
|
||||
double adx, bdx, cdx, ady, bdy, cdy, adz, bdz, cdz, pm, eb;
|
||||
double bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady, det;
|
||||
|
||||
adx = pa[0]-pd[0]; bdx = pb[0]-pd[0]; cdx = pc[0]-pd[0];
|
||||
ady = pa[1]-pd[1]; bdy = pb[1]-pd[1]; cdy = pc[1]-pd[1];
|
||||
adz = pa[2]-pd[2]; bdz = pb[2]-pd[2]; cdz = pc[2]-pd[2];
|
||||
|
||||
bdxcdy = bdx*cdy; cdxbdy = cdx*bdy;
|
||||
cdxady = cdx*ady; adxcdy = adx*cdy;
|
||||
adxbdy = adx*bdy; bdxady = bdx*ady;
|
||||
|
||||
det = adz*(bdxcdy-cdxbdy)+bdz*(cdxady-adxcdy)+cdz*(adxbdy-bdxady);
|
||||
pm=(FABS(bdxcdy)+FABS(cdxbdy))*FABS(adz)+(FABS(cdxady)+FABS(adxcdy))*FABS(bdz)+(FABS(adxbdy)+FABS(bdxady))*FABS(cdz);
|
||||
eb = _o3ebA*pm;
|
||||
if ((det>eb) || (-det>eb)) return det;
|
||||
return _adaptive3dorientation(pa, pb, pc, pd, pm);
|
||||
}
|
653
src/mesh_fix/src/Kernel/point.cpp
Normal file
653
src/mesh_fix/src/Kernel/point.cpp
Normal file
@ -0,0 +1,653 @@
|
||||
/****************************************************************************
|
||||
* TMesh *
|
||||
* *
|
||||
* Consiglio Nazionale delle Ricerche *
|
||||
* Istituto di Matematica Applicata e Tecnologie Informatiche *
|
||||
* Sezione di Genova *
|
||||
* IMATI-GE / CNR *
|
||||
* *
|
||||
* Authors: Marco Attene *
|
||||
* Copyright(C) 2012: IMATI-GE / CNR *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is dual-licensed as follows: *
|
||||
* *
|
||||
* (1) You may use TMesh as 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. *
|
||||
* In this case the 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 (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
* (2) You may use TMesh as part of a commercial software. In this case a *
|
||||
* proper agreement must be reached with the Authors and with IMATI-GE/CNR *
|
||||
* based on a proper licensing contract. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#include "point.h"
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
|
||||
namespace T_MESH
|
||||
{
|
||||
|
||||
const Point INFINITE_POINT(DBL_MAX, DBL_MAX, DBL_MAX);
|
||||
|
||||
#ifdef USE_HYBRID_KERNEL
|
||||
|
||||
PM_Rational orient2D(const PM_Rational& px, const PM_Rational& py, const PM_Rational& qx, const PM_Rational& qy, const PM_Rational& rx, const PM_Rational& ry)
|
||||
{
|
||||
if (!PM_Rational::isUsingFiltering() && !PM_Rational::isUsingRationals())
|
||||
{
|
||||
return ((px - rx)*(qy - ry) - (py - ry)*(qx - rx));
|
||||
}
|
||||
else if (px.isOfDoubleType() && py.isOfDoubleType() && qx.isOfDoubleType() && qy.isOfDoubleType() && rx.isOfDoubleType() && ry.isOfDoubleType())
|
||||
{
|
||||
double pqr[6];
|
||||
pqr[0] = px.getDVal(); pqr[1] = py.getDVal();
|
||||
pqr[2] = qx.getDVal(); pqr[3] = qy.getDVal();
|
||||
pqr[4] = rx.getDVal(); pqr[5] = ry.getDVal();
|
||||
return orient2d(pqr, pqr + 2, pqr + 4);
|
||||
}
|
||||
else if (PM_Rational::isUsingRationals())
|
||||
{
|
||||
return ((px - rx)*(qy - ry) - (py - ry)*(qx - rx));
|
||||
}
|
||||
else
|
||||
{
|
||||
PM_Rational::use_rationals = true;
|
||||
PM_Rational O = ((px - rx)*(qy - ry) - (py - ry)*(qx - rx));
|
||||
PM_Rational::use_rationals = false;
|
||||
return O;
|
||||
}
|
||||
}
|
||||
|
||||
PM_Rational orient3D(const Point *t, const Point *a, const Point *b, const Point *c)
|
||||
{
|
||||
if (!PM_Rational::isUsingFiltering() && !PM_Rational::isUsingRationals())
|
||||
{
|
||||
return TMESH_DETERMINANT3X3(t->x - c->x, t->y - c->y, t->z - c->z, a->x - c->x, a->y - c->y, a->z - c->z, b->x - c->x, b->y - c->y, b->z - c->z);
|
||||
} else if (a->x.isOfDoubleType() && a->y.isOfDoubleType() && a->z.isOfDoubleType() &&
|
||||
t->x.isOfDoubleType() && t->y.isOfDoubleType() && t->z.isOfDoubleType() &&
|
||||
b->x.isOfDoubleType() && b->y.isOfDoubleType() && b->z.isOfDoubleType() &&
|
||||
c->x.isOfDoubleType() && c->y.isOfDoubleType() && c->z.isOfDoubleType())
|
||||
{
|
||||
double p1[3], p2[3], p3[3], p4[3];
|
||||
p1[0] = (t->x).getDVal(); p1[1] = (t->y).getDVal(); p1[2] = (t->z).getDVal();
|
||||
p2[0] = (a->x).getDVal(); p2[1] = (a->y).getDVal(); p2[2] = (a->z).getDVal();
|
||||
p3[0] = (b->x).getDVal(); p3[1] = (b->y).getDVal(); p3[2] = (b->z).getDVal();
|
||||
p4[0] = (c->x).getDVal(); p4[1] = (c->y).getDVal(); p4[2] = (c->z).getDVal();
|
||||
return orient3d(p1, p2, p3, p4);
|
||||
} else if (PM_Rational::isUsingRationals())
|
||||
{
|
||||
return TMESH_DETERMINANT3X3(t->x - c->x, t->y - c->y, t->z - c->z, a->x - c->x, a->y - c->y, a->z - c->z, b->x - c->x, b->y - c->y, b->z - c->z);
|
||||
} else
|
||||
{
|
||||
PM_Rational::use_rationals = true;
|
||||
PM_Rational O = TMESH_DETERMINANT3X3(t->x - c->x, t->y - c->y, t->z - c->z, a->x - c->x, a->y - c->y, a->z - c->z, b->x - c->x, b->y - c->y, b->z - c->z);
|
||||
PM_Rational::use_rationals = false;
|
||||
return O;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
PM_Rational orient2D(const PM_Rational& px, const PM_Rational& py, const PM_Rational& qx, const PM_Rational& qy, const PM_Rational& rx, const PM_Rational& ry)
|
||||
{
|
||||
// return ((px - rx)*(qy - ry) - (py - ry)*(qx - rx));
|
||||
|
||||
double pqr[6];
|
||||
pqr[0] = TMESH_TO_DOUBLE(px); pqr[1] = TMESH_TO_DOUBLE(py);
|
||||
pqr[2] = TMESH_TO_DOUBLE(qx); pqr[3] = TMESH_TO_DOUBLE(qy);
|
||||
pqr[4] = TMESH_TO_DOUBLE(rx); pqr[5] = TMESH_TO_DOUBLE(ry);
|
||||
return orient2d(pqr, pqr + 2, pqr + 4);
|
||||
}
|
||||
|
||||
PM_Rational orient3D(const Point *t, const Point *a, const Point *b, const Point *c)
|
||||
{
|
||||
// return TMESH_DETERMINANT3X3(t->x - c->x, t->y - c->y, t->z - c->z, a->x - c->x, a->y - c->y, a->z - c->z, b->x - c->x, b->y - c->y, b->z - c->z);
|
||||
|
||||
double p1[3], p2[3], p3[3], p4[3];
|
||||
p1[0] = TMESH_TO_DOUBLE(t->x); p1[1] = TMESH_TO_DOUBLE(t->y); p1[2] = TMESH_TO_DOUBLE(t->z);
|
||||
p2[0] = TMESH_TO_DOUBLE(a->x); p2[1] = TMESH_TO_DOUBLE(a->y); p2[2] = TMESH_TO_DOUBLE(a->z);
|
||||
p3[0] = TMESH_TO_DOUBLE(b->x); p3[1] = TMESH_TO_DOUBLE(b->y); p3[2] = TMESH_TO_DOUBLE(b->z);
|
||||
p4[0] = TMESH_TO_DOUBLE(c->x); p4[1] = TMESH_TO_DOUBLE(c->y); p4[2] = TMESH_TO_DOUBLE(c->z);
|
||||
return orient3d(p1, p2, p3, p4);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
coord Point::exactOrientation(const Point *a, const Point *b, const Point *c) const
|
||||
{
|
||||
return orient3D(this, a, b, c);
|
||||
}
|
||||
|
||||
|
||||
////////////// Alignment check /////////////
|
||||
|
||||
bool Point::exactMisalignment(const Point *A, const Point *B) const
|
||||
{
|
||||
if (orient2D(x, y, A->x, A->y, B->x, B->y) != 0) return true;
|
||||
if (orient2D(y, z, A->y, A->z, B->y, B->z) != 0) return true;
|
||||
if (orient2D(z, x, A->z, A->x, B->z, B->x) != 0) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Point::exactSameSideOnPlane(const Point *Q, const Point *A, const Point *B) const
|
||||
{
|
||||
coord o1, o2;
|
||||
int s1, s2;
|
||||
|
||||
o1 = orient2D(x, y, A->x, A->y, B->x, B->y);
|
||||
o2 = orient2D(Q->x, Q->y, A->x, A->y, B->x, B->y);
|
||||
s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0));
|
||||
if (s1 != s2) return false;
|
||||
|
||||
o1 = orient2D(y, z, A->y, A->z, B->y, B->z);
|
||||
o2 = orient2D(Q->y, Q->z, A->y, A->z, B->y, B->z);
|
||||
s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0));
|
||||
if (s1 != s2) return false;
|
||||
|
||||
o1 = orient2D(z, x, A->z, A->x, B->z, B->x);
|
||||
o2 = orient2D(Q->z, Q->x, A->z, A->x, B->z, B->x);
|
||||
s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0));
|
||||
if (s1 != s2) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns true if the coplanar point 'p' is in the inner area of 't'.
|
||||
// Undetermined if p and t are not coplanar.
|
||||
bool Point::pointInInnerTriangle(const Point *p, const Point *v1, const Point *v2, const Point *v3)
|
||||
{
|
||||
//if (!p->exactSameSideOnPlane(v1, v2, v3)) return false;
|
||||
//if (!p->exactSameSideOnPlane(v2, v3, v1)) return false;
|
||||
//if (!p->exactSameSideOnPlane(v3, v1, v2)) return false;
|
||||
//return true;
|
||||
|
||||
// Less readable, but slightly more efficient (12 predicates instead of 18)
|
||||
|
||||
coord o1, o2, oo2, oo4, oo6;
|
||||
int s1, s2;
|
||||
|
||||
o1 = orient2D(p->x, p->y, v2->x, v2->y, v3->x, v3->y);
|
||||
o2 = oo2 = orient2D(v1->x, v1->y, v2->x, v2->y, v3->x, v3->y);
|
||||
s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0));
|
||||
if (s1 != s2) return false;
|
||||
|
||||
o1 = orient2D(p->y, p->z, v2->y, v2->z, v3->y, v3->z);
|
||||
o2 = oo4 = orient2D(v1->y, v1->z, v2->y, v2->z, v3->y, v3->z);
|
||||
s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0));
|
||||
if (s1 != s2) return false;
|
||||
|
||||
o1 = orient2D(p->z, p->x, v2->z, v2->x, v3->z, v3->x);
|
||||
o2 = oo6 = orient2D(v1->z, v1->x, v2->z, v2->x, v3->z, v3->x);
|
||||
s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0));
|
||||
if (s1 != s2) return false;
|
||||
|
||||
o1 = orient2D(p->x, p->y, v3->x, v3->y, v1->x, v1->y);
|
||||
o2 = oo2,
|
||||
s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0));
|
||||
if (s1 != s2) return false;
|
||||
|
||||
o1 = orient2D(p->y, p->z, v3->y, v3->z, v1->y, v1->z);
|
||||
o2 = oo4;
|
||||
s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0));
|
||||
if (s1 != s2) return false;
|
||||
|
||||
o1 = orient2D(p->z, p->x, v3->z, v3->x, v1->z, v1->x);
|
||||
o2 = oo6;
|
||||
s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0));
|
||||
if (s1 != s2) return false;
|
||||
|
||||
o1 = orient2D(p->x, p->y, v1->x, v1->y, v2->x, v2->y);
|
||||
o2 = oo2;
|
||||
s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0));
|
||||
if (s1 != s2) return false;
|
||||
|
||||
o1 = orient2D(p->y, p->z, v1->y, v1->z, v2->y, v2->z);
|
||||
o2 = oo4;
|
||||
s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0));
|
||||
if (s1 != s2) return false;
|
||||
|
||||
o1 = orient2D(p->z, p->x, v1->z, v1->x, v2->z, v2->x);
|
||||
o2 = oo6;
|
||||
s1 = (o1>0) ? (1) : ((o1<0) ? (-1) : (0)); s2 = (o2>0) ? (1) : ((o2<0) ? (-1) : (0));
|
||||
if (s1 != s2) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//////// Lexicographic Point comparison //////////
|
||||
|
||||
// This can be used with std::sort()
|
||||
bool Point::operator<(const Point& s) const
|
||||
{
|
||||
if (x<s.x) return true; else if (x>s.x) return false;
|
||||
if (y<s.y) return true; else if (y>s.y) return false;
|
||||
if (z<s.z) return true; else return false;
|
||||
}
|
||||
|
||||
// This can be used with jqsort
|
||||
int xyzCompare(const Data *a, const Data *b)
|
||||
{
|
||||
coord c;
|
||||
|
||||
if ((c=(((Point *)a)->x - ((Point *)b)->x)) < 0) return -1;
|
||||
if (c > 0) return 1;
|
||||
if ((c=(((Point *)a)->y - ((Point *)b)->y)) < 0) return -1;
|
||||
if (c > 0) return 1;
|
||||
if ((c=(((Point *)a)->z - ((Point *)b)->z)) < 0) return -1;
|
||||
if (c > 0) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//////////////// Normalization /////////////////////////
|
||||
|
||||
void Point::normalize()
|
||||
{
|
||||
coord l = length();
|
||||
|
||||
if (l == 0) TMesh::error("normalize : Trying to normalize a null vector !\n");
|
||||
|
||||
x/=l;
|
||||
y/=l;
|
||||
z/=l;
|
||||
}
|
||||
|
||||
|
||||
//////////////////// Point rotation ////////////////////
|
||||
/////////// 'ang' radians CCW around 'axis' ////////////
|
||||
|
||||
void Point::rotate(const Point& a, const double& ang)
|
||||
{
|
||||
double l, q[4], m[3][3];
|
||||
if ((l = a.length())==0.0) return;
|
||||
l = sin(ang/2.0)/l;
|
||||
|
||||
q[0] = TMESH_TO_DOUBLE(a.x)*l;
|
||||
q[1] = TMESH_TO_DOUBLE(a.y)*l;
|
||||
q[2] = TMESH_TO_DOUBLE(a.z)*l;
|
||||
q[3] = cos(ang/2.0);
|
||||
|
||||
m[0][0] = 1.0 - (q[1]*q[1] + q[2]*q[2])*2.0;
|
||||
m[0][1] = (q[0] * q[1] + q[2] * q[3])*2.0;
|
||||
m[0][2] = (q[2] * q[0] - q[1] * q[3])*2.0;
|
||||
|
||||
m[1][0] = (q[0] * q[1] - q[2] * q[3])*2.0;
|
||||
m[1][1] = 1.0 - (q[2] * q[2] + q[0] * q[0])*2.0;
|
||||
m[1][2] = (q[1] * q[2] + q[0] * q[3])*2.0;
|
||||
|
||||
m[2][0] = (q[2] * q[0] + q[1] * q[3])*2.0;
|
||||
m[2][1] = (q[1] * q[2] - q[0] * q[3])*2.0;
|
||||
m[2][2] = 1.0 - (q[1] * q[1] + q[0] * q[0])*2.0;
|
||||
|
||||
q[0] = TMESH_TO_DOUBLE(x); q[1] = TMESH_TO_DOUBLE(y); q[2] = TMESH_TO_DOUBLE(z);
|
||||
x = m[0][0]*q[0] + m[1][0]*q[1] + m[2][0]*q[2];
|
||||
y = m[0][1]*q[0] + m[1][1]*q[1] + m[2][1]*q[2];
|
||||
z = m[0][2]*q[0] + m[1][2]*q[1] + m[2][2]*q[2];
|
||||
}
|
||||
|
||||
|
||||
///// Project the point on the plane whose normal is 'nor' /////
|
||||
|
||||
void Point::project(const Point *nor)
|
||||
{
|
||||
Point pr = (*this)-((*nor)*((*this)*(*nor)));
|
||||
x = pr.x; y = pr.y; z = pr.z;
|
||||
}
|
||||
|
||||
|
||||
/////////// Distance from the line passing through A and B ////////
|
||||
|
||||
double Point::distanceFromLine(const Point *A, const Point *B) const
|
||||
{
|
||||
Point BA = (*B)-(*A);
|
||||
double lba = BA.length();
|
||||
|
||||
if (lba == 0.0) TMesh::error("distanceFromLine : Degenerate line passed !\n");
|
||||
|
||||
return ((((*this)-(*A))&BA).length())/(lba);
|
||||
}
|
||||
|
||||
|
||||
/////////////////// Distance from a line ///////////////////////
|
||||
//// 'cc' is initialized as the point of the line whose ////
|
||||
//// distance from 'this' is minimum. ////
|
||||
|
||||
double Point::distanceFromLine(const Point *A, const Point *B, Point *cc) const
|
||||
{
|
||||
Point AB = (*A)-(*B);
|
||||
Point AP = (*A)-(*this);
|
||||
Point BP = (*B)-(*this);
|
||||
|
||||
if (AP.isNull())
|
||||
{
|
||||
cc->x = A->x; cc->y = A->y; cc->z = A->z;
|
||||
return 0.0;
|
||||
}
|
||||
else if (BP.isNull())
|
||||
{
|
||||
cc->x = B->x; cc->y = B->y; cc->z = B->z;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
coord t = (AB*AB);
|
||||
if (t == 0.0) TMesh::error("distanceFromLine : Degenerate line passed !\n");
|
||||
else t = (AP*AB)/(-t);
|
||||
cc->x = t*AB.x + A->x;
|
||||
cc->y = t*AB.y + A->y;
|
||||
cc->z = t*AB.z + A->z;
|
||||
return distanceFromLine(A,B);
|
||||
}
|
||||
|
||||
|
||||
////////////// Projection on the line passing through A and B ///////////
|
||||
|
||||
Point Point::projection(const Point *A, const Point *B) const
|
||||
{
|
||||
Point BA = (*B)-(*A);
|
||||
coord l = BA*BA;
|
||||
if (l == 0.0) TMesh::error("projection : Degenerate line passed !\n");
|
||||
|
||||
return ((*A)+(BA*((BA*((*this)-(*A)))/(l))));
|
||||
}
|
||||
|
||||
|
||||
////////////// Distance from a segment /////////////////
|
||||
|
||||
double Point::distanceFromEdge(const Point *A, const Point *B) const
|
||||
{
|
||||
Point AP = (*A)-(*this); double apl = AP.length();
|
||||
Point BP = (*B) - (*this); double bpl = BP.length();
|
||||
|
||||
if (apl == 0 || bpl == 0.0) return 0.0;
|
||||
|
||||
Point AB = (*A) - (*B); double abl = AP.length();
|
||||
Point BA = (*B)-(*A);
|
||||
|
||||
if (abl*apl == 0.0 || abl*bpl == 0.0) return apl;
|
||||
|
||||
if (AB.getAngle(AP) > PI2) return apl;
|
||||
else if (BA.getAngle(BP) > PI2) return bpl;
|
||||
|
||||
return distanceFromLine(A,B);
|
||||
}
|
||||
|
||||
/////////////////// Distance from a segment ///////////////////////
|
||||
//// 'cc' is initialized as the point of the segment whose ////
|
||||
//// distance from 'this' is minimum. ////
|
||||
|
||||
double Point::distanceFromEdge(const Point *A, const Point *B, Point *cc) const
|
||||
{
|
||||
Point AP = (*A)-(*this); double apl = AP.length();
|
||||
Point BP = (*B) - (*this); double bpl = BP.length();
|
||||
|
||||
if (apl == 0) {cc->setValue(A); return 0.0;}
|
||||
if (bpl == 0) {cc->setValue(B); return 0.0;}
|
||||
|
||||
Point AB = (*A)-(*B); coord abl = AP.length();
|
||||
Point BA = (*B)-(*A);
|
||||
|
||||
if (abl*apl == 0.0 || abl*bpl == 0.0) {cc->setValue(A); return apl;}
|
||||
|
||||
if (AB.getAngle(AP) > PI2) {cc->setValue(A); return apl;}
|
||||
else if (BA.getAngle(BP) > PI2) {cc->setValue(B); return bpl;}
|
||||
|
||||
coord t = (AB*AB);
|
||||
if (t == 0.0) {cc->setValue(A); return apl;}
|
||||
else t = (AP*AB)/(-t);
|
||||
cc->x = t*AB.x + A->x;
|
||||
cc->y = t*AB.y + A->y;
|
||||
cc->z = t*AB.z + A->z;
|
||||
return distanceFromLine(A,B);
|
||||
}
|
||||
|
||||
///////////////// Angle between two vectors ///////////////
|
||||
|
||||
double Point::getAngle(const Point& p) const
|
||||
{
|
||||
return atan2(((*this)&p).length(), TMESH_TO_DOUBLE(((*this)*p)));
|
||||
}
|
||||
|
||||
|
||||
/////////// Distance of two straight lines ///////////////
|
||||
|
||||
double Point::distanceLineLine(const Point *A, const Point *A1, const Point *B1) const
|
||||
{
|
||||
Point uu1 = ((*this)-(*A))&((*A1)-(*B1));
|
||||
coord nom = ((*A)-(*A1))*(uu1);
|
||||
return FABS(TMESH_TO_DOUBLE(nom)) / (uu1.length());
|
||||
}
|
||||
|
||||
|
||||
/////////// Solution of a linear system 3 x 3 //////////
|
||||
///// System Ax = d, where A = (a,b,c) rows, d = this /////
|
||||
|
||||
Point Point::linearSystem(const Point& a, const Point& b, const Point& c)
|
||||
{
|
||||
Point ret;
|
||||
coord det_A = TMESH_DETERMINANT3X3(a.x, a.y, a.z, b.x, b.y, b.z, c.x, c.y, c.z);
|
||||
if (det_A == 0.0) return INFINITE_POINT;
|
||||
ret.x = TMESH_DETERMINANT3X3(x, a.y, a.z, y, b.y, b.z, z, c.y, c.z);
|
||||
ret.y = TMESH_DETERMINANT3X3(a.x, x, a.z, b.x, y, b.z, c.x, z, c.z);
|
||||
ret.z = TMESH_DETERMINANT3X3(a.x, a.y, x, b.x, b.y, y, c.x, c.y, z);
|
||||
|
||||
return (ret/det_A);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//// Computes the closest points of the two lines 'this'-v1 and p1-p2 ////
|
||||
//// Returns FALSE if the lines are parallel. ////
|
||||
|
||||
int Point::closestPoints(const Point *v1, const Point *p1, const Point *p2, Point *ptOnThis, Point *ptOnLine2) const
|
||||
{
|
||||
Point pos1 = *this; Point dir1 = (*v1)-pos1;
|
||||
Point pos2 = *p1; Point dir2 = (*p2)-pos2;
|
||||
coord d1l = dir1.length(), d2l = dir2.length();
|
||||
|
||||
if (d1l == 0.0 && d2l == 0.0)
|
||||
{ptOnThis->setValue(this); ptOnLine2->setValue(p1); return 1;}
|
||||
if (d1l*d2l == 0.0)
|
||||
{
|
||||
if (d1l <= d2l)
|
||||
{ptOnThis->setValue(this); distanceFromLine(p1, p2, ptOnLine2); return 1;}
|
||||
if (d2l <= d1l)
|
||||
{ptOnLine2->setValue(p1); p1->distanceFromLine(this, v1, ptOnThis); return 1;}
|
||||
}
|
||||
|
||||
coord ang = dir1.getAngle(dir2);
|
||||
if (ang == 0.0 || ang == M_PI) return 0;
|
||||
|
||||
coord s, t, A, B, C, D, E, F, denom;
|
||||
|
||||
denom = ((dir1*dir2)/(d1l*d2l));
|
||||
denom = denom*denom - 1;
|
||||
|
||||
dir1.normalize();
|
||||
dir2.normalize();
|
||||
|
||||
A = E = dir1*dir2;
|
||||
B = dir1*dir1;
|
||||
C = (dir1*pos1) - (dir1*pos2);
|
||||
D = dir2*dir2;
|
||||
F = (dir2*pos1) - (dir2*pos2);
|
||||
|
||||
s = ( C * D - A * F ) / denom;
|
||||
t = ( C * E - B * F ) / denom;
|
||||
*ptOnThis = pos1 + (dir1*s);
|
||||
*ptOnLine2 = pos2 + (dir2*t);
|
||||
|
||||
// Uncomment the following to compute the distance between segments
|
||||
// if (s < 0 || s > ((*v1)-(*this)).length() || t < 0 || t > ((*p2)-(*p1)).length())
|
||||
// return 0; // The points does not belong to the edges
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Returns the point of intersection between the two lines defined by (p,q) and (r,s) respectively
|
||||
// Return INFINITE_POINT is lines are parallel or if p==q or r==s
|
||||
Point Point::lineLineIntersection(const Point& p, const Point& q, const Point& r, const Point& s)
|
||||
{
|
||||
Point da = q - p;
|
||||
Point db = s - r;
|
||||
Point dc = r - p;
|
||||
Point dab = (da&db);
|
||||
|
||||
if (dc*dab != 0.0) return INFINITE_POINT;
|
||||
|
||||
coord k = (((dc&db)*dab) / (dab*dab));
|
||||
return p + (da*k);
|
||||
}
|
||||
|
||||
// Returns the point of intersection between the line for (p,q) and the plane for (r,s,t)
|
||||
// Returns INFINITE_POINT in case of parallelism
|
||||
Point Point::linePlaneIntersection(const Point& p, const Point& q, const Point& r, const Point& s, const Point& t)
|
||||
{
|
||||
coord den = TMESH_DETERMINANT3X3(p.x - q.x, p.y - q.y, p.z - q.z, s.x - r.x, s.y - r.y, s.z - r.z, t.x - r.x, t.y - r.y, t.z - r.z);
|
||||
if (den == 0) return INFINITE_POINT;
|
||||
coord num = TMESH_DETERMINANT3X3(p.x - r.x, p.y - r.y, p.z - r.z, s.x - r.x, s.y - r.y, s.z - r.z, t.x - r.x, t.y - r.y, t.z - r.z);
|
||||
coord gamma = num / den;
|
||||
return p + ((q - p)*gamma);
|
||||
}
|
||||
|
||||
coord Point::squaredTriangleArea3D(const Point& p, const Point& q, const Point& r)
|
||||
{
|
||||
Point pr = (p - r), qr = (q - r);
|
||||
Point n = pr&qr;
|
||||
return (n*n) / 4;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Basic predicates of type 'pointIn'
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
// Returns true if 'p' is a point of the segment v1-v2 (endpoints excluded)
|
||||
bool Point::pointInInnerSegment(const Point *p, const Point *v1, const Point *v2)
|
||||
{
|
||||
if (!p->exactMisalignment(v1, v2)) // Segment and point aligned
|
||||
{
|
||||
if (v1->x < v2->x && v1->x < p->x && p->x < v2->x) return true;
|
||||
if (v1->y < v2->y && v1->y < p->y && p->y < v2->y) return true;
|
||||
if (v1->z < v2->z && v1->z < p->z && p->z < v2->z) return true;
|
||||
if (v1->x > v2->x && v1->x > p->x && p->x > v2->x) return true;
|
||||
if (v1->y > v2->y && v1->y > p->y && p->y > v2->y) return true;
|
||||
if (v1->z > v2->z && v1->z > p->z && p->z > v2->z) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns true if 'p' is a point of the segment v1-v2 (endpoints included)
|
||||
bool Point::pointInSegment(const Point *p, const Point *v1, const Point *v2)
|
||||
{
|
||||
return ((*p) == (*(v1)) || (*p) == (*(v2)) || Point::pointInInnerSegment(p, v1, v2));
|
||||
}
|
||||
|
||||
|
||||
// Returns true if the coplanar point 'p' is either in the inner area of
|
||||
// 't' or on its border. Undetermined if p and t are not coplanar.
|
||||
bool Point::pointInTriangle(const Point *p, const Point *v1, const Point *v2, const Point *v3)
|
||||
{
|
||||
if (Point::pointInSegment(p, v1, v2)) return true;
|
||||
else if (Point::pointInSegment(p, v2, v3)) return true;
|
||||
else if (Point::pointInSegment(p, v3, v1)) return true;
|
||||
else return Point::pointInInnerTriangle(p, v1, v2, v3);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Basic predicates of type 'segmentIntersects'
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
// true if (p1-p2) properly intersects (sp1-sp2) at any point (endpoints included).
|
||||
// Collinear overlapping segments are not considered to be properly intersecting.
|
||||
bool Point::segmentsIntersect(const Point *p1, const Point *p2, const Point *sp1, const Point *sp2)
|
||||
{
|
||||
return (p1->exactOrientation(p2, sp1, sp2) == 0 && !p1->exactSameSideOnPlane(p2, sp1, sp2) && !sp1->exactSameSideOnPlane(sp2, p1, p2));
|
||||
}
|
||||
|
||||
// Returns true if the interior of (p1-p2) properly intersects the interior of (sp1-sp2).
|
||||
// Collinear overlapping segments are not considered to be properly intersecting.
|
||||
bool Point::innerSegmentsCross(const Point& p1, const Point& p2, const Point& sp1, const Point& sp2)
|
||||
{
|
||||
if (p1 == sp1 || p1 == sp2 || p2 == sp1 || p2 == sp2) return false;
|
||||
return (p1.exactOrientation(&p2, &sp1, &sp2) == 0 && !p1.exactSameSideOnPlane(&p2, &sp1, &sp2) && !sp1.exactSameSideOnPlane(&sp2, &p1, &p2));
|
||||
}
|
||||
|
||||
bool Point::segmentIntersectsTriangle(const Point *s1, const Point *s2, const Point *v1, const Point *v2, const Point *v3)
|
||||
{
|
||||
coord o1, o2, o3;
|
||||
|
||||
coord mx = MIN(s1->x, s2->x);
|
||||
if (v1->x < mx && v2->x < mx && v3->x < mx) return false;
|
||||
mx = MAX(s1->x, s2->x);
|
||||
if (v1->x > mx && v2->x > mx && v3->x > mx) return false;
|
||||
mx = MIN(s1->y, s2->y);
|
||||
if (v1->y < mx && v2->y < mx && v3->y < mx) return false;
|
||||
mx = MAX(s1->y, s2->y);
|
||||
if (v1->y > mx && v2->y > mx && v3->y > mx) return false;
|
||||
mx = MIN(s1->z, s2->z);
|
||||
if (v1->z < mx && v2->z < mx && v3->z < mx) return false;
|
||||
mx = MAX(s1->z, s2->z);
|
||||
if (v1->z > mx && v2->z > mx && v3->z > mx) return false;
|
||||
|
||||
o1 = s1->exactOrientation(v1, v2, v3);
|
||||
o2 = s2->exactOrientation(v1, v2, v3);
|
||||
if (o1 == 0 && o2 == 0)
|
||||
{
|
||||
if (!s1->exactSameSideOnPlane(s2, v1, v2) && !v1->exactSameSideOnPlane(v2, s1, s2)) return true;
|
||||
if (!s1->exactSameSideOnPlane(s2, v2, v3) && !v2->exactSameSideOnPlane(v3, s1, s2)) return true;
|
||||
if (!s1->exactSameSideOnPlane(s2, v3, v1) && !v3->exactSameSideOnPlane(v1, s1, s2)) return true;
|
||||
if (Point::pointInInnerTriangle(s1, v1, v2, v3) && Point::pointInInnerTriangle(s2, v1, v2, v3)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((o1>0 && o2>0) || (o1<0 && o2<0)) return false; // s1 and s2 are both above/below v1,v2,v3
|
||||
o1 = s1->exactOrientation(s2, v1, v2);
|
||||
o2 = s1->exactOrientation(s2, v2, v3);
|
||||
if ((o1>0 && o2<0) || (o1<0 && o2>0)) return false;
|
||||
o3 = s1->exactOrientation(s2, v3, v1);
|
||||
if ((o1>0 && o3<0) || (o1<0 && o3>0)) return false;
|
||||
if ((o2>0 && o3<0) || (o2<0 && o3>0)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Point::segmentIntersectsTriangle(const Point *s1, const Point *s2, const Point *v1, const Point *v2, const Point *v3, const coord& oo1, const coord& oo2)
|
||||
{
|
||||
// In this case the fast reject by bounding box appears to be a disadvantage ...
|
||||
if (oo1 == 0 && oo2 == 0)
|
||||
{
|
||||
if (!s1->exactSameSideOnPlane(s2, v1, v2) && !v1->exactSameSideOnPlane(v2, s1, s2)) return true;
|
||||
if (!s1->exactSameSideOnPlane(s2, v2, v3) && !v2->exactSameSideOnPlane(v3, s1, s2)) return true;
|
||||
if (!s1->exactSameSideOnPlane(s2, v3, v1) && !v3->exactSameSideOnPlane(v1, s1, s2)) return true;
|
||||
if (Point::pointInInnerTriangle(s1, v1, v2, v3) && Point::pointInInnerTriangle(s2, v1, v2, v3)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((oo1>0 && oo2>0) || (oo1<0 && oo2<0)) return false; // s1 and s2 are both above/below v1,v2,v3
|
||||
coord o1, o2, o3;
|
||||
o1 = s1->exactOrientation(s2, v1, v2);
|
||||
o2 = s1->exactOrientation(s2, v2, v3);
|
||||
if ((o1>0 && o2<0) || (o1<0 && o2>0)) return false;
|
||||
o3 = s1->exactOrientation(s2, v3, v1);
|
||||
if ((o1>0 && o3<0) || (o1<0 && o3>0)) return false;
|
||||
if ((o2>0 && o3<0) || (o2<0 && o3>0)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
} //namespace T_MESH
|
259
src/mesh_fix/src/Kernel/tmesh.cpp
Normal file
259
src/mesh_fix/src/Kernel/tmesh.cpp
Normal file
@ -0,0 +1,259 @@
|
||||
/****************************************************************************
|
||||
* TMesh *
|
||||
* *
|
||||
* Consiglio Nazionale delle Ricerche *
|
||||
* Istituto di Matematica Applicata e Tecnologie Informatiche *
|
||||
* Sezione di Genova *
|
||||
* IMATI-GE / CNR *
|
||||
* *
|
||||
* Authors: Marco Attene *
|
||||
* Copyright(C) 2012: IMATI-GE / CNR *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is dual-licensed as follows: *
|
||||
* *
|
||||
* (1) You may use TMesh as 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. *
|
||||
* In this case the 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 (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
* (2) You may use TMesh as part of a commercial software. In this case a *
|
||||
* proper agreement must be reached with the Authors and with IMATI-GE/CNR *
|
||||
* based on a proper licensing contract. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#include "tmesh_kernel.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
namespace T_MESH
|
||||
{
|
||||
|
||||
extern "C" void initPredicates();
|
||||
|
||||
void (* TMesh::display_message)(const char*, int) = NULL;
|
||||
|
||||
const char *TMesh::app_name = NULL;
|
||||
const char *TMesh::app_version = NULL;
|
||||
const char *TMesh::app_year = NULL;
|
||||
const char *TMesh::app_authors = NULL;
|
||||
const char *TMesh::app_url = NULL;
|
||||
const char *TMesh::app_maillist = NULL;
|
||||
const char *TMesh::filename = NULL;
|
||||
bool TMesh::quiet = false;
|
||||
|
||||
void TMesh::init(void (*dm)(const char *, int))
|
||||
{
|
||||
display_message = dm;
|
||||
app_name = NULL;
|
||||
app_version = NULL;
|
||||
app_year = NULL;
|
||||
app_authors = NULL;
|
||||
app_url = NULL;
|
||||
app_maillist = NULL;
|
||||
filename = NULL;
|
||||
quiet = false;
|
||||
initPredicates();
|
||||
}
|
||||
|
||||
|
||||
///////////// Prints a fatal error message and exits /////////////
|
||||
|
||||
void TMesh::error(const char *msg, ...)
|
||||
{
|
||||
static char fmt[2048], fms[4096];
|
||||
va_list ap;
|
||||
va_start(ap, msg);
|
||||
strcpy(fmt,"\nERROR- ");
|
||||
strcat(fmt,msg);
|
||||
vsprintf(fms,fmt,ap);
|
||||
|
||||
if (display_message != NULL)
|
||||
display_message(fms, DISPMSG_ACTION_ERRORDIALOG);
|
||||
else
|
||||
{
|
||||
fprintf(stderr,fms);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
///////////// Prints a warning message /////////////
|
||||
|
||||
void TMesh::warning(const char *msg, ...)
|
||||
{
|
||||
if (quiet) return;
|
||||
static char fmt[2048], fms[4096];
|
||||
va_list ap;
|
||||
va_start(ap, msg);
|
||||
strcpy(fmt,"WARNING- ");
|
||||
strcat(fmt,msg);
|
||||
vsprintf(fms,fmt,ap);
|
||||
|
||||
if (display_message != NULL)
|
||||
display_message(fms, DISPMSG_ACTION_PUTMESSAGE);
|
||||
else
|
||||
fputs(fms, stderr);
|
||||
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
///////////// Prints an information message /////////////
|
||||
|
||||
void TMesh::info(const char *msg, ...)
|
||||
{
|
||||
if (quiet) return;
|
||||
static char fmt[2048], fms[4096];
|
||||
va_list ap;
|
||||
va_start(ap, msg);
|
||||
strcpy(fmt,"INFO- ");
|
||||
strcat(fmt,msg);
|
||||
vsprintf(fms,fmt,ap);
|
||||
|
||||
if (display_message != NULL)
|
||||
display_message(fms, DISPMSG_ACTION_PUTMESSAGE);
|
||||
else
|
||||
printf(fms);
|
||||
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
///////// Reports progress status for a process //////////
|
||||
|
||||
void TMesh::begin_progress()
|
||||
{
|
||||
if (quiet) return;
|
||||
if (display_message != NULL)
|
||||
display_message("\n", DISPMSG_ACTION_PUTNEWLINE);
|
||||
else
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void TMesh::report_progress(const char *msg, ...)
|
||||
{
|
||||
if (quiet) return;
|
||||
static char fmt[2048] = "\r";
|
||||
static char fms[4096];
|
||||
static char rotating_bar[5] = "-\\|/";
|
||||
static unsigned char wc=0;
|
||||
|
||||
if (msg == NULL)
|
||||
{
|
||||
sprintf(fms,"%c",rotating_bar[wc++]); if (wc==4) wc=0;
|
||||
strcpy(fmt+1,fms);
|
||||
|
||||
if (display_message != NULL)
|
||||
display_message(fmt, DISPMSG_ACTION_PUTPROGRESS);
|
||||
else
|
||||
{
|
||||
printf("%s",fmt);
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, msg);
|
||||
strcpy(fmt+1,msg);
|
||||
vsprintf(fms,fmt,ap);
|
||||
|
||||
if (display_message != NULL)
|
||||
display_message(fms, DISPMSG_ACTION_PUTPROGRESS);
|
||||
else
|
||||
{
|
||||
printf("%s", fms);
|
||||
fflush(stdout);
|
||||
}
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
|
||||
void TMesh::end_progress()
|
||||
{
|
||||
if (quiet) return;
|
||||
if (display_message != NULL)
|
||||
display_message("\n", DISPMSG_ACTION_PUTNEWLINE);
|
||||
else
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void TMesh::useRationals(bool u)
|
||||
{
|
||||
#ifdef USE_HYBRID_KERNEL
|
||||
coord::useRationals(u);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool TMesh::isUsingRationals()
|
||||
{
|
||||
#ifdef USE_HYBRID_KERNEL
|
||||
return coord::isUsingRationals();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void TMesh::useFiltering(bool u)
|
||||
{
|
||||
#ifdef USE_HYBRID_KERNEL
|
||||
coord::useFiltering(u);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool TMesh::isUsingFiltering()
|
||||
{
|
||||
#ifdef USE_HYBRID_KERNEL
|
||||
return coord::isUsingFiltering();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void TMesh::addMessageToLogFile(const char *msg)
|
||||
{
|
||||
FILE *fp = fopen("tmesh.log", "a");
|
||||
fprintf(fp, msg);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
// Get current date/time, format is YYYY-MM-DD.HH:mm:ss
|
||||
char *currentDateTime()
|
||||
{
|
||||
time_t now = time(0);
|
||||
struct tm tstruct;
|
||||
static char buf[80];
|
||||
tstruct = *localtime(&now);
|
||||
strftime(buf, sizeof(buf), "%Y-%m-%d.%X", &tstruct);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void TMesh::logToFileAndExit(const char *s)
|
||||
{
|
||||
static char msg[2048];
|
||||
sprintf(msg, "%s\nFILE: %s\nRETURN VALUE: %s\n\n", currentDateTime(), (filename) ? (filename) : ("unknown"), s);
|
||||
addMessageToLogFile(msg);
|
||||
TMesh::error(msg);
|
||||
}
|
||||
|
||||
void TMesh::exitOnTimeout(clock_t ts)
|
||||
{
|
||||
static clock_t beginning_time, timeout_secs;
|
||||
if (ts != 0) { beginning_time = clock(); timeout_secs = ts; }
|
||||
else if (((clock() - beginning_time) / 1000) > timeout_secs) logToFileAndExit("Timeout reached");
|
||||
}
|
||||
|
||||
void TMesh::printElapsedTime(bool reset)
|
||||
{
|
||||
static clock_t beginning_time;
|
||||
if (reset) beginning_time = clock();
|
||||
else printf("\n\n********** PARTIAL ELAPSED: %d msecs\n\n", (clock() - beginning_time));
|
||||
}
|
||||
|
||||
} //namespace T_MESH
|
209
src/mesh_fix/src/MeshFix/meshfix.cpp
Normal file
209
src/mesh_fix/src/MeshFix/meshfix.cpp
Normal file
@ -0,0 +1,209 @@
|
||||
#include "tmesh.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
using namespace T_MESH;
|
||||
|
||||
double closestPair(List *bl1, List *bl2, Vertex **closest_on_bl1, Vertex **closest_on_bl2)
|
||||
{
|
||||
Node *n, *m;
|
||||
Vertex *v, *w;
|
||||
double adist, mindist = DBL_MAX;
|
||||
|
||||
FOREACHVVVERTEX(bl1, v, n)
|
||||
FOREACHVVVERTEX(bl2, w, m)
|
||||
if ((adist = w->squaredDistance(v))<mindist)
|
||||
{
|
||||
mindist = adist;
|
||||
*closest_on_bl1 = v;
|
||||
*closest_on_bl2 = w;
|
||||
}
|
||||
|
||||
return mindist;
|
||||
}
|
||||
|
||||
bool joinClosestComponents(Basic_TMesh *tin)
|
||||
{
|
||||
Vertex *v, *w, *gv, *gw;
|
||||
Triangle *t, *s;
|
||||
Node *n;
|
||||
List triList, boundary_loops, *one_loop;
|
||||
List **bloops_array;
|
||||
int i, j, numloops;
|
||||
|
||||
// Mark triangles with connected component's unique ID
|
||||
i = 0;
|
||||
FOREACHVTTRIANGLE((&(tin->T)), t, n) t->info = NULL;
|
||||
FOREACHVTTRIANGLE((&(tin->T)), t, n) if (t->info == NULL)
|
||||
{
|
||||
i++;
|
||||
triList.appendHead(t);
|
||||
t->info = (void *)(intptr_t)i;
|
||||
|
||||
while (triList.numels())
|
||||
{
|
||||
t = (Triangle *)triList.popHead();
|
||||
if ((s = t->t1()) != NULL && s->info == NULL) { triList.appendHead(s); s->info = (void *)(intptr_t)i; }
|
||||
if ((s = t->t2()) != NULL && s->info == NULL) { triList.appendHead(s); s->info = (void *)(intptr_t)i; }
|
||||
if ((s = t->t3()) != NULL && s->info == NULL) { triList.appendHead(s); s->info = (void *)(intptr_t)i; }
|
||||
}
|
||||
}
|
||||
|
||||
if (i<2)
|
||||
{
|
||||
FOREACHVTTRIANGLE((&(tin->T)), t, n) t->info = NULL;
|
||||
// JMesh::info("Mesh is a single component. Nothing done.");
|
||||
return false;
|
||||
}
|
||||
|
||||
FOREACHVTTRIANGLE((&(tin->T)), t, n)
|
||||
{
|
||||
t->v1()->info = t->v2()->info = t->v3()->info = t->info;
|
||||
}
|
||||
|
||||
FOREACHVVVERTEX((&(tin->V)), v, n) if (!IS_VISITED2(v) && v->isOnBoundary())
|
||||
{
|
||||
w = v;
|
||||
one_loop = new List;
|
||||
do
|
||||
{
|
||||
one_loop->appendHead(w); MARK_VISIT2(w);
|
||||
w = w->nextOnBoundary();
|
||||
} while (w != v);
|
||||
boundary_loops.appendHead(one_loop);
|
||||
}
|
||||
FOREACHVVVERTEX((&(tin->V)), v, n) UNMARK_VISIT2(v);
|
||||
|
||||
bloops_array = (List **)boundary_loops.toArray();
|
||||
numloops = boundary_loops.numels();
|
||||
|
||||
int numtris = tin->T.numels();
|
||||
double adist, mindist = DBL_MAX;
|
||||
|
||||
gv = NULL;
|
||||
for (i = 0; i<numloops; i++)
|
||||
for (j = 0; j<numloops; j++)
|
||||
if (((Vertex *)bloops_array[i]->head()->data)->info != ((Vertex *)bloops_array[j]->head()->data)->info)
|
||||
{
|
||||
adist = closestPair(bloops_array[i], bloops_array[j], &v, &w);
|
||||
if (adist<mindist) { mindist = adist; gv = v; gw = w; }
|
||||
}
|
||||
|
||||
if (gv != NULL) tin->joinBoundaryLoops(gv, gw, 1, 0);
|
||||
|
||||
FOREACHVTTRIANGLE((&(tin->T)), t, n) t->info = NULL;
|
||||
FOREACHVVVERTEX((&(tin->V)), v, n) v->info = NULL;
|
||||
|
||||
free(bloops_array);
|
||||
while ((one_loop = (List *)boundary_loops.popHead()) != NULL) delete one_loop;
|
||||
|
||||
return (gv != NULL);
|
||||
}
|
||||
|
||||
void usage()
|
||||
{
|
||||
printf("\nMeshFix V2.0 - by Marco Attene\n------\n");
|
||||
printf("Usage: MeshFix inmeshfile [outmeshfile] [-a] [-j] [-x]\n");
|
||||
printf(" Processes 'inmeshfile' and saves the result to 'outmeshfile'\n");
|
||||
printf(" If 'outmeshfile' is not specified 'inmeshfile_fixed.off' will be produced\n");
|
||||
printf(" Option '-a' = joins multiple open components before starting\n");
|
||||
printf(" Option '-j' = output files in STL format insted of OFF\n");
|
||||
printf(" Option '-x' exits if output file already exists.\n");
|
||||
printf(" Accepted input formats are OFF, PLY and STL.\n Other formats are supported only partially.\n");
|
||||
printf("\nIf MeshFix is used for research purposes, please cite the following paper:\n");
|
||||
printf("\n M. Attene.\n A lightweight approach to repairing digitized polygon meshes.\n The Visual Computer, 2010. (c) Springer.\n");
|
||||
printf("\nHIT ENTER TO EXIT.\n");
|
||||
getchar();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
char *createFilename(const char *iname, const char *subext, char *oname, const char *newextension)
|
||||
{
|
||||
static char tname[2048];
|
||||
strcpy(tname, iname);
|
||||
for (int n = strlen(tname) - 1; n>0; n--) if (tname[n] == '.') { tname[n] = '\0'; break; }
|
||||
sprintf(oname, "%s%s%s", tname, subext, newextension);
|
||||
return oname;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
TMesh::init(); // This is mandatory
|
||||
TMesh::app_name = "MeshFix";
|
||||
TMesh::app_version = "2.0";
|
||||
TMesh::app_year = "2016";
|
||||
TMesh::app_authors = "Marco Attene";
|
||||
TMesh::app_maillist = "attene@ge.imati.cnr.it";
|
||||
|
||||
clock_t beginning = clock();
|
||||
|
||||
// Uncomment the following to prevent message reporting
|
||||
// TMesh::quiet = true;
|
||||
|
||||
Basic_TMesh tin;
|
||||
bool stl_output = false;
|
||||
bool skip_if_fixed = false;
|
||||
bool join_multiple_components = false;
|
||||
char infilename[2048], outfilename[2048], extension[] = ".off";
|
||||
|
||||
if (argc < 2) usage();
|
||||
|
||||
float par;
|
||||
int i = 2;
|
||||
if (argc > 2 && argv[2][0] == '-') i--;
|
||||
|
||||
for (; i<argc; i++)
|
||||
{
|
||||
if (i<argc-1) par = (float)atof(argv[i+1]); else par = 0;
|
||||
if (!strcmp(argv[i], "-x")) skip_if_fixed = true;
|
||||
else if (!strcmp(argv[i], "-a")) join_multiple_components = true;
|
||||
else if (!strcmp(argv[i], "-j")) stl_output = true;
|
||||
else if (argv[i][0] == '-') TMesh::warning("%s - Unknown operation.\n", argv[i]);
|
||||
|
||||
if (par) i++;
|
||||
}
|
||||
|
||||
sprintf(infilename, "%s", argv[1]);
|
||||
if (stl_output) strcpy(extension, ".stl");
|
||||
if (argc>2 && argv[2][0] != '-') sprintf(outfilename, "%s", argv[2]);
|
||||
else createFilename(infilename, "_fixed", outfilename, extension);
|
||||
|
||||
if (skip_if_fixed && fopen(outfilename, "r")) TMesh::error("Output file already exists (-x option specified).");
|
||||
|
||||
// The loader automatically reconstructs a manifold triangle connectivity
|
||||
if (tin.load(infilename) != 0) TMesh::error("Can't open file.\n");
|
||||
|
||||
if (join_multiple_components)
|
||||
{
|
||||
TMesh::info("\nJoining input components ...\n");
|
||||
TMesh::begin_progress();
|
||||
while (joinClosestComponents(&tin)) TMesh::report_progress("Num. components: %d ", tin.shells());
|
||||
TMesh::end_progress();
|
||||
tin.deselectTriangles();
|
||||
}
|
||||
|
||||
// Keep only the largest component (i.e. with most triangles)
|
||||
int sc = tin.removeSmallestComponents();
|
||||
if (sc) TMesh::warning("Removed %d small components\n",sc);
|
||||
|
||||
// Fill holes
|
||||
if (tin.boundaries())
|
||||
{
|
||||
TMesh::warning("Patching holes\n");
|
||||
tin.fillSmallBoundaries(0, true);
|
||||
}
|
||||
|
||||
// Run geometry correction
|
||||
if (!tin.boundaries()) TMesh::warning("Fixing degeneracies and intersections...\n");
|
||||
if (tin.boundaries() || !tin.meshclean()) TMesh::warning("MeshFix could not fix everything.\n", sc);
|
||||
|
||||
|
||||
TMesh::info("Saving output mesh ...\n");
|
||||
tin.save(outfilename);
|
||||
|
||||
printf("Elapsed time: %d ms\n", clock() - beginning);
|
||||
|
||||
return 0;
|
||||
}
|
427
src/mesh_fix/src/TMesh/edge.cpp
Normal file
427
src/mesh_fix/src/TMesh/edge.cpp
Normal file
@ -0,0 +1,427 @@
|
||||
/****************************************************************************
|
||||
* TMesh *
|
||||
* *
|
||||
* Consiglio Nazionale delle Ricerche *
|
||||
* Istituto di Matematica Applicata e Tecnologie Informatiche *
|
||||
* Sezione di Genova *
|
||||
* IMATI-GE / CNR *
|
||||
* *
|
||||
* Authors: Marco Attene *
|
||||
* Copyright(C) 2013: IMATI-GE / CNR *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is dual-licensed as follows: *
|
||||
* *
|
||||
* (1) You may use TMesh as 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. *
|
||||
* In this case the 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 (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
* (2) You may use TMesh as part of a commercial software. In this case a *
|
||||
* proper agreement must be reached with the Authors and with IMATI-GE/CNR *
|
||||
* based on a proper licensing contract. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#include "edge.h"
|
||||
#include "triangle.h"
|
||||
|
||||
namespace T_MESH
|
||||
{
|
||||
|
||||
//////// Length-based edge comparison for qsort //////////
|
||||
|
||||
int edgeCompare(const Data *a, const Data *b)
|
||||
{
|
||||
coord la = ((Edge *)a)->squaredLength();
|
||||
coord lb = ((Edge *)b)->squaredLength();
|
||||
|
||||
if (la<lb) return -1;
|
||||
if (la>lb) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//////// Lexycographic edge comparison for qsort //////////
|
||||
|
||||
int lexEdgeCompare(const Data *a, const Data *b)
|
||||
{
|
||||
Vertex *va1 = ((Edge *)a)->v1;
|
||||
Vertex *va2 = ((Edge *)a)->v2;
|
||||
Vertex *vb1 = ((Edge *)b)->v1;
|
||||
Vertex *vb2 = ((Edge *)b)->v2;
|
||||
|
||||
if (xyzCompare(va1, va2) > 0) p_swap((void **)&va1, (void **)&va2);
|
||||
if (xyzCompare(vb1, vb2) > 0) p_swap((void **)&vb1, (void **)&vb2);
|
||||
|
||||
int ca = xyzCompare(va1, vb1);
|
||||
|
||||
if (ca == 0) return xyzCompare(va2, vb2);
|
||||
|
||||
return ca;
|
||||
}
|
||||
|
||||
|
||||
//////// Vertex-based edge comparison for qsort //////////
|
||||
|
||||
int vtxEdgeCompare(const Data *a, const Data *b)
|
||||
{
|
||||
Vertex *va1 = ((Edge *)a)->v1;
|
||||
Vertex *va2 = ((Edge *)a)->v2;
|
||||
Vertex *vb1 = ((Edge *)b)->v1;
|
||||
Vertex *vb2 = ((Edge *)b)->v2;
|
||||
Vertex *tmp;
|
||||
|
||||
if (va2<va1) { tmp = va1; va1 = va2; va2 = tmp; }
|
||||
if (vb2<vb1) { tmp = vb1; vb1 = vb2; vb2 = tmp; }
|
||||
if (va1<vb1) return -1;
|
||||
if (va1>vb1) return 1;
|
||||
if (va2<vb2) return -1;
|
||||
if (va2>vb2) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////// Constructor ///////////////////////
|
||||
//!< AMF_ADD 1.1-2 >
|
||||
Edge::Edge(){
|
||||
mask = 0;
|
||||
info = NULL;
|
||||
}
|
||||
Edge::Edge(Vertex *va, Vertex *vb)
|
||||
{
|
||||
v1 = va;
|
||||
v2 = vb;
|
||||
t1 = t2 = NULL;
|
||||
info = NULL;
|
||||
mask = 0;
|
||||
}
|
||||
|
||||
|
||||
////////////////// Destructor /////////////////////////////
|
||||
|
||||
Edge::~Edge()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////// Returns the unit vector for the edge direction //////
|
||||
|
||||
Point Edge::toUnitVector() const
|
||||
{
|
||||
Point v = toVector();
|
||||
coord l = v.length();
|
||||
|
||||
if (l == 0) TMesh::error("Edge::toUnitVector : Degenerate Edge !\n");
|
||||
|
||||
return v/l;
|
||||
}
|
||||
|
||||
|
||||
/// Returns the edge normal. ////
|
||||
/// It is the average of the incident triangle normals ////
|
||||
|
||||
Point Edge::getNormal() const
|
||||
{
|
||||
Point nor, n1, n2;
|
||||
|
||||
if (t1 == NULL || t2 == NULL) return Point(0,0,0);
|
||||
|
||||
n1 = t1->getNormal();
|
||||
n2 = t2->getNormal();
|
||||
nor = n1+n2;
|
||||
if (nor.length() != 0.0) nor.normalize();
|
||||
return nor;
|
||||
}
|
||||
|
||||
////////////////////////// Edge swap ////////////////////////
|
||||
|
||||
bool Edge::swap(const bool fast)
|
||||
{
|
||||
if (!fast && (t1 == NULL || t2 == NULL ||
|
||||
t2->oppositeVertex(this)->getEdge(t1->oppositeVertex(this)) != NULL)) return 0;
|
||||
|
||||
Edge *e1 = t1->nextEdge(this);
|
||||
Edge *e3 = t2->nextEdge(this);
|
||||
v1->e0 = e3;
|
||||
v2->e0 = e1;
|
||||
v1 = t2->oppositeVertex(this);
|
||||
v2 = t1->oppositeVertex(this);
|
||||
t1->replaceEdge(e1, e3);
|
||||
t2->replaceEdge(e3, e1);
|
||||
t1->invert();
|
||||
t2->invert();
|
||||
e1->replaceTriangle(t1, t2);
|
||||
e3->replaceTriangle(t2, t1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////// Edge collapse ////////////////////////
|
||||
|
||||
Vertex *Edge::collapseOnV1()
|
||||
{
|
||||
Edge *e;
|
||||
Node *n;
|
||||
List *ve;
|
||||
Vertex *tv;
|
||||
|
||||
Edge *e1 = (t1 != NULL)?(t1->nextEdge(this)):(NULL);
|
||||
Edge *e2 = (t1 != NULL)?(t1->prevEdge(this)):(NULL);
|
||||
Edge *e3 = (t2 != NULL)?(t2->nextEdge(this)):(NULL);
|
||||
Edge *e4 = (t2 != NULL)?(t2->prevEdge(this)):(NULL);
|
||||
Vertex *v3 = (e1 != NULL)?(e1->oppositeVertex(v2)):(NULL);
|
||||
Vertex *v4 = (e4 != NULL)?(e4->oppositeVertex(v2)):(NULL);
|
||||
Triangle *ta1 = (e1 != NULL)?(e1->oppositeTriangle(t1)):(NULL);
|
||||
Triangle *ta2 = (e2 != NULL)?(e2->oppositeTriangle(t1)):(NULL);
|
||||
Triangle *ta3 = (e3 != NULL)?(e3->oppositeTriangle(t2)):(NULL);
|
||||
Triangle *ta4 = (e4 != NULL)?(e4->oppositeTriangle(t2)):(NULL);
|
||||
|
||||
if (v1->isOnBoundary() && v2->isOnBoundary())
|
||||
if (!(((ta1 || ta2) && !ta3 && !ta4) || ((ta3 || ta4) && !ta1 && !ta2))) return NULL;
|
||||
|
||||
if (ta1 != NULL && ta2 != NULL && ta1->oppositeVertex(e1) == ta2->oppositeVertex(e2))
|
||||
return NULL;
|
||||
if (ta3 != NULL && ta4 != NULL && ta3->oppositeVertex(e3) == ta4->oppositeVertex(e4))
|
||||
return NULL;
|
||||
|
||||
if (ta1 == NULL && ta2 == NULL) v1->e0 = e3;
|
||||
else v1->e0 = e2;
|
||||
|
||||
if (v3 != NULL) v3->e0 = e2;
|
||||
if (v4 != NULL) v4->e0 = e3;
|
||||
|
||||
ve = v2->VE();
|
||||
FOREACHVEEDGE(ve, e, n)
|
||||
{
|
||||
tv = e->oppositeVertex(v2);
|
||||
if (tv != v3 && tv != v4 && tv->getEdge(v1) != NULL) {delete(ve); return NULL;}
|
||||
}
|
||||
FOREACHVEEDGE(ve, e, n) if (e != this) e->replaceVertex(v2, v1);
|
||||
delete(ve);
|
||||
|
||||
if (e2 != NULL) e2->replaceTriangle(t1, ta1);
|
||||
if (e3 != NULL) e3->replaceTriangle(t2, ta4);
|
||||
|
||||
if (ta1 != NULL) ta1->replaceEdge(e1, e2);
|
||||
if (ta4 != NULL) ta4->replaceEdge(e4, e3);
|
||||
|
||||
v2->e0 = NULL; // v2 must be removed
|
||||
if (e4 != NULL) e4->v1 = e4->v2 = NULL; // e4 must be removed
|
||||
if (e1 != NULL) e1->v1 = e1->v2 = NULL; // e1 must be removed
|
||||
if (t1 != NULL) t1->e1 = t1->e2 = t1->e3 = NULL; // t1 must be removed
|
||||
if (t2 != NULL) t2->e1 = t2->e2 = t2->e3 = NULL; // t2 must be removed
|
||||
|
||||
if (e2 != NULL && e2->t1 == NULL && e2->t2 == NULL)
|
||||
{
|
||||
v3->e0 = NULL;
|
||||
e2->v1 = e2->v2 = NULL;
|
||||
}
|
||||
if (e3 != NULL && e3->t1 == NULL && e3->t2 == NULL)
|
||||
{
|
||||
v4->e0 = NULL;
|
||||
e3->v1 = e3->v2 = NULL;
|
||||
}
|
||||
|
||||
v4 = v1; // This is the remaining vertex to be returned
|
||||
|
||||
v2 = v1 = NULL; // this edge must be removed
|
||||
|
||||
return v4;
|
||||
}
|
||||
|
||||
Vertex *Edge::collapseOnV2()
|
||||
{
|
||||
invert();
|
||||
return collapseOnV1();
|
||||
}
|
||||
|
||||
bool Edge::collapse(const Point& p)
|
||||
{
|
||||
Vertex *r = collapseOnV1();
|
||||
if (r==NULL) return false;
|
||||
else r->setValue(&p); // Average the collapse
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Edge::collapse()
|
||||
{
|
||||
return collapse(((*v1)+(*v2))/2);
|
||||
}
|
||||
|
||||
|
||||
///// Merge with another boundary edge /////
|
||||
|
||||
bool Edge::merge(Edge *e)
|
||||
{
|
||||
if (t1 && t2) return 0;
|
||||
if (e->t1 && e->t2) return 0;
|
||||
Triangle *ot = (e->t1==NULL)?(e->t2):(e->t1);
|
||||
if (ot == getBoundaryTriangle()) return 0;
|
||||
if ((t1 && e->t1) || (t2 && e->t2)) e->invert();
|
||||
Vertex *ov1 = e->v1, *ov2 = e->v2;
|
||||
List *ve1=NULL, *ve2=NULL;
|
||||
Node *n;
|
||||
Edge *f, *f2;
|
||||
|
||||
if (ov1 != v1)
|
||||
{
|
||||
ve1 = ov1->VE();
|
||||
FOREACHVEEDGE(ve1, f, n)
|
||||
{
|
||||
f2 = f->oppositeVertex(ov1)->getEdge(v1);
|
||||
if (f2 != NULL && (!f2->isOnBoundary() || !f->isOnBoundary()))
|
||||
{delete(ve1); return 0;}
|
||||
}
|
||||
}
|
||||
if (ov2 != v2)
|
||||
{
|
||||
ve2 = ov2->VE();
|
||||
FOREACHVEEDGE(ve2, f, n)
|
||||
{
|
||||
f2 = f->oppositeVertex(ov2)->getEdge(v2);
|
||||
if (f2 != NULL && (!f2->isOnBoundary() || !f->isOnBoundary()))
|
||||
{delete(ve1); delete(ve2); return 0;}
|
||||
}
|
||||
}
|
||||
|
||||
if (ov1 != v1)
|
||||
{
|
||||
FOREACHVEEDGE(ve1, f, n) f->replaceVertex(ov1, v1);
|
||||
delete(ve1);
|
||||
ov1->e0 = NULL;
|
||||
}
|
||||
if (ov2 != v2)
|
||||
{
|
||||
FOREACHVEEDGE(ve2, f, n) f->replaceVertex(ov2, v2);
|
||||
delete(ve2);
|
||||
ov2->e0 = NULL;
|
||||
}
|
||||
ot->replaceEdge(e, this);
|
||||
((t1==NULL)?(t1):(t2)) = ot;
|
||||
v1->e0 = v2->e0 = this;
|
||||
e->v1 = e->v2 = NULL;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
///// Angle between the normal of incident triangles /////
|
||||
|
||||
double Edge::curvature() const
|
||||
{
|
||||
if (!t1 || !t2) return -1.0;
|
||||
return t1->getDAngle(t2);
|
||||
}
|
||||
|
||||
|
||||
//// Dihedral angle
|
||||
|
||||
double Edge::dihedralAngle() const
|
||||
{
|
||||
if (!t1 || !t2) return -1.0;
|
||||
Point nor1 = t1->getNormal();
|
||||
Point nor2 = t2->getNormal();
|
||||
if (nor1.isNull() || nor2.isNull()) return -1.0;
|
||||
double c = nor1.getAngle(&nor2);
|
||||
|
||||
Vertex *ov = t2->oppositeVertex(this);
|
||||
if (((*ov)*nor1) - ((*v1)*nor1) < 0) return -(c - M_PI);
|
||||
|
||||
return c+M_PI;
|
||||
}
|
||||
|
||||
//// Min Angle among those of the two incident triangles ////
|
||||
|
||||
double Edge::delaunayMinAngle() const
|
||||
{
|
||||
if (t1==NULL || t2==NULL) return 2*M_PI;
|
||||
if (squaredLength()==0) return 0;
|
||||
if (t1->nextEdge(this)->squaredLength() == 0) return 0;
|
||||
if (t1->prevEdge(this)->squaredLength() == 0) return 0;
|
||||
double a1 = t1->getAngle(v1);
|
||||
double a2 = t1->getAngle(v2);
|
||||
double a3 = t1->getAngle(t1->oppositeVertex(this));
|
||||
if (t2->nextEdge(this)->length()==0) return 0;
|
||||
if (t2->prevEdge(this)->length()==0) return 0;
|
||||
double a4 = t2->getAngle(v1);
|
||||
double a5 = t2->getAngle(v2);
|
||||
double a6 = t2->getAngle(t2->oppositeVertex(this));
|
||||
|
||||
if (a1+a4 >= M_PI || a2+a5 >= M_PI) return 3*M_PI;
|
||||
return MIN(a1,(MIN(a2,(MIN(a3,(MIN(a4,(MIN(a5,a6)))))))));
|
||||
}
|
||||
|
||||
|
||||
// If edge is stitchable, merge it with its copy
|
||||
|
||||
bool Edge::stitch()
|
||||
{
|
||||
// This function seems to be insufficient to stitch in every case !
|
||||
if (!isOnBoundary()) return 0;
|
||||
|
||||
Triangle *t, *t0 = (t1 != NULL) ? (t1) : (t2);
|
||||
Vertex *v0;
|
||||
Edge *e1;
|
||||
|
||||
for (v0 = v1; v0 != NULL; v0 = ((v0 == v1) ? (v2) : (NULL)))
|
||||
{
|
||||
e1 = this;
|
||||
t = t0;
|
||||
while (t != NULL)
|
||||
{
|
||||
e1 = t->nextEdge(e1); if (!e1->hasVertex(v0)) e1 = t->nextEdge(e1);
|
||||
t = e1->oppositeTriangle(t);
|
||||
}
|
||||
if (e1->oppositeVertex(v0) == oppositeVertex(v0))
|
||||
{
|
||||
t = (e1->t1 != NULL) ? (e1->t1) : (e1->t2);
|
||||
t->replaceEdge(e1, this);
|
||||
v1->e0 = v2->e0 = this;
|
||||
e1->v1 = e1->v2 = NULL;
|
||||
replaceTriangle(NULL, t);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Edge::overlaps() const
|
||||
{
|
||||
if (t1 == NULL || t2 == NULL) return false;
|
||||
|
||||
Vertex *ov = t2->oppositeVertex(this);
|
||||
if (ov->exactOrientation(t1->v1(), t1->v2(), t1->v3()) == 0 && ov->exactSameSideOnPlane(t1->oppositeVertex(this), v1, v2)) return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
bool Edge::intersects(const Triangle *t) const
|
||||
{
|
||||
if (t->hasEdge(this)) return false;
|
||||
|
||||
Vertex *cv = (t->hasVertex(v1)) ? (v1) : ((t->hasVertex(v2)) ? (v2) : (NULL));
|
||||
if (cv) // If they share a vertex, intersection occurs if t's opposite edge intersect this edge
|
||||
{
|
||||
Edge *oe = t->oppositeEdge(cv);
|
||||
if (Point::pointInTriangle(oppositeVertex(cv), cv, oe->v1, oe->v2)) return true;
|
||||
else return (Point::segmentsIntersect(oe->v1, oe->v2, v1, v2));
|
||||
}
|
||||
else return Point::segmentIntersectsTriangle(v1, v2, t->v1(), t->v2(), t->v3());
|
||||
}
|
||||
|
||||
coord Edge::getConvexity() const
|
||||
{
|
||||
if (t1 == NULL || t2 == NULL) return DBL_MAX;
|
||||
else return (t1->oppositeVertex(this)->exactOrientation(t2->v3(), t2->v2(), t2->v1()));
|
||||
}
|
||||
|
||||
} //namespace T_MESH
|
1623
src/mesh_fix/src/TMesh/io.cpp
Normal file
1623
src/mesh_fix/src/TMesh/io.cpp
Normal file
File diff suppressed because it is too large
Load Diff
2122
src/mesh_fix/src/TMesh/tin.cpp
Normal file
2122
src/mesh_fix/src/TMesh/tin.cpp
Normal file
File diff suppressed because it is too large
Load Diff
410
src/mesh_fix/src/TMesh/triangle.cpp
Normal file
410
src/mesh_fix/src/TMesh/triangle.cpp
Normal file
@ -0,0 +1,410 @@
|
||||
/****************************************************************************
|
||||
* TMesh *
|
||||
* *
|
||||
* Consiglio Nazionale delle Ricerche *
|
||||
* Istituto di Matematica Applicata e Tecnologie Informatiche *
|
||||
* Sezione di Genova *
|
||||
* IMATI-GE / CNR *
|
||||
* *
|
||||
* Authors: Marco Attene *
|
||||
* Copyright(C) 2013: IMATI-GE / CNR *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is dual-licensed as follows: *
|
||||
* *
|
||||
* (1) You may use TMesh as 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. *
|
||||
* In this case the 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 (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
* (2) You may use TMesh as part of a commercial software. In this case a *
|
||||
* proper agreement must be reached with the Authors and with IMATI-GE/CNR *
|
||||
* based on a proper licensing contract. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#include "triangle.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace T_MESH
|
||||
{
|
||||
|
||||
extern "C" double orient2d(double *, double *, double *);
|
||||
|
||||
//////////////////// Constructor //////////////////////
|
||||
|
||||
//!< AMF_ADD 1.1>
|
||||
Triangle::Triangle(){
|
||||
mask = 0;
|
||||
info = NULL;
|
||||
}
|
||||
|
||||
Triangle::Triangle(Edge *a, Edge *b, Edge *c)
|
||||
{
|
||||
e1 = a;
|
||||
e2 = b;
|
||||
e3 = c;
|
||||
mask = 0;
|
||||
info = NULL;
|
||||
}
|
||||
|
||||
|
||||
//////////////////// Normal vector //////////////////////
|
||||
|
||||
Point Triangle::getNormal() const
|
||||
{
|
||||
Vertex *va = v1(), *vb = v2(), *vc = v3();
|
||||
Point vd = (((*va)-(*vb))&((*vb)-(*vc)));
|
||||
coord l = vd.length();
|
||||
|
||||
if (l == 0) return Point(0,0,0);
|
||||
|
||||
return vd/l;
|
||||
}
|
||||
|
||||
|
||||
////// Directional vector ////////
|
||||
|
||||
Point Triangle::getVector() const
|
||||
{
|
||||
Vertex *va = v1(), *vb = v2(), *vc = v3();
|
||||
return (((*va) - (*vb))&((*vb) - (*vc)));
|
||||
}
|
||||
|
||||
|
||||
/////////////////// Normal consistence check ////////////////////
|
||||
|
||||
bool Triangle::checkAdjNor(const Triangle *t) const
|
||||
{
|
||||
Edge *e = commonEdge(t);
|
||||
if (e == NULL) return 1;
|
||||
|
||||
Edge *ea = nextEdge(e);
|
||||
Edge *eb = t->nextEdge(e);
|
||||
if (ea->commonVertex(eb) == ea->commonVertex(e)) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////// Triangle area /////////////////////////
|
||||
|
||||
double Triangle::area() const
|
||||
{
|
||||
double a = e1->length(), b = e2->length(), c = e3->length();
|
||||
if (a==0.0 || b==0.0 || c==0.0) return 0.0;
|
||||
double p = (a+b+c)/2.0;
|
||||
p = p*(p-a)*(p-b)*(p-c); if (p<0) return 0.0;
|
||||
return sqrt(p);
|
||||
}
|
||||
|
||||
|
||||
/////////////////////// Triangle perimeter /////////////////////
|
||||
|
||||
double Triangle::perimeter() const
|
||||
{
|
||||
return e1->length()+e2->length()+e3->length();
|
||||
}
|
||||
|
||||
|
||||
///////////// Barycenter ///////////////////////
|
||||
|
||||
Point Triangle::getCenter() const
|
||||
{
|
||||
Point va = *v1(), vb = *v2(), vc = *v3();
|
||||
return (va+vb+vc)/3.0;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////// Circlecenter /////////////////////////
|
||||
|
||||
Point Triangle::getCircleCenter() const
|
||||
{
|
||||
Point va = *v1(), vb = *v2(), vc = *v3();
|
||||
Point q1 = vb-va;
|
||||
Point q2 = vc-va;
|
||||
Point n = q2&q1;
|
||||
Point m1 = e2->getMidPoint();
|
||||
Point m2 = e1->getMidPoint();
|
||||
|
||||
return Point(n*va,q1*m1,q2*m2).linearSystem(n,q1,q2);
|
||||
}
|
||||
|
||||
|
||||
/////// Check wether the point is inside the triangle's bounding ball /////
|
||||
|
||||
bool Triangle::inSphere(const Point *p) const
|
||||
{
|
||||
Point c = getCircleCenter();
|
||||
coord rad = c.squaredDistance(e1->v1);
|
||||
|
||||
return (p->squaredDistance(&c) < rad);
|
||||
}
|
||||
|
||||
|
||||
//////////////////// Angle at a vertex /////////////////////
|
||||
|
||||
double Triangle::getAngle(const Vertex *v) const
|
||||
{
|
||||
Vertex *va = v1(), *vb = v2(), *vc = v3();
|
||||
if (v == va) return v->getAngle(vb, vc);
|
||||
if (v == vb) return v->getAngle(va, vc);
|
||||
if (v == vc) return v->getAngle(vb, va);
|
||||
|
||||
return -1.0;
|
||||
}
|
||||
|
||||
|
||||
/////////// Angle between the two directional vectors /////////
|
||||
|
||||
double Triangle::getDAngle(const Triangle *t) const
|
||||
{
|
||||
Point thisNormal = getVector();
|
||||
Point otherNormal = t->getVector();
|
||||
|
||||
if (thisNormal.isNull() || otherNormal.isNull()) return -1.0;
|
||||
|
||||
return thisNormal.getAngle(otherNormal);
|
||||
}
|
||||
|
||||
|
||||
///////////// Distance from the plane of the triangle //////////////
|
||||
|
||||
double Triangle::distanceFromPoint(const Point *p) const
|
||||
{
|
||||
return sqrt(TMESH_TO_DOUBLE(squaredDistanceFromPoint(p)));
|
||||
}
|
||||
|
||||
///////////// Squared distance from the plane of the triangle //////////////
|
||||
|
||||
coord Triangle::squaredDistanceFromPoint(const Point *p) const
|
||||
{
|
||||
Point CA = e1->toVector()&e2->toVector();
|
||||
coord CA2 = CA*CA;
|
||||
|
||||
if (CA2 == 0) return -1.0;
|
||||
coord d = ((CA*(*p))-(CA*(*(e1->v1))));
|
||||
|
||||
return (d*d)/CA2;
|
||||
}
|
||||
|
||||
|
||||
///////////// Distance of point from the triangle //////////////
|
||||
|
||||
double Triangle::pointTriangleDistance(const Point *p, Point *cp) const
|
||||
{
|
||||
return sqrt(TMESH_TO_DOUBLE(pointTriangleSquaredDistance(p)));
|
||||
}
|
||||
|
||||
|
||||
///////////// Distance of point from the triangle //////////////
|
||||
|
||||
coord Triangle::pointTriangleSquaredDistance(const Point *p, Edge **closest_edge, Vertex **closest_vertex) const
|
||||
{
|
||||
Vertex *va = v1(), *vb = v2(), *vc = v3();
|
||||
Point n(((*va)-(*vb))&((*vb)-(*vc)));
|
||||
if (n.x == 0 && n.y == 0 && n.z == 0) return -1.0;
|
||||
|
||||
coord d1 = ((((*va)-(*vb))&((*vb)-(*p)))*n);
|
||||
coord d2 = ((((*vb)-(*vc))&((*vc)-(*p)))*n);
|
||||
coord d3 = ((((*vc)-(*va))&((*va)-(*p)))*n);
|
||||
|
||||
if (d1 > 0 && d2 > 0 && d3 > 0) // Closest point in inner triangle
|
||||
{
|
||||
if (closest_edge != NULL) *closest_edge = NULL;
|
||||
if (closest_vertex != NULL) *closest_vertex = NULL;
|
||||
return squaredDistanceFromPoint(p);
|
||||
}
|
||||
|
||||
if (d2 < 0) { va = vb; vb = vc; if (closest_edge != NULL) *closest_edge = e3; }
|
||||
else if (d3 < 0) { vb = va; va = vc; if (closest_edge != NULL) *closest_edge = e1; }
|
||||
else if (closest_edge != NULL) *closest_edge = e2;
|
||||
|
||||
Point i(p->projection(va,vb));
|
||||
Point p1(i-(*va)); Point p2(i-(*vb));
|
||||
|
||||
if (p1*p2 < 0) // Closest point on interior of one edge
|
||||
{
|
||||
return i.squaredDistance(p);
|
||||
}
|
||||
|
||||
d1=p1.squaredLength(); d2=p2.squaredLength();
|
||||
if (d1 < d2) { if (closest_vertex != NULL) *closest_vertex = va; return p->squaredDistance(va); }
|
||||
else { if (closest_vertex != NULL) *closest_vertex = vb; return p->squaredDistance(vb); }
|
||||
}
|
||||
|
||||
|
||||
/////////// Projection of point 'p' on the plane of the triangle /////
|
||||
|
||||
Point Triangle::project(const Point *p) const
|
||||
{
|
||||
Point n = getVector();
|
||||
if (n.isNull()) return INFINITE_POINT;
|
||||
return Point::linePlaneIntersection(*p, (*p) + n, *(v1()), *(v2()), *(v3()));
|
||||
}
|
||||
|
||||
bool Triangle::isExactlyDegenerate() const
|
||||
{
|
||||
return (!v1()->exactMisalignment((v2()), (v3())));
|
||||
}
|
||||
|
||||
//// get longest edge /////
|
||||
|
||||
Edge *Triangle::getLongestEdge() const
|
||||
{
|
||||
coord l1 = e1->squaredLength();
|
||||
coord l2 = e2->squaredLength();
|
||||
coord l3 = e3->squaredLength();
|
||||
if (l1>=l2 && l1>=l3) return e1;
|
||||
if (l2>=l1 && l2>=l3) return e2;
|
||||
return e3;
|
||||
}
|
||||
|
||||
Edge *Triangle::getCapEdge() const
|
||||
{
|
||||
Edge *e;
|
||||
e = e1; if (Point::pointInInnerSegment(oppositeVertex(e), e->v1, e->v2)) return e;
|
||||
e = e2; if (Point::pointInInnerSegment(oppositeVertex(e), e->v1, e->v2)) return e;
|
||||
e = e3; if (Point::pointInInnerSegment(oppositeVertex(e), e->v1, e->v2)) return e;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
///////////// Overlap check ////////////////////
|
||||
|
||||
bool Triangle::overlaps() const
|
||||
{
|
||||
return (e1->overlaps() || e2->overlaps() || e3->overlaps());
|
||||
}
|
||||
|
||||
Vertex *Triangle::commonVertex(const Triangle *t2) const
|
||||
{
|
||||
if (hasVertex(t2->v1())) return t2->v1();
|
||||
if (hasVertex(t2->v2())) return t2->v2();
|
||||
if (hasVertex(t2->v3())) return t2->v3();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/// Debug
|
||||
|
||||
void Triangle::printTriangle(FILE *fp) const
|
||||
{
|
||||
v1()->printPoint(fp);
|
||||
v2()->printPoint(fp);
|
||||
v3()->printPoint(fp);
|
||||
}
|
||||
|
||||
|
||||
// This can be made more efficient, I guess...
|
||||
|
||||
bool Triangle::intersects(const Triangle *t2, bool justproper) const
|
||||
{
|
||||
Vertex *v11, *v12, *v13, *v21, *v22, *v23;
|
||||
|
||||
if (justproper)
|
||||
{
|
||||
// This works for non-degenerate triangles. Not sure it will work for degeneracies too.
|
||||
v11 = v1(); v12 = v2(); v13 = v3();
|
||||
v21 = t2->v1(); v22 = t2->v2(); v23 = t2->v3();
|
||||
Vertex *eq1 = ((*v11) == (*v21)) ? (v21) : (((*v11) == (*v22)) ? (v22) : (((*v11) == (*v23)) ? (v23) : (NULL)));
|
||||
Vertex *eq2 = ((*v12) == (*v21)) ? (v21) : (((*v12) == (*v22)) ? (v22) : (((*v12) == (*v23)) ? (v23) : (NULL)));
|
||||
Vertex *eq3 = ((*v13) == (*v21)) ? (v21) : (((*v13) == (*v22)) ? (v22) : (((*v13) == (*v23)) ? (v23) : (NULL)));
|
||||
if (eq1 && eq2 && eq3) return false; // Triangles coincide
|
||||
Edge *ce1 = NULL, *ce2 = NULL;
|
||||
if (eq1 && eq2) { ce1 = e2; ce2 = (t2->e1->hasVertices(eq1, eq2)) ? (t2->e1) : ((t2->e2->hasVertices(eq1, eq2)) ? (t2->e2) : (t2->e3)); }
|
||||
if (eq2 && eq3) { ce1 = e3; ce2 = (t2->e1->hasVertices(eq3, eq2)) ? (t2->e1) : ((t2->e2->hasVertices(eq3, eq2)) ? (t2->e2) : (t2->e3)); }
|
||||
if (eq3 && eq1) { ce1 = e1; ce2 = (t2->e1->hasVertices(eq3, eq1)) ? (t2->e1) : ((t2->e2->hasVertices(eq3, eq1)) ? (t2->e2) : (t2->e3)); }
|
||||
if (ce1)
|
||||
{
|
||||
Vertex *ov = t2->oppositeVertex(ce2);
|
||||
return (ov->exactOrientation(v11, v12, v13) == 0 && ov->exactSameSideOnPlane(oppositeVertex(ce1), ce1->v1, ce1->v2));
|
||||
}
|
||||
Vertex *cv1 = NULL, *cv2 = NULL;
|
||||
if (eq1) { cv1 = v11; cv2 = eq1; }
|
||||
if (eq2) { cv1 = v12; cv2 = eq2; }
|
||||
if (eq3) { cv1 = v13; cv2 = eq3; }
|
||||
if (cv1) // If they share a vertex, intersection occurs if the opposite edge intersect the triangle
|
||||
{
|
||||
Edge *ee1 = oppositeEdge(cv1), *ee2 = t2->oppositeEdge(cv2);
|
||||
return (Point::segmentIntersectsTriangle(ee1->v1, ee1->v2, v21, v22, v23) ||
|
||||
Point::segmentIntersectsTriangle(ee2->v1, ee2->v2, v11, v12, v13));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Edge *ce = commonEdge(t2);
|
||||
if (ce) // If they share an edge, intersection occurs only if t1 and t2 overlap
|
||||
{
|
||||
Vertex *ov = t2->oppositeVertex(ce);
|
||||
return (ov->exactOrientation(v1(), v2(), v3()) == 0 && ov->exactSameSideOnPlane(oppositeVertex(ce), ce->v1, ce->v2));
|
||||
}
|
||||
|
||||
Vertex *cv = commonVertex(t2);
|
||||
v11 = v1(); v12 = v2(); v13 = v3();
|
||||
v21 = t2->v1(); v22 = t2->v2(); v23 = t2->v3();
|
||||
if (cv) // If they share a vertex, intersection occurs if the opposite edge intersect the triangle
|
||||
{
|
||||
Edge *ee1 = oppositeEdge(cv), *ee2 = t2->oppositeEdge(cv);
|
||||
return (Point::segmentIntersectsTriangle(ee1->v1, ee1->v2, v21, v22, v23) ||
|
||||
Point::segmentIntersectsTriangle(ee2->v1, ee2->v2, v11, v12, v13));
|
||||
}
|
||||
}
|
||||
|
||||
// Fast reject by bounding box
|
||||
coord mx = MIN(v11->x, MIN(v13->x, v12->x));
|
||||
if (v21->x < mx && v22->x < mx && v23->x < mx) return false;
|
||||
mx = MAX(v11->x, MAX(v13->x, v12->x));
|
||||
if (v21->x > mx && v22->x > mx && v23->x > mx) return false;
|
||||
mx = MIN(v11->y, MIN(v13->y, v12->y));
|
||||
if (v21->y < mx && v22->y < mx && v23->y < mx) return false;
|
||||
mx = MAX(v11->y, MAX(v13->y, v12->y));
|
||||
if (v21->y > mx && v22->y > mx && v23->y > mx) return false;
|
||||
mx = MIN(v11->z, MIN(v13->z, v12->z));
|
||||
if (v21->z < mx && v22->z < mx && v23->z < mx) return false;
|
||||
mx = MAX(v11->z, MAX(v13->z, v12->z));
|
||||
if (v21->z > mx && v22->z > mx && v23->z > mx) return false;
|
||||
|
||||
// Calculate relative orientations
|
||||
coord o11 = v11->exactOrientation(v21, v22, v23);
|
||||
coord o12 = v12->exactOrientation(v21, v22, v23);
|
||||
coord o13 = v13->exactOrientation(v21, v22, v23);
|
||||
if ((o11>0 && o12>0 && o13>0) || (o11<0 && o12<0 && o13<0)) return false; // t1 above/below t2
|
||||
coord o21 = v21->exactOrientation(v11, v12, v13);
|
||||
coord o22 = v22->exactOrientation(v11, v12, v13);
|
||||
coord o23 = v23->exactOrientation(v11, v12, v13);
|
||||
if ((o21>0 && o22>0 && o23>0) || (o21<0 && o22<0 && o23<0)) return false; // t2 above/below t1
|
||||
|
||||
if (o11 == 0 && o12 == 0 && o13 == 0) // t1 and t2 are coplanar
|
||||
{
|
||||
if (Point::innerSegmentsCross(v11, v12, v21, v22)) return true;
|
||||
if (Point::innerSegmentsCross(v11, v12, v22, v23)) return true;
|
||||
if (Point::innerSegmentsCross(v11, v12, v23, v21)) return true;
|
||||
if (Point::innerSegmentsCross(v12, v13, v21, v22)) return true;
|
||||
if (Point::innerSegmentsCross(v12, v13, v22, v23)) return true;
|
||||
if (Point::innerSegmentsCross(v12, v13, v23, v21)) return true;
|
||||
if (Point::innerSegmentsCross(v13, v11, v21, v22)) return true;
|
||||
if (Point::innerSegmentsCross(v13, v11, v22, v23)) return true;
|
||||
if (Point::innerSegmentsCross(v13, v11, v23, v21)) return true;
|
||||
return (
|
||||
Point::pointInTriangle(v11, v21, v22, v23) ||
|
||||
Point::pointInTriangle(v12, v21, v22, v23) ||
|
||||
Point::pointInTriangle(v13, v21, v22, v23) ||
|
||||
Point::pointInTriangle(v21, v11, v12, v13) ||
|
||||
Point::pointInTriangle(v22, v11, v12, v13) ||
|
||||
Point::pointInTriangle(v23, v11, v12, v13));
|
||||
}
|
||||
else return (
|
||||
Point::segmentIntersectsTriangle(v11, v12, v21, v22, v23, o11, o12) ||
|
||||
Point::segmentIntersectsTriangle(v12, v13, v21, v22, v23, o12, o13) ||
|
||||
Point::segmentIntersectsTriangle(v13, v11, v21, v22, v23, o13, o11) ||
|
||||
Point::segmentIntersectsTriangle(v21, v22, v11, v12, v13, o21, o22) ||
|
||||
Point::segmentIntersectsTriangle(v22, v23, v11, v12, v13, o22, o23) ||
|
||||
Point::segmentIntersectsTriangle(v23, v21, v11, v12, v13, o23, o21));
|
||||
}
|
||||
|
||||
} //namespace T_MESH
|
682
src/mesh_fix/src/TMesh/vertex.cpp
Normal file
682
src/mesh_fix/src/TMesh/vertex.cpp
Normal file
@ -0,0 +1,682 @@
|
||||
/****************************************************************************
|
||||
* TMesh *
|
||||
* *
|
||||
* Consiglio Nazionale delle Ricerche *
|
||||
* Istituto di Matematica Applicata e Tecnologie Informatiche *
|
||||
* Sezione di Genova *
|
||||
* IMATI-GE / CNR *
|
||||
* *
|
||||
* Authors: Marco Attene *
|
||||
* Copyright(C) 2013: IMATI-GE / CNR *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is dual-licensed as follows: *
|
||||
* *
|
||||
* (1) You may use TMesh as 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. *
|
||||
* In this case the 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 (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
* (2) You may use TMesh as part of a commercial software. In this case a *
|
||||
* proper agreement must be reached with the Authors and with IMATI-GE/CNR *
|
||||
* based on a proper licensing contract. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#include "vertex.h"
|
||||
#include "edge.h"
|
||||
#include "triangle.h"
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
namespace T_MESH
|
||||
{
|
||||
|
||||
//////////////////// Constructors ////////////////////////
|
||||
|
||||
Vertex::Vertex() : Point()
|
||||
{
|
||||
e0 = NULL;
|
||||
mask = 0;
|
||||
}
|
||||
|
||||
|
||||
Vertex::Vertex(const coord& a, const coord& b, const coord& c) : Point(a,b,c)
|
||||
{
|
||||
e0 = NULL;
|
||||
mask = 0;
|
||||
}
|
||||
|
||||
|
||||
Vertex::Vertex(const Point *p) : Point(p->x, p->y, p->z)
|
||||
{
|
||||
e0 = NULL;
|
||||
mask = 0;
|
||||
}
|
||||
|
||||
|
||||
Vertex::Vertex(const Point& p) : Point(p.x, p.y, p.z)
|
||||
{
|
||||
e0 = NULL;
|
||||
mask = 0;
|
||||
}
|
||||
|
||||
///////////////////// Destructor ///////////////////////
|
||||
|
||||
Vertex::~Vertex()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/////////////// VE relation ////////////////////////////
|
||||
|
||||
List *Vertex::VE() const
|
||||
{
|
||||
Triangle *t;
|
||||
Edge *e;
|
||||
Vertex *v;
|
||||
List *ve = new List();
|
||||
|
||||
if (e0 == NULL) return ve;
|
||||
|
||||
|
||||
|
||||
e = e0;
|
||||
do
|
||||
{
|
||||
ve->appendTail(e);
|
||||
v = e->oppositeVertex(this);
|
||||
t = e->leftTriangle(this);
|
||||
if (t == NULL) break;
|
||||
e = t->oppositeEdge(v);
|
||||
} while (e != e0);
|
||||
|
||||
if (e == e0 && ve->numels() > 1) return ve;
|
||||
|
||||
ve->popHead();
|
||||
e = e0;
|
||||
|
||||
do
|
||||
{
|
||||
ve->appendHead(e);
|
||||
v = e->oppositeVertex(this);
|
||||
t = e->rightTriangle(this);
|
||||
if (t == NULL) break;
|
||||
e = t->oppositeEdge(v);
|
||||
} while (e != e0);
|
||||
|
||||
return ve;
|
||||
}
|
||||
|
||||
/////////////// VV relation ////////////////////////////
|
||||
|
||||
List *Vertex::VV() const
|
||||
{
|
||||
Triangle *t;
|
||||
Edge *e;
|
||||
Vertex *v;
|
||||
List *vv = new List();
|
||||
|
||||
if (e0 == NULL) return vv;
|
||||
|
||||
e = e0;
|
||||
do
|
||||
{
|
||||
v = e->oppositeVertex(this);
|
||||
vv->appendTail(v);
|
||||
t = e->leftTriangle(this);
|
||||
if (t == NULL) break;
|
||||
e = t->oppositeEdge(v);
|
||||
} while (e != e0);
|
||||
|
||||
if (e == e0 && vv->numels() > 1) return vv;
|
||||
|
||||
vv->popHead();
|
||||
e = e0;
|
||||
do
|
||||
{
|
||||
v = e->oppositeVertex(this);
|
||||
vv->appendHead(v);
|
||||
t = e->rightTriangle(this);
|
||||
if (t == NULL) break;
|
||||
e = t->oppositeEdge(v);
|
||||
} while (e != e0);
|
||||
|
||||
return vv;
|
||||
}
|
||||
|
||||
/////////////// VT relation ////////////////////////////
|
||||
|
||||
List *Vertex::VT() const
|
||||
{
|
||||
Triangle *t;
|
||||
Edge *e;
|
||||
Vertex *v;
|
||||
List *vt = new List();
|
||||
|
||||
if (e0 == NULL) return vt;
|
||||
|
||||
e = e0;
|
||||
do
|
||||
{
|
||||
v = e->oppositeVertex(this);
|
||||
t = e->leftTriangle(this);
|
||||
if (t == NULL) break;
|
||||
vt->appendTail(t);
|
||||
e = t->oppositeEdge(v);
|
||||
} while (e != e0);
|
||||
|
||||
if (e == e0 && vt->numels() > 1) return vt;
|
||||
|
||||
e = e0;
|
||||
do
|
||||
{
|
||||
v = e->oppositeVertex(this);
|
||||
t = e->rightTriangle(this);
|
||||
if (t == NULL) break;
|
||||
vt->appendHead(t);
|
||||
e = t->oppositeEdge(v);
|
||||
} while (e != e0);
|
||||
|
||||
return vt;
|
||||
}
|
||||
|
||||
/////////////// Returns the edge (this,v2) ////////////////
|
||||
|
||||
Edge *Vertex::getEdge(const Vertex *v2) const
|
||||
{
|
||||
List *ve = VE();
|
||||
Node *m;
|
||||
Edge *e;
|
||||
|
||||
FOREACHVEEDGE(ve, e, m)
|
||||
if (e->oppositeVertex(this) == v2) {delete(ve); return e;}
|
||||
|
||||
delete(ve);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
///////////// Returns the vertex valence ///////////////////////
|
||||
|
||||
int Vertex::valence() const
|
||||
{
|
||||
List *ve = VE();
|
||||
int n = ve->numels();
|
||||
delete(ve);
|
||||
return n;
|
||||
}
|
||||
|
||||
/////////////// Checks the boundary ////////////////////////////
|
||||
|
||||
int Vertex::isOnBoundary() const
|
||||
{
|
||||
Triangle *t;
|
||||
Edge *e;
|
||||
Vertex *v;
|
||||
|
||||
if (e0 == NULL) return 0;
|
||||
|
||||
e = e0;
|
||||
do
|
||||
{
|
||||
v = e->oppositeVertex(this);
|
||||
t = e->leftTriangle(this);
|
||||
if (t == NULL) return 1;
|
||||
e = t->oppositeEdge(v);
|
||||
} while (e != e0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/////////////// Next boundary edge ////////////////////////////
|
||||
|
||||
Edge *Vertex::nextBoundaryEdge() const
|
||||
{
|
||||
Triangle *t;
|
||||
Edge *e;
|
||||
Vertex *v;
|
||||
|
||||
if (e0 == NULL) return NULL;
|
||||
|
||||
e = e0;
|
||||
do
|
||||
{
|
||||
v = e->oppositeVertex(this);
|
||||
t = e->leftTriangle(this);
|
||||
if (t == NULL) return e;
|
||||
e = t->oppositeEdge(v);
|
||||
} while (e != e0);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/////////////// Next boundary vertex ////////////////////////////
|
||||
|
||||
Vertex *Vertex::nextOnBoundary() const
|
||||
{
|
||||
Edge *e = nextBoundaryEdge();
|
||||
if (e != NULL) return e->oppositeVertex(this);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/////////////// Previous boundary edge ////////////////////////////
|
||||
|
||||
Edge *Vertex::prevBoundaryEdge() const
|
||||
{
|
||||
Triangle *t;
|
||||
Edge *e;
|
||||
Vertex *v;
|
||||
|
||||
if (e0 == NULL) return NULL;
|
||||
|
||||
e = e0;
|
||||
do
|
||||
{
|
||||
v = e->oppositeVertex(this);
|
||||
t = e->rightTriangle(this);
|
||||
if (t == NULL) return e;
|
||||
e = t->oppositeEdge(v);
|
||||
} while (e != e0);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/////////////// Previous boundary vertex ////////////////////////////
|
||||
|
||||
Vertex *Vertex::prevOnBoundary() const
|
||||
{
|
||||
Edge *e = prevBoundaryEdge();
|
||||
if (e != NULL) return e->oppositeVertex(this);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//// TRUE iff vertex neighborhood is a flat disk. Always FALSE for boundary vertices.
|
||||
bool Vertex::isFlat() const
|
||||
{
|
||||
List *ve = VE();
|
||||
Node *n;
|
||||
Edge *e;
|
||||
|
||||
FOREACHVEEDGE(ve, e, n)
|
||||
if (e->getConvexity() != 0) { delete ve; return false; }
|
||||
|
||||
delete ve;
|
||||
return true;
|
||||
}
|
||||
|
||||
//// TRUE iff vertex neighborhood is made of either two flat halfdisks or one flat halfdisk on a rectilinear boundary.
|
||||
bool Vertex::isDoubleFlat(Edge **e1, Edge **e2) const
|
||||
{
|
||||
List *ve = VE();
|
||||
Node *n;
|
||||
Edge *e;
|
||||
int nne = 0;
|
||||
*e1 = *e2 = NULL;
|
||||
|
||||
FOREACHVEEDGE(ve, e, n)
|
||||
if (e->getConvexity() != 0)
|
||||
{
|
||||
if (++nne > 2) { delete ve; return false; }
|
||||
else if (nne == 1) *e1 = e;
|
||||
else *e2 = e;
|
||||
}
|
||||
delete ve;
|
||||
if (nne == 0) return true; // This means that vertex is flat
|
||||
if (nne == 1) return false; // This should not be possible, but just in case...
|
||||
return (!((*e1)->oppositeVertex(this)->exactMisalignment(this, (*e2)->oppositeVertex(this))));
|
||||
}
|
||||
|
||||
//// Unlinks the vertex if it is either Flat() or DoubleFlat(). On success, the function returns TRUE,
|
||||
//// the vertex neighborhood is retriangulated, and the geometric realization does not change.
|
||||
bool Vertex::removeIfRedundant(bool check_neighborhood)
|
||||
{
|
||||
Edge *e, *e1 = NULL, *e2 = NULL;
|
||||
if (!isDoubleFlat(&e1, &e2)) return false;
|
||||
|
||||
Node *n;
|
||||
Vertex *vo1, *vo2;
|
||||
List *ve;
|
||||
|
||||
if (check_neighborhood)
|
||||
{
|
||||
ve = VT();
|
||||
Triangle *t;
|
||||
FOREACHVTTRIANGLE(ve, t, n) if (t->isExactlyDegenerate()) { delete ve; return false; }
|
||||
delete ve;
|
||||
ve = VE();
|
||||
FOREACHVEEDGE(ve, e, n) if (e->overlaps()) { delete ve; return false; }
|
||||
} else ve = VE();
|
||||
|
||||
if (e1 != NULL) ve->removeNode(e1); // means isDoubleFlat()
|
||||
if (e2 != NULL) ve->removeNode(e2); // means isDoubleFlat()
|
||||
if (e2 != NULL && *e1->oppositeVertex(this) == *e2->oppositeVertex(this)) { delete ve; return false; }
|
||||
|
||||
while (1)
|
||||
{
|
||||
FOREACHVEEDGE(ve, e, n)
|
||||
{
|
||||
vo1 = e->t1->oppositeVertex(e);
|
||||
vo2 = e->t2->oppositeVertex(e);
|
||||
if (!e->v1->exactSameSideOnPlane(e->v2, vo1, vo2) && vo1->exactMisalignment(e->v1, vo2) && vo1->exactMisalignment(e->v2, vo2))
|
||||
{
|
||||
if (!e->swap()) { delete ve; return false; }
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (n != NULL) ve->removeCell(n);
|
||||
else break;
|
||||
}
|
||||
|
||||
if (e1 != NULL) e = e1; // means isDoubleFlat()
|
||||
else if (ve->numels() == 3) e = (Edge *)ve->head()->data;
|
||||
else
|
||||
{
|
||||
FOREACHVEEDGE(ve, e, n)
|
||||
if (!e->t1->oppositeVertex(e)->exactMisalignment(this, e->t2->oppositeVertex(e))) break;
|
||||
if (n == NULL) { delete ve; return false; } // Should not happen...
|
||||
else e = (Edge *)((n == ve->head()) ? (ve->tail()) : (n->prev()))->data;
|
||||
}
|
||||
delete ve;
|
||||
|
||||
if (e->v1 == this) e->invert();
|
||||
if (e->collapseOnV1() == NULL) return false; // This is a very rare case. Should be treated, but does not hurt too much.
|
||||
else return true;
|
||||
}
|
||||
|
||||
///// Vertex normal as weighted average of the incident triangle normals ////
|
||||
///// The weight is the incidence angle. ////
|
||||
///// Possible degenerate triangles are not taken into account. ////
|
||||
|
||||
Point Vertex::getNormal() const
|
||||
{
|
||||
List *vt = VT();
|
||||
Node *n;
|
||||
Triangle *t;
|
||||
coord pa;
|
||||
Point tnor, ttn;
|
||||
|
||||
FOREACHVTTRIANGLE(vt, t, n)
|
||||
{
|
||||
pa = t->getAngle(this);
|
||||
ttn = t->getNormal();
|
||||
if (!ttn.isNull()) tnor = tnor+(ttn*pa);
|
||||
}
|
||||
delete(vt);
|
||||
|
||||
if (tnor.isNull()) return Point(0,0,0);
|
||||
|
||||
tnor.normalize();
|
||||
return tnor;
|
||||
}
|
||||
|
||||
|
||||
////////// Returns the angle between the two boundary edges ////////
|
||||
|
||||
double Vertex::getBoundaryAngle() const
|
||||
{
|
||||
Edge *e1 = prevBoundaryEdge();
|
||||
Edge *e2 = nextBoundaryEdge();
|
||||
if (e1 == NULL || e2 == NULL) return -1.0;
|
||||
Vertex *v1 = e1->oppositeVertex(this);
|
||||
Vertex *v2 = e2->oppositeVertex(this);
|
||||
double ang = getAngle(v1, v2);
|
||||
|
||||
return ang;
|
||||
}
|
||||
|
||||
|
||||
////////// Returns the discriminant for triangulation ////////
|
||||
|
||||
double Vertex::getAngleForTriangulation() const
|
||||
{
|
||||
Edge *e1 = prevBoundaryEdge();
|
||||
Edge *e2 = nextBoundaryEdge();
|
||||
if (e1 == NULL || e2 == NULL) return DBL_MAX;
|
||||
Triangle *t1 = e1->getBoundaryTriangle();
|
||||
Triangle *t2 = e2->getBoundaryTriangle();
|
||||
Vertex *v1 = e1->oppositeVertex(this);
|
||||
Vertex *v2 = e2->oppositeVertex(this);
|
||||
if ((*v2)==(*v1)) return -2;
|
||||
if (distance(v1)*distance(v2) == 0.0) return -1;
|
||||
|
||||
double ang = getAngle(v1, v2);
|
||||
if (ang == M_PI) return 3*M_PI;
|
||||
if (ang == 0) return 0;
|
||||
|
||||
Edge e3(v1,v2);
|
||||
Triangle t(e1,e2,&e3);
|
||||
double da1 = t.getDAngle(t1);
|
||||
double da2 = t.getDAngle(t2);
|
||||
|
||||
if (da1==M_PI && da2==M_PI) return (DBL_MAX/2.0);
|
||||
if (da1==M_PI || da2==M_PI) return (DBL_MAX/4.0);
|
||||
|
||||
return da1+da2+ang;
|
||||
}
|
||||
|
||||
|
||||
////////// Returns the AP discriminant for triangulation ////////
|
||||
|
||||
double Vertex::getAngleOnAveragePlane(Point *nor) const
|
||||
{
|
||||
Edge *e1 = prevBoundaryEdge();
|
||||
Edge *e2 = nextBoundaryEdge();
|
||||
if (e1 == NULL || e2 == NULL) return DBL_MAX;
|
||||
Vertex *v1 = e1->oppositeVertex(this);
|
||||
Vertex *v2 = e2->oppositeVertex(this);
|
||||
Point p, p1, p2;
|
||||
p1.setValue(v1);
|
||||
p2.setValue(v2);
|
||||
p.setValue(this);
|
||||
p.project(nor);
|
||||
p1.project(nor);
|
||||
p2.project(nor);
|
||||
if (p.distance(p1)*p.distance(p2) == 0.0)
|
||||
{
|
||||
TMesh::warning("getAngleOnAveragePlane: coincident projections\n");
|
||||
return 0.0;
|
||||
}
|
||||
double ang = p.getAngle(&p1, &p2);
|
||||
if (nor->side3D(&p1, &p, &p2) < 0) ang = -(ang-(2*M_PI));
|
||||
|
||||
return ang;
|
||||
}
|
||||
|
||||
|
||||
///// mean curvature at the vertex: sum of signed dihedral angles ////
|
||||
|
||||
double Vertex::totalDihedralAngle() const
|
||||
{
|
||||
List *ve = VE();
|
||||
double mc = 0;
|
||||
Edge *e;
|
||||
Node *n;
|
||||
|
||||
FOREACHVEEDGE(ve, e, n)
|
||||
if (e->isOnBoundary()) {delete(ve); return DBL_MAX;}
|
||||
else mc -= (e->dihedralAngle()-M_PI);
|
||||
mc /= ve->numels();
|
||||
|
||||
delete(ve);
|
||||
|
||||
return mc;
|
||||
}
|
||||
|
||||
|
||||
///// Sum of all the incident angles ////
|
||||
|
||||
double Vertex::totalAngle() const
|
||||
{
|
||||
List *ve = VE();
|
||||
double ta = 0.0;
|
||||
Edge *e;
|
||||
Node *n;
|
||||
|
||||
FOREACHVEEDGE(ve, e, n)
|
||||
if (e->isOnBoundary()) {delete(ve); return -1.0;}
|
||||
else ta += e->leftTriangle(this)->getAngle(this);
|
||||
|
||||
delete(ve);
|
||||
|
||||
return ta;
|
||||
}
|
||||
|
||||
|
||||
/////// Voronoi area around the vertex ///////////////////
|
||||
|
||||
double Vertex::voronoiArea() const
|
||||
{
|
||||
List *vt = VT();
|
||||
Node *n;
|
||||
Triangle *t;
|
||||
double va = 0.0;
|
||||
|
||||
FOREACHVTTRIANGLE(vt, t, n) va += t->area();
|
||||
delete(vt);
|
||||
|
||||
return va/3.0;
|
||||
}
|
||||
|
||||
|
||||
// Closes the gap starting from this vertex
|
||||
// If 'check_geom' is true, the zipping stops
|
||||
// whether the coordinates of the vertices to
|
||||
// be zipped are not equal.
|
||||
|
||||
int Vertex::zip(const bool check_geom)
|
||||
{
|
||||
Node *n;
|
||||
Edge *e;
|
||||
|
||||
List *ve = VE();
|
||||
Edge *be1 = (Edge *)ve->head()->data;
|
||||
Edge *be2 = (Edge *)ve->tail()->data;
|
||||
delete(ve);
|
||||
if (!be1->isOnBoundary() || !be2->isOnBoundary()) return 0;
|
||||
Vertex *ov1 = be1->oppositeVertex(this);
|
||||
Vertex *ov2 = be2->oppositeVertex(this);
|
||||
|
||||
if (check_geom && ((*ov1)!=(*ov2))) return 0;
|
||||
|
||||
if (ov1 != ov2)
|
||||
{
|
||||
ve = ov2->VE();
|
||||
FOREACHVEEDGE(ve, e, n) e->replaceVertex(ov2, ov1);
|
||||
delete(ve);
|
||||
ov2->e0 = NULL;
|
||||
}
|
||||
|
||||
Triangle *t = (be2->t1!=NULL)?(be2->t1):(be2->t2);
|
||||
t->replaceEdge(be2, be1);
|
||||
be1->replaceTriangle(NULL, t);
|
||||
be2->v1=be2->v2=NULL;
|
||||
e0 = ov1->e0 = be1;
|
||||
return 1+ov1->zip(check_geom);
|
||||
}
|
||||
|
||||
|
||||
/////// Progressive Mesh: Vertex split ///////////////////
|
||||
|
||||
//Edge *Vertex::inverseCollapse(Vertex *v2, Vertex *v3, Vertex *v4)
|
||||
//{
|
||||
// Edge *e, *e1, *e2=NULL, *e3=NULL, *e4;
|
||||
// Triangle *t1, *t2, *ta1, *ta4;
|
||||
// Node *n;
|
||||
// Vertex *tmp;
|
||||
//
|
||||
// List *ve = VE();
|
||||
// FOREACHVEEDGE(ve, e, n)
|
||||
// {
|
||||
// tmp = e->oppositeVertex(this);
|
||||
// if (tmp == v3) e2 = e;
|
||||
// else if (tmp == v4) e3 = e;
|
||||
// }
|
||||
//
|
||||
// if (!e2 || !e3) {delete(ve); return NULL;}
|
||||
//
|
||||
// ta1 = e2->rightTriangle(this);
|
||||
// ta4 = e3->leftTriangle(this);
|
||||
//
|
||||
// FOREACHVEEDGE(ve, e, n) if (e == e3) break;
|
||||
// FOREACHNODECIRCULAR((*ve), n, n)
|
||||
// {
|
||||
// e = ((Edge *)n->data);
|
||||
// if (e == e2) break;
|
||||
// else e->replaceVertex(this, v2);
|
||||
// }
|
||||
// delete(ve);
|
||||
//
|
||||
// e = new Edge(this, v2);
|
||||
// e1 = new Edge(v2, v3);
|
||||
// e4 = new Edge(v2, v4);
|
||||
// t1 = newTriangle(e, e1, e2);
|
||||
// t2 = newTriangle(e, e3, e4);
|
||||
//
|
||||
// e->t1 = t1; e->t2 = t2;
|
||||
// e2->replaceTriangle(ta1, t1);
|
||||
// e3->replaceTriangle(ta4, t2);
|
||||
// if (ta1) ta1->replaceEdge(e2, e1);
|
||||
// if (ta4) ta4->replaceEdge(e3, e4);
|
||||
// e1->t1 = t1; e1->t2 = ta1;
|
||||
// e4->t1 = ta4; e4->t2 = t2;
|
||||
// v2->e0 = e0 = e;
|
||||
//
|
||||
//// Point p = (*this)-((*v2)-(*this));
|
||||
//// x = p.x; y = p.y; z = p.z;
|
||||
//
|
||||
// return e;
|
||||
//}
|
||||
|
||||
|
||||
/////// Progressive Mesh: Vertex split ///////////////////
|
||||
|
||||
Edge *Vertex::inverseCollapse(Vertex *v2, Edge *e, Edge *e1, Edge *e2, Edge *e3, Edge *e4, Triangle *t1, Triangle *t2)
|
||||
{
|
||||
Triangle *ta1, *ta4;
|
||||
Node *n;
|
||||
Edge *f;
|
||||
|
||||
ta1 = e2->rightTriangle(this);
|
||||
ta4 = e3->leftTriangle(this);
|
||||
|
||||
List *ve = VE();
|
||||
FOREACHVEEDGE(ve, f, n) if (f == e3) break;
|
||||
FOREACHNODECIRCULAR((*ve), n, n)
|
||||
{
|
||||
f = ((Edge *)n->data);
|
||||
if (f == e2) break;
|
||||
else f->replaceVertex(this, v2);
|
||||
}
|
||||
delete(ve);
|
||||
|
||||
e->v1 = this; e->v2 = v2;
|
||||
e1->v1 = v2; e1->v2 = e2->oppositeVertex(this);
|
||||
e4->v1 = v2; e4->v2 = e3->oppositeVertex(this);
|
||||
t1->e1 = e; t1->e2 = e1; t1->e3 = e2;
|
||||
t2->e1 = e; t2->e2 = e3; t2->e3 = e4;
|
||||
|
||||
e->t1 = t1; e->t2 = t2;
|
||||
e2->replaceTriangle(ta1, t1);
|
||||
e3->replaceTriangle(ta4, t2);
|
||||
if (ta1) ta1->replaceEdge(e2, e1);
|
||||
if (ta4) ta4->replaceEdge(e3, e4);
|
||||
e1->t1 = t1; e1->t2 = ta1;
|
||||
e4->t1 = ta4; e4->t2 = t2;
|
||||
v2->e0 = e0 = e;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
} //namespace T_MESH
|
@ -214,6 +214,8 @@ set(SLIC3R_GUI_SOURCES
|
||||
Utils/Http.hpp
|
||||
Utils/FixModelByWin10.cpp
|
||||
Utils/FixModelByWin10.hpp
|
||||
Utils/FixModelByMeshFix.cpp
|
||||
Utils/FixModelByMeshFix.hpp
|
||||
Utils/OctoPrint.cpp
|
||||
Utils/OctoPrint.hpp
|
||||
Utils/Duet.cpp
|
||||
@ -260,7 +262,7 @@ add_library(libslic3r_gui STATIC ${SLIC3R_GUI_SOURCES})
|
||||
|
||||
encoding_check(libslic3r_gui)
|
||||
|
||||
target_link_libraries(libslic3r_gui libslic3r avrdude cereal imgui GLEW::GLEW OpenGL::GL hidapi libcurl ${wxWidgets_LIBRARIES})
|
||||
target_link_libraries(libslic3r_gui libslic3r avrdude cereal imgui GLEW::GLEW OpenGL::GL hidapi libcurl meshfix ${wxWidgets_LIBRARIES})
|
||||
|
||||
if (MSVC)
|
||||
target_link_libraries(libslic3r_gui Setupapi.lib)
|
||||
|
@ -694,8 +694,18 @@ wxMenuItem* MenuFactory::append_menu_item_fix_through_netfabb(wxMenu* menu)
|
||||
if (!is_windows10())
|
||||
return nullptr;
|
||||
wxMenuItem* menu_item = append_menu_item(menu, wxID_ANY, _L("Fix through the Netfabb"), "",
|
||||
[](wxCommandEvent&) { obj_list()->fix_through_netfabb(); }, "", menu,
|
||||
[]() {return plater()->can_fix_through_netfabb(); }, m_parent);
|
||||
[](wxCommandEvent&) { obj_list()->repair_mesh(ObjectList::rmaNetfabb); }, "", menu,
|
||||
[]() {return plater()->can_repair_mesh(); }, m_parent);
|
||||
|
||||
return menu_item;
|
||||
}
|
||||
|
||||
|
||||
wxMenuItem* MenuFactory::append_menu_item_fix_through_meshfix(wxMenu* menu)
|
||||
{
|
||||
wxMenuItem* menu_item = append_menu_item(menu, wxID_ANY, _L("Fix through MeshFix (experimental)"), "",
|
||||
[](wxCommandEvent&) { obj_list()->repair_mesh(ObjectList::rmaMeshfix); }, "", menu,
|
||||
[]() {return plater()->can_repair_mesh(); }, m_parent);
|
||||
|
||||
return menu_item;
|
||||
}
|
||||
@ -923,6 +933,7 @@ void MenuFactory::create_common_object_menu(wxMenu* menu)
|
||||
append_menu_item_scale_selection_to_fit_print_volume(menu);
|
||||
|
||||
append_menu_item_fix_through_netfabb(menu);
|
||||
append_menu_item_fix_through_meshfix(menu);
|
||||
append_menu_item_simplify(menu);
|
||||
append_menu_items_mirror(menu);
|
||||
}
|
||||
|
@ -92,6 +92,7 @@ private:
|
||||
wxMenuItem* append_menu_item_printable(wxMenu* menu);
|
||||
void append_menu_items_osx(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_fix_through_netfabb(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_fix_through_meshfix(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_simplify(wxMenu* menu);
|
||||
void append_menu_item_export_stl(wxMenu* menu);
|
||||
void append_menu_item_reload_from_disk(wxMenu* menu);
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <wx/numformatter.h>
|
||||
|
||||
#include "slic3r/Utils/FixModelByWin10.hpp"
|
||||
#include "slic3r/Utils/FixModelByMeshFix.hpp"
|
||||
|
||||
#ifdef __WXMSW__
|
||||
#include "wx/uiaction.h"
|
||||
@ -916,7 +917,7 @@ void ObjectList::list_manipulation(const wxPoint& mouse_pos, bool evt_context_me
|
||||
{
|
||||
if (is_windows10() && m_objects_model->HasWarningIcon(item) &&
|
||||
mouse_pos.x > 2 * wxGetApp().em_unit() && mouse_pos.x < 4 * wxGetApp().em_unit())
|
||||
fix_through_netfabb();
|
||||
repair_mesh(rmaNetfabb);
|
||||
else if (evt_context_menu)
|
||||
show_context_menu(evt_context_menu); // show context menu for "Name" column too
|
||||
}
|
||||
@ -4031,7 +4032,7 @@ void ObjectList::rename_item()
|
||||
update_name_in_model(item);
|
||||
}
|
||||
|
||||
void ObjectList::fix_through_netfabb()
|
||||
void ObjectList::repair_mesh(ObjectList::REPAIR_MESH_ALG alg)
|
||||
{
|
||||
// Do not fix anything when a gizmo is open. There might be issues with updates
|
||||
// and what is worse, the snapshot time would refer to the internal stack.
|
||||
@ -4051,28 +4052,28 @@ void ObjectList::fix_through_netfabb()
|
||||
// clear selections from the non-broken models if any exists
|
||||
// and than fill names of models to repairing
|
||||
if (vol_idxs.empty()) {
|
||||
#if !FIX_THROUGH_NETFABB_ALWAYS
|
||||
#if !FIX_MESH_ALWAYS
|
||||
for (int i = int(obj_idxs.size())-1; i >= 0; --i)
|
||||
if (object(obj_idxs[i])->get_repaired_errors_count() == 0)
|
||||
obj_idxs.erase(obj_idxs.begin()+i);
|
||||
#endif // FIX_THROUGH_NETFABB_ALWAYS
|
||||
#endif // FIX_MESH_ALWAYS
|
||||
for (int obj_idx : obj_idxs)
|
||||
model_names.push_back(object(obj_idx)->name);
|
||||
}
|
||||
else {
|
||||
ModelObject* obj = object(obj_idxs.front());
|
||||
#if !FIX_THROUGH_NETFABB_ALWAYS
|
||||
#if !FIX_MESH_ALWAYS
|
||||
for (int i = int(vol_idxs.size()) - 1; i >= 0; --i)
|
||||
if (obj->get_repaired_errors_count(vol_idxs[i]) == 0)
|
||||
vol_idxs.erase(vol_idxs.begin() + i);
|
||||
#endif // FIX_THROUGH_NETFABB_ALWAYS
|
||||
#endif // FIX_MESH_ALWAYS
|
||||
for (int vol_idx : vol_idxs)
|
||||
model_names.push_back(obj->volumes[vol_idx]->name);
|
||||
}
|
||||
|
||||
auto plater = wxGetApp().plater();
|
||||
|
||||
auto fix_and_update_progress = [this, plater, model_names](const int obj_idx, const int vol_idx,
|
||||
auto fix_and_update_progress = [this, plater, model_names, alg](const int obj_idx, const int vol_idx,
|
||||
int model_idx,
|
||||
wxProgressDialog& progress_dlg,
|
||||
std::vector<std::string>& succes_models,
|
||||
@ -4091,8 +4092,19 @@ void ObjectList::fix_through_netfabb()
|
||||
|
||||
plater->clear_before_change_mesh(obj_idx);
|
||||
std::string res;
|
||||
if (!fix_model_by_win10_sdk_gui(*(object(obj_idx)), vol_idx, progress_dlg, msg, res))
|
||||
return false;
|
||||
bool result = false;
|
||||
switch (alg) {
|
||||
case rmaNetfabb:
|
||||
result = fix_model_by_win10_sdk_gui(*(object(obj_idx)), vol_idx, progress_dlg, msg, res);
|
||||
break;
|
||||
case rmaMeshfix:
|
||||
result = fix_model_by_meshfix(*(object(obj_idx)), vol_idx, progress_dlg, msg, res);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!result) return false;
|
||||
|
||||
wxGetApp().plater()->changed_mesh(obj_idx);
|
||||
|
||||
plater->changed_mesh(obj_idx);
|
||||
@ -4108,19 +4120,19 @@ void ObjectList::fix_through_netfabb()
|
||||
return true;
|
||||
};
|
||||
|
||||
Plater::TakeSnapshot snapshot(plater, _L("Fix through NetFabb"));
|
||||
Plater::TakeSnapshot snapshot(plater, _L("Repair model mesh"));
|
||||
|
||||
// Open a progress dialog.
|
||||
wxProgressDialog progress_dlg(_L("Fixing through NetFabb"), "", 100, find_toplevel_parent(plater),
|
||||
wxProgressDialog progress_dlg(_L("Repair model mesh"), "", 100, find_toplevel_parent(plater),
|
||||
wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT);
|
||||
int model_idx{ 0 };
|
||||
if (vol_idxs.empty()) {
|
||||
int vol_idx{ -1 };
|
||||
for (int obj_idx : obj_idxs) {
|
||||
#if !FIX_THROUGH_NETFABB_ALWAYS
|
||||
#if !FIX_MESH_ALWAYS
|
||||
if (object(obj_idx)->get_repaired_errors_count(vol_idx) == 0)
|
||||
continue;
|
||||
#endif // FIX_THROUGH_NETFABB_ALWAYS
|
||||
#endif // FIX_MESH_ALWAYS
|
||||
if (!fix_and_update_progress(obj_idx, vol_idx, model_idx, progress_dlg, succes_models, failed_models))
|
||||
break;
|
||||
model_idx++;
|
||||
@ -4153,7 +4165,7 @@ void ObjectList::fix_through_netfabb()
|
||||
}
|
||||
if (msg.IsEmpty())
|
||||
msg = _L("Repairing was canceled");
|
||||
plater->get_notification_manager()->push_notification(NotificationType::NetfabbFinished, NotificationManager::NotificationLevel::PrintInfoShortNotificationLevel, boost::nowide::narrow(msg));
|
||||
plater->get_notification_manager()->push_notification(NotificationType::RepairMeshFinished, NotificationManager::NotificationLevel::PrintInfoShortNotificationLevel, boost::nowide::narrow(msg));
|
||||
}
|
||||
|
||||
void ObjectList::simplify()
|
||||
|
@ -37,7 +37,7 @@ typedef std::pair<coordf_t, coordf_t> t_layer_height_range;
|
||||
typedef std::map<t_layer_height_range, ModelConfig> t_layer_config_ranges;
|
||||
|
||||
// Manifold mesh may contain self-intersections, so we want to always allow fixing the mesh.
|
||||
#define FIX_THROUGH_NETFABB_ALWAYS 1
|
||||
#define FIX_MESH_ALWAYS 1
|
||||
|
||||
namespace GUI {
|
||||
|
||||
@ -367,7 +367,8 @@ public:
|
||||
void instances_to_separated_objects(const int obj_idx);
|
||||
void split_instances();
|
||||
void rename_item();
|
||||
void fix_through_netfabb();
|
||||
enum REPAIR_MESH_ALG{rmaNetfabb, rmaMeshfix};
|
||||
void repair_mesh(REPAIR_MESH_ALG alg);
|
||||
void simplify();
|
||||
void update_item_error_icon(const int obj_idx, int vol_idx) const ;
|
||||
|
||||
|
@ -130,7 +130,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
||||
if (m_fix_throught_netfab_bitmap->GetBitmap().GetRefData() == wxNullBitmap.GetRefData())
|
||||
return;
|
||||
|
||||
wxGetApp().obj_list()->fix_through_netfabb();
|
||||
wxGetApp().obj_list()->repair_mesh(ObjectList::rmaNetfabb);
|
||||
update_warning_icon_state(wxGetApp().obj_list()->get_mesh_errors_info());
|
||||
});
|
||||
|
||||
|
@ -109,8 +109,8 @@ enum class NotificationType
|
||||
// Give user advice to simplify object with big amount of triangles
|
||||
// Contains ObjectID for closing when object is deleted
|
||||
SimplifySuggestion,
|
||||
// information about netfabb is finished repairing model (blocking proccess)
|
||||
NetfabbFinished,
|
||||
// information about finished model repairing (blocking proccess)
|
||||
RepairMeshFinished,
|
||||
// Short meesage to fill space between start and finish of export
|
||||
ExportOngoing,
|
||||
};
|
||||
|
@ -1935,7 +1935,7 @@ struct Plater::priv
|
||||
bool can_split_to_volumes() const;
|
||||
bool can_arrange() const;
|
||||
bool can_layers_editing() const;
|
||||
bool can_fix_through_netfabb() const;
|
||||
bool can_repair_mesh() const;
|
||||
bool can_simplify() const;
|
||||
bool can_set_instance_to_object() const;
|
||||
bool can_mirror() const;
|
||||
@ -4642,15 +4642,15 @@ bool Plater::priv::can_delete_all() const
|
||||
return !model.objects.empty();
|
||||
}
|
||||
|
||||
bool Plater::priv::can_fix_through_netfabb() const
|
||||
bool Plater::priv::can_repair_mesh() const
|
||||
{
|
||||
std::vector<int> obj_idxs, vol_idxs;
|
||||
sidebar->obj_list()->get_selection_indexes(obj_idxs, vol_idxs);
|
||||
|
||||
#if FIX_THROUGH_NETFABB_ALWAYS
|
||||
#if FIX_MESH_ALWAYS
|
||||
// Fixing always.
|
||||
return ! obj_idxs.empty() || ! vol_idxs.empty();
|
||||
#else // FIX_THROUGH_NETFABB_ALWAYS
|
||||
#else // FIX_MESH_ALWAYS
|
||||
// Fixing only if the model is not manifold.
|
||||
if (vol_idxs.empty()) {
|
||||
for (auto obj_idx : obj_idxs)
|
||||
@ -4664,7 +4664,7 @@ bool Plater::priv::can_fix_through_netfabb() const
|
||||
if (model.objects[obj_idx]->get_repaired_errors_count(vol_idx) > 0)
|
||||
return true;
|
||||
return false;
|
||||
#endif // FIX_THROUGH_NETFABB_ALWAYS
|
||||
#endif // FIX_MESH_ALWAYS
|
||||
}
|
||||
|
||||
bool Plater::priv::can_simplify() const
|
||||
@ -6848,7 +6848,7 @@ bool Plater::can_delete_all() const { return p->can_delete_all(); }
|
||||
bool Plater::can_increase_instances() const { return p->can_increase_instances(); }
|
||||
bool Plater::can_decrease_instances() const { return p->can_decrease_instances(); }
|
||||
bool Plater::can_set_instance_to_object() const { return p->can_set_instance_to_object(); }
|
||||
bool Plater::can_fix_through_netfabb() const { return p->can_fix_through_netfabb(); }
|
||||
bool Plater::can_repair_mesh() const { return p->can_repair_mesh(); }
|
||||
bool Plater::can_simplify() const { return p->can_simplify(); }
|
||||
bool Plater::can_split_to_objects() const { return p->can_split_to_objects(); }
|
||||
bool Plater::can_split_to_volumes() const { return p->can_split_to_volumes(); }
|
||||
|
@ -309,7 +309,7 @@ public:
|
||||
bool can_increase_instances() const;
|
||||
bool can_decrease_instances() const;
|
||||
bool can_set_instance_to_object() const;
|
||||
bool can_fix_through_netfabb() const;
|
||||
bool can_repair_mesh() const;
|
||||
bool can_simplify() const;
|
||||
bool can_split_to_objects() const;
|
||||
bool can_split_to_volumes() const;
|
||||
|
395
src/slic3r/Utils/FixModelByMeshFix.cpp
Normal file
395
src/slic3r/Utils/FixModelByMeshFix.cpp
Normal file
@ -0,0 +1,395 @@
|
||||
#include "FixModelByMeshFix.hpp"
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
|
||||
#include "tmesh.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <condition_variable>
|
||||
#include <exception>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/nowide/convert.hpp>
|
||||
#include <boost/nowide/cstdio.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/Print.hpp"
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
#include "libslic3r/Format/3mf.hpp"
|
||||
#include "../GUI/GUI.hpp"
|
||||
#include "../GUI/I18N.hpp"
|
||||
#include "../GUI/MsgDialog.hpp"
|
||||
|
||||
#include <wx/msgdlg.h>
|
||||
#include <wx/progdlg.h>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class RepairCanceledException: public std::exception {
|
||||
public:
|
||||
const char* what() const throw () {
|
||||
return "Model repair has been canceled";
|
||||
}
|
||||
};
|
||||
|
||||
class RepairFailedException: public std::exception {
|
||||
public:
|
||||
const char* what() const throw () {
|
||||
return "Model repair has failed";
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
using namespace T_MESH;
|
||||
|
||||
double closestPair(List *bl1, List *bl2, Vertex **closest_on_bl1, Vertex **closest_on_bl2)
|
||||
{
|
||||
Node *n, *m;
|
||||
Vertex *v, *w;
|
||||
double adist, mindist = DBL_MAX;
|
||||
|
||||
FOREACHVVVERTEX(bl1, v, n)
|
||||
FOREACHVVVERTEX(bl2, w, m)
|
||||
if ((adist = w->squaredDistance(v)) < mindist)
|
||||
{
|
||||
mindist = adist;
|
||||
*closest_on_bl1 = v;
|
||||
*closest_on_bl2 = w;
|
||||
}
|
||||
|
||||
return mindist;
|
||||
}
|
||||
|
||||
bool joinClosestComponents(Basic_TMesh *tin)
|
||||
{
|
||||
Vertex *v, *w, *gv, *gw;
|
||||
Triangle *t, *s;
|
||||
Node *n;
|
||||
List triList, boundary_loops, *one_loop;
|
||||
List **bloops_array;
|
||||
int i, j, numloops;
|
||||
|
||||
// Mark triangles with connected component's unique ID
|
||||
i = 0;
|
||||
FOREACHVTTRIANGLE((&(tin->T)), t, n) t->info = NULL;
|
||||
FOREACHVTTRIANGLE((&(tin->T)), t, n) if (t->info == NULL)
|
||||
{
|
||||
i++;
|
||||
triList.appendHead(t);
|
||||
t->info = (void *)(intptr_t)i;
|
||||
|
||||
while (triList.numels())
|
||||
{
|
||||
t = (Triangle *)triList.popHead();
|
||||
if ((s = t->t1()) != NULL && s->info == NULL) {triList.appendHead(s); s->info = (void *)(intptr_t)i;}
|
||||
if ((s = t->t2()) != NULL && s->info == NULL) {triList.appendHead(s); s->info = (void *)(intptr_t)i;}
|
||||
if ((s = t->t3()) != NULL && s->info == NULL) {triList.appendHead(s); s->info = (void *)(intptr_t)i;}
|
||||
}
|
||||
}
|
||||
|
||||
if (i<2)
|
||||
{
|
||||
FOREACHVTTRIANGLE((&(tin->T)), t, n) t->info = NULL;
|
||||
// JMesh::info("Mesh is a single component. Nothing done.");
|
||||
return false;
|
||||
}
|
||||
|
||||
FOREACHVTTRIANGLE((&(tin->T)), t, n)
|
||||
{
|
||||
t->v1()->info = t->v2()->info = t->v3()->info = t->info;
|
||||
}
|
||||
|
||||
FOREACHVVVERTEX((&(tin->V)), v, n) if (!IS_VISITED2(v) && v->isOnBoundary())
|
||||
{
|
||||
w = v;
|
||||
one_loop = new List;
|
||||
do
|
||||
{
|
||||
one_loop->appendHead(w); MARK_VISIT2(w);
|
||||
w = w->nextOnBoundary();
|
||||
}while (w != v);
|
||||
boundary_loops.appendHead(one_loop);
|
||||
}
|
||||
FOREACHVVVERTEX((&(tin->V)), v, n) UNMARK_VISIT2(v);
|
||||
|
||||
bloops_array = (List **)boundary_loops.toArray();
|
||||
numloops = boundary_loops.numels();
|
||||
|
||||
double adist,
|
||||
mindist = DBL_MAX;
|
||||
|
||||
gv = NULL;
|
||||
for (i = 0; i < numloops; i++)
|
||||
for (j = 0; j < numloops; j++)
|
||||
if (((Vertex*) bloops_array[i]->head()->data)->info != ((Vertex*) bloops_array[j]->head()->data)->info)
|
||||
{
|
||||
adist = closestPair(bloops_array[i], bloops_array[j], &v, &w);
|
||||
if (adist < mindist) {
|
||||
mindist = adist;
|
||||
gv = v;
|
||||
gw = w;
|
||||
}
|
||||
}
|
||||
|
||||
if (gv != NULL)
|
||||
tin->joinBoundaryLoops(gv, gw, 1, 0);
|
||||
|
||||
FOREACHVTTRIANGLE((&(tin->T)), t, n)
|
||||
t->info = NULL;
|
||||
FOREACHVVVERTEX((&(tin->V)), v, n)
|
||||
v->info = NULL;
|
||||
|
||||
free(bloops_array);
|
||||
while ((one_loop = (List*) boundary_loops.popHead()) != NULL)
|
||||
delete one_loop;
|
||||
|
||||
return (gv != NULL);
|
||||
}
|
||||
|
||||
class Basic_TMesh_Adapter: public Basic_TMesh {
|
||||
public:
|
||||
void load_indexed_triangle_set(const indexed_triangle_set &its) {
|
||||
|
||||
for (const auto &vertex : its.vertices) {
|
||||
this->V.appendTail(this->newVertex(vertex.x(), vertex.y(), vertex.z()));
|
||||
}
|
||||
|
||||
int nv = this->V.numels();
|
||||
Node *n = this->V.head();
|
||||
ExtVertex **tmp = (ExtVertex**) malloc(sizeof(ExtVertex*) * nv);
|
||||
for (int index = 0; index < nv; ++index) {
|
||||
tmp[index] = new ExtVertex(static_cast<Vertex*>(n->data));
|
||||
n = n->next();
|
||||
}
|
||||
|
||||
for (const auto &face : its.indices) {
|
||||
if (face.x() == face.y() || face.y() == face.z() || face.z() == face.x()) {
|
||||
continue;
|
||||
}
|
||||
this->CreateIndexedTriangle(tmp, face.x(), face.y(), face.z());
|
||||
}
|
||||
|
||||
closeLoadingSession(this->T.numels(), tmp, false);
|
||||
}
|
||||
|
||||
indexed_triangle_set to_indexed_triangle_set() {
|
||||
indexed_triangle_set out;
|
||||
out.vertices.resize(this->V.numels());
|
||||
out.indices.resize(this->T.numels());
|
||||
|
||||
Node *n = this->V.head();
|
||||
for (int vertex_idx = 0; vertex_idx < this->V.numels(); ++vertex_idx) {
|
||||
T_MESH::Vertex *v = static_cast<T_MESH::Vertex*>(n->data);
|
||||
out.vertices[vertex_idx] = Vec3f { float(v->x), float(v->y), float(v->z) };
|
||||
n = n->next();
|
||||
//store vertex index in the first coord, makes export of faces simple (inspired by saveOBJ method)
|
||||
v->x = vertex_idx;
|
||||
}
|
||||
|
||||
n = this->T.head();
|
||||
for (int face_idx = 0; face_idx < this->T.numels(); ++face_idx) {
|
||||
T_MESH::Triangle *t = static_cast<T_MESH::Triangle*>(n->data);
|
||||
out.indices[face_idx] = Vec3i { int(t->v1()->x), int(t->v2()->x), int(t->v3()->x) };
|
||||
n = n->next();
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
bool meshclean_single_iteration(int inner_loops, const std::atomic<bool> &canceled) {
|
||||
bool ni, nd;
|
||||
Triangle *t;
|
||||
Node *m;
|
||||
|
||||
nd = strongDegeneracyRemoval(inner_loops);
|
||||
if (canceled)
|
||||
throw RepairCanceledException();
|
||||
deselectTriangles();
|
||||
invertSelection();
|
||||
ni = strongIntersectionRemoval(inner_loops);
|
||||
if (canceled)
|
||||
throw RepairCanceledException();
|
||||
if (ni && nd) {
|
||||
FOREACHTRIANGLE(t, m)
|
||||
if (t->isExactlyDegenerate())
|
||||
ni = false;
|
||||
if (ni)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void closeLoadingSession(int loaded_faces, ExtVertex **tmp, bool triangulate) {
|
||||
int i, nv = this->V.numels();
|
||||
if (tmp != NULL)
|
||||
{
|
||||
for (i = 0; i < nv; i++)
|
||||
delete (tmp[i]);
|
||||
free(tmp);
|
||||
}
|
||||
fixConnectivity();
|
||||
this->d_boundaries = this->d_handles = this->d_shells = 1;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
bool fix_model_by_meshfix(ModelObject &model_object, int volume_idx, wxProgressDialog &progress_dlg,
|
||||
const wxString &msg_header, std::string &fix_result) {
|
||||
std::mutex mtx;
|
||||
std::condition_variable condition;
|
||||
struct Progress {
|
||||
std::string message;
|
||||
int percent = 0;
|
||||
bool updated = false;
|
||||
} progress;
|
||||
std::atomic<bool> canceled = false;
|
||||
std::atomic<bool> finished = false;
|
||||
|
||||
std::vector<ModelVolume*> volumes;
|
||||
if (volume_idx == -1)
|
||||
volumes = model_object.volumes;
|
||||
else
|
||||
volumes.emplace_back(model_object.volumes[volume_idx]);
|
||||
|
||||
// Executing the calculation in a background thread, so that the COM context could be created with its own threading model.
|
||||
// (It seems like wxWidgets initialize the COM contex as single threaded and we need a multi-threaded context).
|
||||
bool success = false;
|
||||
size_t ivolume = 0;
|
||||
auto on_progress = [&mtx, &condition, &ivolume, &volumes, &progress](const char *msg, unsigned prcnt) {
|
||||
std::unique_lock<std::mutex> lock(mtx);
|
||||
progress.message = msg;
|
||||
progress.percent = (int) floor((float(prcnt) + float(ivolume) * 100.f) / float(volumes.size()));
|
||||
progress.updated = true;
|
||||
condition.notify_all();
|
||||
};
|
||||
auto worker_thread = boost::thread(
|
||||
[&model_object, &volumes, &ivolume, on_progress, &success, &canceled, &finished]() {
|
||||
try {
|
||||
std::vector<TriangleMesh> meshes_repaired;
|
||||
meshes_repaired.reserve(volumes.size());
|
||||
for (ModelVolume *mv : volumes) {
|
||||
std::vector<indexed_triangle_set> parts = its_split(mv->mesh().its);
|
||||
for (size_t part_idx = 0; part_idx < parts.size(); ++part_idx) {
|
||||
|
||||
detail::Basic_TMesh_Adapter tin { };
|
||||
on_progress(L("Loading source model"), 0);
|
||||
if (canceled)
|
||||
throw RepairCanceledException();
|
||||
tin.load_indexed_triangle_set(parts[part_idx]);
|
||||
tin.boundaries();
|
||||
on_progress(L("Join closest components"), 10);
|
||||
if (canceled)
|
||||
throw RepairCanceledException();
|
||||
joinClosestComponents(&tin);
|
||||
tin.deselectTriangles();
|
||||
tin.boundaries();
|
||||
// Keep only the largest component (i.e. with most triangles)
|
||||
on_progress(L("Remove smallest components"), 20);
|
||||
if (canceled)
|
||||
throw RepairCanceledException();
|
||||
tin.removeSmallestComponents();
|
||||
|
||||
// Fill holes
|
||||
on_progress(L("Check holes"), 30);
|
||||
if (canceled)
|
||||
throw RepairCanceledException();
|
||||
if (tin.boundaries()) {
|
||||
on_progress(L("Patch small holes"), 40);
|
||||
if (canceled)
|
||||
throw RepairCanceledException();
|
||||
tin.fillSmallBoundaries(0, true);
|
||||
}
|
||||
|
||||
on_progress(L("Geometry check"), 50);
|
||||
if (canceled)
|
||||
throw RepairCanceledException();
|
||||
// Run geometry correction
|
||||
if (!tin.boundaries()) {
|
||||
int iteration = 0;
|
||||
on_progress(L("Iterative geometry correction"), 55);
|
||||
tin.deselectTriangles();
|
||||
tin.invertSelection();
|
||||
bool fixed = false;
|
||||
while (iteration < 10 && !fixed) { //default constants taken from TMesh library
|
||||
fixed = tin.meshclean_single_iteration(3, canceled);
|
||||
on_progress(L("Fixing geometry"), std::min(95, 60 + iteration * 8)); // majority of objects should finish in 4 iterations
|
||||
if (canceled)
|
||||
throw RepairCanceledException();
|
||||
iteration++;
|
||||
}
|
||||
}
|
||||
|
||||
if (tin.boundaries() || tin.T.numels() == 0) {
|
||||
throw RepairFailedException();
|
||||
}
|
||||
parts[part_idx] = tin.to_indexed_triangle_set();
|
||||
}
|
||||
|
||||
for (size_t part_idx = 1; part_idx < parts.size(); ++part_idx) {
|
||||
its_merge(parts[0], parts[part_idx]);
|
||||
}
|
||||
|
||||
meshes_repaired.emplace_back(std::move(parts[0]));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < volumes.size(); ++i) {
|
||||
volumes[i]->set_mesh(std::move(meshes_repaired[i]));
|
||||
volumes[i]->calculate_convex_hull();
|
||||
volumes[i]->set_new_unique_id();
|
||||
}
|
||||
model_object.invalidate_bounding_box();
|
||||
--ivolume;
|
||||
on_progress(L("Model repair finished"), 100);
|
||||
success = true;
|
||||
finished = true;
|
||||
} catch (RepairCanceledException& /* ex */) {
|
||||
canceled = true;
|
||||
finished = true;
|
||||
on_progress(L("Model repair canceled"), 100);
|
||||
} catch (std::exception &ex) {
|
||||
success = false;
|
||||
finished = true;
|
||||
on_progress(ex.what(), 100);
|
||||
}
|
||||
});
|
||||
|
||||
while (!finished) {
|
||||
std::unique_lock<std::mutex> lock(mtx);
|
||||
condition.wait_for(lock, std::chrono::milliseconds(250), [&progress] {
|
||||
return progress.updated;
|
||||
});
|
||||
// decrease progress.percent value to avoid closing of the progress dialog
|
||||
if (!progress_dlg.Update(progress.percent - 1, msg_header + _(progress.message)))
|
||||
canceled = true;
|
||||
else
|
||||
progress_dlg.Fit();
|
||||
progress.updated = false;
|
||||
}
|
||||
|
||||
worker_thread.join();
|
||||
|
||||
if (canceled) {
|
||||
// Nothing to show.
|
||||
} else if (success) {
|
||||
fix_result = "";
|
||||
} else {
|
||||
fix_result = progress.message;
|
||||
}
|
||||
|
||||
return !canceled;
|
||||
}
|
||||
|
||||
}
|
20
src/slic3r/Utils/FixModelByMeshFix.hpp
Normal file
20
src/slic3r/Utils/FixModelByMeshFix.hpp
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef SRC_SLIC3R_UTILS_FIXMODELBYMESHFIX_HPP_
|
||||
#define SRC_SLIC3R_UTILS_FIXMODELBYMESHFIX_HPP_
|
||||
|
||||
#include <string>
|
||||
#include <wx/string.h>
|
||||
|
||||
class wxProgressDialog;
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class Model;
|
||||
class ModelObject;
|
||||
class Print;
|
||||
|
||||
bool fix_model_by_meshfix(ModelObject &model_object, int volume_idx, wxProgressDialog &progress_dlg,
|
||||
const wxString &msg_header, std::string &fix_result);
|
||||
|
||||
}
|
||||
|
||||
#endif /* SRC_SLIC3R_UTILS_FIXMODELBYMESHFIX_HPP_ */
|
Loading…
Reference in New Issue
Block a user