forked from bartvdbraak/blender
Merged changes in the trunk up to revision 43585.
Conflicts resolved: source/blender/editors/include/UI_resources.h source/blender/editors/interface/resources.c source/blender/makesrna/intern/rna_scene.c
This commit is contained in:
commit
68ae82bb47
@ -208,6 +208,9 @@ option(WITH_LZMA "Enable best LZMA compression, (used for pointcache)"
|
||||
# Camera/motion tracking
|
||||
option(WITH_LIBMV "Enable libmv structure from motion library" ON)
|
||||
|
||||
# Mesh boolean lib
|
||||
option(WITH_CARVE "Enable Carve library to handle mesh boolean operations" ON)
|
||||
|
||||
# Misc
|
||||
option(WITH_INPUT_NDOF "Enable NDOF input devices (SpaceNavigator and friends)" ON)
|
||||
option(WITH_RAYOPTIMIZATION "Enable use of SIMD (SSE) optimizations for the raytracer" ON)
|
||||
@ -300,9 +303,13 @@ if(WITH_PYTHON_MODULE)
|
||||
set(WITH_HEADLESS ON)
|
||||
endif()
|
||||
|
||||
# auto enable openimageio and boost for cycles
|
||||
# auto enable openimageio for cycles
|
||||
if(WITH_CYCLES)
|
||||
set(WITH_OPENIMAGEIO ON)
|
||||
endif()
|
||||
|
||||
# auto enable boost for cycles and carve
|
||||
if(WITH_CYCLES OR WITH_CARVE)
|
||||
set(WITH_BOOST ON)
|
||||
endif()
|
||||
|
||||
@ -1085,15 +1092,27 @@ elseif(APPLE)
|
||||
endif()
|
||||
|
||||
if(WITH_PYTHON)
|
||||
# we use precompiled libraries for py 3.2 and up by default
|
||||
if(NOT WITH_PYTHON_MODULE)
|
||||
# we use precompiled libraries for py 3.2 and up by default
|
||||
|
||||
# normally cached but not since we include them with blender
|
||||
set(PYTHON_VERSION 3.2)
|
||||
set(PYTHON_INCLUDE_DIR "${LIBDIR}/python/include/python${PYTHON_VERSION}")
|
||||
# set(PYTHON_BINARY "${LIBDIR}/python/bin/python${PYTHON_VERSION}") # not used yet
|
||||
set(PYTHON_LIBRARY python${PYTHON_VERSION})
|
||||
set(PYTHON_LIBPATH "${LIBDIR}/python/lib/python${PYTHON_VERSION}")
|
||||
# set(PYTHON_LINKFLAGS "-u _PyMac_Error") # won't build with this enabled
|
||||
# normally cached but not since we include them with blender
|
||||
set(PYTHON_VERSION 3.2)
|
||||
set(PYTHON_INCLUDE_DIR "${LIBDIR}/python/include/python${PYTHON_VERSION}")
|
||||
# set(PYTHON_BINARY "${LIBDIR}/python/bin/python${PYTHON_VERSION}") # not used yet
|
||||
set(PYTHON_LIBRARY python${PYTHON_VERSION})
|
||||
set(PYTHON_LIBPATH "${LIBDIR}/python/lib/python${PYTHON_VERSION}")
|
||||
# set(PYTHON_LINKFLAGS "-u _PyMac_Error") # won't build with this enabled
|
||||
else()
|
||||
# module must be compiled against Python framework
|
||||
|
||||
# normally cached but not since we include them with blender
|
||||
set(PYTHON_VERSION 3.2)
|
||||
set(PYTHON_INCLUDE_DIR "/Library/Frameworks/Python.framework/Versions/${PYTHON_VERSION}/include/python${PYTHON_VERSION}m")
|
||||
set(PYTHON_BINARY "/Library/Frameworks/Python.framework/Versions/${PYTHON_VERSION}/bin/python${PYTHON_VERSION}")
|
||||
#set(PYTHON_LIBRARY python${PYTHON_VERSION})
|
||||
set(PYTHON_LIBPATH "/Library/Frameworks/Python.framework/Versions/${PYTHON_VERSION}/lib/python${PYTHON_VERSION}/config-3.2m")
|
||||
#set(PYTHON_LINKFLAGS "-u _PyMac_Error -framework Python") # won't build with this enabled
|
||||
endif()
|
||||
|
||||
# uncached vars
|
||||
set(PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_DIR}")
|
||||
@ -1190,6 +1209,10 @@ elseif(APPLE)
|
||||
set(WITH_INPUT_NDOF OFF) # unsupported
|
||||
endif()
|
||||
|
||||
if(WITH_PYTHON_MODULE)
|
||||
set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} /Library/Frameworks/Python.framework/Versions/${PYTHON_VERSION}/python")# force cmake to link right framework
|
||||
endif()
|
||||
|
||||
if(WITH_OPENCOLLADA)
|
||||
set(OPENCOLLADA ${LIBDIR}/opencollada)
|
||||
|
||||
|
@ -147,9 +147,8 @@ if toolset:
|
||||
env.Tool('mstoolkit', [toolpath])
|
||||
else:
|
||||
env = BlenderEnvironment(tools=[toolset], ENV = os.environ)
|
||||
# xxx commented out, as was supressing warnings under mingw..
|
||||
#if env:
|
||||
# btools.SetupSpawn(env)
|
||||
if env:
|
||||
btools.SetupSpawn(env)
|
||||
else:
|
||||
if bitness==64 and platform=='win32':
|
||||
env = BlenderEnvironment(ENV = os.environ, MSVS_ARCH='amd64')
|
||||
|
@ -37,7 +37,8 @@ CHECKER_BIN = "cppcheck"
|
||||
CHECKER_ARGS = [
|
||||
# not sure why this is needed, but it is.
|
||||
"-I" + os.path.join(project_source_info.SOURCE_DIR, "extern", "glew", "include"),
|
||||
|
||||
"--suppress=*:%s/extern/glew/include/GL/glew.h:241" % project_source_info.SOURCE_DIR,
|
||||
# "--max-configs=1", # speeds up execution
|
||||
# "--check-config", # when includes are missing
|
||||
# "--enable=all", # if you want sixty hundred pedantic suggestions
|
||||
]
|
||||
|
@ -15,6 +15,7 @@ set(WITH_CODEC_SNDFILE OFF CACHE FORCE BOOL)
|
||||
set(WITH_CYCLES OFF CACHE FORCE BOOL)
|
||||
set(WITH_FFTW3 OFF CACHE FORCE BOOL)
|
||||
set(WITH_LIBMV OFF CACHE FORCE BOOL)
|
||||
set(WITH_CARVE OFF CACHE FORCE BOOL)
|
||||
set(WITH_GAMEENGINE OFF CACHE FORCE BOOL)
|
||||
set(WITH_IK_ITASC OFF CACHE FORCE BOOL)
|
||||
set(WITH_IMAGE_CINEON OFF CACHE FORCE BOOL)
|
||||
@ -33,6 +34,7 @@ set(WITH_LZO OFF CACHE FORCE BOOL)
|
||||
set(WITH_MOD_BOOLEAN OFF CACHE FORCE BOOL)
|
||||
set(WITH_MOD_DECIMATE OFF CACHE FORCE BOOL)
|
||||
set(WITH_MOD_FLUID OFF CACHE FORCE BOOL)
|
||||
set(WITH_MOD_REMESH OFF CACHE FORCE BOOL)
|
||||
set(WITH_MOD_SMOKE OFF CACHE FORCE BOOL)
|
||||
set(WITH_MOD_OCEANSIM OFF CACHE FORCE BOOL)
|
||||
set(WITH_AUDASPACE OFF CACHE FORCE BOOL)
|
||||
@ -43,3 +45,4 @@ set(WITH_PYTHON_INSTALL OFF CACHE FORCE BOOL)
|
||||
set(WITH_RAYOPTIMIZATION OFF CACHE FORCE BOOL)
|
||||
set(WITH_SDL OFF CACHE FORCE BOOL)
|
||||
set(WITH_X11_XINPUT OFF CACHE FORCE BOOL)
|
||||
set(WITH_X11_XF86VMODE OFF CACHE FORCE BOOL)
|
||||
|
@ -133,7 +133,7 @@ def cmake_advanced_info():
|
||||
""" Extracr includes and defines from cmake.
|
||||
"""
|
||||
|
||||
def create_eclipse_project(CMAKE_DIR):
|
||||
def create_eclipse_project():
|
||||
print("CMAKE_DIR %r" % CMAKE_DIR)
|
||||
if sys.platform == "win32":
|
||||
cmd = 'cmake "%s" -G"Eclipse CDT4 - MinGW Makefiles"' % CMAKE_DIR
|
||||
@ -145,7 +145,7 @@ def cmake_advanced_info():
|
||||
includes = []
|
||||
defines = []
|
||||
|
||||
create_eclipse_project(CMAKE_DIR)
|
||||
create_eclipse_project()
|
||||
|
||||
from xml.dom.minidom import parse
|
||||
tree = parse(join(CMAKE_DIR, ".cproject"))
|
||||
|
@ -160,7 +160,6 @@ def build_info(use_c=True, use_cxx=True, ignore_prefix_list=None):
|
||||
def queue_processes(process_funcs, job_total=-1):
|
||||
""" Takes a list of function arg pairs, each function must return a process
|
||||
"""
|
||||
import sys
|
||||
|
||||
if job_total == -1:
|
||||
import multiprocessing
|
||||
|
@ -272,7 +272,7 @@ def setup_syslibs(lenv):
|
||||
syslibs += Split(lenv['BF_PTHREADS_LIB'])
|
||||
if lenv['WITH_BF_COLLADA']:
|
||||
syslibs.append(lenv['BF_PCRE_LIB'])
|
||||
if lenv['BF_DEBUG']:
|
||||
if lenv['BF_DEBUG'] and (lenv['OURPLATFORM'] != 'linux'):
|
||||
syslibs += [colladalib+'_d' for colladalib in Split(lenv['BF_OPENCOLLADA_LIB'])]
|
||||
else:
|
||||
syslibs += Split(lenv['BF_OPENCOLLADA_LIB'])
|
||||
|
@ -161,7 +161,7 @@ def validate_arguments(args, bc):
|
||||
'WITH_BF_CYCLES', 'WITH_BF_CYCLES_CUDA_BINARIES' 'BF_CYCLES_CUDA_NVCC', 'BF_CYCLES_CUDA_NVCC', 'WITH_BF_CYCLES_CUDA_THREADED_COMPILE',
|
||||
'WITH_BF_OIIO', 'WITH_BF_STATICOIIO', 'BF_OIIO', 'BF_OIIO_INC', 'BF_OIIO_LIB', 'BF_OIIO_LIB_STATIC', 'BF_OIIO_LIBPATH',
|
||||
'WITH_BF_BOOST', 'WITH_BF_STATICBOOST', 'BF_BOOST', 'BF_BOOST_INC', 'BF_BOOST_LIB', 'BF_BOOST_LIB_STATIC', 'BF_BOOST_LIBPATH',
|
||||
'WITH_BF_LIBMV'
|
||||
'WITH_BF_LIBMV', 'WITH_BF_CARVE'
|
||||
]
|
||||
|
||||
# Have options here that scons expects to be lists
|
||||
@ -222,15 +222,15 @@ class ourSpawn:
|
||||
newargs = string.join(args[1:], ' ')
|
||||
cmdline = cmd + " " + newargs
|
||||
startupinfo = subprocess.STARTUPINFO()
|
||||
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
||||
#startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
||||
proc = subprocess.Popen(cmdline, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE, startupinfo=startupinfo, shell = False)
|
||||
data, err = proc.communicate()
|
||||
rv = proc.wait()
|
||||
if rv:
|
||||
print "====="
|
||||
print err
|
||||
print "====="
|
||||
if data:
|
||||
print(data)
|
||||
if err:
|
||||
print(err)
|
||||
return rv
|
||||
|
||||
def SetupSpawn( env ):
|
||||
@ -521,6 +521,7 @@ def read_opts(env, cfg, args):
|
||||
|
||||
(BoolVariable('WITH_BF_LZO', 'Enable fast LZO pointcache compression', True)),
|
||||
(BoolVariable('WITH_BF_LZMA', 'Enable best LZMA pointcache compression', True)),
|
||||
(BoolVariable('WITH_BF_CARVE', 'Enable carve library for mesh boolean operations', True)),
|
||||
|
||||
(BoolVariable('WITH_BF_LIBMV', 'Enable libmv structure from motion library', True)),
|
||||
|
||||
|
4
extern/CMakeLists.txt
vendored
4
extern/CMakeLists.txt
vendored
@ -67,3 +67,7 @@ endif()
|
||||
if(WITH_LIBMV)
|
||||
add_subdirectory(libmv)
|
||||
endif()
|
||||
|
||||
if(WITH_CARVE)
|
||||
add_subdirectory(carve)
|
||||
endif()
|
||||
|
3
extern/SConscript
vendored
3
extern/SConscript
vendored
@ -31,3 +31,6 @@ if env['WITH_BF_LZMA']:
|
||||
|
||||
if env['WITH_BF_LIBMV']:
|
||||
SConscript(['libmv/SConscript'])
|
||||
|
||||
if env['WITH_BF_CARVE']:
|
||||
SConscript(['carve/SConscript'])
|
||||
|
166
extern/carve/CMakeLists.txt
vendored
Normal file
166
extern/carve/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,166 @@
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# 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 2
|
||||
# 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, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# The Original Code is Copyright (C) 2006, Blender Foundation
|
||||
# All rights reserved.
|
||||
#
|
||||
# The Original Code is: all of this file.
|
||||
#
|
||||
# Contributor(s): Jacques Beaurai, Erwin Coumans
|
||||
#
|
||||
# ***** END GPL LICENSE BLOCK *****
|
||||
|
||||
# NOTE: This file is automatically generated by bundle.sh script
|
||||
# If you're doing changes in this file, please update template
|
||||
# in that script too
|
||||
|
||||
set(INC
|
||||
include
|
||||
)
|
||||
|
||||
set(INC_SYS
|
||||
)
|
||||
|
||||
set(SRC
|
||||
lib/carve.cpp
|
||||
lib/mesh.cpp
|
||||
lib/intersect_group.cpp
|
||||
lib/intersect_classify_edge.cpp
|
||||
lib/intersect_classify_group.cpp
|
||||
lib/polyhedron.cpp
|
||||
lib/geom3d.cpp
|
||||
lib/polyline.cpp
|
||||
lib/csg_collector.cpp
|
||||
lib/triangulator.cpp
|
||||
lib/intersect_face_division.cpp
|
||||
lib/intersect_half_classify_group.cpp
|
||||
lib/edge.cpp
|
||||
lib/math.cpp
|
||||
lib/geom2d.cpp
|
||||
lib/tag.cpp
|
||||
lib/intersection.cpp
|
||||
lib/convex_hull.cpp
|
||||
lib/csg.cpp
|
||||
lib/intersect.cpp
|
||||
lib/face.cpp
|
||||
lib/pointset.cpp
|
||||
lib/timing.cpp
|
||||
lib/octree.cpp
|
||||
lib/aabb.cpp
|
||||
lib/intersect_debug.cpp
|
||||
|
||||
lib/intersect_classify_common.hpp
|
||||
lib/csg_data.hpp
|
||||
lib/csg_collector.hpp
|
||||
lib/intersect_common.hpp
|
||||
lib/intersect_classify_common_impl.hpp
|
||||
lib/csg_detail.hpp
|
||||
lib/intersect_debug.hpp
|
||||
|
||||
include/carve/polyhedron_decl.hpp
|
||||
include/carve/geom2d.hpp
|
||||
include/carve/exact.hpp
|
||||
include/carve/triangulator_impl.hpp
|
||||
include/carve/collection.hpp
|
||||
include/carve/pointset.hpp
|
||||
include/carve/djset.hpp
|
||||
include/carve/kd_node.hpp
|
||||
include/carve/polyline.hpp
|
||||
include/carve/polyline_iter.hpp
|
||||
include/carve/geom3d.hpp
|
||||
include/carve/edge_decl.hpp
|
||||
include/carve/face_decl.hpp
|
||||
include/carve/aabb_impl.hpp
|
||||
include/carve/colour.hpp
|
||||
include/carve/pointset_iter.hpp
|
||||
include/carve/polyline_decl.hpp
|
||||
include/carve/rescale.hpp
|
||||
include/carve/mesh_impl.hpp
|
||||
include/carve/classification.hpp
|
||||
include/carve/util.hpp
|
||||
include/carve/triangulator.hpp
|
||||
include/carve/polyhedron_base.hpp
|
||||
include/carve/rtree.hpp
|
||||
include/carve/math.hpp
|
||||
include/carve/math_constants.hpp
|
||||
include/carve/octree_decl.hpp
|
||||
include/carve/input.hpp
|
||||
include/carve/mesh_ops.hpp
|
||||
include/carve/debug_hooks.hpp
|
||||
include/carve/mesh_simplify.hpp
|
||||
include/carve/interpolator.hpp
|
||||
include/carve/poly_decl.hpp
|
||||
include/carve/csg.hpp
|
||||
include/carve/mesh.hpp
|
||||
include/carve/carve.hpp
|
||||
include/carve/gnu_cxx.h
|
||||
include/carve/polyhedron_impl.hpp
|
||||
include/carve/poly_impl.hpp
|
||||
include/carve/aabb.hpp
|
||||
include/carve/convex_hull.hpp
|
||||
include/carve/vertex_decl.hpp
|
||||
include/carve/win32.h
|
||||
include/carve/edge_impl.hpp
|
||||
include/carve/tag.hpp
|
||||
include/carve/tree.hpp
|
||||
include/carve/heap.hpp
|
||||
include/carve/matrix.hpp
|
||||
include/carve/poly.hpp
|
||||
include/carve/vector.hpp
|
||||
include/carve/intersection.hpp
|
||||
include/carve/faceloop.hpp
|
||||
include/carve/geom_impl.hpp
|
||||
include/carve/octree_impl.hpp
|
||||
include/carve/spacetree.hpp
|
||||
include/carve/collection/unordered/std_impl.hpp
|
||||
include/carve/collection/unordered/tr1_impl.hpp
|
||||
include/carve/collection/unordered/libstdcpp_impl.hpp
|
||||
include/carve/collection/unordered/boost_impl.hpp
|
||||
include/carve/collection/unordered/vcpp_impl.hpp
|
||||
include/carve/collection/unordered/fallback_impl.hpp
|
||||
include/carve/collection/unordered.hpp
|
||||
include/carve/face_impl.hpp
|
||||
include/carve/pointset_impl.hpp
|
||||
include/carve/cbrt.h
|
||||
include/carve/vcpp_config.h
|
||||
include/carve/geom.hpp
|
||||
include/carve/vertex_impl.hpp
|
||||
include/carve/polyline_impl.hpp
|
||||
include/carve/pointset_decl.hpp
|
||||
include/carve/timing.hpp
|
||||
include/carve/csg_triangulator.hpp
|
||||
include/carve/iobj.hpp
|
||||
include/carve/collection_types.hpp
|
||||
)
|
||||
|
||||
if(WITH_BOOST)
|
||||
if(NOT MSVC)
|
||||
# Boost is setting as preferred collections library in the Carve code when using MSVC compiler
|
||||
add_definitions(
|
||||
-DHAVE_BOOST_UNORDERED_COLLECTIONS
|
||||
)
|
||||
endif()
|
||||
|
||||
add_definitions(
|
||||
-DCARVE_SYSTEM_BOOST
|
||||
)
|
||||
|
||||
list(APPEND INC
|
||||
${BOOST_INCLUDE_DIR}
|
||||
)
|
||||
endif()
|
||||
|
||||
blender_add_lib(extern_carve "${SRC}" "${INC}" "${INC_SYS}")
|
361
extern/carve/LICENSE.GPL2
vendored
Normal file
361
extern/carve/LICENSE.GPL2
vendored
Normal file
@ -0,0 +1,361 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
|
||||
The Qt GUI Toolkit is Copyright (C) 1994-2008 Trolltech ASA.
|
||||
|
||||
You may use, distribute and copy the Qt GUI Toolkit under the terms of
|
||||
GNU General Public License version 2, which is displayed below.
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) 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
|
||||
this service 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 make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. 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.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
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
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the 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 a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE 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.
|
||||
|
||||
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
|
||||
convey 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 2 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, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision 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, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This 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 Library General
|
||||
Public License instead of this License.
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
|
||||
In addition, as a special exception, Trolltech gives permission to link the
|
||||
code of its release of Qt with the OpenSSL project's "OpenSSL" library (or
|
||||
modified versions of it that use the same license as the "OpenSSL"
|
||||
library), and distribute the linked executables. You must comply with the GNU
|
||||
General Public License version 2 or the GNU General Public License version 3
|
||||
in all respects for all of the code used other than the "OpenSSL" code. If
|
||||
you modify this file, you may extend this exception to your version of the
|
||||
file, but you are not obligated to do so. If you do not wish to do so,
|
||||
delete this exception statement from your version of this file.
|
23
extern/carve/SConscript
vendored
Normal file
23
extern/carve/SConscript
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# NOTE: This file is automatically generated by bundle.sh script
|
||||
# If you're doing changes in this file, please update template
|
||||
# in that script too
|
||||
|
||||
Import ('env')
|
||||
|
||||
sources = env.Glob('lib/*.cpp')
|
||||
|
||||
defs = []
|
||||
incs = ['include']
|
||||
|
||||
if env['WITH_BF_BOOST']:
|
||||
if env['OURPLATFORM'] not in ('win32-vc', 'win64-vc'):
|
||||
# Boost is setting as preferred collections library in the Carve code when using MSVC compiler
|
||||
if env['OURPLATFORM'] != 'win32-mingw':
|
||||
defs.append('HAVE_BOOST_UNORDERED_COLLECTIONS')
|
||||
|
||||
defs.append('CARVE_SYSTEM_BOOST')
|
||||
incs.append(env['BF_BOOST_INC'])
|
||||
|
||||
env.BlenderLib ('extern_carve', Split(sources), incs, defs, libtype=['extern'], priority=[40] )
|
124
extern/carve/bundle.sh
vendored
Executable file
124
extern/carve/bundle.sh
vendored
Executable file
@ -0,0 +1,124 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ -d ./.svn ]; then
|
||||
echo "This script is supposed to work only when using git-svn"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
tmp=`mktemp -d`
|
||||
|
||||
hg clone https://code.google.com/p/carve/ $tmp/carve
|
||||
|
||||
for p in `cat ./patches/series`; do
|
||||
echo "Applying patch $p..."
|
||||
cat ./patches/$p | patch -d $tmp/carve -p1
|
||||
done
|
||||
|
||||
rm -rf include
|
||||
rm -rf lib
|
||||
|
||||
cat "files.txt" | while f=`line`; do
|
||||
mkdir -p `dirname $f`
|
||||
cp $tmp/carve/$f $f
|
||||
done
|
||||
|
||||
rm -rf $tmp
|
||||
|
||||
sources=`find ./lib -type f -iname '*.cc' -or -iname '*.cpp' -or -iname '*.c' | sed -r 's/^\.\//\t/'`
|
||||
headers=`find ./lib -type f -iname '*.h' -or -iname '*.hpp' | sed -r 's/^\.\//\t/'`
|
||||
includes=`find ./include -type f -iname '*.h' -or -iname '*.hpp' | sed -r 's/^\.\//\t/'`
|
||||
|
||||
mkdir -p include/carve/external/boost
|
||||
cp patches/files/random.hpp include/carve/external/boost/random.hpp
|
||||
cp patches/files/config.h include/carve/config.h
|
||||
|
||||
cat > CMakeLists.txt << EOF
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# 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 2
|
||||
# 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, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# The Original Code is Copyright (C) 2006, Blender Foundation
|
||||
# All rights reserved.
|
||||
#
|
||||
# The Original Code is: all of this file.
|
||||
#
|
||||
# Contributor(s): Jacques Beaurai, Erwin Coumans
|
||||
#
|
||||
# ***** END GPL LICENSE BLOCK *****
|
||||
|
||||
# NOTE: This file is automatically generated by bundle.sh script
|
||||
# If you're doing changes in this file, please update template
|
||||
# in that script too
|
||||
|
||||
set(INC
|
||||
include
|
||||
)
|
||||
|
||||
set(INC_SYS
|
||||
)
|
||||
|
||||
set(SRC
|
||||
${sources}
|
||||
|
||||
${headers}
|
||||
|
||||
${includes}
|
||||
)
|
||||
|
||||
if(WITH_BOOST)
|
||||
if(NOT MSVC)
|
||||
# Boost is setting as preferred collections library in the Carve code when using MSVC compiler
|
||||
add_definitions(
|
||||
-DHAVE_BOOST_UNORDERED_COLLECTIONS
|
||||
)
|
||||
endif()
|
||||
|
||||
add_definitions(
|
||||
-DCARVE_SYSTEM_BOOST
|
||||
)
|
||||
|
||||
list(APPEND INC
|
||||
\${BOOST_INCLUDE_DIR}
|
||||
)
|
||||
endif()
|
||||
|
||||
blender_add_lib(extern_carve "\${SRC}" "\${INC}" "\${INC_SYS}")
|
||||
EOF
|
||||
|
||||
cat > SConscript << EOF
|
||||
#!/usr/bin/python
|
||||
|
||||
# NOTE: This file is automatically generated by bundle.sh script
|
||||
# If you're doing changes in this file, please update template
|
||||
# in that script too
|
||||
|
||||
Import ('env')
|
||||
|
||||
sources = env.Glob('lib/*.cpp')
|
||||
|
||||
defs = []
|
||||
incs = ['include']
|
||||
|
||||
if env['WITH_BF_BOOST']:
|
||||
if env['OURPLATFORM'] not in ('win32-vc', 'win64-vc'):
|
||||
# Boost is setting as preferred collections library in the Carve code when using MSVC compiler
|
||||
if env['OURPLATFORM'] != 'win32-mingw':
|
||||
defs.append('HAVE_BOOST_UNORDERED_COLLECTIONS')
|
||||
|
||||
defs.append('CARVE_SYSTEM_BOOST')
|
||||
incs.append(env['BF_BOOST_INC'])
|
||||
|
||||
env.BlenderLib ('extern_carve', Split(sources), incs, defs, libtype=['extern'], priority=[40] )
|
||||
EOF
|
107
extern/carve/files.txt
vendored
Normal file
107
extern/carve/files.txt
vendored
Normal file
@ -0,0 +1,107 @@
|
||||
include/carve/polyhedron_decl.hpp
|
||||
include/carve/geom2d.hpp
|
||||
include/carve/exact.hpp
|
||||
include/carve/triangulator_impl.hpp
|
||||
include/carve/collection.hpp
|
||||
include/carve/pointset.hpp
|
||||
include/carve/djset.hpp
|
||||
include/carve/kd_node.hpp
|
||||
include/carve/polyline.hpp
|
||||
include/carve/polyline_iter.hpp
|
||||
include/carve/geom3d.hpp
|
||||
include/carve/edge_decl.hpp
|
||||
include/carve/face_decl.hpp
|
||||
include/carve/aabb_impl.hpp
|
||||
include/carve/colour.hpp
|
||||
include/carve/pointset_iter.hpp
|
||||
include/carve/polyline_decl.hpp
|
||||
include/carve/rescale.hpp
|
||||
include/carve/mesh_impl.hpp
|
||||
include/carve/classification.hpp
|
||||
include/carve/util.hpp
|
||||
include/carve/triangulator.hpp
|
||||
include/carve/polyhedron_base.hpp
|
||||
include/carve/rtree.hpp
|
||||
include/carve/math.hpp
|
||||
include/carve/math_constants.hpp
|
||||
include/carve/octree_decl.hpp
|
||||
include/carve/input.hpp
|
||||
include/carve/mesh_ops.hpp
|
||||
include/carve/debug_hooks.hpp
|
||||
include/carve/mesh_simplify.hpp
|
||||
include/carve/interpolator.hpp
|
||||
include/carve/poly_decl.hpp
|
||||
include/carve/csg.hpp
|
||||
include/carve/mesh.hpp
|
||||
include/carve/carve.hpp
|
||||
include/carve/gnu_cxx.h
|
||||
include/carve/polyhedron_impl.hpp
|
||||
include/carve/poly_impl.hpp
|
||||
include/carve/aabb.hpp
|
||||
include/carve/convex_hull.hpp
|
||||
include/carve/vertex_decl.hpp
|
||||
include/carve/win32.h
|
||||
include/carve/edge_impl.hpp
|
||||
include/carve/tag.hpp
|
||||
include/carve/tree.hpp
|
||||
include/carve/heap.hpp
|
||||
include/carve/matrix.hpp
|
||||
include/carve/poly.hpp
|
||||
include/carve/vector.hpp
|
||||
include/carve/intersection.hpp
|
||||
include/carve/faceloop.hpp
|
||||
include/carve/geom_impl.hpp
|
||||
include/carve/octree_impl.hpp
|
||||
include/carve/spacetree.hpp
|
||||
include/carve/collection/unordered/std_impl.hpp
|
||||
include/carve/collection/unordered/tr1_impl.hpp
|
||||
include/carve/collection/unordered/libstdcpp_impl.hpp
|
||||
include/carve/collection/unordered/boost_impl.hpp
|
||||
include/carve/collection/unordered/vcpp_impl.hpp
|
||||
include/carve/collection/unordered/fallback_impl.hpp
|
||||
include/carve/collection/unordered.hpp
|
||||
include/carve/face_impl.hpp
|
||||
include/carve/pointset_impl.hpp
|
||||
include/carve/cbrt.h
|
||||
include/carve/vcpp_config.h
|
||||
include/carve/geom.hpp
|
||||
include/carve/vertex_impl.hpp
|
||||
include/carve/polyline_impl.hpp
|
||||
include/carve/pointset_decl.hpp
|
||||
include/carve/timing.hpp
|
||||
include/carve/csg_triangulator.hpp
|
||||
include/carve/iobj.hpp
|
||||
include/carve/collection_types.hpp
|
||||
lib/carve.cpp
|
||||
lib/mesh.cpp
|
||||
lib/intersect_group.cpp
|
||||
lib/intersect_classify_common.hpp
|
||||
lib/intersect_classify_edge.cpp
|
||||
lib/intersect_classify_group.cpp
|
||||
lib/csg_data.hpp
|
||||
lib/polyhedron.cpp
|
||||
lib/csg_collector.hpp
|
||||
lib/geom3d.cpp
|
||||
lib/polyline.cpp
|
||||
lib/csg_collector.cpp
|
||||
lib/triangulator.cpp
|
||||
lib/intersect_face_division.cpp
|
||||
lib/intersect_half_classify_group.cpp
|
||||
lib/edge.cpp
|
||||
lib/math.cpp
|
||||
lib/geom2d.cpp
|
||||
lib/tag.cpp
|
||||
lib/intersection.cpp
|
||||
lib/convex_hull.cpp
|
||||
lib/intersect_common.hpp
|
||||
lib/intersect_classify_common_impl.hpp
|
||||
lib/csg.cpp
|
||||
lib/intersect.cpp
|
||||
lib/csg_detail.hpp
|
||||
lib/face.cpp
|
||||
lib/pointset.cpp
|
||||
lib/timing.cpp
|
||||
lib/octree.cpp
|
||||
lib/aabb.cpp
|
||||
lib/intersect_debug.hpp
|
||||
lib/intersect_debug.cpp
|
150
extern/carve/include/carve/aabb.hpp
vendored
Normal file
150
extern/carve/include/carve/aabb.hpp
vendored
Normal file
@ -0,0 +1,150 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
|
||||
#include <carve/geom.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace carve {
|
||||
namespace geom {
|
||||
|
||||
|
||||
|
||||
// n-dimensional AABB
|
||||
template<unsigned ndim>
|
||||
struct aabb {
|
||||
typedef vector<ndim> vector_t;
|
||||
typedef aabb<ndim> aabb_t;
|
||||
|
||||
vector_t pos; // the centre of the AABB
|
||||
vector_t extent; // the extent of the AABB - the vector from the centre to the maximal vertex.
|
||||
|
||||
void empty();
|
||||
|
||||
bool isEmpty() const;
|
||||
|
||||
void fit(const vector_t &v1);
|
||||
void fit(const vector_t &v1, const vector_t &v2);
|
||||
void fit(const vector_t &v1, const vector_t &v2, const vector_t &v3);
|
||||
|
||||
template<typename iter_t, typename value_type>
|
||||
void _fit(iter_t begin, iter_t end, value_type);
|
||||
|
||||
template<typename iter_t>
|
||||
void _fit(iter_t begin, iter_t end, vector_t);
|
||||
|
||||
template<typename iter_t>
|
||||
void _fit(iter_t begin, iter_t end, aabb_t);
|
||||
|
||||
template<typename iter_t>
|
||||
void fit(iter_t begin, iter_t end);
|
||||
|
||||
template<typename iter_t, typename adapt_t>
|
||||
void fit(iter_t begin, iter_t end, adapt_t adapt);
|
||||
|
||||
void unionAABB(const aabb<ndim> &a);
|
||||
|
||||
void expand(double pad);
|
||||
|
||||
bool completelyContains(const aabb<ndim> &other) const;
|
||||
|
||||
bool containsPoint(const vector_t &v) const;
|
||||
|
||||
bool intersectsLineSegment(const vector_t &v1, const vector_t &v2) const;
|
||||
|
||||
double axisSeparation(const aabb<ndim> &other, unsigned axis) const;
|
||||
|
||||
double maxAxisSeparation(const aabb<ndim> &other) const;
|
||||
|
||||
bool intersects(const aabb<ndim> &other) const;
|
||||
bool intersects(const sphere<ndim> &s) const;
|
||||
bool intersects(const plane<ndim> &plane) const;
|
||||
bool intersects(const ray<ndim> &ray) const;
|
||||
bool intersects(tri<ndim> tri) const;
|
||||
bool intersects(const linesegment<ndim> &ls) const;
|
||||
|
||||
std::pair<double, double> rangeInDirection(const carve::geom::vector<ndim> &v) const;
|
||||
|
||||
vector_t min() const;
|
||||
vector_t mid() const;
|
||||
vector_t max() const;
|
||||
|
||||
double min(unsigned dim) const;
|
||||
double mid(unsigned dim) const;
|
||||
double max(unsigned dim) const;
|
||||
|
||||
double volume() const;
|
||||
|
||||
int compareAxis(const axis_pos &ap) const;
|
||||
|
||||
void constrainMax(const axis_pos &ap);
|
||||
void constrainMin(const axis_pos &ap);
|
||||
|
||||
aabb getAABB() const;
|
||||
|
||||
aabb(const vector_t &_pos = vector_t::ZERO(),
|
||||
const vector_t &_extent = vector_t::ZERO());
|
||||
|
||||
template<typename iter_t, typename adapt_t>
|
||||
aabb(iter_t begin, iter_t end, adapt_t adapt);
|
||||
|
||||
template<typename iter_t>
|
||||
aabb(iter_t begin, iter_t end);
|
||||
|
||||
aabb(const aabb<ndim> &a, const aabb<ndim> &b);
|
||||
};
|
||||
|
||||
template<unsigned ndim>
|
||||
bool operator==(const aabb<ndim> &a, const aabb<ndim> &b);
|
||||
|
||||
template<unsigned ndim>
|
||||
bool operator!=(const aabb<ndim> &a, const aabb<ndim> &b);
|
||||
|
||||
template<unsigned ndim>
|
||||
std::ostream &operator<<(std::ostream &o, const aabb<ndim> &a);
|
||||
|
||||
|
||||
|
||||
template<unsigned ndim, typename obj_t>
|
||||
struct get_aabb {
|
||||
aabb<ndim> operator()(const obj_t &obj) const {
|
||||
return obj.getAABB();
|
||||
}
|
||||
};
|
||||
|
||||
template<unsigned ndim, typename obj_t>
|
||||
struct get_aabb<ndim, obj_t *> {
|
||||
aabb<ndim> operator()(const obj_t *obj) const {
|
||||
return obj->getAABB();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
namespace carve {
|
||||
namespace geom3d {
|
||||
typedef carve::geom::aabb<3> AABB;
|
||||
}
|
||||
}
|
||||
|
||||
#include <carve/aabb_impl.hpp>
|
423
extern/carve/include/carve/aabb_impl.hpp
vendored
Normal file
423
extern/carve/include/carve/aabb_impl.hpp
vendored
Normal file
@ -0,0 +1,423 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
|
||||
#include <carve/vector.hpp>
|
||||
#include <carve/geom3d.hpp>
|
||||
|
||||
#include <carve/geom.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace carve {
|
||||
namespace geom {
|
||||
|
||||
template<unsigned ndim>
|
||||
void aabb<ndim>::empty() {
|
||||
pos.setZero();
|
||||
extent.setZero();
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
bool aabb<ndim>::isEmpty() const {
|
||||
return extent.exactlyZero();
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
template<typename iter_t, typename value_type>
|
||||
void aabb<ndim>::_fit(iter_t begin, iter_t end, value_type) {
|
||||
if (begin == end) {
|
||||
empty();
|
||||
return;
|
||||
}
|
||||
|
||||
vector_t min, max;
|
||||
aabb<ndim> a = get_aabb<ndim, value_type>()(*begin); ++begin;
|
||||
min = a.min();
|
||||
max = a.max();
|
||||
while (begin != end) {
|
||||
aabb<ndim> a = get_aabb<ndim, value_type>()(*begin); ++begin;
|
||||
assign_op(min, min, a.min(), carve::util::min_functor());
|
||||
assign_op(max, max, a.max(), carve::util::max_functor());
|
||||
}
|
||||
|
||||
pos = (min + max) / 2.0;
|
||||
assign_op(extent, max - pos, pos - min, carve::util::max_functor());
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
template<typename iter_t>
|
||||
void aabb<ndim>::_fit(iter_t begin, iter_t end, vector_t) {
|
||||
if (begin == end) {
|
||||
empty();
|
||||
return;
|
||||
}
|
||||
|
||||
vector_t min, max;
|
||||
bounds(begin, end, min, max);
|
||||
pos = (min + max) / 2.0;
|
||||
assign_op(extent, max - pos, pos - min, carve::util::max_functor());
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
template<typename iter_t>
|
||||
void aabb<ndim>::_fit(iter_t begin, iter_t end, aabb_t) {
|
||||
if (begin == end) {
|
||||
empty();
|
||||
return;
|
||||
}
|
||||
|
||||
vector_t min, max;
|
||||
aabb<ndim> a = *begin++;
|
||||
min = a.min();
|
||||
max = a.max();
|
||||
while (begin != end) {
|
||||
aabb<ndim> a = *begin; ++begin;
|
||||
assign_op(min, min, a.min(), carve::util::min_functor());
|
||||
assign_op(max, max, a.max(), carve::util::max_functor());
|
||||
}
|
||||
|
||||
pos = (min + max) / 2.0;
|
||||
assign_op(extent, max - pos, pos - min, carve::util::max_functor());
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
void aabb<ndim>::fit(const vector_t &v1) {
|
||||
pos = v1;
|
||||
extent.setZero();
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
void aabb<ndim>::fit(const vector_t &v1, const vector_t &v2) {
|
||||
vector_t min, max;
|
||||
assign_op(min, v1, v2, carve::util::min_functor());
|
||||
assign_op(max, v1, v2, carve::util::max_functor());
|
||||
|
||||
pos = (min + max) / 2.0;
|
||||
assign_op(extent, max - pos, pos - min, carve::util::max_functor());
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
void aabb<ndim>::fit(const vector_t &v1, const vector_t &v2, const vector_t &v3) {
|
||||
vector_t min, max;
|
||||
min = max = v1;
|
||||
|
||||
assign_op(min, min, v2, carve::util::min_functor());
|
||||
assign_op(max, max, v2, carve::util::max_functor());
|
||||
assign_op(min, min, v3, carve::util::min_functor());
|
||||
assign_op(max, max, v3, carve::util::max_functor());
|
||||
|
||||
pos = (min + max) / 2.0;
|
||||
assign_op(extent, max - pos, pos - min, carve::util::max_functor());
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
template<typename iter_t, typename adapt_t>
|
||||
void aabb<ndim>::fit(iter_t begin, iter_t end, adapt_t adapt) {
|
||||
vector_t min, max;
|
||||
|
||||
bounds(begin, end, adapt, min, max);
|
||||
pos = (min + max) / 2.0;
|
||||
assign_op(extent, max - pos, pos - min, carve::util::max_functor());
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
template<typename iter_t>
|
||||
void aabb<ndim>::fit(iter_t begin, iter_t end) {
|
||||
_fit(begin, end, typename std::iterator_traits<iter_t>::value_type());
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
void aabb<ndim>::expand(double pad) {
|
||||
extent += pad;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
void aabb<ndim>::unionAABB(const aabb<ndim> &a) {
|
||||
vector_t vmin, vmax;
|
||||
|
||||
assign_op(vmin, min(), a.min(), carve::util::min_functor());
|
||||
assign_op(vmax, max(), a.max(), carve::util::max_functor());
|
||||
pos = (vmin + vmax) / 2.0;
|
||||
assign_op(extent, vmax - pos, pos - vmin, carve::util::max_functor());
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
bool aabb<ndim>::completelyContains(const aabb<ndim> &other) const {
|
||||
for (unsigned i = 0; i < ndim; ++i) {
|
||||
if (fabs(other.pos.v[i] - pos.v[i]) + other.extent.v[i] > extent.v[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
bool aabb<ndim>::containsPoint(const vector_t &v) const {
|
||||
for (unsigned i = 0; i < ndim; ++i) {
|
||||
if (fabs(v.v[i] - pos.v[i]) > extent.v[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
double aabb<ndim>::axisSeparation(const aabb<ndim> &other, unsigned axis) const {
|
||||
return fabs(other.pos.v[axis] - pos.v[axis]) - extent.v[axis] - other.extent.v[axis];
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
double aabb<ndim>::maxAxisSeparation(const aabb<ndim> &other) const {
|
||||
double m = axisSeparation(other, 0);
|
||||
for (unsigned i = 1; i < ndim; ++i) {
|
||||
m = std::max(m, axisSeparation(other, i));
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
bool aabb<ndim>::intersects(const aabb<ndim> &other) const {
|
||||
return maxAxisSeparation(other) <= 0.0;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
bool aabb<ndim>::intersects(const sphere<ndim> &s) const {
|
||||
double r = 0.0;
|
||||
for (unsigned i = 0; i < ndim; ++i) {
|
||||
double t = fabs(s.C[i] - pos[i]) - extent[i]; if (t > 0.0) r += t*t;
|
||||
}
|
||||
return r <= s.r*s.r;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
bool aabb<ndim>::intersects(const plane<ndim> &plane) const {
|
||||
double d1 = fabs(distance(plane, pos));
|
||||
double d2 = dot(abs(plane.N), extent);
|
||||
return d1 <= d2;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
bool aabb<ndim>::intersects(const linesegment<ndim> &ls) const {
|
||||
return intersectsLineSegment(ls.v1, ls.v2);
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
std::pair<double, double> aabb<ndim>::rangeInDirection(const carve::geom::vector<ndim> &v) const {
|
||||
double d1 = dot(v, pos);
|
||||
double d2 = dot(abs(v), extent);
|
||||
|
||||
return std::make_pair(d1 - d2, d1 + d2);
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
typename aabb<ndim>::vector_t aabb<ndim>::min() const { return pos - extent; }
|
||||
|
||||
template<unsigned ndim>
|
||||
typename aabb<ndim>::vector_t aabb<ndim>::mid() const { return pos; }
|
||||
|
||||
template<unsigned ndim>
|
||||
typename aabb<ndim>::vector_t aabb<ndim>::max() const { return pos + extent; }
|
||||
|
||||
template<unsigned ndim>
|
||||
double aabb<ndim>::min(unsigned dim) const { return pos.v[dim] - extent.v[dim]; }
|
||||
|
||||
template<unsigned ndim>
|
||||
double aabb<ndim>::mid(unsigned dim) const { return pos.v[dim]; }
|
||||
|
||||
template<unsigned ndim>
|
||||
double aabb<ndim>::max(unsigned dim) const { return pos.v[dim] + extent.v[dim]; }
|
||||
|
||||
template<unsigned ndim>
|
||||
double aabb<ndim>::volume() const {
|
||||
double v = 1.0;
|
||||
for (size_t dim = 0; dim < ndim; ++dim) { v *= 2.0 * extent.v[dim]; }
|
||||
return v;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
int aabb<ndim>::compareAxis(const axis_pos &ap) const {
|
||||
double p = ap.pos - pos[ap.axis];
|
||||
if (p > extent[ap.axis]) return -1;
|
||||
if (p < -extent[ap.axis]) return +1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
void aabb<ndim>::constrainMax(const axis_pos &ap) {
|
||||
if (pos[ap.axis] + extent[ap.axis] > ap.pos) {
|
||||
double min = std::min(ap.pos, pos[ap.axis] - extent[ap.axis]);
|
||||
pos[ap.axis] = (min + ap.pos) / 2.0;
|
||||
extent[ap.axis] = ap.pos - pos[ap.axis];
|
||||
}
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
void aabb<ndim>::constrainMin(const axis_pos &ap) {
|
||||
if (pos[ap.axis] - extent[ap.axis] < ap.pos) {
|
||||
double max = std::max(ap.pos, pos[ap.axis] + extent[ap.axis]);
|
||||
pos[ap.axis] = (ap.pos + max) / 2.0;
|
||||
extent[ap.axis] = pos[ap.axis] - ap.pos;
|
||||
}
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
aabb<ndim> aabb<ndim>::getAABB() const {
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
aabb<ndim>::aabb(const vector_t &_pos,
|
||||
const vector_t &_extent) : pos(_pos), extent(_extent) {
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
template<typename iter_t, typename adapt_t>
|
||||
aabb<ndim>::aabb(iter_t begin, iter_t end, adapt_t adapt) {
|
||||
fit(begin, end, adapt);
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
template<typename iter_t>
|
||||
aabb<ndim>::aabb(iter_t begin, iter_t end) {
|
||||
fit(begin, end);
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
aabb<ndim>::aabb(const aabb<ndim> &a, const aabb<ndim> &b) {
|
||||
fit(a, b);
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
bool operator==(const aabb<ndim> &a, const aabb<ndim> &b) {
|
||||
return a.pos == b.pos && a.extent == b.extent;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
bool operator!=(const aabb<ndim> &a, const aabb<ndim> &b) {
|
||||
return a.pos != b.pos || a.extent != b.extent;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
std::ostream &operator<<(std::ostream &o, const aabb<ndim> &a) {
|
||||
o << (a.pos - a.extent) << "--" << (a.pos + a.extent);
|
||||
return o;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool aabb<3>::intersects(const ray<3> &ray) const {
|
||||
vector<3> t = pos - ray.v;
|
||||
double r;
|
||||
|
||||
//l.cross(x-axis)?
|
||||
r = extent.y * fabs(ray.D.z) + extent.z * fabs(ray.D.y);
|
||||
if (fabs(t.y * ray.D.z - t.z * ray.D.y) > r) return false;
|
||||
|
||||
//ray.D.cross(y-axis)?
|
||||
r = extent.x * fabs(ray.D.z) + extent.z * fabs(ray.D.x);
|
||||
if (fabs(t.z * ray.D.x - t.x * ray.D.z) > r) return false;
|
||||
|
||||
//ray.D.cross(z-axis)?
|
||||
r = extent.x*fabs(ray.D.y) + extent.y*fabs(ray.D.x);
|
||||
if (fabs(t.x * ray.D.y - t.y * ray.D.x) > r) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool aabb<3>::intersectsLineSegment(const vector<3> &v1, const vector<3> &v2) const {
|
||||
vector<3> half_length = 0.5 * (v2 - v1);
|
||||
vector<3> t = pos - half_length - v1;
|
||||
double r;
|
||||
|
||||
//do any of the principal axes form a separating axis?
|
||||
if(fabs(t.x) > extent.x + fabs(half_length.x)) return false;
|
||||
if(fabs(t.y) > extent.y + fabs(half_length.y)) return false;
|
||||
if(fabs(t.z) > extent.z + fabs(half_length.z)) return false;
|
||||
|
||||
// NOTE: Since the separating axis is perpendicular to the line in
|
||||
// these last four cases, the line does not contribute to the
|
||||
// projection.
|
||||
|
||||
//line.cross(x-axis)?
|
||||
r = extent.y * fabs(half_length.z) + extent.z * fabs(half_length.y);
|
||||
if (fabs(t.y * half_length.z - t.z * half_length.y) > r) return false;
|
||||
|
||||
//half_length.cross(y-axis)?
|
||||
r = extent.x * fabs(half_length.z) + extent.z * fabs(half_length.x);
|
||||
if (fabs(t.z * half_length.x - t.x * half_length.z) > r) return false;
|
||||
|
||||
//half_length.cross(z-axis)?
|
||||
r = extent.x*fabs(half_length.y) + extent.y*fabs(half_length.x);
|
||||
if (fabs(t.x * half_length.y - t.y * half_length.x) > r) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<int Ax, int Ay, int Az, int c>
|
||||
static inline bool intersectsTriangle_axisTest_3(const aabb<3> &aabb, const tri<3> &tri) {
|
||||
const int d = (c+1) % 3, e = (c+2) % 3;
|
||||
const vector<3> a = cross(VECTOR(Ax, Ay, Az), tri.v[d] - tri.v[c]);
|
||||
double p1 = dot(a, tri.v[c]), p2 = dot(a, tri.v[e]);
|
||||
if (p1 > p2) std::swap(p1, p2);
|
||||
const double r = dot(abs(a), aabb.extent);
|
||||
return !(p1 > r || p2 < -r);
|
||||
}
|
||||
|
||||
template<int c>
|
||||
static inline bool intersectsTriangle_axisTest_2(const aabb<3> &aabb, const tri<3> &tri) {
|
||||
double vmin = std::min(std::min(tri.v[0][c], tri.v[1][c]), tri.v[2][c]),
|
||||
vmax = std::max(std::max(tri.v[0][c], tri.v[1][c]), tri.v[2][c]);
|
||||
return !(vmin > aabb.extent[c] || vmax < -aabb.extent[c]);
|
||||
}
|
||||
|
||||
static inline bool intersectsTriangle_axisTest_1(const aabb<3> &aabb, const tri<3> &tri) {
|
||||
vector<3> n = cross(tri.v[1] - tri.v[0], tri.v[2] - tri.v[0]);
|
||||
double d1 = fabs(dot(n, tri.v[0]));
|
||||
double d2 = dot(abs(n), aabb.extent);
|
||||
return d1 <= d2;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool aabb<3>::intersects(tri<3> tri) const {
|
||||
tri.v[0] -= pos;
|
||||
tri.v[1] -= pos;
|
||||
tri.v[2] -= pos;
|
||||
|
||||
if (!intersectsTriangle_axisTest_2<0>(*this, tri)) return false;
|
||||
if (!intersectsTriangle_axisTest_2<1>(*this, tri)) return false;
|
||||
if (!intersectsTriangle_axisTest_2<2>(*this, tri)) return false;
|
||||
|
||||
if (!intersectsTriangle_axisTest_3<1,0,0,0>(*this, tri)) return false;
|
||||
if (!intersectsTriangle_axisTest_3<1,0,0,1>(*this, tri)) return false;
|
||||
if (!intersectsTriangle_axisTest_3<1,0,0,2>(*this, tri)) return false;
|
||||
|
||||
if (!intersectsTriangle_axisTest_3<0,1,0,0>(*this, tri)) return false;
|
||||
if (!intersectsTriangle_axisTest_3<0,1,0,1>(*this, tri)) return false;
|
||||
if (!intersectsTriangle_axisTest_3<0,1,0,2>(*this, tri)) return false;
|
||||
|
||||
if (!intersectsTriangle_axisTest_3<0,0,1,0>(*this, tri)) return false;
|
||||
if (!intersectsTriangle_axisTest_3<0,0,1,1>(*this, tri)) return false;
|
||||
if (!intersectsTriangle_axisTest_3<0,0,1,2>(*this, tri)) return false;
|
||||
|
||||
if (!intersectsTriangle_axisTest_1(*this, tri)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
238
extern/carve/include/carve/carve.hpp
vendored
Normal file
238
extern/carve/include/carve/carve.hpp
vendored
Normal file
@ -0,0 +1,238 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(CMAKE_BUILD)
|
||||
# include <carve/config.h>
|
||||
#elif defined(XCODE_BUILD)
|
||||
# include <carve/xcode_config.h>
|
||||
#elif defined(_MSC_VER)
|
||||
# include <carve/vcpp_config.h>
|
||||
#else
|
||||
# include <carve/config.h>
|
||||
#endif
|
||||
|
||||
#if defined(WIN32)
|
||||
# include <carve/win32.h>
|
||||
#elif defined(__GNUC__)
|
||||
# include <carve/gnu_cxx.h>
|
||||
#endif
|
||||
|
||||
#if defined(CARVE_SYSTEM_BOOST)
|
||||
# define BOOST_INCLUDE(x) <boost/x>
|
||||
#else
|
||||
# define BOOST_INCLUDE(x) <carve/external/boost/x>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
#include <carve/collection.hpp>
|
||||
|
||||
#include <carve/util.hpp>
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#define STR(x) #x
|
||||
#define XSTR(x) STR(x)
|
||||
|
||||
/**
|
||||
* \brief Top level Carve namespace.
|
||||
*/
|
||||
namespace carve {
|
||||
static struct noinit_t {} NOINIT;
|
||||
|
||||
inline std::string fmtstring(const char *fmt, ...);
|
||||
|
||||
/**
|
||||
* \brief Base class for all Carve exceptions.
|
||||
*/
|
||||
struct exception {
|
||||
private:
|
||||
mutable std::string err;
|
||||
mutable std::ostringstream accum;
|
||||
|
||||
public:
|
||||
exception(const std::string &e) : err(e), accum() { }
|
||||
exception() : err(), accum() { }
|
||||
exception(const exception &e) : err(e.str()), accum() { }
|
||||
exception &operator=(const exception &e) {
|
||||
if (this != &e) {
|
||||
err = e.str();
|
||||
accum.str("");
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
const std::string &str() const {
|
||||
if (accum.str().size() > 0) {
|
||||
err += accum.str();
|
||||
accum.str("");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
exception &operator<<(const T &t) {
|
||||
accum << t;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename iter_t, typename order_t = std::less<typename std::iterator_traits<iter_t>::value_type > >
|
||||
struct index_sort {
|
||||
iter_t base;
|
||||
order_t order;
|
||||
index_sort(const iter_t &_base) : base(_base), order() { }
|
||||
index_sort(const iter_t &_base, const order_t &_order) : base(_base), order(_order) { }
|
||||
template<typename U>
|
||||
bool operator()(const U &a, const U &b) {
|
||||
return order(*(base + a), *(base + b));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename iter_t, typename order_t>
|
||||
index_sort<iter_t, order_t> make_index_sort(const iter_t &base, const order_t &order) {
|
||||
return index_sort<iter_t, order_t>(base, order);
|
||||
}
|
||||
|
||||
template<typename iter_t>
|
||||
index_sort<iter_t> make_index_sort(const iter_t &base) {
|
||||
return index_sort<iter_t>(base);
|
||||
}
|
||||
|
||||
|
||||
enum RayIntersectionClass {
|
||||
RR_DEGENERATE = -2,
|
||||
RR_PARALLEL = -1,
|
||||
RR_NO_INTERSECTION = 0,
|
||||
RR_INTERSECTION = 1
|
||||
};
|
||||
|
||||
enum LineIntersectionClass {
|
||||
COLINEAR = -1,
|
||||
NO_INTERSECTION = 0,
|
||||
INTERSECTION_LL = 1,
|
||||
INTERSECTION_PL = 2,
|
||||
INTERSECTION_LP = 3,
|
||||
INTERSECTION_PP = 4
|
||||
};
|
||||
|
||||
enum PointClass {
|
||||
POINT_UNK = -2,
|
||||
POINT_OUT = -1,
|
||||
POINT_ON = 0,
|
||||
POINT_IN = 1,
|
||||
POINT_VERTEX = 2,
|
||||
POINT_EDGE = 3
|
||||
};
|
||||
|
||||
enum IntersectionClass {
|
||||
INTERSECT_BAD = -1,
|
||||
INTERSECT_NONE = 0,
|
||||
INTERSECT_FACE = 1,
|
||||
INTERSECT_VERTEX = 2,
|
||||
INTERSECT_EDGE = 3,
|
||||
INTERSECT_PLANE = 4,
|
||||
};
|
||||
|
||||
|
||||
|
||||
extern double EPSILON;
|
||||
extern double EPSILON2;
|
||||
|
||||
static inline void setEpsilon(double ep) { EPSILON = ep; EPSILON2 = ep * ep; }
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct identity_t {
|
||||
typedef T argument_type;
|
||||
typedef T result_type;
|
||||
const T &operator()(const T &t) const { return t; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename iter_t>
|
||||
inline bool is_sorted(iter_t first, iter_t last) {
|
||||
if (first == last) return true;
|
||||
|
||||
iter_t iter = first;
|
||||
iter_t next = first; ++next;
|
||||
for (; next != last; iter = next, ++next) {
|
||||
if (*next < *iter) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename iter_t,
|
||||
typename pred_t>
|
||||
inline bool is_sorted(iter_t first, iter_t last, pred_t pred) {
|
||||
if (first == last) return true;
|
||||
|
||||
iter_t iter = first;
|
||||
iter_t next = first; ++next;
|
||||
for (; next != last; iter = next, ++next) {
|
||||
if (pred(*next, *iter)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline double rangeSeparation(const std::pair<double, double> &a,
|
||||
const std::pair<double, double> &b) {
|
||||
if (a.second < b.first) {
|
||||
return b.first - a.second;
|
||||
} else if (b.second < a.first) {
|
||||
return a.first - b.second;
|
||||
} else {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# define MACRO_BEGIN do {
|
||||
# define MACRO_END __pragma(warning(push)) __pragma(warning(disable:4127)) } while(0) __pragma(warning(pop))
|
||||
#else
|
||||
# define MACRO_BEGIN do {
|
||||
# define MACRO_END } while(0)
|
||||
#endif
|
||||
|
||||
#if !defined(CARVE_NODEBUG)
|
||||
# define CARVE_ASSERT(x) MACRO_BEGIN if (!(x)) throw carve::exception() << __FILE__ << ":" << __LINE__ << " " << #x; MACRO_END
|
||||
#else
|
||||
# define CARVE_ASSERT(X)
|
||||
#endif
|
||||
|
||||
#define CARVE_FAIL(x) MACRO_BEGIN throw carve::exception() << __FILE__ << ":" << __LINE__ << " " << #x; MACRO_END
|
93
extern/carve/include/carve/cbrt.h
vendored
Normal file
93
extern/carve/include/carve/cbrt.h
vendored
Normal file
@ -0,0 +1,93 @@
|
||||
// N.B. only appropriate for IEEE doubles.
|
||||
// Cube root implementation obtained from code with the following notice:
|
||||
|
||||
/* @(#)s_cbrt.c 1.3 95/01/18 */
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunSoft, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*
|
||||
*/
|
||||
|
||||
/* Sometimes it's necessary to define __LITTLE_ENDIAN explicitly
|
||||
but these catch some common cases. */
|
||||
|
||||
#if defined(i386) || defined(i486) || \
|
||||
defined(intel) || defined(x86) || defined(i86pc) || \
|
||||
defined(__alpha) || defined(__osf__)
|
||||
#define __LITTLE_ENDIAN
|
||||
#endif
|
||||
|
||||
#ifdef __LITTLE_ENDIAN
|
||||
#define __HI(x) *(1+(int*)&x)
|
||||
#define __LO(x) *(int*)&x
|
||||
#define __HIp(x) *(1+(int*)x)
|
||||
#define __LOp(x) *(int*)x
|
||||
#else
|
||||
#define __HI(x) *(int*)&x
|
||||
#define __LO(x) *(1+(int*)&x)
|
||||
#define __HIp(x) *(int*)x
|
||||
#define __LOp(x) *(1+(int*)x)
|
||||
#endif
|
||||
|
||||
/* cbrt(x)
|
||||
* Return cube root of x
|
||||
*/
|
||||
|
||||
inline double cbrt(double x) {
|
||||
|
||||
static const unsigned
|
||||
B1 = 715094163, /* B1 = (682-0.03306235651)*2**20 */
|
||||
B2 = 696219795; /* B2 = (664-0.03306235651)*2**20 */
|
||||
static const double
|
||||
C = 5.42857142857142815906e-01, /* 19/35 = 0x3FE15F15, 0xF15F15F1 */
|
||||
D = -7.05306122448979611050e-01, /* -864/1225 = 0xBFE691DE, 0x2532C834 */
|
||||
E = 1.41428571428571436819e+00, /* 99/70 = 0x3FF6A0EA, 0x0EA0EA0F */
|
||||
F = 1.60714285714285720630e+00, /* 45/28 = 0x3FF9B6DB, 0x6DB6DB6E */
|
||||
G = 3.57142857142857150787e-01; /* 5/14 = 0x3FD6DB6D, 0xB6DB6DB7 */
|
||||
|
||||
int hx;
|
||||
double r,s,t=0.0,w;
|
||||
unsigned sign;
|
||||
|
||||
hx = __HI(x); /* high word of x */
|
||||
sign=hx&0x80000000; /* sign= sign(x) */
|
||||
hx ^=sign;
|
||||
if(hx>=0x7ff00000) return(x+x); /* cbrt(NaN,INF) is itself */
|
||||
if((hx|__LO(x))==0)
|
||||
return(x); /* cbrt(0) is itself */
|
||||
|
||||
__HI(x) = hx; /* x <- |x| */
|
||||
/* rough cbrt to 5 bits */
|
||||
if(hx<0x00100000) /* subnormal number */
|
||||
{__HI(t)=0x43500000; /* set t= 2**54 */
|
||||
t*=x; __HI(t)=__HI(t)/3+B2;
|
||||
}
|
||||
else
|
||||
__HI(t)=hx/3+B1;
|
||||
|
||||
|
||||
/* new cbrt to 23 bits, may be implemented in single precision */
|
||||
r=t*t/x;
|
||||
s=C+r*t;
|
||||
t*=G+F/(s+E+D/s);
|
||||
|
||||
/* chopped to 20 bits and make it larger than cbrt(x) */
|
||||
__LO(t)=0; __HI(t)+=0x00000001;
|
||||
|
||||
/* one step newton iteration to 53 bits with error less than 0.667 ulps */
|
||||
s=t*t; /* t*t is exact */
|
||||
r=x/s;
|
||||
w=t+t;
|
||||
r=(r-t)/(w+r); /* r-s is exact */
|
||||
t=t+t*r;
|
||||
|
||||
/* retore the sign bit */
|
||||
__HI(t) |= sign;
|
||||
return(t);
|
||||
}
|
115
extern/carve/include/carve/classification.hpp
vendored
Normal file
115
extern/carve/include/carve/classification.hpp
vendored
Normal file
@ -0,0 +1,115 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
#include <carve/collection_types.hpp>
|
||||
|
||||
namespace carve {
|
||||
namespace csg {
|
||||
|
||||
enum FaceClass {
|
||||
FACE_UNCLASSIFIED = -3,
|
||||
FACE_ON_ORIENT_OUT = -2,
|
||||
FACE_OUT = -1,
|
||||
FACE_ON = 0,
|
||||
FACE_IN = +1,
|
||||
FACE_ON_ORIENT_IN = +2
|
||||
};
|
||||
|
||||
enum FaceClassBit {
|
||||
FACE_ON_ORIENT_OUT_BIT = 0x01,
|
||||
FACE_OUT_BIT = 0x02,
|
||||
FACE_IN_BIT = 0x04,
|
||||
FACE_ON_ORIENT_IN_BIT = 0x08,
|
||||
|
||||
FACE_ANY_BIT = 0x0f,
|
||||
FACE_ON_BIT = 0x09,
|
||||
FACE_NOT_ON_BIT = 0x06
|
||||
};
|
||||
|
||||
static inline FaceClass class_bit_to_class(unsigned i) {
|
||||
if (i & FACE_ON_ORIENT_OUT_BIT) return FACE_ON_ORIENT_OUT;
|
||||
if (i & FACE_OUT_BIT) return FACE_OUT;
|
||||
if (i & FACE_IN_BIT) return FACE_IN;
|
||||
if (i & FACE_ON_ORIENT_IN_BIT) return FACE_ON_ORIENT_IN;
|
||||
return FACE_UNCLASSIFIED;
|
||||
}
|
||||
|
||||
static inline unsigned class_to_class_bit(FaceClass f) {
|
||||
switch (f) {
|
||||
case FACE_ON_ORIENT_OUT: return FACE_ON_ORIENT_OUT_BIT;
|
||||
case FACE_OUT: return FACE_OUT_BIT;
|
||||
case FACE_ON: return FACE_ON_BIT;
|
||||
case FACE_IN: return FACE_IN_BIT;
|
||||
case FACE_ON_ORIENT_IN: return FACE_ON_ORIENT_IN_BIT;
|
||||
case FACE_UNCLASSIFIED: return FACE_ANY_BIT;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
enum EdgeClass {
|
||||
EDGE_UNK = -2,
|
||||
EDGE_OUT = -1,
|
||||
EDGE_ON = 0,
|
||||
EDGE_IN = 1
|
||||
};
|
||||
|
||||
|
||||
|
||||
const char *ENUM(FaceClass f);
|
||||
const char *ENUM(PointClass p);
|
||||
|
||||
|
||||
|
||||
struct ClassificationInfo {
|
||||
const carve::mesh::Mesh<3> *intersected_mesh;
|
||||
FaceClass classification;
|
||||
|
||||
ClassificationInfo() : intersected_mesh(NULL), classification(FACE_UNCLASSIFIED) { }
|
||||
ClassificationInfo(const carve::mesh::Mesh<3> *_intersected_mesh,
|
||||
FaceClass _classification) :
|
||||
intersected_mesh(_intersected_mesh),
|
||||
classification(_classification) {
|
||||
}
|
||||
bool intersectedMeshIsClosed() const {
|
||||
return intersected_mesh->isClosed();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct EC2 {
|
||||
EdgeClass cls[2];
|
||||
EC2() { cls[0] = cls[1] = EDGE_UNK; }
|
||||
EC2(EdgeClass a, EdgeClass b) { cls[0] = a; cls[1] = b; }
|
||||
};
|
||||
|
||||
struct PC2 {
|
||||
PointClass cls[2];
|
||||
PC2() { cls[0] = cls[1] = POINT_UNK; }
|
||||
PC2(PointClass a, PointClass b) { cls[0] = a; cls[1] = b; }
|
||||
};
|
||||
|
||||
typedef std::unordered_map<std::pair<const carve::mesh::MeshSet<3>::vertex_t *, const carve::mesh::MeshSet<3>::vertex_t *>,
|
||||
EC2> EdgeClassification;
|
||||
|
||||
typedef std::unordered_map<const carve::mesh::Vertex<3> *, PC2> VertexClassification;
|
||||
|
||||
}
|
||||
}
|
51
extern/carve/include/carve/collection.hpp
vendored
Normal file
51
extern/carve/include/carve/collection.hpp
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/collection/unordered.hpp>
|
||||
|
||||
namespace carve {
|
||||
|
||||
template<typename set_t>
|
||||
class set_insert_iterator : public std::iterator<std::output_iterator_tag, void, void, void, void> {
|
||||
|
||||
protected:
|
||||
set_t *set;
|
||||
public:
|
||||
|
||||
set_insert_iterator(set_t &s) : set(&s) {
|
||||
}
|
||||
|
||||
set_insert_iterator &
|
||||
operator=(typename set_t::const_reference value) {
|
||||
set->insert(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
set_insert_iterator &operator*() { return *this; }
|
||||
set_insert_iterator &operator++() { return *this; }
|
||||
set_insert_iterator &operator++(int) { return *this; }
|
||||
};
|
||||
|
||||
template<typename set_t>
|
||||
inline set_insert_iterator<set_t>
|
||||
set_inserter(set_t &s) {
|
||||
return set_insert_iterator<set_t>(s);
|
||||
}
|
||||
|
||||
}
|
43
extern/carve/include/carve/collection/unordered.hpp
vendored
Normal file
43
extern/carve/include/carve/collection/unordered.hpp
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(HAVE_STD_UNORDERED_COLLECTIONS)
|
||||
|
||||
# include <carve/collection/unordered/std_impl.hpp>
|
||||
|
||||
#elif defined(HAVE_TR1_UNORDERED_COLLECTIONS)
|
||||
|
||||
# include <carve/collection/unordered/tr1_impl.hpp>
|
||||
|
||||
#elif defined(HAVE_BOOST_UNORDERED_COLLECTIONS)
|
||||
|
||||
# include <carve/collection/unordered/boost_impl.hpp>
|
||||
|
||||
#elif defined(HAVE_LIBSTDCPP_UNORDERED_COLLECTIONS)
|
||||
|
||||
# include <carve/collection/unordered/libstdcpp_impl.hpp>
|
||||
|
||||
#elif defined(_MSC_VER) && _MSC_VER >= 1300
|
||||
|
||||
# include <carve/collection/unordered/vcpp_impl.hpp>
|
||||
|
||||
#else
|
||||
|
||||
# include <carve/collection/unordered/fallback_impl.hpp>
|
||||
|
||||
#endif
|
45
extern/carve/include/carve/collection/unordered/boost_impl.hpp
vendored
Normal file
45
extern/carve/include/carve/collection/unordered/boost_impl.hpp
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include BOOST_INCLUDE(unordered_set.hpp)
|
||||
#include BOOST_INCLUDE(unordered_map.hpp)
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace std {
|
||||
template <typename Key, typename T, typename Hash = boost::hash<Key>,
|
||||
typename Pred = std::equal_to<Key> >
|
||||
class unordered_map : public boost::unordered_map<Key, T, Hash, Pred> {
|
||||
|
||||
public:
|
||||
typedef T data_type;
|
||||
};
|
||||
|
||||
template <typename Key, typename T, typename Hash = boost::hash<Key>,
|
||||
typename Pred = std::equal_to<Key> >
|
||||
class unordered_multimap : public boost::unordered_multimap<Key, T, Hash, Pred> {
|
||||
};
|
||||
|
||||
template <typename Value, typename Hash = boost::hash<Value>,
|
||||
typename Pred = std::equal_to<Value> >
|
||||
class unordered_set : public boost::unordered_set<Value, Hash, Pred> {
|
||||
};
|
||||
}
|
||||
|
||||
#undef UNORDERED_COLLECTIONS_SUPPORT_RESIZE
|
40
extern/carve/include/carve/collection/unordered/fallback_impl.hpp
vendored
Normal file
40
extern/carve/include/carve/collection/unordered/fallback_impl.hpp
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
namespace std {
|
||||
|
||||
template<typename K, typename T, typename H = int>
|
||||
class unordered_map : public std::map<K, T> {
|
||||
typedef std::map<K, T> super;
|
||||
public:
|
||||
typedef T data_type;
|
||||
};
|
||||
|
||||
template<typename K, typename H = int>
|
||||
class unordered_set : public std::set<K> {
|
||||
typedef std::set<K> super;
|
||||
public:
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#undef UNORDERED_COLLECTIONS_SUPPORT_RESIZE
|
61
extern/carve/include/carve/collection/unordered/libstdcpp_impl.hpp
vendored
Normal file
61
extern/carve/include/carve/collection/unordered/libstdcpp_impl.hpp
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ext/hash_map>
|
||||
#include <ext/hash_set>
|
||||
|
||||
namespace __gnu_cxx {
|
||||
template <typename T>
|
||||
struct hash<T *> : public std::unary_function<T *, size_t> {
|
||||
size_t operator()(T *v) const {
|
||||
size_t x = (size_t)(v);
|
||||
return x + (x>>3);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename A, typename B>
|
||||
struct hash<std::pair<A, B> > : public std::unary_function<std::pair<A, B>, size_t> {
|
||||
size_t operator()(const std::pair<A, B> &v) const {
|
||||
std::size_t seed = 0;
|
||||
|
||||
seed ^= hash<A>()(v.first);
|
||||
seed ^= hash<B>()(v.second) + (seed<<6) + (seed>>2);
|
||||
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace std {
|
||||
|
||||
template<typename K, typename V, typename H = __gnu_cxx::hash<K> >
|
||||
class unordered_map : public __gnu_cxx::hash_map<K, V, H> {
|
||||
typedef __gnu_cxx::hash_map<K, V, H> super;
|
||||
public:
|
||||
typedef typename super::mapped_type data_type;
|
||||
};
|
||||
|
||||
template<typename K, typename H = __gnu_cxx::hash<K> >
|
||||
class unordered_set : public __gnu_cxx::hash_set<K, H> {
|
||||
typedef __gnu_cxx::hash_set<K, H> super;
|
||||
public:
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#define UNORDERED_COLLECTIONS_SUPPORT_RESIZE 1
|
23
extern/carve/include/carve/collection/unordered/std_impl.hpp
vendored
Normal file
23
extern/carve/include/carve/collection/unordered/std_impl.hpp
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#undef UNORDERED_COLLECTIONS_SUPPORT_RESIZE
|
58
extern/carve/include/carve/collection/unordered/tr1_impl.hpp
vendored
Normal file
58
extern/carve/include/carve/collection/unordered/tr1_impl.hpp
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <tr1/unordered_map>
|
||||
#include <tr1/unordered_set>
|
||||
#include <tr1/functional>
|
||||
|
||||
namespace std {
|
||||
namespace tr1 {
|
||||
template <typename A, typename B>
|
||||
struct hash<std::pair<A, B> > : public std::unary_function<std::pair<A, B>, size_t> {
|
||||
size_t operator()(const std::pair<A, B> &v) const {
|
||||
std::size_t seed = 0;
|
||||
|
||||
seed ^= hash<A>()(v.first);
|
||||
seed ^= hash<B>()(v.second) + (seed<<6) + (seed>>2);
|
||||
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename Key, typename T,
|
||||
typename Hash = tr1::hash<Key>,
|
||||
typename Pred = std::equal_to<Key> >
|
||||
class unordered_map : public std::tr1::unordered_map<Key, T, Hash, Pred> {
|
||||
public:
|
||||
typedef T data_type;
|
||||
};
|
||||
|
||||
template <typename Value,
|
||||
typename Hash = tr1::hash<Value>,
|
||||
typename Pred = std::equal_to<Value> >
|
||||
class unordered_set : public std::tr1::unordered_set<Value, Hash, Pred> {
|
||||
public:
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#undef UNORDERED_COLLECTIONS_SUPPORT_RESIZE
|
65
extern/carve/include/carve/collection/unordered/vcpp_impl.hpp
vendored
Normal file
65
extern/carve/include/carve/collection/unordered/vcpp_impl.hpp
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <hash_map>
|
||||
#include <hash_set>
|
||||
|
||||
namespace std {
|
||||
|
||||
namespace {
|
||||
|
||||
template<class Value, class Hash> class hash_traits {
|
||||
Hash hash_value;
|
||||
std::less<Value> comp;
|
||||
public:
|
||||
enum {
|
||||
bucket_size = 4,
|
||||
min_buckets = 8
|
||||
};
|
||||
// hash _Keyval to size_t value
|
||||
size_t operator()(const Value& v) const {
|
||||
return ((size_t)hash_value(v));
|
||||
}
|
||||
// test if _Keyval1 ordered before _Keyval2
|
||||
bool operator()(const Value& v1, const Value& v2) const {
|
||||
return (comp(v1, v2));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template <typename Key, typename T, typename Hash = stdext::hash_compare<Key, less<Key> >, typename Pred = std::equal_to<Key> >
|
||||
class unordered_map
|
||||
: public stdext::hash_map<Key, T, hash_traits<Key, Hash> > {
|
||||
typedef stdext::hash_map<Key, T, hash_traits<Key, Hash> > super;
|
||||
public:
|
||||
unordered_map() : super() {}
|
||||
};
|
||||
|
||||
template <typename Value, typename Hash = stdext::hash_compare<Key, less<Key> >, typename Pred = std::equal_to<Value> >
|
||||
class unordered_set
|
||||
: public stdext::hash_set<Value, hash_traits<Value, Hash> > {
|
||||
typedef stdext::hash_set<Value, hash_traits<Value, Hash> > super;
|
||||
public:
|
||||
unordered_set() : super() {}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#undef UNORDERED_COLLECTIONS_SUPPORT_RESIZE
|
63
extern/carve/include/carve/collection_types.hpp
vendored
Normal file
63
extern/carve/include/carve/collection_types.hpp
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
|
||||
#include <carve/mesh.hpp>
|
||||
|
||||
namespace carve {
|
||||
namespace csg {
|
||||
|
||||
typedef std::pair<
|
||||
carve::mesh::MeshSet<3>::vertex_t *,
|
||||
carve::mesh::MeshSet<3>::vertex_t *> V2;
|
||||
|
||||
typedef std::pair<
|
||||
carve::mesh::MeshSet<3>::face_t *,
|
||||
carve::mesh::MeshSet<3>::face_t *> F2;
|
||||
|
||||
static inline V2 ordered_edge(
|
||||
carve::mesh::MeshSet<3>::vertex_t *a,
|
||||
carve::mesh::MeshSet<3>::vertex_t *b) {
|
||||
return V2(std::min(a, b), std::max(a, b));
|
||||
}
|
||||
|
||||
static inline V2 flip(const V2 &v) {
|
||||
return V2(v.second, v.first);
|
||||
}
|
||||
|
||||
// include/carve/csg.hpp include/carve/faceloop.hpp
|
||||
// lib/intersect.cpp lib/intersect_classify_common_impl.hpp
|
||||
// lib/intersect_classify_edge.cpp
|
||||
// lib/intersect_classify_group.cpp
|
||||
// lib/intersect_classify_simple.cpp
|
||||
// lib/intersect_face_division.cpp lib/intersect_group.cpp
|
||||
// lib/intersect_half_classify_group.cpp
|
||||
typedef std::unordered_set<V2> V2Set;
|
||||
|
||||
// include/carve/csg.hpp include/carve/polyhedron_decl.hpp
|
||||
// lib/csg_collector.cpp lib/intersect.cpp
|
||||
// lib/intersect_common.hpp lib/intersect_face_division.cpp
|
||||
// lib/polyhedron.cpp
|
||||
typedef std::unordered_map<
|
||||
carve::mesh::MeshSet<3>::vertex_t *,
|
||||
carve::mesh::MeshSet<3>::vertex_t *> VVMap;
|
||||
}
|
||||
}
|
47
extern/carve/include/carve/colour.hpp
vendored
Normal file
47
extern/carve/include/carve/colour.hpp
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
#include <carve/geom.hpp>
|
||||
|
||||
namespace carve {
|
||||
namespace colour {
|
||||
static inline void HSV2RGB(float H, float S, float V, float &r, float &g, float &b) {
|
||||
H = 6.0f * H;
|
||||
if (S < 5.0e-6) {
|
||||
r = g = b = V; return;
|
||||
} else {
|
||||
int i = (int)H;
|
||||
float f = H - i;
|
||||
float p1 = V * (1.0f - S);
|
||||
float p2 = V * (1.0f - S * f);
|
||||
float p3 = V * (1.0f - S * (1.0f - f));
|
||||
switch (i) {
|
||||
case 0: r = V; g = p3; b = p1; return;
|
||||
case 1: r = p2; g = V; b = p1; return;
|
||||
case 2: r = p1; g = V; b = p3; return;
|
||||
case 3: r = p1; g = p2; b = V; return;
|
||||
case 4: r = p3; g = p1; b = V; return;
|
||||
case 5: r = V; g = p1; b = p2; return;
|
||||
}
|
||||
}
|
||||
r = g = b = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
12
extern/carve/include/carve/config.h
vendored
Normal file
12
extern/carve/include/carve/config.h
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
#define CARVE_VERSION "2.0.0a"
|
||||
|
||||
#undef CARVE_DEBUG
|
||||
#undef CARVE_DEBUG_WRITE_PLY_DATA
|
||||
|
||||
#if defined(__GNUC__)
|
||||
# if !defined(HAVE_BOOST_UNORDERED_COLLECTIONS)
|
||||
# define HAVE_TR1_UNORDERED_COLLECTIONS
|
||||
# endif
|
||||
|
||||
# define HAVE_STDINT_H
|
||||
#endif
|
52
extern/carve/include/carve/convex_hull.hpp
vendored
Normal file
52
extern/carve/include/carve/convex_hull.hpp
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
|
||||
#include <carve/geom2d.hpp>
|
||||
|
||||
namespace carve {
|
||||
namespace geom {
|
||||
std::vector<int> convexHull(const std::vector<carve::geom2d::P2> &points);
|
||||
|
||||
template<typename project_t, typename polygon_container_t>
|
||||
std::vector<int> convexHull(const project_t &project, const polygon_container_t &points) {
|
||||
std::vector<carve::geom2d::P2> proj;
|
||||
proj.reserve(points.size());
|
||||
for (typename polygon_container_t::const_iterator i = points.begin(); i != points.end(); ++i) {
|
||||
proj.push_back(project(*i));
|
||||
}
|
||||
return convexHull(proj);
|
||||
}
|
||||
|
||||
template<typename project_t, typename iter_t>
|
||||
std::vector<int> convexHull(const project_t &project, iter_t beg, iter_t end, size_t size_hint = 0) {
|
||||
std::vector<carve::geom2d::P2> proj;
|
||||
if (size_hint) proj.reserve(size_hint);
|
||||
for (; beg != end; ++beg) {
|
||||
proj.push_back(project(*beg));
|
||||
}
|
||||
return convexHull(proj);
|
||||
}
|
||||
}
|
||||
}
|
498
extern/carve/include/carve/csg.hpp
vendored
Normal file
498
extern/carve/include/carve/csg.hpp
vendored
Normal file
@ -0,0 +1,498 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
|
||||
#include <carve/geom3d.hpp>
|
||||
|
||||
#include <carve/mesh.hpp>
|
||||
|
||||
#include <carve/collection_types.hpp>
|
||||
#include <carve/classification.hpp>
|
||||
#include <carve/iobj.hpp>
|
||||
#include <carve/faceloop.hpp>
|
||||
#include <carve/intersection.hpp>
|
||||
#include <carve/rtree.hpp>
|
||||
|
||||
namespace carve {
|
||||
namespace csg {
|
||||
|
||||
class VertexPool {
|
||||
typedef carve::mesh::MeshSet<3>::vertex_t vertex_t;
|
||||
|
||||
const static unsigned blocksize = 1024;
|
||||
typedef std::list<std::vector<vertex_t> > pool_t;
|
||||
pool_t pool;
|
||||
public:
|
||||
void reset();
|
||||
vertex_t *get(const vertex_t::vector_t &v = vertex_t::vector_t::ZERO());
|
||||
bool inPool(vertex_t *v) const;
|
||||
|
||||
VertexPool();
|
||||
~VertexPool();
|
||||
};
|
||||
|
||||
|
||||
|
||||
namespace detail {
|
||||
struct Data;
|
||||
class LoopEdges;
|
||||
}
|
||||
|
||||
/**
|
||||
* \class CSG
|
||||
* \brief The class responsible for the computation of CSG operations.
|
||||
*
|
||||
*/
|
||||
class CSG {
|
||||
private:
|
||||
|
||||
public:
|
||||
typedef carve::mesh::MeshSet<3> meshset_t;
|
||||
|
||||
struct Hook {
|
||||
/**
|
||||
* \class Hook
|
||||
* \brief Provides API access to intermediate steps in CSG calculation.
|
||||
*
|
||||
*/
|
||||
virtual void intersectionVertex(const meshset_t::vertex_t * /* vertex */,
|
||||
const IObjPairSet & /* intersections */) {
|
||||
}
|
||||
virtual void processOutputFace(std::vector<meshset_t::face_t *> & /* faces */,
|
||||
const meshset_t::face_t * /* orig_face */,
|
||||
bool /* flipped */) {
|
||||
}
|
||||
virtual void resultFace(const meshset_t::face_t * /* new_face */,
|
||||
const meshset_t::face_t * /* orig_face */,
|
||||
bool /* flipped */) {
|
||||
}
|
||||
|
||||
virtual ~Hook() {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* \class Hooks
|
||||
* \brief Management of API hooks.
|
||||
*
|
||||
*/
|
||||
class Hooks {
|
||||
public:
|
||||
enum {
|
||||
RESULT_FACE_HOOK = 0,
|
||||
PROCESS_OUTPUT_FACE_HOOK = 1,
|
||||
INTERSECTION_VERTEX_HOOK = 2,
|
||||
HOOK_MAX = 3,
|
||||
|
||||
RESULT_FACE_BIT = 0x0001,
|
||||
PROCESS_OUTPUT_FACE_BIT = 0x0002,
|
||||
INTERSECTION_VERTEX_BIT = 0x0004
|
||||
};
|
||||
|
||||
std::vector<std::list<Hook *> > hooks;
|
||||
|
||||
bool hasHook(unsigned hook_num);
|
||||
|
||||
void intersectionVertex(const meshset_t::vertex_t *vertex,
|
||||
const IObjPairSet &intersections);
|
||||
|
||||
void processOutputFace(std::vector<meshset_t::face_t *> &faces,
|
||||
const meshset_t::face_t *orig_face,
|
||||
bool flipped);
|
||||
|
||||
void resultFace(const meshset_t::face_t *new_face,
|
||||
const meshset_t::face_t *orig_face,
|
||||
bool flipped);
|
||||
|
||||
void registerHook(Hook *hook, unsigned hook_bits);
|
||||
void unregisterHook(Hook *hook);
|
||||
|
||||
void reset();
|
||||
|
||||
Hooks();
|
||||
~Hooks();
|
||||
};
|
||||
|
||||
/**
|
||||
* \class Collector
|
||||
* \brief Base class for objects responsible for selecting result from which form the result polyhedron.
|
||||
*
|
||||
*/
|
||||
class Collector {
|
||||
Collector(const Collector &);
|
||||
Collector &operator=(const Collector &);
|
||||
|
||||
protected:
|
||||
|
||||
public:
|
||||
virtual void collect(FaceLoopGroup *group, CSG::Hooks &) =0;
|
||||
virtual meshset_t *done(CSG::Hooks &) =0;
|
||||
|
||||
Collector() {}
|
||||
virtual ~Collector() {}
|
||||
};
|
||||
|
||||
private:
|
||||
typedef carve::geom::RTreeNode<3, carve::mesh::Face<3> *> face_rtree_t;
|
||||
typedef std::unordered_map<carve::mesh::Face<3> *, std::vector<carve::mesh::Face<3> *> > face_pairs_t;
|
||||
|
||||
/// The computed intersection data.
|
||||
Intersections intersections;
|
||||
|
||||
/// A map from intersection point to a set of intersections
|
||||
/// represented by pairs of intersection objects.
|
||||
VertexIntersections vertex_intersections;
|
||||
|
||||
/// A pool from which temporary vertices are allocated. Also
|
||||
/// provides testing for pool membership.
|
||||
VertexPool vertex_pool;
|
||||
|
||||
void init();
|
||||
|
||||
void makeVertexIntersections();
|
||||
|
||||
void groupIntersections();
|
||||
|
||||
void _generateVertexVertexIntersections(carve::mesh::MeshSet<3>::vertex_t *va,
|
||||
carve::mesh::MeshSet<3>::edge_t *eb);
|
||||
void generateVertexVertexIntersections(carve::mesh::MeshSet<3>::face_t *a,
|
||||
const std::vector<carve::mesh::MeshSet<3>::face_t *> &b);
|
||||
|
||||
void _generateVertexEdgeIntersections(carve::mesh::MeshSet<3>::vertex_t *va,
|
||||
carve::mesh::MeshSet<3>::edge_t *eb);
|
||||
void generateVertexEdgeIntersections(carve::mesh::MeshSet<3>::face_t *a,
|
||||
const std::vector<carve::mesh::MeshSet<3>::face_t *> &b);
|
||||
|
||||
void _generateEdgeEdgeIntersections(carve::mesh::MeshSet<3>::edge_t *ea,
|
||||
carve::mesh::MeshSet<3>::edge_t *eb);
|
||||
void generateEdgeEdgeIntersections(carve::mesh::MeshSet<3>::face_t *a,
|
||||
const std::vector<carve::mesh::MeshSet<3>::face_t *> &b);
|
||||
|
||||
void _generateVertexFaceIntersections(carve::mesh::MeshSet<3>::face_t *fa,
|
||||
carve::mesh::MeshSet<3>::edge_t *eb);
|
||||
void generateVertexFaceIntersections(carve::mesh::MeshSet<3>::face_t *a,
|
||||
const std::vector<carve::mesh::MeshSet<3>::face_t *> &b);
|
||||
|
||||
void _generateEdgeFaceIntersections(carve::mesh::MeshSet<3>::face_t *fa,
|
||||
carve::mesh::MeshSet<3>::edge_t *eb);
|
||||
void generateEdgeFaceIntersections(carve::mesh::MeshSet<3>::face_t *a,
|
||||
const std::vector<carve::mesh::MeshSet<3>::face_t *> &b);
|
||||
|
||||
void generateIntersectionCandidates(carve::mesh::MeshSet<3> *a,
|
||||
const face_rtree_t *a_node,
|
||||
carve::mesh::MeshSet<3> *b,
|
||||
const face_rtree_t *b_node,
|
||||
face_pairs_t &face_pairs,
|
||||
bool descend_a = true);
|
||||
/**
|
||||
* \brief Compute all points of intersection between poly \a a and poly \a b
|
||||
*
|
||||
* @param a Polyhedron a.
|
||||
* @param b Polyhedron b.
|
||||
*/
|
||||
void generateIntersections(meshset_t *a,
|
||||
const face_rtree_t *a_node,
|
||||
meshset_t *b,
|
||||
const face_rtree_t *b_node,
|
||||
detail::Data &data);
|
||||
|
||||
/**
|
||||
* \brief Generate tables of intersecting pairs of faces.
|
||||
*
|
||||
* @param[out] data Internal data-structure holding intersection info.
|
||||
*/
|
||||
void intersectingFacePairs(detail::Data &data);
|
||||
|
||||
/**
|
||||
* \brief Divide edges in \a edges that are intersected by polyhedron \a poly
|
||||
*
|
||||
* @param edges The edges to divide.
|
||||
* @param[in] poly The polyhedron to divide against.
|
||||
* @param[in,out] data Intersection information.
|
||||
*/
|
||||
void divideEdges(
|
||||
const std::vector<meshset_t::edge_t> &edges,
|
||||
meshset_t *poly,
|
||||
detail::Data &data);
|
||||
|
||||
void divideIntersectedEdges(detail::Data &data);
|
||||
|
||||
/**
|
||||
* \brief From the intersection points of pairs of intersecting faces, compute intersection edges.
|
||||
*
|
||||
* @param[out] eclass Classification information about created edges.
|
||||
* @param[in,out] data Intersection information.
|
||||
*/
|
||||
void makeFaceEdges(
|
||||
EdgeClassification &eclass,
|
||||
detail::Data &data);
|
||||
|
||||
friend void classifyEasyFaces(
|
||||
FaceLoopList &face_loops,
|
||||
VertexClassification &vclass,
|
||||
meshset_t *other_poly,
|
||||
int other_poly_num,
|
||||
CSG &csg,
|
||||
CSG::Collector &collector);
|
||||
|
||||
size_t generateFaceLoops(
|
||||
meshset_t *poly,
|
||||
const detail::Data &data,
|
||||
FaceLoopList &face_loops_out);
|
||||
|
||||
|
||||
|
||||
// intersect_group.cpp
|
||||
|
||||
/**
|
||||
* \brief Build a loop edge mapping from a list of face loops.
|
||||
*
|
||||
* @param[in] loops A list of face loops.
|
||||
* @param[in] edge_count A hint as to the number of edges in \a loops.
|
||||
* @param[out] edge_map The calculated map of edges to loops.
|
||||
*/
|
||||
void makeEdgeMap(
|
||||
const FaceLoopList &loops,
|
||||
size_t edge_count,
|
||||
detail::LoopEdges &edge_map);
|
||||
|
||||
/**
|
||||
* \brief Divide a list of face loops into groups that are connected by at least one edge not present in \a no_cross.
|
||||
*
|
||||
* @param[in] src The source mesh from which these loops derive.
|
||||
* @param[in,out] face_loops The list of loops (will be emptied as a side effect)
|
||||
* @param[in] loop_edges A loop edge map used for traversing connected loops.
|
||||
* @param[in] no_cross A set of edges not to cross.
|
||||
* @param[out] out_loops A list of grouped face loops.
|
||||
*/
|
||||
void groupFaceLoops(
|
||||
carve::mesh::MeshSet<3> *src,
|
||||
FaceLoopList &face_loops,
|
||||
const detail::LoopEdges &loop_edges,
|
||||
const V2Set &no_cross,
|
||||
FLGroupList &out_loops);
|
||||
|
||||
/**
|
||||
* \brief Find the set of edges shared between two edge maps.
|
||||
*
|
||||
* @param[in] edge_map_a The first edge map.
|
||||
* @param[in] edge_map_b The second edge map.
|
||||
* @param[out] shared_edges The resulting set of common edges.
|
||||
*/
|
||||
void findSharedEdges(
|
||||
const detail::LoopEdges &edge_map_a,
|
||||
const detail::LoopEdges &edge_map_b,
|
||||
V2Set &shared_edges);
|
||||
|
||||
|
||||
// intersect_classify_edge.cpp
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param shared_edges
|
||||
* @param vclass
|
||||
* @param poly_a
|
||||
* @param a_loops_grouped
|
||||
* @param a_edge_map
|
||||
* @param poly_b
|
||||
* @param b_loops_grouped
|
||||
* @param b_edge_map
|
||||
* @param collector
|
||||
*/
|
||||
void classifyFaceGroupsEdge(
|
||||
const V2Set &shared_edges,
|
||||
VertexClassification &vclass,
|
||||
meshset_t *poly_a,
|
||||
const face_rtree_t *poly_a_rtree,
|
||||
FLGroupList &a_loops_grouped,
|
||||
const detail::LoopEdges &a_edge_map,
|
||||
meshset_t *poly_b,
|
||||
const face_rtree_t *poly_b_rtree,
|
||||
FLGroupList &b_loops_grouped,
|
||||
const detail::LoopEdges &b_edge_map,
|
||||
CSG::Collector &collector);
|
||||
|
||||
// intersect_classify_group.cpp
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param shared_edges
|
||||
* @param vclass
|
||||
* @param poly_a
|
||||
* @param a_loops_grouped
|
||||
* @param a_edge_map
|
||||
* @param poly_b
|
||||
* @param b_loops_grouped
|
||||
* @param b_edge_map
|
||||
* @param collector
|
||||
*/
|
||||
void classifyFaceGroups(
|
||||
const V2Set &shared_edges,
|
||||
VertexClassification &vclass,
|
||||
meshset_t *poly_a,
|
||||
const face_rtree_t *poly_a_rtree,
|
||||
FLGroupList &a_loops_grouped,
|
||||
const detail::LoopEdges &a_edge_map,
|
||||
meshset_t *poly_b,
|
||||
const face_rtree_t *poly_b_rtree,
|
||||
FLGroupList &b_loops_grouped,
|
||||
const detail::LoopEdges &b_edge_map,
|
||||
CSG::Collector &collector);
|
||||
|
||||
// intersect_half_classify_group.cpp
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param shared_edges
|
||||
* @param vclass
|
||||
* @param poly_a
|
||||
* @param a_loops_grouped
|
||||
* @param a_edge_map
|
||||
* @param poly_b
|
||||
* @param b_loops_grouped
|
||||
* @param b_edge_map
|
||||
* @param FaceClass
|
||||
* @param b_out
|
||||
*/
|
||||
void halfClassifyFaceGroups(
|
||||
const V2Set &shared_edges,
|
||||
VertexClassification &vclass,
|
||||
meshset_t *poly_a,
|
||||
const face_rtree_t *poly_a_rtree,
|
||||
FLGroupList &a_loops_grouped,
|
||||
const detail::LoopEdges &a_edge_map,
|
||||
meshset_t *poly_b,
|
||||
const face_rtree_t *poly_b_rtree,
|
||||
FLGroupList &b_loops_grouped,
|
||||
const detail::LoopEdges &b_edge_map,
|
||||
std::list<std::pair<FaceClass, meshset_t *> > &b_out);
|
||||
|
||||
// intersect.cpp
|
||||
|
||||
/**
|
||||
* \brief The main calculation method for CSG.
|
||||
*
|
||||
* @param[in] a Polyhedron a
|
||||
* @param[in] b Polyhedron b
|
||||
* @param[out] vclass
|
||||
* @param[out] eclass
|
||||
* @param[out] a_face_loops
|
||||
* @param[out] b_face_loops
|
||||
* @param[out] a_edge_count
|
||||
* @param[out] b_edge_count
|
||||
*/
|
||||
void calc(
|
||||
meshset_t *a,
|
||||
const face_rtree_t *a_rtree,
|
||||
meshset_t *b,
|
||||
const face_rtree_t *b_rtree,
|
||||
VertexClassification &vclass,
|
||||
EdgeClassification &eclass,
|
||||
FaceLoopList &a_face_loops,
|
||||
FaceLoopList &b_face_loops,
|
||||
size_t &a_edge_count,
|
||||
size_t &b_edge_count);
|
||||
|
||||
public:
|
||||
/**
|
||||
* \enum OP
|
||||
* \brief Enumeration of the supported CSG operations.
|
||||
*/
|
||||
enum OP {
|
||||
UNION, /**< in a or b. */
|
||||
INTERSECTION, /**< in a and b. */
|
||||
A_MINUS_B, /**< in a, but not b. */
|
||||
B_MINUS_A, /**< in b, but not a. */
|
||||
SYMMETRIC_DIFFERENCE, /**< in a or b, but not both. */
|
||||
ALL /**< all split faces from a and b */
|
||||
};
|
||||
|
||||
/**
|
||||
* \enum CLASSIFY_TYPE
|
||||
* \brief The type of classification algorithm to use.
|
||||
*/
|
||||
enum CLASSIFY_TYPE {
|
||||
CLASSIFY_NORMAL, /**< Normal (group) classifier. */
|
||||
CLASSIFY_EDGE /**< Edge classifier. */
|
||||
};
|
||||
|
||||
CSG::Hooks hooks; /**< The manager for calculation hooks. */
|
||||
|
||||
CSG();
|
||||
~CSG();
|
||||
|
||||
/**
|
||||
* \brief Compute a CSG operation between two polyhedra, \a a and \a b.
|
||||
*
|
||||
* @param a Polyhedron a
|
||||
* @param b Polyhedron b
|
||||
* @param collector The collector (determines the CSG operation performed)
|
||||
* @param shared_edges A pointer to a set that will be populated with shared edges (if not NULL).
|
||||
* @param classify_type The type of classifier to use.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
meshset_t *compute(
|
||||
meshset_t *a,
|
||||
meshset_t *b,
|
||||
CSG::Collector &collector,
|
||||
V2Set *shared_edges = NULL,
|
||||
CLASSIFY_TYPE classify_type = CLASSIFY_NORMAL);
|
||||
|
||||
/**
|
||||
* \brief Compute a CSG operation between two closed polyhedra, \a a and \a b.
|
||||
*
|
||||
* @param a Polyhedron a
|
||||
* @param b Polyhedron b
|
||||
* @param op The CSG operation (A collector is created automatically).
|
||||
* @param shared_edges A pointer to a set that will be populated with shared edges (if not NULL).
|
||||
* @param classify_type The type of classifier to use.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
meshset_t *compute(
|
||||
meshset_t *a,
|
||||
meshset_t *b,
|
||||
OP op,
|
||||
V2Set *shared_edges = NULL,
|
||||
CLASSIFY_TYPE classify_type = CLASSIFY_NORMAL);
|
||||
|
||||
void slice(
|
||||
meshset_t *a,
|
||||
meshset_t *b,
|
||||
std::list<meshset_t *> &a_sliced,
|
||||
std::list<meshset_t *> &b_sliced,
|
||||
V2Set *shared_edges = NULL);
|
||||
|
||||
bool sliceAndClassify(
|
||||
meshset_t *closed,
|
||||
meshset_t *open,
|
||||
std::list<std::pair<FaceClass, meshset_t *> > &result,
|
||||
V2Set *shared_edges = NULL);
|
||||
};
|
||||
}
|
||||
}
|
434
extern/carve/include/carve/csg_triangulator.hpp
vendored
Normal file
434
extern/carve/include/carve/csg_triangulator.hpp
vendored
Normal file
@ -0,0 +1,434 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
#include <carve/csg.hpp>
|
||||
#include <carve/tag.hpp>
|
||||
#include <carve/poly.hpp>
|
||||
#include <carve/triangulator.hpp>
|
||||
#include <deque>
|
||||
|
||||
namespace carve {
|
||||
namespace csg {
|
||||
|
||||
namespace detail {
|
||||
template<bool with_improvement>
|
||||
class CarveTriangulator : public csg::CSG::Hook {
|
||||
|
||||
public:
|
||||
CarveTriangulator() {
|
||||
}
|
||||
|
||||
virtual ~CarveTriangulator() {
|
||||
}
|
||||
|
||||
virtual void processOutputFace(std::vector<carve::mesh::MeshSet<3>::face_t *> &faces,
|
||||
const carve::mesh::MeshSet<3>::face_t *orig,
|
||||
bool flipped) {
|
||||
std::vector<carve::mesh::MeshSet<3>::face_t *> out_faces;
|
||||
|
||||
size_t n_tris = 0;
|
||||
for (size_t f = 0; f < faces.size(); ++f) {
|
||||
CARVE_ASSERT(faces[f]->nVertices() >= 3);
|
||||
n_tris += faces[f]->nVertices() - 2;
|
||||
}
|
||||
|
||||
out_faces.reserve(n_tris);
|
||||
|
||||
for (size_t f = 0; f < faces.size(); ++f) {
|
||||
carve::mesh::MeshSet<3>::face_t *face = faces[f];
|
||||
|
||||
if (face->nVertices() == 3) {
|
||||
out_faces.push_back(face);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::vector<triangulate::tri_idx> result;
|
||||
|
||||
std::vector<carve::mesh::MeshSet<3>::vertex_t *> vloop;
|
||||
face->getVertices(vloop);
|
||||
|
||||
triangulate::triangulate(
|
||||
carve::mesh::MeshSet<3>::face_t::projection_mapping(face->project),
|
||||
vloop,
|
||||
result);
|
||||
|
||||
if (with_improvement) {
|
||||
triangulate::improve(
|
||||
carve::mesh::MeshSet<3>::face_t::projection_mapping(face->project),
|
||||
vloop,
|
||||
carve::mesh::vertex_distance(),
|
||||
result);
|
||||
}
|
||||
|
||||
std::vector<carve::mesh::MeshSet<3>::vertex_t *> fv;
|
||||
fv.resize(3);
|
||||
for (size_t i = 0; i < result.size(); ++i) {
|
||||
fv[0] = vloop[result[i].a];
|
||||
fv[1] = vloop[result[i].b];
|
||||
fv[2] = vloop[result[i].c];
|
||||
out_faces.push_back(face->create(fv.begin(), fv.end(), false));
|
||||
}
|
||||
delete face;
|
||||
}
|
||||
std::swap(faces, out_faces);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
typedef detail::CarveTriangulator<false> CarveTriangulator;
|
||||
typedef detail::CarveTriangulator<true> CarveTriangulatorWithImprovement;
|
||||
|
||||
class CarveTriangulationImprover : public csg::CSG::Hook {
|
||||
public:
|
||||
CarveTriangulationImprover() {
|
||||
}
|
||||
|
||||
virtual ~CarveTriangulationImprover() {
|
||||
}
|
||||
|
||||
virtual void processOutputFace(std::vector<carve::mesh::MeshSet<3>::face_t *> &faces,
|
||||
const carve::mesh::MeshSet<3>::face_t *orig,
|
||||
bool flipped) {
|
||||
if (faces.size() == 1) return;
|
||||
|
||||
// doing improvement as a separate hook is much messier than
|
||||
// just incorporating it into the triangulation hook.
|
||||
|
||||
typedef std::map<carve::mesh::MeshSet<3>::vertex_t *, size_t> vert_map_t;
|
||||
std::vector<carve::mesh::MeshSet<3>::face_t *> out_faces;
|
||||
vert_map_t vert_map;
|
||||
|
||||
out_faces.reserve(faces.size());
|
||||
|
||||
|
||||
carve::mesh::MeshSet<3>::face_t::projection_mapping projector(faces[0]->project);
|
||||
|
||||
std::vector<triangulate::tri_idx> result;
|
||||
|
||||
for (size_t f = 0; f < faces.size(); ++f) {
|
||||
carve::mesh::MeshSet<3>::face_t *face = faces[f];
|
||||
if (face->nVertices() != 3) {
|
||||
out_faces.push_back(face);
|
||||
} else {
|
||||
triangulate::tri_idx tri;
|
||||
for (carve::mesh::MeshSet<3>::face_t::edge_iter_t i = face->begin(); i != face->end(); ++i) {
|
||||
size_t v = 0;
|
||||
vert_map_t::iterator j = vert_map.find(i->vert);
|
||||
if (j == vert_map.end()) {
|
||||
v = vert_map.size();
|
||||
vert_map[i->vert] = v;
|
||||
} else {
|
||||
v = (*j).second;
|
||||
}
|
||||
tri.v[i.idx()] = v;
|
||||
}
|
||||
result.push_back(tri);
|
||||
delete face;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<carve::mesh::MeshSet<3>::vertex_t *> verts;
|
||||
verts.resize(vert_map.size());
|
||||
for (vert_map_t::iterator i = vert_map.begin(); i != vert_map.end(); ++i) {
|
||||
verts[(*i).second] = (*i).first;
|
||||
}
|
||||
|
||||
triangulate::improve(projector, verts, carve::mesh::vertex_distance(), result);
|
||||
|
||||
std::vector<carve::mesh::MeshSet<3>::vertex_t *> fv;
|
||||
fv.resize(3);
|
||||
for (size_t i = 0; i < result.size(); ++i) {
|
||||
fv[0] = verts[result[i].a];
|
||||
fv[1] = verts[result[i].b];
|
||||
fv[2] = verts[result[i].c];
|
||||
out_faces.push_back(orig->create(fv.begin(), fv.end(), false));
|
||||
}
|
||||
|
||||
std::swap(faces, out_faces);
|
||||
}
|
||||
};
|
||||
|
||||
class CarveTriangulationQuadMerger : public csg::CSG::Hook {
|
||||
// this code is incomplete.
|
||||
typedef std::map<V2, F2> edge_map_t;
|
||||
|
||||
public:
|
||||
CarveTriangulationQuadMerger() {
|
||||
}
|
||||
|
||||
virtual ~CarveTriangulationQuadMerger() {
|
||||
}
|
||||
|
||||
double scoreQuad(edge_map_t::iterator i, edge_map_t &edge_map) {
|
||||
if (!(*i).second.first || !(*i).second.second) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
carve::mesh::MeshSet<3>::face_t *mergeQuad(edge_map_t::iterator i, edge_map_t &edge_map) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void recordEdge(carve::mesh::MeshSet<3>::vertex_t *v1,
|
||||
carve::mesh::MeshSet<3>::vertex_t *v2,
|
||||
carve::mesh::MeshSet<3>::face_t *f,
|
||||
edge_map_t &edge_map) {
|
||||
if (v1 < v2) {
|
||||
edge_map[V2(v1, v2)].first = f;
|
||||
} else {
|
||||
edge_map[V2(v2, v1)].second = f;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void processOutputFace(std::vector<carve::mesh::MeshSet<3>::face_t *> &faces,
|
||||
const carve::mesh::MeshSet<3>::face_t *orig,
|
||||
bool flipped) {
|
||||
if (faces.size() == 1) return;
|
||||
|
||||
std::vector<carve::mesh::MeshSet<3>::face_t *> out_faces;
|
||||
edge_map_t edge_map;
|
||||
|
||||
out_faces.reserve(faces.size());
|
||||
|
||||
poly::p2_adapt_project<3> projector(faces[0]->project);
|
||||
|
||||
for (size_t f = 0; f < faces.size(); ++f) {
|
||||
carve::mesh::MeshSet<3>::face_t *face = faces[f];
|
||||
if (face->nVertices() != 3) {
|
||||
out_faces.push_back(face);
|
||||
} else {
|
||||
carve::mesh::MeshSet<3>::face_t::vertex_t *v1, *v2, *v3;
|
||||
v1 = face->edge->vert;
|
||||
v2 = face->edge->next->vert;
|
||||
v3 = face->edge->next->next->vert;
|
||||
recordEdge(v1, v2, face, edge_map);
|
||||
recordEdge(v2, v3, face, edge_map);
|
||||
recordEdge(v3, v1, face, edge_map);
|
||||
}
|
||||
}
|
||||
|
||||
for (edge_map_t::iterator i = edge_map.begin(); i != edge_map.end();) {
|
||||
if ((*i).second.first && (*i).second.second) {
|
||||
++i;
|
||||
} else {
|
||||
edge_map.erase(i++);
|
||||
}
|
||||
}
|
||||
|
||||
while (edge_map.size()) {
|
||||
edge_map_t::iterator i = edge_map.begin();
|
||||
edge_map_t::iterator best = i;
|
||||
double best_score = scoreQuad(i, edge_map);
|
||||
for (++i; i != edge_map.end(); ++i) {
|
||||
double score = scoreQuad(i, edge_map);
|
||||
if (score > best_score) best = i;
|
||||
}
|
||||
if (best_score < 0) break;
|
||||
out_faces.push_back(mergeQuad(best, edge_map));
|
||||
}
|
||||
|
||||
if (edge_map.size()) {
|
||||
tagable::tag_begin();
|
||||
for (edge_map_t::iterator i = edge_map.begin(); i != edge_map.end(); ++i) {
|
||||
carve::mesh::MeshSet<3>::face_t *a = const_cast<carve::mesh::MeshSet<3>::face_t *>((*i).second.first);
|
||||
carve::mesh::MeshSet<3>::face_t *b = const_cast<carve::mesh::MeshSet<3>::face_t *>((*i).second.first);
|
||||
if (a && a->tag_once()) out_faces.push_back(a);
|
||||
if (b && b->tag_once()) out_faces.push_back(b);
|
||||
}
|
||||
}
|
||||
|
||||
std::swap(faces, out_faces);
|
||||
}
|
||||
};
|
||||
|
||||
class CarveHoleResolver : public csg::CSG::Hook {
|
||||
|
||||
public:
|
||||
CarveHoleResolver() {
|
||||
}
|
||||
|
||||
virtual ~CarveHoleResolver() {
|
||||
}
|
||||
|
||||
bool findRepeatedEdges(const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &vertices,
|
||||
std::list<std::pair<size_t, size_t> > &edge_pos) {
|
||||
std::map<V2, size_t> edges;
|
||||
for (size_t i = 0; i < vertices.size() - 1; ++i) {
|
||||
edges[std::make_pair(vertices[i], vertices[i+1])] = i;
|
||||
}
|
||||
edges[std::make_pair(vertices[vertices.size()-1], vertices[0])] = vertices.size() - 1;
|
||||
|
||||
for (std::map<V2, size_t>::iterator i = edges.begin(); i != edges.end(); ++i) {
|
||||
V2 rev = V2((*i).first.second, (*i).first.first);
|
||||
std::map<V2, size_t>::iterator j = edges.find(rev);
|
||||
if (j != edges.end()) {
|
||||
edge_pos.push_back(std::make_pair((*i).second, (*j).second));
|
||||
}
|
||||
}
|
||||
return edge_pos.size() > 0;
|
||||
}
|
||||
|
||||
void flood(size_t t1,
|
||||
size_t t2,
|
||||
size_t old_grp,
|
||||
size_t new_grp_1,
|
||||
size_t new_grp_2,
|
||||
std::vector<size_t> &grp,
|
||||
const std::vector<triangulate::tri_idx> &tris,
|
||||
const std::map<std::pair<size_t, size_t>, size_t> &tri_edge) {
|
||||
grp[t1] = new_grp_1;
|
||||
grp[t2] = new_grp_2;
|
||||
|
||||
std::deque<size_t> to_visit;
|
||||
to_visit.push_back(t1);
|
||||
to_visit.push_back(t2);
|
||||
std::vector<std::pair<size_t, size_t> > rev;
|
||||
rev.resize(3);
|
||||
while (to_visit.size()) {
|
||||
size_t curr = to_visit.front();
|
||||
to_visit.pop_front();
|
||||
triangulate::tri_idx ct = tris[curr];
|
||||
rev[0] = std::make_pair(ct.b, ct.a);
|
||||
rev[1] = std::make_pair(ct.c, ct.b);
|
||||
rev[2] = std::make_pair(ct.a, ct.c);
|
||||
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
std::map<std::pair<size_t, size_t>, size_t>::const_iterator adj = tri_edge.find(rev[i]);
|
||||
if (adj == tri_edge.end()) continue;
|
||||
size_t next = (*adj).second;
|
||||
if (grp[next] != old_grp) continue;
|
||||
grp[next] = grp[curr];
|
||||
to_visit.push_back(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void findPerimeter(const std::vector<triangulate::tri_idx> &tris,
|
||||
const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &verts,
|
||||
std::vector<carve::mesh::MeshSet<3>::vertex_t *> &out) {
|
||||
std::map<std::pair<size_t, size_t>, size_t> edges;
|
||||
for (size_t i = 0; i < tris.size(); ++i) {
|
||||
edges[std::make_pair(tris[i].a, tris[i].b)] = i;
|
||||
edges[std::make_pair(tris[i].b, tris[i].c)] = i;
|
||||
edges[std::make_pair(tris[i].c, tris[i].a)] = i;
|
||||
}
|
||||
std::map<size_t, size_t> unpaired;
|
||||
for (std::map<std::pair<size_t, size_t>, size_t>::iterator i = edges.begin(); i != edges.end(); ++i) {
|
||||
if (edges.find(std::make_pair((*i).first.second, (*i).first.first)) == edges.end()) {
|
||||
CARVE_ASSERT(unpaired.find((*i).first.first) == unpaired.end());
|
||||
unpaired[(*i).first.first] = (*i).first.second;
|
||||
}
|
||||
}
|
||||
out.clear();
|
||||
out.reserve(unpaired.size());
|
||||
size_t start = (*unpaired.begin()).first;
|
||||
size_t vert = start;
|
||||
do {
|
||||
out.push_back(verts[vert]);
|
||||
CARVE_ASSERT(unpaired.find(vert) != unpaired.end());
|
||||
vert = unpaired[vert];
|
||||
} while (vert != start);
|
||||
}
|
||||
|
||||
virtual void processOutputFace(std::vector<carve::mesh::MeshSet<3>::face_t *> &faces,
|
||||
const carve::mesh::MeshSet<3>::face_t *orig,
|
||||
bool flipped) {
|
||||
std::vector<carve::mesh::MeshSet<3>::face_t *> out_faces;
|
||||
|
||||
for (size_t f = 0; f < faces.size(); ++f) {
|
||||
carve::mesh::MeshSet<3>::face_t *face = faces[f];
|
||||
|
||||
if (face->nVertices() == 3) {
|
||||
out_faces.push_back(face);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::vector<carve::mesh::MeshSet<3>::vertex_t *> vloop;
|
||||
face->getVertices(vloop);
|
||||
|
||||
std::list<std::pair<size_t, size_t> > rep_edges;
|
||||
if (!findRepeatedEdges(vloop, rep_edges)) {
|
||||
out_faces.push_back(face);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::vector<triangulate::tri_idx> result;
|
||||
triangulate::triangulate(
|
||||
carve::mesh::MeshSet<3>::face_t::projection_mapping(face->project),
|
||||
vloop,
|
||||
result);
|
||||
|
||||
std::map<std::pair<size_t, size_t>, size_t> tri_edge;
|
||||
for (size_t i = 0; i < result.size(); ++i) {
|
||||
tri_edge[std::make_pair(result[i].a, result[i].b)] = i;
|
||||
tri_edge[std::make_pair(result[i].b, result[i].c)] = i;
|
||||
tri_edge[std::make_pair(result[i].c, result[i].a)] = i;
|
||||
}
|
||||
|
||||
std::vector<size_t> grp;
|
||||
grp.resize(result.size(), 0);
|
||||
|
||||
size_t grp_max = 0;
|
||||
|
||||
while (rep_edges.size()) {
|
||||
std::pair<size_t, size_t> e1, e2;
|
||||
|
||||
e1.first = rep_edges.front().first;
|
||||
e1.second = (e1.first + 1) % vloop.size();
|
||||
|
||||
e2.first = rep_edges.front().second;
|
||||
e2.second = (e2.first + 1) % vloop.size();
|
||||
|
||||
rep_edges.pop_front();
|
||||
|
||||
CARVE_ASSERT(tri_edge.find(e1) != tri_edge.end());
|
||||
size_t t1 = tri_edge[e1];
|
||||
CARVE_ASSERT(tri_edge.find(e2) != tri_edge.end());
|
||||
size_t t2 = tri_edge[e2];
|
||||
|
||||
if (grp[t1] != grp[t2]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t t1g = ++grp_max;
|
||||
size_t t2g = ++grp_max;
|
||||
|
||||
flood(t1, t2, grp[t1], t1g, t2g, grp, result, tri_edge);
|
||||
}
|
||||
|
||||
std::set<size_t> groups;
|
||||
std::copy(grp.begin(), grp.end(), std::inserter(groups, groups.begin()));
|
||||
|
||||
// now construct perimeters for each group.
|
||||
std::vector<triangulate::tri_idx> grp_tris;
|
||||
grp_tris.reserve(result.size());
|
||||
for (std::set<size_t>::iterator i = groups.begin(); i != groups.end(); ++i) {
|
||||
size_t grp_id = *i;
|
||||
grp_tris.clear();
|
||||
for (size_t j = 0; j < grp.size(); ++j) {
|
||||
if (grp[j] == grp_id) {
|
||||
grp_tris.push_back(result[j]);
|
||||
}
|
||||
}
|
||||
std::vector<carve::mesh::MeshSet<3>::vertex_t *> grp_perim;
|
||||
findPerimeter(grp_tris, vloop, grp_perim);
|
||||
out_faces.push_back(face->create(grp_perim.begin(), grp_perim.end(), false));
|
||||
}
|
||||
}
|
||||
std::swap(faces, out_faces);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
97
extern/carve/include/carve/debug_hooks.hpp
vendored
Normal file
97
extern/carve/include/carve/debug_hooks.hpp
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
|
||||
#include <carve/vector.hpp>
|
||||
#include <carve/geom3d.hpp>
|
||||
#include <carve/csg.hpp>
|
||||
|
||||
#include <iomanip>
|
||||
|
||||
template<typename MAP>
|
||||
void map_histogram(std::ostream &out, const MAP &map) {
|
||||
std::vector<int> hist;
|
||||
for (typename MAP::const_iterator i = map.begin(); i != map.end(); ++i) {
|
||||
size_t n = (*i).second.size();
|
||||
if (hist.size() <= n) {
|
||||
hist.resize(n + 1);
|
||||
}
|
||||
hist[n]++;
|
||||
}
|
||||
int total = map.size();
|
||||
std::string bar(50, '*');
|
||||
for (size_t i = 0; i < hist.size(); i++) {
|
||||
if (hist[i] > 0) {
|
||||
out << std::setw(5) << i << " : " << std::setw(5) << hist[i] << " " << bar.substr(50 - hist[i] * 50 / total) << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace carve {
|
||||
namespace csg {
|
||||
class IntersectDebugHooks {
|
||||
public:
|
||||
virtual void drawIntersections(const VertexIntersections & /* vint */) {
|
||||
}
|
||||
|
||||
virtual void drawPoint(const carve::mesh::MeshSet<3>::vertex_t * /* v */,
|
||||
float /* r */,
|
||||
float /* g */,
|
||||
float /* b */,
|
||||
float /* a */,
|
||||
float /* rad */) {
|
||||
}
|
||||
virtual void drawEdge(const carve::mesh::MeshSet<3>::vertex_t * /* v1 */,
|
||||
const carve::mesh::MeshSet<3>::vertex_t * /* v2 */,
|
||||
float /* rA */, float /* gA */, float /* bA */, float /* aA */,
|
||||
float /* rB */, float /* gB */, float /* bB */, float /* aB */,
|
||||
float /* thickness */ = 1.0) {
|
||||
}
|
||||
|
||||
virtual void drawFaceLoopWireframe(const std::vector<carve::mesh::MeshSet<3>::vertex_t *> & /* face_loop */,
|
||||
const carve::mesh::MeshSet<3>::vertex_t & /* normal */,
|
||||
float /* r */, float /* g */, float /* b */, float /* a */,
|
||||
bool /* inset */ = true) {
|
||||
}
|
||||
|
||||
virtual void drawFaceLoop(const std::vector<carve::mesh::MeshSet<3>::vertex_t *> & /* face_loop */,
|
||||
const carve::mesh::MeshSet<3>::vertex_t & /* normal */,
|
||||
float /* r */, float /* g */, float /* b */, float /* a */,
|
||||
bool /* offset */ = true,
|
||||
bool /* lit */ = true) {
|
||||
}
|
||||
|
||||
virtual void drawFaceLoop2(const std::vector<carve::mesh::MeshSet<3>::vertex_t *> & /* face_loop */,
|
||||
const carve::mesh::MeshSet<3>::vertex_t & /* normal */,
|
||||
float /* rF */, float /* gF */, float /* bF */, float /* aF */,
|
||||
float /* rB */, float /* gB */, float /* bB */, float /* aB */,
|
||||
bool /* offset */ = true,
|
||||
bool /* lit */ = true) {
|
||||
}
|
||||
|
||||
virtual ~IntersectDebugHooks() {
|
||||
}
|
||||
};
|
||||
|
||||
IntersectDebugHooks *intersect_installDebugHooks(IntersectDebugHooks *hooks);
|
||||
bool intersect_debugEnabled();
|
||||
|
||||
}
|
||||
}
|
134
extern/carve/include/carve/djset.hpp
vendored
Normal file
134
extern/carve/include/carve/djset.hpp
vendored
Normal file
@ -0,0 +1,134 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
#include <vector>
|
||||
|
||||
|
||||
|
||||
namespace carve {
|
||||
namespace djset {
|
||||
|
||||
|
||||
|
||||
class djset {
|
||||
|
||||
protected:
|
||||
struct elem {
|
||||
size_t parent, rank;
|
||||
elem(size_t p, size_t r) : parent(p), rank(r) {}
|
||||
elem() {}
|
||||
};
|
||||
|
||||
std::vector<elem> set;
|
||||
size_t n_sets;
|
||||
|
||||
public:
|
||||
djset() : set(), n_sets(0) {
|
||||
}
|
||||
|
||||
djset(size_t N) {
|
||||
n_sets = N;
|
||||
set.reserve(N);
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
set.push_back(elem(i,0));
|
||||
}
|
||||
}
|
||||
|
||||
void init(size_t N) {
|
||||
if (N == set.size()) {
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
set[i] = elem(i,0);
|
||||
}
|
||||
n_sets = N;
|
||||
} else {
|
||||
djset temp(N);
|
||||
std::swap(set, temp.set);
|
||||
std::swap(n_sets, temp.n_sets);
|
||||
}
|
||||
}
|
||||
|
||||
size_t count() const {
|
||||
return n_sets;
|
||||
}
|
||||
|
||||
size_t find_set_head(size_t a) {
|
||||
if (a == set[a].parent) return a;
|
||||
|
||||
size_t a_head = a;
|
||||
while (set[a_head].parent != a_head) a_head = set[a_head].parent;
|
||||
set[a].parent = a_head;
|
||||
return a_head;
|
||||
}
|
||||
|
||||
bool same_set(size_t a, size_t b) {
|
||||
return find_set_head(a) == find_set_head(b);
|
||||
}
|
||||
|
||||
void merge_sets(size_t a, size_t b) {
|
||||
a = find_set_head(a);
|
||||
b = find_set_head(b);
|
||||
if (a != b) {
|
||||
n_sets--;
|
||||
if (set[a].rank < set[b].rank) {
|
||||
set[a].parent = b;
|
||||
} else if (set[b].rank < set[a].rank) {
|
||||
set[b].parent = a;
|
||||
} else {
|
||||
set[a].rank++;
|
||||
set[b].parent = a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void get_index_to_set(std::vector<size_t> &index_set, std::vector<size_t> &set_size) {
|
||||
index_set.clear();
|
||||
index_set.resize(set.size(), n_sets);
|
||||
set_size.clear();
|
||||
set_size.resize(n_sets, 0);
|
||||
|
||||
size_t c = 0;
|
||||
for (size_t i = 0; i < set.size(); ++i) {
|
||||
size_t s = find_set_head(i);
|
||||
if (index_set[s] == n_sets) index_set[s] = c++;
|
||||
index_set[i] = index_set[s];
|
||||
set_size[index_set[s]]++;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename in_iter_t, typename out_collection_t>
|
||||
void collate(in_iter_t in, out_collection_t &out) {
|
||||
std::vector<size_t> set_id(set.size(), n_sets);
|
||||
out.clear();
|
||||
out.resize(n_sets);
|
||||
size_t c = 0;
|
||||
for (size_t i = 0; i < set.size(); ++i) {
|
||||
size_t s = find_set_head(i);
|
||||
if (set_id[s] == n_sets) set_id[s] = c++;
|
||||
s = set_id[s];
|
||||
std::insert_iterator<typename out_collection_t::value_type> j(out[s], out[s].end());
|
||||
*j = *in++;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
68
extern/carve/include/carve/edge_decl.hpp
vendored
Normal file
68
extern/carve/include/carve/edge_decl.hpp
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
|
||||
#include <carve/vector.hpp>
|
||||
#include <carve/tag.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
||||
namespace carve {
|
||||
namespace poly {
|
||||
|
||||
|
||||
|
||||
struct Object;
|
||||
|
||||
|
||||
|
||||
template<unsigned ndim>
|
||||
class Edge : public tagable {
|
||||
public:
|
||||
typedef Vertex<ndim> vertex_t;
|
||||
typedef typename Vertex<ndim>::vector_t vector_t;
|
||||
typedef Object obj_t;
|
||||
|
||||
const vertex_t *v1, *v2;
|
||||
const obj_t *owner;
|
||||
|
||||
Edge(const vertex_t *_v1, const vertex_t *_v2, const obj_t *_owner) :
|
||||
tagable(), v1(_v1), v2(_v2), owner(_owner) {
|
||||
}
|
||||
|
||||
~Edge() {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct hash_edge_ptr {
|
||||
template<unsigned ndim>
|
||||
size_t operator()(const Edge<ndim> * const &e) const {
|
||||
return (size_t)e;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
23
extern/carve/include/carve/edge_impl.hpp
vendored
Normal file
23
extern/carve/include/carve/edge_impl.hpp
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace carve {
|
||||
namespace poly {
|
||||
}
|
||||
}
|
702
extern/carve/include/carve/exact.hpp
vendored
Normal file
702
extern/carve/include/carve/exact.hpp
vendored
Normal file
@ -0,0 +1,702 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <numeric>
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
namespace carve {
|
||||
namespace exact {
|
||||
|
||||
class exact_t : public std::vector<double> {
|
||||
typedef std::vector<double> super;
|
||||
|
||||
public:
|
||||
exact_t() : super() {
|
||||
}
|
||||
|
||||
exact_t(double v, size_t sz = 1) : super(sz, v) {
|
||||
}
|
||||
|
||||
template<typename iter_t>
|
||||
exact_t(iter_t a, iter_t b) : super(a, b) {
|
||||
}
|
||||
|
||||
exact_t(double a, double b) : super() {
|
||||
reserve(2);
|
||||
push_back(a);
|
||||
push_back(b);
|
||||
}
|
||||
|
||||
exact_t(double a, double b, double c) : super() {
|
||||
reserve(3);
|
||||
push_back(a);
|
||||
push_back(b);
|
||||
push_back(c);
|
||||
}
|
||||
|
||||
exact_t(double a, double b, double c, double d) : super() {
|
||||
reserve(4);
|
||||
push_back(a);
|
||||
push_back(b);
|
||||
push_back(c);
|
||||
push_back(d);
|
||||
}
|
||||
|
||||
exact_t(double a, double b, double c, double d, double e) : super() {
|
||||
reserve(5);
|
||||
push_back(a);
|
||||
push_back(b);
|
||||
push_back(c);
|
||||
push_back(d);
|
||||
push_back(e);
|
||||
}
|
||||
|
||||
exact_t(double a, double b, double c, double d, double e, double f) : super() {
|
||||
reserve(6);
|
||||
push_back(a);
|
||||
push_back(b);
|
||||
push_back(c);
|
||||
push_back(d);
|
||||
push_back(e);
|
||||
push_back(f);
|
||||
}
|
||||
|
||||
exact_t(double a, double b, double c, double d, double e, double f, double g) : super() {
|
||||
reserve(7);
|
||||
push_back(a);
|
||||
push_back(b);
|
||||
push_back(c);
|
||||
push_back(d);
|
||||
push_back(e);
|
||||
push_back(f);
|
||||
push_back(g);
|
||||
}
|
||||
|
||||
exact_t(double a, double b, double c, double d, double e, double f, double g, double h) : super() {
|
||||
reserve(8);
|
||||
push_back(a);
|
||||
push_back(b);
|
||||
push_back(c);
|
||||
push_back(d);
|
||||
push_back(e);
|
||||
push_back(f);
|
||||
push_back(g);
|
||||
push_back(h);
|
||||
}
|
||||
|
||||
void compress();
|
||||
|
||||
exact_t compressed() const {
|
||||
exact_t result(*this);
|
||||
result.compress();
|
||||
return result;
|
||||
}
|
||||
|
||||
operator double() const {
|
||||
return std::accumulate(begin(), end(), 0.0);
|
||||
}
|
||||
|
||||
void removeZeroes() {
|
||||
erase(std::remove(begin(), end(), 0.0), end());
|
||||
}
|
||||
};
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &out, const exact_t &p) {
|
||||
out << '{';
|
||||
out << p[0];
|
||||
for (size_t i = 1; i < p.size(); ++i) out << ';' << p[i];
|
||||
out << '}';
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace detail {
|
||||
const struct constants_t {
|
||||
double splitter; /* = 2^ceiling(p / 2) + 1. Used to split floats in half. */
|
||||
double epsilon; /* = 2^(-p). Used to estimate roundoff errors. */
|
||||
/* A set of coefficients used to calculate maximum roundoff errors. */
|
||||
double resulterrbound;
|
||||
double ccwerrboundA, ccwerrboundB, ccwerrboundC;
|
||||
double o3derrboundA, o3derrboundB, o3derrboundC;
|
||||
double iccerrboundA, iccerrboundB, iccerrboundC;
|
||||
double isperrboundA, isperrboundB, isperrboundC;
|
||||
|
||||
constants_t() {
|
||||
double half;
|
||||
double check, lastcheck;
|
||||
int every_other;
|
||||
|
||||
every_other = 1;
|
||||
half = 0.5;
|
||||
epsilon = 1.0;
|
||||
splitter = 1.0;
|
||||
check = 1.0;
|
||||
/* Repeatedly divide `epsilon' by two until it is too small to add to */
|
||||
/* one without causing roundoff. (Also check if the sum is equal to */
|
||||
/* the previous sum, for machines that round up instead of using exact */
|
||||
/* rounding. Not that this library will work on such machines anyway. */
|
||||
do {
|
||||
lastcheck = check;
|
||||
epsilon *= half;
|
||||
if (every_other) {
|
||||
splitter *= 2.0;
|
||||
}
|
||||
every_other = !every_other;
|
||||
check = 1.0 + epsilon;
|
||||
} while ((check != 1.0) && (check != lastcheck));
|
||||
splitter += 1.0;
|
||||
|
||||
/* Error bounds for orientation and incircle tests. */
|
||||
resulterrbound = (3.0 + 8.0 * epsilon) * epsilon;
|
||||
ccwerrboundA = (3.0 + 16.0 * epsilon) * epsilon;
|
||||
ccwerrboundB = (2.0 + 12.0 * epsilon) * epsilon;
|
||||
ccwerrboundC = (9.0 + 64.0 * epsilon) * epsilon * epsilon;
|
||||
o3derrboundA = (7.0 + 56.0 * epsilon) * epsilon;
|
||||
o3derrboundB = (3.0 + 28.0 * epsilon) * epsilon;
|
||||
o3derrboundC = (26.0 + 288.0 * epsilon) * epsilon * epsilon;
|
||||
iccerrboundA = (10.0 + 96.0 * epsilon) * epsilon;
|
||||
iccerrboundB = (4.0 + 48.0 * epsilon) * epsilon;
|
||||
iccerrboundC = (44.0 + 576.0 * epsilon) * epsilon * epsilon;
|
||||
isperrboundA = (16.0 + 224.0 * epsilon) * epsilon;
|
||||
isperrboundB = (5.0 + 72.0 * epsilon) * epsilon;
|
||||
isperrboundC = (71.0 + 1408.0 * epsilon) * epsilon * epsilon;
|
||||
}
|
||||
} constants;
|
||||
|
||||
template<unsigned U, unsigned V>
|
||||
struct op {
|
||||
enum {
|
||||
Vlo = V / 2,
|
||||
Vhi = V - Vlo
|
||||
};
|
||||
|
||||
static inline void add(const double *a, const double *b, double *r) {
|
||||
double t[U + Vlo];
|
||||
op<U, Vlo>::add(a, b, t);
|
||||
for (size_t i = 0; i < Vlo; ++i) r[i] = t[i];
|
||||
op<U, Vhi>::add(t + Vlo, b + Vlo, r + Vlo);
|
||||
}
|
||||
|
||||
static inline void sub(const double *a, const double *b, double *r) {
|
||||
double t[U + Vlo];
|
||||
op<U, Vlo>::sub(a, b, t);
|
||||
for (size_t i = 0; i < Vlo; ++i) r[i] = t[i];
|
||||
op<U, Vhi>::sub(t + Vlo, b + Vlo, r + Vlo);
|
||||
}
|
||||
};
|
||||
|
||||
template<unsigned U>
|
||||
struct op<U, 1> {
|
||||
enum {
|
||||
Ulo = U / 2,
|
||||
Uhi = U - Ulo
|
||||
};
|
||||
static void add(const double *a, const double *b, double *r) {
|
||||
double t[Ulo + 1];
|
||||
op<Ulo, 1>::add(a, b, t);
|
||||
for (size_t i = 0; i < Ulo; ++i) r[i] = t[i];
|
||||
op<Uhi, 1>::add(a + Ulo, t + Ulo, r + Ulo);
|
||||
}
|
||||
|
||||
static void sub(const double *a, const double *b, double *r) {
|
||||
double t[Ulo + 1];
|
||||
op<Ulo, 1>::sub(a, b, t);
|
||||
for (size_t i = 0; i < Ulo; ++i) r[i] = t[i];
|
||||
op<Uhi, 1>::add(a + Ulo, t + Ulo, r + Ulo);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct op<1, 1> {
|
||||
static void add_fast(const double *a, const double *b, double *r) {
|
||||
assert(fabs(a[0]) >= fabs(b[0]));
|
||||
volatile double sum = a[0] + b[0];
|
||||
volatile double bvirt = sum - a[0];
|
||||
r[0] = b[0] - bvirt;
|
||||
r[1] = sum;
|
||||
}
|
||||
|
||||
static void sub_fast(const double *a, const double *b, double *r) {
|
||||
assert(fabs(a[0]) >= fabs(b[0]));
|
||||
volatile double diff = a[0] - b[0];
|
||||
volatile double bvirt = a[0] - diff;
|
||||
r[0] = bvirt - b[0];
|
||||
r[1] = diff;
|
||||
}
|
||||
|
||||
static void add(const double *a, const double *b, double *r) {
|
||||
volatile double sum = a[0] + b[0];
|
||||
volatile double bvirt = sum - a[0];
|
||||
double avirt = sum - bvirt;
|
||||
double bround = b[0] - bvirt;
|
||||
double around = a[0] - avirt;
|
||||
r[0] = around + bround;
|
||||
r[1] = sum;
|
||||
}
|
||||
|
||||
static void sub(const double *a, const double *b, double *r) {
|
||||
volatile double diff = a[0] - b[0];
|
||||
volatile double bvirt = a[0] - diff;
|
||||
double avirt = diff + bvirt;
|
||||
double bround = bvirt - b[0];
|
||||
double around = a[0] - avirt;
|
||||
r[0] = around + bround;
|
||||
r[1] = diff;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<unsigned U, unsigned V>
|
||||
static exact_t add(const double *a, const double *b) {
|
||||
exact_t result;
|
||||
result.resize(U + V);
|
||||
op<U,V>::add(a, b, &result[0]);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
template<unsigned U, unsigned V>
|
||||
static exact_t sub(const double *a, const double *b) {
|
||||
exact_t result;
|
||||
result.resize(U + V);
|
||||
op<U,V>::sub(a, b, &result[0]);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
template<unsigned U, unsigned V>
|
||||
static exact_t add(const exact_t &a, const exact_t &b) {
|
||||
assert(a.size() == U);
|
||||
assert(b.size() == V);
|
||||
exact_t result;
|
||||
result.resize(U + V);
|
||||
std::fill(result.begin(), result.end(), std::numeric_limits<double>::quiet_NaN());
|
||||
op<U,V>::add(&a[0], &b[0], &result[0]);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
template<unsigned U, unsigned V>
|
||||
static exact_t add(const exact_t &a, const double *b) {
|
||||
assert(a.size() == U);
|
||||
exact_t result;
|
||||
result.resize(U + V);
|
||||
std::fill(result.begin(), result.end(), std::numeric_limits<double>::quiet_NaN());
|
||||
op<U,V>::add(&a[0], b, &result[0]);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
template<unsigned U, unsigned V>
|
||||
static exact_t sub(const exact_t &a, const exact_t &b) {
|
||||
assert(a.size() == U);
|
||||
assert(b.size() == V);
|
||||
exact_t result;
|
||||
result.resize(U + V);
|
||||
std::fill(result.begin(), result.end(), std::numeric_limits<double>::quiet_NaN());
|
||||
op<U,V>::sub(&a[0], &b[0], &result[0]);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
template<unsigned U, unsigned V>
|
||||
static exact_t sub(const exact_t &a, const double *b) {
|
||||
assert(a.size() == U);
|
||||
exact_t result;
|
||||
result.resize(U + V);
|
||||
std::fill(result.begin(), result.end(), std::numeric_limits<double>::quiet_NaN());
|
||||
op<U,V>::sub(&a[0], &b[0], &result[0]);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static inline void split(const double a, double *r) {
|
||||
volatile double c = constants.splitter * a;
|
||||
volatile double abig = c - a;
|
||||
r[1] = c - abig;
|
||||
r[0] = a - r[1];
|
||||
}
|
||||
|
||||
static inline void prod_1_1(const double *a, const double *b, double *r) {
|
||||
r[1] = a[0] * b[0];
|
||||
double a_sp[2]; split(a[0], a_sp);
|
||||
double b_sp[2]; split(b[0], b_sp);
|
||||
double err1 = r[1] - a_sp[1] * b_sp[1];
|
||||
double err2 = err1 - a_sp[0] * b_sp[1];
|
||||
double err3 = err2 - a_sp[1] * b_sp[0];
|
||||
r[0] = a_sp[0] * b_sp[0] - err3;
|
||||
}
|
||||
|
||||
static inline void prod_1_1s(const double *a, const double *b, const double *b_sp, double *r) {
|
||||
r[1] = a[0] * b[0];
|
||||
double a_sp[2]; split(a[0], a_sp);
|
||||
double err1 = r[1] - a_sp[1] * b_sp[1];
|
||||
double err2 = err1 - a_sp[0] * b_sp[1];
|
||||
double err3 = err2 - a_sp[1] * b_sp[0];
|
||||
r[0] = a_sp[0] * b_sp[0] - err3;
|
||||
}
|
||||
|
||||
static inline void prod_1s_1s(const double *a, const double *a_sp, const double *b, const double *b_sp, double *r) {
|
||||
r[1] = a[0] * b[0];
|
||||
double err1 = r[1] - a_sp[1] * b_sp[1];
|
||||
double err2 = err1 - a_sp[0] * b_sp[1];
|
||||
double err3 = err2 - a_sp[1] * b_sp[0];
|
||||
r[0] = a_sp[0] * b_sp[0] - err3;
|
||||
}
|
||||
|
||||
static inline void prod_2_1(const double *a, const double *b, double *r) {
|
||||
double b_sp[2]; split(b[0], b_sp);
|
||||
double t1[2]; prod_1_1s(a+0, b, b_sp, t1);
|
||||
r[0] = t1[0];
|
||||
double t2[2]; prod_1_1s(a+1, b, b_sp, t2);
|
||||
double t3[2]; op<1,1>::add(t1+1, t2, t3);
|
||||
r[1] = t3[0];
|
||||
double t4[2]; op<1,1>::add_fast(t2+1, t3+1, r + 2);
|
||||
}
|
||||
|
||||
static inline void prod_1_2(const double *a, const double *b, double *r) {
|
||||
prod_2_1(b, a, r);
|
||||
}
|
||||
|
||||
static inline void prod_4_1(const double *a, const double *b, double *r) {
|
||||
double b_sp[2]; split(b[0], b_sp);
|
||||
double t1[2]; prod_1_1s(a+0, b, b_sp, t1);
|
||||
r[0] = t1[0];
|
||||
double t2[2]; prod_1_1s(a+1, b, b_sp, t2);
|
||||
double t3[2]; op<1,1>::add(t1+1, t2, t3);
|
||||
r[1] = t3[0];
|
||||
double t4[2]; op<1,1>::add_fast(t2+1, t3+1, t4);
|
||||
r[2] = t4[0];
|
||||
double t5[2]; prod_1_1s(a+2, b, b_sp, t5);
|
||||
double t6[2]; op<1,1>::add(t4+1, t5, t6);
|
||||
r[3] = t6[0];
|
||||
double t7[2]; op<1,1>::add_fast(t5+1, t6+1, t7);
|
||||
r[4] = t7[0];
|
||||
double t8[2]; prod_1_1s(a+3, b, b_sp, t8);
|
||||
double t9[2]; op<1,1>::add(t7+1, t8, t9);
|
||||
r[5] = t9[0];
|
||||
op<1,1>::add_fast(t8+1, t9+1, r + 6);
|
||||
}
|
||||
|
||||
static inline void prod_1_4(const double *a, const double *b, double *r) {
|
||||
prod_4_1(b, a, r);
|
||||
}
|
||||
|
||||
static inline void prod_2_2(const double *a, const double *b, double *r) {
|
||||
double a1_sp[2]; split(a[1], a1_sp);
|
||||
double a0_sp[2]; split(a[0], a0_sp);
|
||||
double b1_sp[2]; split(b[1], b1_sp);
|
||||
double b0_sp[2]; split(b[0], b0_sp);
|
||||
|
||||
double t1[2]; prod_1s_1s(a+0, a0_sp, b+0, b0_sp, t1);
|
||||
r[0] = t1[0];
|
||||
double t2[2]; prod_1s_1s(a+1, a1_sp, b+0, b0_sp, t2);
|
||||
|
||||
double t3[2]; op<1,1>::add(t1+1, t2, t3);
|
||||
double t4[2]; op<1,1>::add_fast(t2+1, t3+1, t4);
|
||||
|
||||
double t5[2]; prod_1s_1s(a+0, a0_sp, b+1, b1_sp, t5);
|
||||
|
||||
double t6[2]; op<1,1>::add(t3, t5, t6);
|
||||
r[1] = t6[0];
|
||||
double t7[2]; op<1,1>::add(t4, t6+1, t7);
|
||||
double t8[2]; op<1,1>::add(t4+1, t7+1, t8);
|
||||
|
||||
double t9[2]; prod_1s_1s(a+1, a1_sp, b+1, b1_sp, t9);
|
||||
|
||||
double t10[2]; op<1,1>::add(t5+1, t9, t10);
|
||||
double t11[2]; op<1,1>::add(t7, t10, t11);
|
||||
r[2] = t11[0];
|
||||
double t12[2]; op<1,1>::add(t8, t11+1, t12);
|
||||
double t13[2]; op<1,1>::add(t8+1, t12+1, t13);
|
||||
double t14[2]; op<1,1>::add(t9+1, t10+1, t14);
|
||||
double t15[2]; op<1,1>::add(t12, t14, t15);
|
||||
r[3] = t15[0];
|
||||
double t16[2]; op<1,1>::add(t13, t15+1, t16);
|
||||
double t17[2]; op<1,1>::add(t13+1, t16+1, t17);
|
||||
double t18[2]; op<1,1>::add(t16, t14+1, t18);
|
||||
r[4] = t18[0];
|
||||
double t19[2]; op<1,1>::add(t17, t18+1, t19);
|
||||
r[5] = t19[0];
|
||||
double t20[2]; op<1,1>::add(t17+1, t19+1, t20);
|
||||
r[6] = t20[0];
|
||||
r[7] = t20[1];
|
||||
}
|
||||
|
||||
|
||||
|
||||
static inline void square(const double a, double *r) {
|
||||
r[1] = a * a;
|
||||
double a_sp[2]; split(a, a_sp);
|
||||
double err1 = r[1] - (a_sp[1] * a_sp[1]);
|
||||
double err3 = err1 - ((a_sp[1] + a_sp[1]) * a_sp[0]);
|
||||
r[0] = a_sp[0] * a_sp[0] - err3;
|
||||
}
|
||||
|
||||
static inline void square_2(const double *a, double *r) {
|
||||
double t1[2]; square(a[0], t1);
|
||||
r[0] = t1[0];
|
||||
double t2 = a[0] + a[0];
|
||||
double t3[2]; prod_1_1(a+1, &t2, t3);
|
||||
double t4[3]; op<2,1>::add(t3, t1 + 1, t4);
|
||||
r[1] = t4[0];
|
||||
double t5[2]; square(a[1], t5);
|
||||
double t6[4]; op<2,2>::add(t5, t4 + 1, r + 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void exact_t::compress() {
|
||||
double sum[2];
|
||||
|
||||
int j = size() - 1;
|
||||
double Q = (*this)[j];
|
||||
for (int i = (int)size()-2; i >= 0; --i) {
|
||||
detail::op<1,1>::add_fast(&Q, &(*this)[i], sum);
|
||||
if (sum[0] != 0) {
|
||||
(*this)[j--] = sum[1];
|
||||
Q = sum[0];
|
||||
} else {
|
||||
Q = sum[1];
|
||||
}
|
||||
}
|
||||
int j2 = 0;
|
||||
for (int i = j + 1; i < (int)size(); ++i) {
|
||||
detail::op<1,1>::add_fast(&(*this)[i], &Q, sum);
|
||||
if (sum[0] != 0) {
|
||||
(*this)[j2++] = sum[0];
|
||||
}
|
||||
Q = sum[1];
|
||||
}
|
||||
(*this)[j2++] = Q;
|
||||
|
||||
erase(begin() + j2, end());
|
||||
}
|
||||
|
||||
template<typename iter_t>
|
||||
void negate(iter_t begin, iter_t end) {
|
||||
while (begin != end) { *begin = -*begin; ++begin; }
|
||||
}
|
||||
|
||||
void negate(exact_t &e) {
|
||||
negate(&e[0], &e[e.size()]);
|
||||
}
|
||||
|
||||
template<typename iter_t>
|
||||
void scale_zeroelim(iter_t ebegin,
|
||||
iter_t eend,
|
||||
double b,
|
||||
exact_t &h) {
|
||||
double Q;
|
||||
|
||||
h.clear();
|
||||
double b_sp[2]; detail::split(b, b_sp);
|
||||
|
||||
double prod[2], sum[2];
|
||||
|
||||
detail::prod_1_1s((double *)ebegin++, &b, b_sp, prod);
|
||||
Q = prod[1];
|
||||
if (prod[0] != 0.0) {
|
||||
h.push_back(prod[0]);
|
||||
}
|
||||
while (ebegin != eend) {
|
||||
double enow = *ebegin++;
|
||||
detail::prod_1_1s(&enow, &b, b_sp, prod);
|
||||
detail::op<1,1>::add(&Q, prod, sum);
|
||||
if (sum[0] != 0) {
|
||||
h.push_back(sum[0]);
|
||||
}
|
||||
detail::op<1,1>::add_fast(prod+1, sum+1, sum);
|
||||
Q = sum[1];
|
||||
if (sum[0] != 0) {
|
||||
h.push_back(sum[0]);
|
||||
}
|
||||
}
|
||||
if ((Q != 0.0) || (h.size() == 0)) {
|
||||
h.push_back(Q);
|
||||
}
|
||||
}
|
||||
|
||||
void scale_zeroelim(const exact_t &e,
|
||||
double b,
|
||||
exact_t &h) {
|
||||
scale_zeroelim(&e[0], &e[e.size()], b, h);
|
||||
}
|
||||
|
||||
template<typename iter_t>
|
||||
void sum_zeroelim(iter_t ebegin,
|
||||
iter_t eend,
|
||||
iter_t fbegin,
|
||||
iter_t fend,
|
||||
exact_t &h) {
|
||||
double Q;
|
||||
double enow, fnow;
|
||||
|
||||
double sum[2];
|
||||
|
||||
enow = *ebegin;
|
||||
fnow = *fbegin;
|
||||
|
||||
h.clear();
|
||||
|
||||
if ((fnow > enow) == (fnow > -enow)) {
|
||||
Q = enow;
|
||||
enow = *++ebegin;
|
||||
} else {
|
||||
Q = fnow;
|
||||
fnow = *++fbegin;
|
||||
}
|
||||
|
||||
if (ebegin != eend && fbegin != fend) {
|
||||
if ((fnow > enow) == (fnow > -enow)) {
|
||||
detail::op<1,1>::add_fast(&enow, &Q, sum);
|
||||
enow = *++ebegin;
|
||||
} else {
|
||||
detail::op<1,1>::add_fast(&fnow, &Q, sum);
|
||||
fnow = *++fbegin;
|
||||
}
|
||||
Q = sum[1];
|
||||
if (sum[0] != 0.0) {
|
||||
h.push_back(sum[0]);
|
||||
}
|
||||
while (ebegin != eend && fbegin != fend) {
|
||||
if ((fnow > enow) == (fnow > -enow)) {
|
||||
detail::op<1,1>::add(&Q, &enow, sum);
|
||||
enow = *++ebegin;
|
||||
} else {
|
||||
detail::op<1,1>::add(&Q, &fnow, sum);
|
||||
fnow = *++fbegin;
|
||||
}
|
||||
Q = sum[1];
|
||||
if (sum[0] != 0.0) {
|
||||
h.push_back(sum[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (ebegin != eend) {
|
||||
detail::op<1,1>::add(&Q, &enow, sum);
|
||||
enow = *++ebegin;
|
||||
Q = sum[1];
|
||||
if (sum[0] != 0.0) {
|
||||
h.push_back(sum[0]);
|
||||
}
|
||||
}
|
||||
while (fbegin != fend) {
|
||||
detail::op<1,1>::add(&Q, &fnow, sum);
|
||||
fnow = *++fbegin;
|
||||
Q = sum[1];
|
||||
if (sum[0] != 0.0) {
|
||||
h.push_back(sum[0]);
|
||||
}
|
||||
}
|
||||
|
||||
if (Q != 0.0 || !h.size()) {
|
||||
h.push_back(Q);
|
||||
}
|
||||
}
|
||||
|
||||
void sum_zeroelim(const exact_t &e,
|
||||
const exact_t &f,
|
||||
exact_t &h) {
|
||||
sum_zeroelim(&e[0], &e[e.size()], &f[0], &f[f.size()], h);
|
||||
}
|
||||
|
||||
void sum_zeroelim(const double *ebegin,
|
||||
const double *eend,
|
||||
const exact_t &f,
|
||||
exact_t &h) {
|
||||
sum_zeroelim(ebegin, eend, &f[0], &f[f.size()], h);
|
||||
}
|
||||
|
||||
void sum_zeroelim(const exact_t &e,
|
||||
const double *fbegin,
|
||||
const double *fend,
|
||||
exact_t &h) {
|
||||
sum_zeroelim(&e[0], &e[e.size()], fbegin, fend, h);
|
||||
}
|
||||
|
||||
|
||||
// XXX: not implemented yet
|
||||
//exact_t operator+(const exact_t &a, const exact_t &b) {
|
||||
//}
|
||||
|
||||
|
||||
|
||||
void diffprod(const double a, const double b, const double c, const double d, double *r) {
|
||||
// return ab - cd;
|
||||
double ab[2], cd[2];
|
||||
detail::prod_1_1(&a, &b, ab);
|
||||
detail::prod_1_1(&c, &d, cd);
|
||||
detail::op<2,2>::sub(ab, cd, r);
|
||||
}
|
||||
|
||||
double orient3dexact(const double *pa,
|
||||
const double *pb,
|
||||
const double *pc,
|
||||
const double *pd) {
|
||||
using namespace detail;
|
||||
|
||||
double ab[4]; diffprod(pa[0], pb[1], pb[0], pa[1], ab);
|
||||
double bc[4]; diffprod(pb[0], pc[1], pc[0], pb[1], bc);
|
||||
double cd[4]; diffprod(pc[0], pd[1], pd[0], pc[1], cd);
|
||||
double da[4]; diffprod(pd[0], pa[1], pa[0], pd[1], da);
|
||||
double ac[4]; diffprod(pa[0], pc[1], pc[0], pa[1], ac);
|
||||
double bd[4]; diffprod(pb[0], pd[1], pd[0], pb[1], bd);
|
||||
|
||||
exact_t temp;
|
||||
exact_t cda, dab, abc, bcd;
|
||||
exact_t adet, bdet, cdet, ddet, abdet, cddet, det;
|
||||
|
||||
sum_zeroelim(cd, cd + 4, da, da + 4, temp);
|
||||
sum_zeroelim(temp, ac, ac + 4, cda);
|
||||
|
||||
sum_zeroelim(da, da + 4, ab, ab + 4, temp);
|
||||
sum_zeroelim(temp, bd, bd + 4, dab);
|
||||
|
||||
negate(bd, bd + 4);
|
||||
negate(ac, bd + 4);
|
||||
|
||||
sum_zeroelim(ab, ab + 4, bc, bc + 4, temp);
|
||||
sum_zeroelim(temp, ac, ac + 4, abc);
|
||||
|
||||
sum_zeroelim(bc, bc + 4, cd, cd + 4, temp);
|
||||
sum_zeroelim(temp, bd, bd + 4, bcd);
|
||||
|
||||
scale_zeroelim(bcd, +pa[2], adet);
|
||||
scale_zeroelim(cda, -pb[2], bdet);
|
||||
scale_zeroelim(dab, +pc[2], cdet);
|
||||
scale_zeroelim(abc, -pd[2], ddet);
|
||||
|
||||
sum_zeroelim(adet, bdet, abdet);
|
||||
sum_zeroelim(cdet, ddet, cddet);
|
||||
|
||||
sum_zeroelim(abdet, cddet, det);
|
||||
|
||||
return det[det.size() - 1];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
208
extern/carve/include/carve/face_decl.hpp
vendored
Normal file
208
extern/carve/include/carve/face_decl.hpp
vendored
Normal file
@ -0,0 +1,208 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
|
||||
#include <carve/geom2d.hpp>
|
||||
#include <carve/vector.hpp>
|
||||
#include <carve/matrix.hpp>
|
||||
#include <carve/geom3d.hpp>
|
||||
#include <carve/aabb.hpp>
|
||||
#include <carve/tag.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
namespace carve {
|
||||
namespace poly {
|
||||
|
||||
|
||||
|
||||
struct Object;
|
||||
|
||||
template<unsigned ndim>
|
||||
class Edge;
|
||||
|
||||
|
||||
|
||||
template<unsigned ndim>
|
||||
struct p2_adapt_project {
|
||||
typedef carve::geom2d::P2 (*proj_t)(const carve::geom::vector<ndim> &);
|
||||
proj_t proj;
|
||||
p2_adapt_project(proj_t _proj) : proj(_proj) { }
|
||||
carve::geom2d::P2 operator()(const carve::geom::vector<ndim> &v) const { return proj(v); }
|
||||
carve::geom2d::P2 operator()(const carve::geom::vector<ndim> *v) const { return proj(*v); }
|
||||
carve::geom2d::P2 operator()(const Vertex<ndim> &v) const { return proj(v.v); }
|
||||
carve::geom2d::P2 operator()(const Vertex<ndim> *v) const { return proj(v->v); }
|
||||
};
|
||||
|
||||
|
||||
template<unsigned ndim>
|
||||
class Face : public tagable {
|
||||
public:
|
||||
typedef Vertex<ndim> vertex_t;
|
||||
typedef typename Vertex<ndim>::vector_t vector_t;
|
||||
typedef Edge<ndim> edge_t;
|
||||
typedef Object obj_t;
|
||||
typedef carve::geom::aabb<ndim> aabb_t;
|
||||
typedef carve::geom::plane<ndim> plane_t;
|
||||
|
||||
typedef carve::geom2d::P2 (*project_t)(const vector_t &);
|
||||
typedef vector_t (*unproject_t)(const carve::geom2d::P2 &, const plane_t &);
|
||||
|
||||
protected:
|
||||
std::vector<const vertex_t *> vertices; // pointer into polyhedron.vertices
|
||||
std::vector<const edge_t *> edges; // pointer into polyhedron.edges
|
||||
|
||||
project_t getProjector(bool positive_facing, int axis);
|
||||
unproject_t getUnprojector(bool positive_facing, int axis);
|
||||
|
||||
public:
|
||||
typedef typename std::vector<const vertex_t *>::iterator vertex_iter_t;
|
||||
typedef typename std::vector<const vertex_t *>::const_iterator const_vertex_iter_t;
|
||||
|
||||
typedef typename std::vector<const edge_t *>::iterator edge_iter_t;
|
||||
typedef typename std::vector<const edge_t *>::const_iterator const_edge_iter_t;
|
||||
|
||||
obj_t *owner;
|
||||
|
||||
aabb_t aabb;
|
||||
plane_t plane_eqn;
|
||||
int manifold_id;
|
||||
int group_id;
|
||||
|
||||
project_t project;
|
||||
unproject_t unproject;
|
||||
|
||||
Face(const std::vector<const vertex_t *> &_vertices, bool delay_recalc = false);
|
||||
Face(const vertex_t *v1, const vertex_t *v2, const vertex_t *v3, bool delay_recalc = false);
|
||||
Face(const vertex_t *v1, const vertex_t *v2, const vertex_t *v3, const vertex_t *v4, bool delay_recalc = false);
|
||||
|
||||
template <typename iter_t>
|
||||
Face(const Face *base, iter_t vbegin, iter_t vend, bool flipped) {
|
||||
init(base, vbegin, vend, flipped);
|
||||
}
|
||||
|
||||
Face(const Face *base, const std::vector<const vertex_t *> &_vertices, bool flipped) {
|
||||
init(base, _vertices, flipped);
|
||||
}
|
||||
|
||||
Face() {}
|
||||
~Face() {}
|
||||
|
||||
bool recalc();
|
||||
|
||||
template<typename iter_t>
|
||||
Face *init(const Face *base, iter_t vbegin, iter_t vend, bool flipped);
|
||||
Face *init(const Face *base, const std::vector<const vertex_t *> &_vertices, bool flipped);
|
||||
|
||||
template<typename iter_t>
|
||||
Face *create(iter_t vbegin, iter_t vend, bool flipped) const;
|
||||
Face *create(const std::vector<const vertex_t *> &_vertices, bool flipped) const;
|
||||
|
||||
Face *clone(bool flipped = false) const;
|
||||
void invert();
|
||||
|
||||
void getVertexLoop(std::vector<const vertex_t *> &loop) const;
|
||||
|
||||
const vertex_t *&vertex(size_t idx);
|
||||
const vertex_t *vertex(size_t idx) const;
|
||||
size_t nVertices() const;
|
||||
|
||||
vertex_iter_t vbegin() { return vertices.begin(); }
|
||||
vertex_iter_t vend() { return vertices.end(); }
|
||||
const_vertex_iter_t vbegin() const { return vertices.begin(); }
|
||||
const_vertex_iter_t vend() const { return vertices.end(); }
|
||||
|
||||
std::vector<carve::geom::vector<2> > projectedVertices() const;
|
||||
|
||||
const edge_t *&edge(size_t idx);
|
||||
const edge_t *edge(size_t idx) const;
|
||||
size_t nEdges() const;
|
||||
|
||||
edge_iter_t ebegin() { return edges.begin(); }
|
||||
edge_iter_t eend() { return edges.end(); }
|
||||
const_edge_iter_t ebegin() const { return edges.begin(); }
|
||||
const_edge_iter_t eend() const { return edges.end(); }
|
||||
|
||||
bool containsPoint(const vector_t &p) const;
|
||||
bool containsPointInProjection(const vector_t &p) const;
|
||||
bool simpleLineSegmentIntersection(const carve::geom::linesegment<ndim> &line,
|
||||
vector_t &intersection) const;
|
||||
IntersectionClass lineSegmentIntersection(const carve::geom::linesegment<ndim> &line,
|
||||
vector_t &intersection) const;
|
||||
vector_t centroid() const;
|
||||
|
||||
p2_adapt_project<ndim> projector() const {
|
||||
return p2_adapt_project<ndim>(project);
|
||||
}
|
||||
|
||||
void swap(Face<ndim> &other);
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct hash_face_ptr {
|
||||
template<unsigned ndim>
|
||||
size_t operator()(const Face<ndim> * const &f) const {
|
||||
return (size_t)f;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
namespace face {
|
||||
|
||||
|
||||
|
||||
template<unsigned ndim>
|
||||
static inline carve::geom2d::P2 project(const Face<ndim> *f, const typename Face<ndim>::vector_t &v) {
|
||||
return f->project(v);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<unsigned ndim>
|
||||
static inline carve::geom2d::P2 project(const Face<ndim> &f, const typename Face<ndim>::vector_t &v) {
|
||||
return f.project(v);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<unsigned ndim>
|
||||
static inline typename Face<ndim>::vector_t unproject(const Face<ndim> *f, const carve::geom2d::P2 &p) {
|
||||
return f->unproject(p, f->plane_eqn);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<unsigned ndim>
|
||||
static inline typename Face<ndim>::vector_t unproject(const Face<ndim> &f, const carve::geom2d::P2 &p) {
|
||||
return f.unproject(p, f.plane_eqn);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
140
extern/carve/include/carve/face_impl.hpp
vendored
Normal file
140
extern/carve/include/carve/face_impl.hpp
vendored
Normal file
@ -0,0 +1,140 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace std {
|
||||
template<unsigned ndim>
|
||||
inline void swap(carve::poly::Face<ndim> &a, carve::poly::Face<ndim> &b) {
|
||||
a.swap(b);
|
||||
}
|
||||
}
|
||||
|
||||
namespace carve {
|
||||
namespace poly {
|
||||
template<unsigned ndim>
|
||||
void Face<ndim>::swap(Face<ndim> &other) {
|
||||
std::swap(vertices, other.vertices);
|
||||
std::swap(edges, other.edges);
|
||||
std::swap(owner, other.owner);
|
||||
std::swap(aabb, other.aabb);
|
||||
std::swap(plane_eqn, other.plane_eqn);
|
||||
std::swap(manifold_id, other.manifold_id);
|
||||
std::swap(group_id, other.group_id);
|
||||
std::swap(project, other.project);
|
||||
std::swap(unproject, other.unproject);
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
template<typename iter_t>
|
||||
Face<ndim> *Face<ndim>::init(const Face<ndim> *base, iter_t vbegin, iter_t vend, bool flipped) {
|
||||
vertices.reserve(std::distance(vbegin, vend));
|
||||
|
||||
if (flipped) {
|
||||
std::reverse_copy(vbegin, vend, std::back_inserter(vertices));
|
||||
plane_eqn = -base->plane_eqn;
|
||||
} else {
|
||||
std::copy(vbegin, vend, std::back_inserter(vertices));
|
||||
plane_eqn = base->plane_eqn;
|
||||
}
|
||||
|
||||
edges.clear();
|
||||
edges.resize(nVertices(), NULL);
|
||||
|
||||
aabb.fit(vertices.begin(), vertices.end(), vec_adapt_vertex_ptr());
|
||||
untag();
|
||||
|
||||
int da = carve::geom::largestAxis(plane_eqn.N);
|
||||
|
||||
project = getProjector(plane_eqn.N.v[da] > 0, da);
|
||||
unproject = getUnprojector(plane_eqn.N.v[da] > 0, da);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
template<typename iter_t>
|
||||
Face<ndim> *Face<ndim>::create(iter_t vbegin, iter_t vend, bool flipped) const {
|
||||
return (new Face)->init(this, vbegin, vend, flipped);
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
Face<ndim> *Face<ndim>::create(const std::vector<const vertex_t *> &_vertices, bool flipped) const {
|
||||
return (new Face)->init(this, _vertices.begin(), _vertices.end(), flipped);
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
Face<ndim> *Face<ndim>::clone(bool flipped) const {
|
||||
return (new Face)->init(this, vertices, flipped);
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
void Face<ndim>::getVertexLoop(std::vector<const vertex_t *> &loop) const {
|
||||
loop.resize(nVertices(), NULL);
|
||||
std::copy(vbegin(), vend(), loop.begin());
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
const typename Face<ndim>::edge_t *&Face<ndim>::edge(size_t idx) {
|
||||
return edges[idx];
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
const typename Face<ndim>::edge_t *Face<ndim>::edge(size_t idx) const {
|
||||
return edges[idx];
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
size_t Face<ndim>::nEdges() const {
|
||||
return edges.size();
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
const typename Face<ndim>::vertex_t *&Face<ndim>::vertex(size_t idx) {
|
||||
return vertices[idx];
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
const typename Face<ndim>::vertex_t *Face<ndim>::vertex(size_t idx) const {
|
||||
return vertices[idx];
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
size_t Face<ndim>::nVertices() const {
|
||||
return vertices.size();
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
typename Face<ndim>::vector_t Face<ndim>::centroid() const {
|
||||
vector_t c;
|
||||
carve::geom::centroid(vertices.begin(), vertices.end(), vec_adapt_vertex_ptr(), c);
|
||||
return c;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
std::vector<carve::geom::vector<2> > Face<ndim>::projectedVertices() const {
|
||||
p2_adapt_project<ndim> proj = projector();
|
||||
std::vector<carve::geom::vector<2> > result;
|
||||
result.reserve(nVertices());
|
||||
for (size_t i = 0; i < nVertices(); ++i) {
|
||||
result.push_back(proj(vertex(i)->v));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
103
extern/carve/include/carve/faceloop.hpp
vendored
Normal file
103
extern/carve/include/carve/faceloop.hpp
vendored
Normal file
@ -0,0 +1,103 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
#include <carve/classification.hpp>
|
||||
#include <carve/collection_types.hpp>
|
||||
|
||||
namespace carve {
|
||||
namespace csg {
|
||||
|
||||
struct FaceLoopGroup;
|
||||
|
||||
struct FaceLoop {
|
||||
FaceLoop *next, *prev;
|
||||
const carve::mesh::MeshSet<3>::face_t *orig_face;
|
||||
std::vector<carve::mesh::MeshSet<3>::vertex_t *> vertices;
|
||||
FaceLoopGroup *group;
|
||||
|
||||
FaceLoop(const carve::mesh::MeshSet<3>::face_t *f, const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &v) : next(NULL), prev(NULL), orig_face(f), vertices(v), group(NULL) {}
|
||||
};
|
||||
|
||||
|
||||
struct FaceLoopList {
|
||||
FaceLoop *head, *tail;
|
||||
unsigned count;
|
||||
|
||||
FaceLoopList() : head(NULL), tail(NULL), count(0) { }
|
||||
|
||||
void append(FaceLoop *f) {
|
||||
f->prev = tail;
|
||||
f->next = NULL;
|
||||
if (tail) tail->next = f;
|
||||
tail = f;
|
||||
if (!head) head = f;
|
||||
count++;
|
||||
}
|
||||
|
||||
void prepend(FaceLoop *f) {
|
||||
f->next = head;
|
||||
f->prev = NULL;
|
||||
if (head) head->prev = f;
|
||||
head = f;
|
||||
if (!tail) tail = f;
|
||||
count++;
|
||||
}
|
||||
|
||||
unsigned size() const {
|
||||
return count;
|
||||
}
|
||||
|
||||
FaceLoop *remove(FaceLoop *f) {
|
||||
FaceLoop *r = f->next;
|
||||
if (f->prev) { f->prev->next = f->next; } else { head = f->next; }
|
||||
if (f->next) { f->next->prev = f->prev; } else { tail = f->prev; }
|
||||
f->next = f->prev = NULL;
|
||||
count--;
|
||||
return r;
|
||||
}
|
||||
|
||||
~FaceLoopList() {
|
||||
FaceLoop *a = head, *b;
|
||||
while (a) {
|
||||
b = a;
|
||||
a = a->next;
|
||||
delete b;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct FaceLoopGroup {
|
||||
const carve::mesh::MeshSet<3> *src;
|
||||
FaceLoopList face_loops;
|
||||
V2Set perimeter;
|
||||
std::list<ClassificationInfo> classification;
|
||||
|
||||
FaceLoopGroup(const carve::mesh::MeshSet<3> *_src) : src(_src) {
|
||||
}
|
||||
|
||||
FaceClass classificationAgainst(const carve::mesh::MeshSet<3>::mesh_t *mesh) const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
typedef std::list<FaceLoopGroup> FLGroupList;
|
||||
|
||||
}
|
||||
}
|
363
extern/carve/include/carve/geom.hpp
vendored
Normal file
363
extern/carve/include/carve/geom.hpp
vendored
Normal file
@ -0,0 +1,363 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace carve {
|
||||
namespace geom {
|
||||
|
||||
template<unsigned ndim> struct aabb;
|
||||
|
||||
// ========================================================================
|
||||
struct _uninitialized { };
|
||||
|
||||
template<unsigned ndim>
|
||||
struct base {
|
||||
double v[ndim];
|
||||
};
|
||||
|
||||
template<> struct base<2> {union { double v[2]; struct { double x, y; }; }; };
|
||||
template<> struct base<3> {union { double v[3]; struct { double x, y, z; }; }; };
|
||||
template<> struct base<4> {union { double v[4]; struct { double x, y, z, w; }; }; };
|
||||
|
||||
template<unsigned ndim>
|
||||
struct vector : public base<ndim> {
|
||||
enum { __ndim = ndim };
|
||||
|
||||
static vector ZERO();
|
||||
double length2() const;
|
||||
double length() const;
|
||||
vector<ndim> &normalize();
|
||||
vector<ndim> normalized() const;
|
||||
bool exactlyZero() const;
|
||||
bool isZero(double epsilon = EPSILON) const;
|
||||
void setZero();
|
||||
void fill(double val);
|
||||
vector<ndim> &scaleBy(double d);
|
||||
vector<ndim> &invscaleBy(double d);
|
||||
vector<ndim> scaled(double d) const;
|
||||
vector<ndim> invscaled(double d) const;
|
||||
vector<ndim> &negate();
|
||||
vector<ndim> negated() const;
|
||||
double &operator[](unsigned i);
|
||||
const double &operator[](unsigned i) const;
|
||||
template<typename assign_t>
|
||||
vector<ndim> &operator=(const assign_t &t);
|
||||
std::string asStr() const;
|
||||
|
||||
aabb<ndim> getAABB() const;
|
||||
|
||||
vector() { setZero(); }
|
||||
vector(noinit_t) { }
|
||||
};
|
||||
|
||||
template<unsigned ndim>
|
||||
vector<ndim> vector<ndim>::ZERO() { vector<ndim> r; r.setZero(); return r; }
|
||||
|
||||
static inline vector<2> VECTOR(double x, double y) { vector<2> r; r.x = x; r.y = y; return r; }
|
||||
static inline vector<3> VECTOR(double x, double y, double z) { vector<3> r; r.x = x; r.y = y; r.z = z; return r; }
|
||||
static inline vector<4> VECTOR(double x, double y, double z, double w) { vector<4> r; r.x = x; r.y = y; r.z = z; r.w = w; return r; }
|
||||
|
||||
template<unsigned ndim> vector<ndim> operator+(const vector<ndim> &a, const vector<ndim> &b);
|
||||
template<unsigned ndim> vector<ndim> operator+(const vector<ndim> &a, double b);
|
||||
template<unsigned ndim, typename val_t> vector<ndim> operator+(const vector<ndim> &a, const val_t &b);
|
||||
template<unsigned ndim, typename val_t> vector<ndim> operator+(const val_t &a, const vector<ndim> &b);
|
||||
|
||||
template<unsigned ndim> vector<ndim> &operator+=(vector<ndim> &a, const vector<ndim> &b);
|
||||
template<unsigned ndim> vector<ndim> &operator+=(vector<ndim> &a, double b);
|
||||
template<unsigned ndim, typename val_t> vector<ndim> &operator+=(vector<ndim> &a, const val_t &b);
|
||||
|
||||
template<unsigned ndim> vector<ndim> operator-(const vector<ndim> &a);
|
||||
|
||||
template<unsigned ndim> vector<ndim> operator-(const vector<ndim> &a, const vector<ndim> &b);
|
||||
template<unsigned ndim> vector<ndim> operator-(const vector<ndim> &a, double b);
|
||||
template<unsigned ndim, typename val_t> vector<ndim> operator-(const vector<ndim> &a, const val_t &b);
|
||||
template<unsigned ndim, typename val_t> vector<ndim> operator-(const val_t &a, const vector<ndim> &b);
|
||||
|
||||
template<unsigned ndim> vector<ndim> &operator-=(vector<ndim> &a, const vector<ndim> &b);
|
||||
template<unsigned ndim> vector<ndim> &operator-=(vector<ndim> &a, double b);
|
||||
template<unsigned ndim, typename val_t> vector<ndim> &operator-=(vector<ndim> &a, const val_t &b);
|
||||
|
||||
template<unsigned ndim> vector<ndim> operator*(const vector<ndim> &a, double s);
|
||||
template<unsigned ndim> vector<ndim> operator*(double s, const vector<ndim> &a);
|
||||
template<unsigned ndim> vector<ndim> &operator*=(vector<ndim> &a, double s);
|
||||
|
||||
template<unsigned ndim> vector<ndim> operator/(const vector<ndim> &a, double s);
|
||||
template<unsigned ndim> vector<ndim> &operator/=(vector<ndim> &a, double s);
|
||||
|
||||
template<unsigned ndim> bool operator==(const vector<ndim> &a, const vector<ndim> &b);
|
||||
template<unsigned ndim> bool operator!=(const vector<ndim> &a, const vector<ndim> &b);
|
||||
template<unsigned ndim> bool operator<(const vector<ndim> &a, const vector<ndim> &b);
|
||||
template<unsigned ndim> bool operator<=(const vector<ndim> &a, const vector<ndim> &b);
|
||||
template<unsigned ndim> bool operator>(const vector<ndim> &a, const vector<ndim> &b);
|
||||
template<unsigned ndim> bool operator>=(const vector<ndim> &a, const vector<ndim> &b);
|
||||
|
||||
template<unsigned ndim> vector<ndim> abs(const vector<ndim> &a);
|
||||
|
||||
template<unsigned ndim> double distance2(const vector<ndim> &a, const vector<ndim> &b);
|
||||
|
||||
template<unsigned ndim> double distance(const vector<ndim> &a, const vector<ndim> &b);
|
||||
|
||||
template<unsigned ndim> bool equal(const vector<ndim> &a, const vector<ndim> &b);
|
||||
|
||||
template<unsigned ndim> int smallestAxis(const vector<ndim> &a);
|
||||
|
||||
template<unsigned ndim> int largestAxis(const vector<ndim> &a);
|
||||
|
||||
template<unsigned ndim> vector<2> select(const vector<ndim> &a, int a1, int a2);
|
||||
|
||||
template<unsigned ndim> vector<3> select(const vector<ndim> &a, int a1, int a2, int a3);
|
||||
|
||||
template<unsigned ndim, typename assign_t, typename oper_t>
|
||||
vector<ndim> &assign_op(vector<ndim> &a, const assign_t &t, oper_t op);
|
||||
|
||||
template<unsigned ndim, typename assign1_t, typename assign2_t, typename oper_t>
|
||||
vector<ndim> &assign_op(vector<ndim> &a, const assign1_t &t1, const assign2_t &t2, oper_t op);
|
||||
|
||||
template<unsigned ndim, typename iter_t>
|
||||
void bounds(iter_t begin, iter_t end, vector<ndim> &min, vector<ndim> &max);
|
||||
|
||||
template<unsigned ndim, typename iter_t, typename adapt_t>
|
||||
void bounds(iter_t begin, iter_t end, adapt_t adapt, vector<ndim> &min, vector<ndim> &max);
|
||||
|
||||
template<unsigned ndim, typename iter_t, typename adapt_t>
|
||||
void centroid(iter_t begin, iter_t end, adapt_t adapt, vector<ndim> &c);
|
||||
|
||||
template<unsigned ndim, typename val_t> double dot(const vector<ndim> &a, const val_t &b);
|
||||
|
||||
static inline vector<3> cross(const vector<3> &a, const vector<3> &b);
|
||||
|
||||
static inline double cross(const vector<2> &a, const vector<2> &b);
|
||||
|
||||
static inline double dotcross(const vector<3> &a, const vector<3> &b, const vector<3> &c);
|
||||
|
||||
|
||||
|
||||
// ========================================================================
|
||||
struct axis_pos {
|
||||
int axis;
|
||||
double pos;
|
||||
|
||||
axis_pos(int _axis, double _pos) : axis(_axis), pos(_pos) { }
|
||||
};
|
||||
|
||||
template<unsigned ndim>
|
||||
double distance(const axis_pos &a, const vector<ndim> &b);
|
||||
|
||||
template<unsigned ndim>
|
||||
double distance2(const axis_pos &a, const vector<ndim> &b);
|
||||
|
||||
template<unsigned ndim> bool operator<(const axis_pos &a, const vector<ndim> &b);
|
||||
template<unsigned ndim> bool operator<(const vector<ndim> &a, const axis_pos &b);
|
||||
|
||||
template<unsigned ndim> bool operator<=(const axis_pos &a, const vector<ndim> &b);
|
||||
template<unsigned ndim> bool operator<=(const vector<ndim> &a, const axis_pos &b);
|
||||
|
||||
template<unsigned ndim> bool operator>(const axis_pos &a, const vector<ndim> &b);
|
||||
template<unsigned ndim> bool operator>(const vector<ndim> &a, const axis_pos &b);
|
||||
|
||||
template<unsigned ndim> bool operator>=(const axis_pos &a, const vector<ndim> &b);
|
||||
template<unsigned ndim> bool operator>=(const vector<ndim> &a, const axis_pos &b);
|
||||
|
||||
template<unsigned ndim> bool operator==(const axis_pos &a, const vector<ndim> &b);
|
||||
template<unsigned ndim> bool operator==(const vector<ndim> &a, const axis_pos &b);
|
||||
|
||||
template<unsigned ndim> bool operator!=(const axis_pos &a, const vector<ndim> &b);
|
||||
template<unsigned ndim> bool operator!=(const vector<ndim> &a, const axis_pos &b);
|
||||
|
||||
|
||||
|
||||
// ========================================================================
|
||||
template<unsigned ndim>
|
||||
struct ray {
|
||||
typedef vector<ndim> vector_t;
|
||||
|
||||
vector_t D, v;
|
||||
|
||||
bool OK() const;
|
||||
|
||||
ray() { }
|
||||
ray(vector_t _D, vector_t _v) : D(_D), v(_v) { }
|
||||
};
|
||||
|
||||
template<unsigned ndim>
|
||||
ray<ndim> rayThrough(const vector<ndim> &a, const vector<ndim> &b);
|
||||
|
||||
static inline double distance2(const ray<3> &r, const vector<3> &v);
|
||||
|
||||
static inline double distance(const ray<3> &r, const vector<3> &v);
|
||||
|
||||
static inline double distance2(const ray<2> &r, const vector<2> &v);
|
||||
|
||||
static inline double distance(const ray<2> &r, const vector<2> &v);
|
||||
|
||||
|
||||
|
||||
// ========================================================================
|
||||
template<unsigned ndim>
|
||||
struct linesegment {
|
||||
typedef vector<ndim> vector_t;
|
||||
|
||||
vector_t v1;
|
||||
vector_t v2;
|
||||
vector_t midpoint;
|
||||
vector_t half_length;
|
||||
|
||||
void update();
|
||||
bool OK() const;
|
||||
void flip();
|
||||
|
||||
aabb<ndim> getAABB() const;
|
||||
|
||||
linesegment(const vector_t &_v1, const vector_t &_v2);
|
||||
};
|
||||
|
||||
template<unsigned ndim>
|
||||
double distance2(const linesegment<ndim> &l, const vector<ndim> &v);
|
||||
|
||||
template<unsigned ndim>
|
||||
double distance(const linesegment<ndim> &l, const vector<ndim> &v);
|
||||
|
||||
|
||||
|
||||
// ========================================================================
|
||||
template<unsigned ndim>
|
||||
struct plane {
|
||||
typedef vector<ndim> vector_t;
|
||||
|
||||
vector_t N;
|
||||
double d;
|
||||
|
||||
void negate();
|
||||
|
||||
plane();
|
||||
plane(const vector_t &_N, vector_t _p);
|
||||
plane(const vector_t &_N, double _d);
|
||||
};
|
||||
|
||||
template<unsigned ndim>
|
||||
inline plane<ndim> operator-(const plane<ndim> &p);
|
||||
|
||||
template<unsigned ndim, typename val_t>
|
||||
double distance(const plane<ndim> &plane, const val_t &point);
|
||||
|
||||
template<unsigned ndim, typename val_t>
|
||||
double distance2(const plane<ndim> &plane, const val_t &point);
|
||||
|
||||
template<unsigned ndim>
|
||||
static inline vector<ndim> closestPoint(const plane<ndim> &p, const vector<ndim> &v);
|
||||
|
||||
|
||||
|
||||
// ========================================================================
|
||||
template<unsigned ndim>
|
||||
struct sphere {
|
||||
typedef vector<ndim> vector_t;
|
||||
|
||||
vector_t C;
|
||||
double r;
|
||||
|
||||
aabb<ndim> getAABB() const;
|
||||
|
||||
sphere();
|
||||
sphere(const vector_t &_C, double _r);
|
||||
};
|
||||
|
||||
template<unsigned ndim, typename val_t>
|
||||
double distance(const sphere<ndim> &sphere, const val_t &point);
|
||||
|
||||
template<unsigned ndim, typename val_t>
|
||||
double distance2(const sphere<ndim> &sphere, const val_t &point);
|
||||
|
||||
template<unsigned ndim>
|
||||
static inline vector<ndim> closestPoint(const sphere<ndim> &sphere, const vector<ndim> &point);
|
||||
|
||||
|
||||
// ========================================================================
|
||||
template<unsigned ndim>
|
||||
struct tri {
|
||||
typedef vector<ndim> vector_t;
|
||||
|
||||
vector_t v[3];
|
||||
|
||||
aabb<ndim> getAABB() const;
|
||||
|
||||
tri(vector_t _v[3]);
|
||||
tri(const vector_t &a, const vector_t &b, const vector_t &c);
|
||||
|
||||
vector_t normal() const {
|
||||
return cross(v[1] - v[0], v[2] - v[1]).normalized();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<unsigned ndim> std::ostream &operator<<(std::ostream &o, const vector<ndim> &v);
|
||||
template<unsigned ndim> std::ostream &operator<<(std::ostream &o, const carve::geom::plane<ndim> &p);
|
||||
template<unsigned ndim> std::ostream &operator<<(std::ostream &o, const carve::geom::sphere<ndim> &sphere);
|
||||
template<unsigned ndim> std::ostream &operator<<(std::ostream &o, const carve::geom::tri<ndim> &tri);
|
||||
|
||||
|
||||
|
||||
template<unsigned ndim> vector<ndim> closestPoint(const tri<ndim> &tri, const vector<ndim> &pt);
|
||||
template<unsigned ndim> double distance(const tri<ndim> &tri, const vector<ndim> &pt);
|
||||
template<unsigned ndim> double distance2(const tri<ndim> &tri, const vector<ndim> &pt);
|
||||
|
||||
|
||||
|
||||
// ========================================================================
|
||||
struct distance_functor {
|
||||
template<typename obj1_t, typename obj2_t>
|
||||
double operator()(const obj1_t &o1, const obj2_t &o2) {
|
||||
return distance(o1, o2);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
// ========================================================================
|
||||
template<int base, int power> struct __pow__ { enum { val = __pow__<base, (power >> 1)>::val * __pow__<base, power - (power >> 1)>::val }; };
|
||||
template<int base> struct __pow__<base, 1> { enum { val = base }; };
|
||||
template<int base> struct __pow__<base, 0> { enum { val = 1 }; };
|
||||
|
||||
template<unsigned base, unsigned ndigits>
|
||||
struct quantize {
|
||||
typedef __pow__<base, ndigits> fac;
|
||||
|
||||
double operator()(double in) {
|
||||
return round(in * fac::val) / fac::val;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
vector<ndim> operator()(const vector<ndim> &in) {
|
||||
vector<ndim> r(NOINIT);
|
||||
assign_op(r, in, *this);
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#include <carve/geom_impl.hpp>
|
403
extern/carve/include/carve/geom2d.hpp
vendored
Normal file
403
extern/carve/include/carve/geom2d.hpp
vendored
Normal file
@ -0,0 +1,403 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
|
||||
#include <carve/math.hpp>
|
||||
#include <carve/math_constants.hpp>
|
||||
|
||||
#include <carve/geom.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#if defined(CARVE_DEBUG)
|
||||
# include <iostream>
|
||||
#endif
|
||||
|
||||
#if defined CARVE_USE_EXACT_PREDICATES
|
||||
# include <carve/shewchuk_predicates.hpp>
|
||||
#endif
|
||||
|
||||
namespace carve {
|
||||
namespace geom2d {
|
||||
|
||||
typedef carve::geom::vector<2> P2;
|
||||
typedef carve::geom::ray<2> Ray2;
|
||||
typedef carve::geom::linesegment<2> LineSegment2;
|
||||
|
||||
|
||||
|
||||
struct p2_adapt_ident {
|
||||
P2 &operator()(P2 &p) const { return p; }
|
||||
const P2 &operator()(const P2 &p) const { return p; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
typedef std::vector<P2> P2Vector;
|
||||
|
||||
/**
|
||||
* \brief Return the orientation of c with respect to the ray defined by a->b.
|
||||
*
|
||||
* (Can be implemented exactly)
|
||||
*
|
||||
* @param[in] a
|
||||
* @param[in] b
|
||||
* @param[in] c
|
||||
*
|
||||
* @return positive, if c to the left of a->b.
|
||||
* zero, if c is colinear with a->b.
|
||||
* negative, if c to the right of a->b.
|
||||
*/
|
||||
#if defined CARVE_USE_EXACT_PREDICATES
|
||||
inline double orient2d(const P2 &a, const P2 &b, const P2 &c) {
|
||||
return shewchuk::orient2d(a.v, b.v, c.v);
|
||||
}
|
||||
#else
|
||||
inline double orient2d(const P2 &a, const P2 &b, const P2 &c) {
|
||||
double acx = a.x - c.x;
|
||||
double bcx = b.x - c.x;
|
||||
double acy = a.y - c.y;
|
||||
double bcy = b.y - c.y;
|
||||
return acx * bcy - acy * bcx;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Determine whether p is internal to the anticlockwise
|
||||
* angle abc, where b is the apex of the angle.
|
||||
*
|
||||
* @param[in] a
|
||||
* @param[in] b
|
||||
* @param[in] c
|
||||
* @param[in] p
|
||||
*
|
||||
* @return true, if p is contained in the anticlockwise angle from
|
||||
* b->a to b->c. Reflex angles contain p if p lies
|
||||
* on b->a or on b->c. Acute angles do not contain p
|
||||
* if p lies on b->a or on b->c. This is so that
|
||||
* internalToAngle(a,b,c,p) = !internalToAngle(c,b,a,p)
|
||||
*/
|
||||
inline bool internalToAngle(const P2 &a,
|
||||
const P2 &b,
|
||||
const P2 &c,
|
||||
const P2 &p) {
|
||||
bool reflex = (a < c) ? orient2d(b, a, c) <= 0.0 : orient2d(b, c, a) > 0.0;
|
||||
double d1 = orient2d(b, a, p);
|
||||
double d2 = orient2d(b, c, p);
|
||||
if (reflex) {
|
||||
return d1 >= 0.0 || d2 <= 0.0;
|
||||
} else {
|
||||
return d1 > 0.0 && d2 < 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Determine whether p is internal to the anticlockwise
|
||||
* angle ac, with apex at (0,0).
|
||||
*
|
||||
* @param[in] a
|
||||
* @param[in] c
|
||||
* @param[in] p
|
||||
*
|
||||
* @return true, if p is contained in a0c.
|
||||
*/
|
||||
inline bool internalToAngle(const P2 &a,
|
||||
const P2 &c,
|
||||
const P2 &p) {
|
||||
return internalToAngle(a, P2::ZERO(), c, p);
|
||||
}
|
||||
|
||||
template<typename P2vec>
|
||||
bool isAnticlockwise(const P2vec &tri) {
|
||||
return orient2d(tri[0], tri[1], tri[2]) > 0.0;
|
||||
}
|
||||
|
||||
template<typename P2vec>
|
||||
bool pointIntersectsTriangle(const P2 &p, const P2vec &tri) {
|
||||
int orient = isAnticlockwise(tri) ? +1 : -1;
|
||||
if (orient2d(tri[0], tri[1], p) * orient < 0) return false;
|
||||
if (orient2d(tri[1], tri[2], p) * orient < 0) return false;
|
||||
if (orient2d(tri[2], tri[0], p) * orient < 0) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename P2vec>
|
||||
bool lineIntersectsTriangle(const P2 &p1, const P2 &p2, const P2vec &tri) {
|
||||
double s[3];
|
||||
// does tri lie on one side or the other of p1-p2?
|
||||
s[0] = orient2d(p1, p2, tri[0]);
|
||||
s[1] = orient2d(p1, p2, tri[1]);
|
||||
s[2] = orient2d(p1, p2, tri[2]);
|
||||
if (*std::max_element(s, s+3) < 0) return false;
|
||||
if (*std::min_element(s, s+3) > 0) return false;
|
||||
|
||||
// does line lie entirely to the right of a triangle edge?
|
||||
int orient = isAnticlockwise(tri) ? +1 : -1;
|
||||
if (orient2d(tri[0], tri[1], p1) * orient < 0 && orient2d(tri[0], tri[1], p2) * orient < 0) return false;
|
||||
if (orient2d(tri[1], tri[2], p1) * orient < 0 && orient2d(tri[1], tri[2], p2) * orient < 0) return false;
|
||||
if (orient2d(tri[2], tri[0], p1) * orient < 0 && orient2d(tri[2], tri[0], p2) * orient < 0) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename P2vec>
|
||||
int triangleLineOrientation(const P2 &p1, const P2 &p2, const P2vec &tri) {
|
||||
double lo, hi, tmp;
|
||||
lo = hi = orient2d(p1, p2, tri[0]);
|
||||
tmp = orient2d(p1, p2, tri[1]); lo = std::min(lo, tmp); hi = std::max(hi, tmp);
|
||||
tmp = orient2d(p1, p2, tri[2]); lo = std::min(lo, tmp); hi = std::max(hi, tmp);
|
||||
if (hi < 0.0) return -1;
|
||||
if (lo > 0.0) return +1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename P2vec>
|
||||
bool triangleIntersectsTriangle(const P2vec &tri_b, const P2vec &tri_a) {
|
||||
int orient_a = isAnticlockwise(tri_a) ? +1 : -1;
|
||||
if (triangleLineOrientation(tri_a[0], tri_a[1], tri_b) * orient_a < 0) return false;
|
||||
if (triangleLineOrientation(tri_a[1], tri_a[2], tri_b) * orient_a < 0) return false;
|
||||
if (triangleLineOrientation(tri_a[2], tri_a[0], tri_b) * orient_a < 0) return false;
|
||||
|
||||
int orient_b = isAnticlockwise(tri_b) ? +1 : -1;
|
||||
if (triangleLineOrientation(tri_b[0], tri_b[1], tri_a) * orient_b < 0) return false;
|
||||
if (triangleLineOrientation(tri_b[1], tri_b[2], tri_a) * orient_b < 0) return false;
|
||||
if (triangleLineOrientation(tri_b[2], tri_b[0], tri_a) * orient_b < 0) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static inline double atan2(const P2 &p) {
|
||||
return ::atan2(p.y, p.x);
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct LineIntersectionInfo {
|
||||
LineIntersectionClass iclass;
|
||||
P2 ipoint;
|
||||
int p1, p2;
|
||||
|
||||
LineIntersectionInfo(LineIntersectionClass _iclass,
|
||||
P2 _ipoint = P2::ZERO(),
|
||||
int _p1 = -1,
|
||||
int _p2 = -1) :
|
||||
iclass(_iclass), ipoint(_ipoint), p1(_p1), p2(_p2) {
|
||||
}
|
||||
};
|
||||
|
||||
struct PolyInclusionInfo {
|
||||
PointClass iclass;
|
||||
int iobjnum;
|
||||
|
||||
PolyInclusionInfo(PointClass _iclass,
|
||||
int _iobjnum = -1) :
|
||||
iclass(_iclass), iobjnum(_iobjnum) {
|
||||
}
|
||||
};
|
||||
|
||||
struct PolyIntersectionInfo {
|
||||
IntersectionClass iclass;
|
||||
P2 ipoint;
|
||||
size_t iobjnum;
|
||||
|
||||
PolyIntersectionInfo(IntersectionClass _iclass,
|
||||
const P2 &_ipoint,
|
||||
size_t _iobjnum) :
|
||||
iclass(_iclass), ipoint(_ipoint), iobjnum(_iobjnum) {
|
||||
}
|
||||
};
|
||||
|
||||
bool lineSegmentIntersection_simple(const P2 &l1v1, const P2 &l1v2,
|
||||
const P2 &l2v1, const P2 &l2v2);
|
||||
bool lineSegmentIntersection_simple(const LineSegment2 &l1,
|
||||
const LineSegment2 &l2);
|
||||
|
||||
LineIntersectionInfo lineSegmentIntersection(const P2 &l1v1, const P2 &l1v2,
|
||||
const P2 &l2v1, const P2 &l2v2);
|
||||
LineIntersectionInfo lineSegmentIntersection(const LineSegment2 &l1,
|
||||
const LineSegment2 &l2);
|
||||
|
||||
int lineSegmentPolyIntersections(const std::vector<P2> &points,
|
||||
LineSegment2 line,
|
||||
std::vector<PolyInclusionInfo> &out);
|
||||
|
||||
int sortedLineSegmentPolyIntersections(const std::vector<P2> &points,
|
||||
LineSegment2 line,
|
||||
std::vector<PolyInclusionInfo> &out);
|
||||
|
||||
|
||||
|
||||
static inline bool quadIsConvex(const P2 &a, const P2 &b, const P2 &c, const P2 &d) {
|
||||
double s_1, s_2;
|
||||
|
||||
s_1 = carve::geom2d::orient2d(a, c, b);
|
||||
s_2 = carve::geom2d::orient2d(a, c, d);
|
||||
if ((s_1 < 0.0 && s_2 < 0.0) || (s_1 > 0.0 && s_2 > 0.0)) return false;
|
||||
|
||||
s_1 = carve::geom2d::orient2d(b, d, a);
|
||||
s_2 = carve::geom2d::orient2d(b, d, c);
|
||||
if ((s_1 < 0.0 && s_2 < 0.0) || (s_1 > 0.0 && s_2 > 0.0)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T, typename adapt_t>
|
||||
inline bool quadIsConvex(const T &a, const T &b, const T &c, const T &d, adapt_t adapt) {
|
||||
return quadIsConvex(adapt(a), adapt(b), adapt(c), adapt(d));
|
||||
}
|
||||
|
||||
|
||||
|
||||
double signedArea(const std::vector<P2> &points);
|
||||
|
||||
static inline double signedArea(const P2 &a, const P2 &b, const P2 &c) {
|
||||
return ((b.y + a.y) * (b.x - a.x) + (c.y + b.y) * (c.x - b.x) + (a.y + c.y) * (a.x - c.x)) / 2.0;
|
||||
}
|
||||
|
||||
template<typename T, typename adapt_t>
|
||||
double signedArea(const std::vector<T> &points, adapt_t adapt) {
|
||||
P2Vector::size_type l = points.size();
|
||||
double A = 0.0;
|
||||
|
||||
for (P2Vector::size_type i = 0; i < l - 1; i++) {
|
||||
A += (adapt(points[i + 1]).y + adapt(points[i]).y) * (adapt(points[i + 1]).x - adapt(points[i]).x);
|
||||
}
|
||||
A += (adapt(points[0]).y + adapt(points[l - 1]).y) * (adapt(points[0]).x - adapt(points[l - 1]).x);
|
||||
|
||||
return A / 2.0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename iter_t, typename adapt_t>
|
||||
double signedArea(iter_t begin, iter_t end, adapt_t adapt) {
|
||||
double A = 0.0;
|
||||
P2 p, n;
|
||||
|
||||
if (begin == end) return 0.0;
|
||||
|
||||
p = adapt(*begin);
|
||||
for (iter_t c = begin; ++c != end; ) {
|
||||
P2 n = adapt(*c);
|
||||
A += (n.y + p.y) * (n.x - p.x);
|
||||
p = n;
|
||||
}
|
||||
n = adapt(*begin);
|
||||
A += (n.y + p.y) * (n.x - p.x);
|
||||
|
||||
return A / 2.0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool pointInPolySimple(const std::vector<P2> &points, const P2 &p);
|
||||
|
||||
template<typename T, typename adapt_t>
|
||||
bool pointInPolySimple(const std::vector<T> &points, adapt_t adapt, const P2 &p) {
|
||||
CARVE_ASSERT(points.size() > 0);
|
||||
P2Vector::size_type l = points.size();
|
||||
double s = 0.0;
|
||||
double rp, r0, d;
|
||||
|
||||
rp = r0 = atan2(adapt(points[0]) - p);
|
||||
|
||||
for (P2Vector::size_type i = 1; i < l; i++) {
|
||||
double r = atan2(adapt(points[i]) - p);
|
||||
d = r - rp;
|
||||
if (d > M_PI) d -= M_TWOPI;
|
||||
if (d < -M_PI) d += M_TWOPI;
|
||||
s = s + d;
|
||||
rp = r;
|
||||
}
|
||||
|
||||
d = r0 - rp;
|
||||
if (d > M_PI) d -= M_TWOPI;
|
||||
if (d < -M_PI) d += M_TWOPI;
|
||||
s = s + d;
|
||||
|
||||
return !carve::math::ZERO(s);
|
||||
}
|
||||
|
||||
|
||||
|
||||
PolyInclusionInfo pointInPoly(const std::vector<P2> &points, const P2 &p);
|
||||
|
||||
template<typename T, typename adapt_t>
|
||||
PolyInclusionInfo pointInPoly(const std::vector<T> &points, adapt_t adapt, const P2 &p) {
|
||||
P2Vector::size_type l = points.size();
|
||||
for (unsigned i = 0; i < l; i++) {
|
||||
if (equal(adapt(points[i]), p)) return PolyInclusionInfo(POINT_VERTEX, i);
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < l; i++) {
|
||||
unsigned j = (i + 1) % l;
|
||||
|
||||
if (std::min(adapt(points[i]).x, adapt(points[j]).x) - EPSILON < p.x &&
|
||||
std::max(adapt(points[i]).x, adapt(points[j]).x) + EPSILON > p.x &&
|
||||
std::min(adapt(points[i]).y, adapt(points[j]).y) - EPSILON < p.y &&
|
||||
std::max(adapt(points[i]).y, adapt(points[j]).y) + EPSILON > p.y &&
|
||||
distance2(carve::geom::rayThrough(adapt(points[i]), adapt(points[j])), p) < EPSILON2) {
|
||||
return PolyInclusionInfo(POINT_EDGE, i);
|
||||
}
|
||||
}
|
||||
|
||||
if (pointInPolySimple(points, adapt, p)) {
|
||||
return PolyInclusionInfo(POINT_IN);
|
||||
}
|
||||
|
||||
return PolyInclusionInfo(POINT_OUT);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool pickContainedPoint(const std::vector<P2> &poly, P2 &result);
|
||||
|
||||
template<typename T, typename adapt_t>
|
||||
bool pickContainedPoint(const std::vector<T> &poly, adapt_t adapt, P2 &result) {
|
||||
#if defined(CARVE_DEBUG)
|
||||
std::cerr << "pickContainedPoint ";
|
||||
for (unsigned i = 0; i < poly.size(); ++i) std::cerr << " " << adapt(poly[i]);
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
const size_t S = poly.size();
|
||||
P2 a, b, c;
|
||||
for (unsigned i = 0; i < S; ++i) {
|
||||
a = adapt(poly[i]);
|
||||
b = adapt(poly[(i + 1) % S]);
|
||||
c = adapt(poly[(i + 2) % S]);
|
||||
|
||||
if (cross(a - b, c - b) < 0) {
|
||||
P2 p = (a + b + c) / 3;
|
||||
if (pointInPolySimple(poly, adapt, p)) {
|
||||
result = p;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
310
extern/carve/include/carve/geom3d.hpp
vendored
Normal file
310
extern/carve/include/carve/geom3d.hpp
vendored
Normal file
@ -0,0 +1,310 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
#include <carve/geom.hpp>
|
||||
|
||||
#include <math.h>
|
||||
#include <carve/math_constants.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
#if defined(CARVE_DEBUG)
|
||||
# include <iostream>
|
||||
#endif
|
||||
|
||||
#if defined CARVE_USE_EXACT_PREDICATES
|
||||
# include <carve/shewchuk_predicates.hpp>
|
||||
#endif
|
||||
|
||||
namespace carve {
|
||||
namespace geom3d {
|
||||
|
||||
typedef carve::geom::plane<3> Plane;
|
||||
typedef carve::geom::ray<3> Ray;
|
||||
typedef carve::geom::linesegment<3> LineSegment;
|
||||
typedef carve::geom::vector<3> Vector;
|
||||
|
||||
template<typename iter_t, typename adapt_t>
|
||||
bool fitPlane(iter_t begin, iter_t end, adapt_t adapt, Plane &plane) {
|
||||
Vector centroid;
|
||||
carve::geom::centroid(begin, end, adapt, centroid);
|
||||
iter_t i;
|
||||
|
||||
Vector n = Vector::ZERO();
|
||||
Vector v;
|
||||
Vector p1, p2, p3, c1, c2;
|
||||
if (begin == end) return false;
|
||||
|
||||
i = begin;
|
||||
p1 = c1 = adapt(*i); if (++i == end) return false;
|
||||
p2 = c2 = adapt(*i); if (++i == end) return false;
|
||||
|
||||
#if defined(CARVE_DEBUG)
|
||||
size_t N = 2;
|
||||
#endif
|
||||
do {
|
||||
p3 = adapt(*i);
|
||||
v = cross(p3 - p2, p1 - p2);
|
||||
if (v.v[largestAxis(v)]) v.negate();
|
||||
n += v;
|
||||
p1 = p2; p2 = p3;
|
||||
#if defined(CARVE_DEBUG)
|
||||
++N;
|
||||
#endif
|
||||
} while (++i != end);
|
||||
|
||||
p1 = p2; p2 = p3; p3 = c1;
|
||||
v = cross(p3 - p2, p1 - p2);
|
||||
if (v.v[largestAxis(v)]) v.negate();
|
||||
n += v;
|
||||
|
||||
p1 = p2; p2 = p3; p3 = c2;
|
||||
v = cross(p3 - p2, p1 - p2);
|
||||
if (v.v[largestAxis(v)]) v.negate();
|
||||
n += v;
|
||||
|
||||
n.normalize();
|
||||
plane.N = n;
|
||||
plane.d = -dot(n, centroid);
|
||||
#if defined(CARVE_DEBUG)
|
||||
if (N > 3) {
|
||||
std::cerr << "N = " << N << " fitted distance:";
|
||||
for (i = begin; i != end; ++i) {
|
||||
Vector p = adapt(*i);
|
||||
std::cerr << " {" << p << "} " << distance(plane, p);
|
||||
}
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool planeIntersection(const Plane &a, const Plane &b, Ray &r);
|
||||
|
||||
IntersectionClass rayPlaneIntersection(const Plane &p,
|
||||
const Vector &v1,
|
||||
const Vector &v2,
|
||||
Vector &v,
|
||||
double &t);
|
||||
|
||||
IntersectionClass lineSegmentPlaneIntersection(const Plane &p,
|
||||
const LineSegment &line,
|
||||
Vector &v);
|
||||
|
||||
RayIntersectionClass rayRayIntersection(const Ray &r1,
|
||||
const Ray &r2,
|
||||
Vector &v1,
|
||||
Vector &v2,
|
||||
double &mu1,
|
||||
double &mu2);
|
||||
|
||||
|
||||
|
||||
// test whether point d is above, below or on the plane formed by the triangle a,b,c.
|
||||
// return: +ve = d is below a,b,c
|
||||
// -ve = d is above a,b,c
|
||||
// 0 = d is on a,b,c
|
||||
#if defined CARVE_USE_EXACT_PREDICATES
|
||||
inline double orient3d(const Vector &a,
|
||||
const Vector &b,
|
||||
const Vector &c,
|
||||
const Vector &d) {
|
||||
return shewchuk::orient3d(a.v, b.v, c.v, d.v);
|
||||
}
|
||||
#else
|
||||
inline double orient3d(const Vector &a,
|
||||
const Vector &b,
|
||||
const Vector &c,
|
||||
const Vector &d) {
|
||||
return dotcross((a - d), (b - d), (c - d));
|
||||
}
|
||||
#endif
|
||||
|
||||
// Volume of a tetrahedron described by 4 points. Will be
|
||||
// positive if the anticlockwise normal of a,b,c is oriented out
|
||||
// of the tetrahedron.
|
||||
//
|
||||
// see: http://mathworld.wolfram.com/Tetrahedron.html
|
||||
inline double tetrahedronVolume(const Vector &a,
|
||||
const Vector &b,
|
||||
const Vector &c,
|
||||
const Vector &d) {
|
||||
return dotcross((a - d), (b - d), (c - d)) / 6.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Determine whether p is internal to the wedge defined by
|
||||
* the area between the planes defined by a,b,c and a,b,d
|
||||
* angle abc, where ab is the apex of the angle.
|
||||
*
|
||||
* @param[in] a
|
||||
* @param[in] b
|
||||
* @param[in] c
|
||||
* @param[in] d
|
||||
* @param[in] p
|
||||
*
|
||||
* @return true, if p is contained in the wedge defined by the
|
||||
* area between the planes defined by a,b,c and
|
||||
* a,b,d. If the wedge is reflex, p is considered to
|
||||
* be contained if it lies on either plane. Acute
|
||||
* wdges do not contain p if p lies on either
|
||||
* plane. This is so that internalToWedge(a,b,c,d,p) =
|
||||
* !internalToWedge(a,b,d,c,p)
|
||||
*/
|
||||
inline bool internalToWedge(const Vector &a,
|
||||
const Vector &b,
|
||||
const Vector &c,
|
||||
const Vector &d,
|
||||
const Vector &p) {
|
||||
bool reflex = (c < d) ?
|
||||
orient3d(a, b, c, d) >= 0.0 :
|
||||
orient3d(a, b, d, c) < 0.0;
|
||||
|
||||
double d1 = orient3d(a, b, c, p);
|
||||
double d2 = orient3d(a, b, d, p);
|
||||
|
||||
if (reflex) {
|
||||
// above a,b,c or below a,b,d (or coplanar with either)
|
||||
return d1 <= 0.0 || d2 >= 0.0;
|
||||
} else {
|
||||
// above a,b,c and below a,b,d
|
||||
return d1 < 0.0 && d2 > 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Determine the ordering relationship of a and b, when
|
||||
* rotating around direction, starting from base.
|
||||
*
|
||||
* @param[in] adirection
|
||||
* @param[in] base
|
||||
* @param[in] a
|
||||
* @param[in] b
|
||||
*
|
||||
* @return
|
||||
* * -1, if a is ordered before b around, rotating about direction.
|
||||
* * 0, if a and b are equal in angle.
|
||||
* * +1, if a is ordered after b around, rotating about direction.
|
||||
*/
|
||||
inline int compareAngles(const Vector &direction, const Vector &base, const Vector &a, const Vector &b) {
|
||||
const double d1 = carve::geom3d::orient3d(carve::geom::VECTOR(0,0,0), direction, a, b);
|
||||
const double d2 = carve::geom3d::orient3d(carve::geom::VECTOR(0,0,0), direction, base, a);
|
||||
const double d3 = carve::geom3d::orient3d(carve::geom::VECTOR(0,0,0), direction, base, b);
|
||||
|
||||
// CASE: a and b are coplanar wrt. direction.
|
||||
if (d1 == 0.0) {
|
||||
// a and b point in the same direction.
|
||||
if (dot(a, b) > 0.0) {
|
||||
// Neither is less than the other.
|
||||
return 0;
|
||||
}
|
||||
|
||||
// a and b point in opposite directions.
|
||||
// * if d2 < 0.0, a is above plane(direction, base) and is less
|
||||
// than b.
|
||||
// * if d2 == 0.0 a is coplanar with plane(direction, base) and is
|
||||
// less than b if it points in the same direction as base.
|
||||
// * if d2 > 0.0, a is below plane(direction, base) and is greater
|
||||
// than b.
|
||||
|
||||
if (d2 == 0.0) { return dot(a, base) > 0.0 ? -1 : +1; }
|
||||
if (d3 == 0.0) { return dot(b, base) > 0.0 ? +1 : -1; }
|
||||
if (d2 < 0.0 && d3 > 0.0) return -1;
|
||||
if (d2 > 0.0 && d3 < 0.0) return +1;
|
||||
|
||||
// both a and b are to one side of plane(direction, base) -
|
||||
// rounding error (if a and b are truly coplanar with
|
||||
// direction, one should be above, and one should be below any
|
||||
// other plane that is not itself coplanar with
|
||||
// plane(direction, a|b) - which would imply d2 and d3 == 0.0).
|
||||
|
||||
// If both are below plane(direction, base) then the one that
|
||||
// points in the same direction as base is greater.
|
||||
// If both are above plane(direction, base) then the one that
|
||||
// points in the same direction as base is lesser.
|
||||
if (d2 > 0.0) { return dot(a, base) > 0.0 ? +1 : -1; }
|
||||
else { return dot(a, base) > 0.0 ? -1 : +1; }
|
||||
}
|
||||
|
||||
// CASE: a and b are not coplanar wrt. direction
|
||||
|
||||
if (d2 < 0.0) {
|
||||
// if a is above plane(direction,base), then a is less than b if
|
||||
// b is below plane(direction,base) or b is above plane(direction,a)
|
||||
return (d3 > 0.0 || d1 < 0.0) ? -1 : +1;
|
||||
} else if (d2 == 0.0) {
|
||||
// if a is on plane(direction,base) then a is less than b if a
|
||||
// points in the same direction as base, or b is below
|
||||
// plane(direction,base)
|
||||
return (dot(a, base) > 0.0 || d3 > 0.0) ? -1 : +1;
|
||||
} else {
|
||||
// if a is below plane(direction,base), then a is less than b if b
|
||||
// is below plane(direction,base) and b is above plane(direction,a)
|
||||
return (d3 > 0.0 && d1 < 0.0) ? -1 : +1;
|
||||
}
|
||||
}
|
||||
|
||||
// The anticlockwise angle from vector "from" to vector "to", oriented around the vector "orient".
|
||||
static inline double antiClockwiseAngle(const Vector &from, const Vector &to, const Vector &orient) {
|
||||
double dp = dot(from, to);
|
||||
Vector cp = cross(from, to);
|
||||
if (cp.isZero()) {
|
||||
if (dp < 0) {
|
||||
return M_PI;
|
||||
} else {
|
||||
return 0.0;
|
||||
}
|
||||
} else {
|
||||
if (dot(cp, orient) > 0.0) {
|
||||
return acos(dp);
|
||||
} else {
|
||||
return M_TWOPI - acos(dp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static inline double antiClockwiseOrdering(const Vector &from, const Vector &to, const Vector &orient) {
|
||||
double dp = dot(from, to);
|
||||
Vector cp = cross(from, to);
|
||||
if (cp.isZero()) {
|
||||
if (dp < 0) {
|
||||
return 2.0;
|
||||
} else {
|
||||
return 0.0;
|
||||
}
|
||||
} else {
|
||||
if (dot(cp, orient) > 0.0) {
|
||||
// 1..-1 -> 0..2
|
||||
return 1.0 - dp;
|
||||
} else {
|
||||
// -1..1 -> 2..4
|
||||
return dp + 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
651
extern/carve/include/carve/geom_impl.hpp
vendored
Normal file
651
extern/carve/include/carve/geom_impl.hpp
vendored
Normal file
@ -0,0 +1,651 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/math.hpp>
|
||||
|
||||
namespace carve {
|
||||
namespace geom {
|
||||
|
||||
|
||||
|
||||
template<unsigned ndim>
|
||||
double vector<ndim>::length2() const { return dot(*this, *this); }
|
||||
template<unsigned ndim>
|
||||
double vector<ndim>::length() const { return sqrt(dot(*this, *this)); }
|
||||
|
||||
template<unsigned ndim>
|
||||
vector<ndim> &vector<ndim>::normalize() { *this /= length(); return *this; }
|
||||
template<unsigned ndim>
|
||||
vector<ndim> vector<ndim>::normalized() const { return *this / length(); }
|
||||
|
||||
template<unsigned ndim>
|
||||
bool vector<ndim>::exactlyZero() const {
|
||||
for (unsigned i = 0; i < ndim; ++i) if (this->v[i]) return false;
|
||||
return true;
|
||||
}
|
||||
template<unsigned ndim>
|
||||
bool vector<ndim>::isZero(double epsilon) const {
|
||||
return length2() < epsilon * epsilon;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
void vector<ndim>::setZero() { for (size_t i = 0; i < ndim; ++i) this->v[i] = 0.0; }
|
||||
|
||||
template<unsigned ndim>
|
||||
void vector<ndim>::fill(double val) { for (size_t i = 0; i < ndim; ++i) this->v[i] = val; }
|
||||
|
||||
template<unsigned ndim>
|
||||
vector<ndim> &vector<ndim>::scaleBy(double d) { for (unsigned i = 0; i < ndim; ++i) this->v[i] *= d; return *this; }
|
||||
template<unsigned ndim>
|
||||
vector<ndim> &vector<ndim>::invscaleBy(double d) { for (unsigned i = 0; i < ndim; ++i) this->v[i] /= d; return *this; }
|
||||
|
||||
template<unsigned ndim>
|
||||
vector<ndim> vector<ndim>::scaled(double d) const { return *this * d; }
|
||||
template<unsigned ndim>
|
||||
vector<ndim> vector<ndim>::invscaled(double d) const { return *this / d; }
|
||||
|
||||
template<unsigned ndim>
|
||||
vector<ndim> &vector<ndim>::negate() { for (unsigned i = 0; i < ndim; ++i) this->v[i] = -this->v[i]; return *this; }
|
||||
template<unsigned ndim>
|
||||
vector<ndim> vector<ndim>::negated() const { return -*this; }
|
||||
|
||||
template<unsigned ndim>
|
||||
double &vector<ndim>::operator[](unsigned i) { return this->v[i]; }
|
||||
template<unsigned ndim>
|
||||
const double &vector<ndim>::operator[](unsigned i) const { return this->v[i]; }
|
||||
|
||||
template<unsigned ndim>
|
||||
template<typename assign_t>
|
||||
vector<ndim> &vector<ndim>::operator=(const assign_t &t) {
|
||||
for (unsigned i = 0; i < ndim; ++i) this->v[i] = t[i];
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
std::string vector<ndim>::asStr() const {
|
||||
std::ostringstream out;
|
||||
out << '<';
|
||||
out << std::setprecision(24);
|
||||
for (unsigned i = 0; i < ndim; ++i) { if (i) out << ','; out << this->v[i]; }
|
||||
out << '>';
|
||||
return out.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<unsigned ndim>
|
||||
vector<ndim> operator+(const vector<ndim> &a, const vector<ndim> &b) {
|
||||
vector<ndim> c(NOINIT);
|
||||
for (unsigned i = 0; i < ndim; ++i) c[i] = a[i] + b[i];
|
||||
return c;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
vector<ndim> operator+(const vector<ndim> &a, double b) {
|
||||
vector<ndim> c(NOINIT);
|
||||
for (unsigned i = 0; i < ndim; ++i) c[i] = a[i] + b;
|
||||
return c;
|
||||
}
|
||||
|
||||
template<unsigned ndim, typename val_t>
|
||||
vector<ndim> operator+(const vector<ndim> &a, const val_t &b) {
|
||||
vector<ndim> c(NOINIT);
|
||||
for (unsigned i = 0; i < ndim; ++i) c[i] = a[i] + b[i];
|
||||
return c;
|
||||
}
|
||||
|
||||
template<unsigned ndim, typename val_t>
|
||||
vector<ndim> operator+(const val_t &a, const vector<ndim> &b) {
|
||||
vector<ndim> c(NOINIT);
|
||||
for (unsigned i = 0; i < ndim; ++i) c[i] = a[i] + b[i];
|
||||
return c;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
vector<ndim> &operator+=(vector<ndim> &a, const vector<ndim> &b) {
|
||||
for (unsigned i = 0; i < ndim; ++i) a[i] += b[i];
|
||||
return a;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
vector<ndim> &operator+=(vector<ndim> &a, double b) {
|
||||
for (unsigned i = 0; i < ndim; ++i) a[i] += b;
|
||||
return a;
|
||||
}
|
||||
|
||||
template<unsigned ndim, typename val_t>
|
||||
vector<ndim> &operator+=(vector<ndim> &a, const val_t &b) {
|
||||
for (unsigned i = 0; i < ndim; ++i) a[i] += b[i];
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<unsigned ndim>
|
||||
vector<ndim> operator-(const vector<ndim> &a) {
|
||||
vector<ndim> c(NOINIT);
|
||||
for (unsigned i = 0; i < ndim; ++i) c[i] = -a[i];
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<unsigned ndim>
|
||||
vector<ndim> operator-(const vector<ndim> &a, double b) {
|
||||
vector<ndim> c(NOINIT);
|
||||
for (unsigned i = 0; i < ndim; ++i) c[i] = a[i] - b;
|
||||
return c;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
vector<ndim> operator-(const vector<ndim> &a, const vector<ndim> &b) {
|
||||
vector<ndim> c(NOINIT);
|
||||
for (unsigned i = 0; i < ndim; ++i) c[i] = a[i] - b[i];
|
||||
return c;
|
||||
}
|
||||
|
||||
template<unsigned ndim, typename val_t>
|
||||
vector<ndim> operator-(const vector<ndim> &a, const val_t &b) {
|
||||
vector<ndim> c(NOINIT);
|
||||
for (unsigned i = 0; i < ndim; ++i) c[i] = a[i] - b[i];
|
||||
return c;
|
||||
}
|
||||
|
||||
template<unsigned ndim, typename val_t>
|
||||
vector<ndim> operator-(const val_t &a, const vector<ndim> &b) {
|
||||
vector<ndim> c(NOINIT);
|
||||
for (unsigned i = 0; i < ndim; ++i) c[i] = a[i] - b[i];
|
||||
return c;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
vector<ndim> &operator-=(vector<ndim> &a, const vector<ndim> &b) {
|
||||
for (unsigned i = 0; i < ndim; ++i) a[i] -= b[i];
|
||||
return a;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
vector<ndim> &operator-=(vector<ndim> &a, double b) {
|
||||
for (unsigned i = 0; i < ndim; ++i) a[i] -= b;
|
||||
return a;
|
||||
}
|
||||
|
||||
template<unsigned ndim, typename val_t>
|
||||
vector<ndim> &operator-=(vector<ndim> &a, const val_t &b) {
|
||||
for (unsigned i = 0; i < ndim; ++i) a[i] -= b[i];
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<unsigned ndim>
|
||||
vector<ndim> operator*(const vector<ndim> &a, double s) {
|
||||
vector<ndim> c(NOINIT);
|
||||
for (unsigned i = 0; i < ndim; ++i) c[i] = a[i] * s;
|
||||
return c;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
vector<ndim> operator*(double s, const vector<ndim> &a) {
|
||||
vector<ndim> c(NOINIT);
|
||||
for (unsigned i = 0; i < ndim; ++i) c[i] = a[i] * s;
|
||||
return c;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
vector<ndim> &operator*=(vector<ndim> &a, double s) {
|
||||
for (unsigned i = 0; i < ndim; ++i) a[i] *= s;
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<unsigned ndim>
|
||||
vector<ndim> operator/(const vector<ndim> &a, double s) {
|
||||
vector<ndim> c(NOINIT);
|
||||
for (unsigned i = 0; i < ndim; ++i) c[i] = a[i] / s;
|
||||
return c;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
vector<ndim> &operator/=(vector<ndim> &a, double s) {
|
||||
for (unsigned i = 0; i < ndim; ++i) a[i] /= s;
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<unsigned ndim>
|
||||
bool operator==(const vector<ndim> &a, const vector<ndim> &b) {
|
||||
for (unsigned i = 0; i < ndim; ++i) { if (a[i] != b[i]) return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
bool operator!=(const vector<ndim> &a, const vector<ndim> &b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
bool operator<(const vector<ndim> &a, const vector<ndim> &b) {
|
||||
for (unsigned i = 0; i < ndim; ++i) { if (a[i] < b[i]) return true; if (a[i] > b[i]) return false; }
|
||||
return false;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
bool operator<=(const vector<ndim> &a, const vector<ndim> &b) {
|
||||
return !(b < a);
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
bool operator>(const vector<ndim> &a, const vector<ndim> &b) {
|
||||
return b < a;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
bool operator>=(const vector<ndim> &a, const vector<ndim> &b) {
|
||||
return !(a < b);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<unsigned ndim>
|
||||
vector<ndim> abs(const vector<ndim> &a) {
|
||||
vector<ndim> c(NOINIT);
|
||||
for (unsigned i = 0; i < ndim; ++i) c[i] = fabs(a[i]);
|
||||
return c;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
double distance2(const vector<ndim> &a, const vector<ndim> &b) {
|
||||
return (b - a).length2();
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
double distance(const vector<ndim> &a, const vector<ndim> &b) {
|
||||
return (b - a).length();
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
bool equal(const vector<ndim> &a, const vector<ndim> &b) {
|
||||
return (b - a).isZero();
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
int smallestAxis(const vector<ndim> &a) {
|
||||
int x = 0;
|
||||
double y = fabs(a[0]);
|
||||
for (unsigned i = 1; i < ndim; ++i) {
|
||||
double z = fabs(a[i]);
|
||||
if (z <= y) { y = z; x = i; }
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
int largestAxis(const vector<ndim> &a) {
|
||||
int x = 0;
|
||||
double y = fabs(a[0]);
|
||||
for (unsigned i = 1; i < ndim; ++i) {
|
||||
double z = fabs(a[i]);
|
||||
if (z > y) { y = z; x = i; }
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
vector<2> select(const vector<ndim> &a, int a1, int a2) {
|
||||
vector<2> r(NOINIT);
|
||||
r.v[0] = a.v[a1]; r.v[1] = a.v[a2];
|
||||
return r;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
vector<3> select(const vector<ndim> &a, int a1, int a2, int a3) {
|
||||
vector<3> r(NOINIT);
|
||||
r.v[0] = a.v[a1]; r.v[1] = a.v[a2]; r.v[2] = a.v[a3];
|
||||
return r;
|
||||
}
|
||||
|
||||
template<unsigned ndim, typename assign_t, typename oper_t>
|
||||
vector<ndim> &assign_op(vector<ndim> &a, const assign_t &t, oper_t op) {
|
||||
for (unsigned i = 0; i < ndim; ++i) a[i] = op(t[i]);
|
||||
return a;
|
||||
}
|
||||
|
||||
template<unsigned ndim, typename assign1_t, typename assign2_t, typename oper_t>
|
||||
vector<ndim> &assign_op(vector<ndim> &a, const assign1_t &t1, const assign2_t &t2, oper_t op) {
|
||||
for (unsigned i = 0; i < ndim; ++i) a[i] = op(t1[i], t2[i]);
|
||||
return a;
|
||||
}
|
||||
|
||||
template<unsigned ndim, typename iter_t>
|
||||
void bounds(iter_t begin, iter_t end, vector<ndim> &min, vector<ndim> &max) {
|
||||
if (begin == end) {
|
||||
min.setZero();
|
||||
max.setZero();
|
||||
} else {
|
||||
min = max = *begin;
|
||||
while (++begin != end) {
|
||||
vector<ndim> v = *begin;
|
||||
assign_op(min, min, v, carve::util::min_functor());
|
||||
assign_op(max, max, v, carve::util::max_functor());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<unsigned ndim, typename iter_t, typename adapt_t>
|
||||
void bounds(iter_t begin, iter_t end, adapt_t adapt, vector<ndim> &min, vector<ndim> &max) {
|
||||
if (begin == end) {
|
||||
min.setZero();
|
||||
max.setZero();
|
||||
} else {
|
||||
min = max = adapt(*begin);
|
||||
while (++begin != end) {
|
||||
vector<ndim> v = adapt(*begin);
|
||||
assign_op(min, min, v, carve::util::min_functor());
|
||||
assign_op(max, max, v, carve::util::max_functor());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<unsigned ndim, typename iter_t, typename adapt_t>
|
||||
void centroid(iter_t begin, iter_t end, adapt_t adapt, vector<ndim> &c) {
|
||||
c.setZero();
|
||||
int n = 0;
|
||||
while (begin != end) { c += adapt(*begin++); ++n; }
|
||||
c /= double(n);
|
||||
}
|
||||
|
||||
template<unsigned ndim, typename val_t>
|
||||
double dot(const vector<ndim> &a, const val_t &b) {
|
||||
double r = 0.0;
|
||||
for (unsigned i = 0; i < ndim; ++i) r += a[i] * b[i];
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline vector<3> cross(const vector<3> &a, const vector<3> &b) {
|
||||
// Compute a x b
|
||||
return VECTOR(+(a.y * b.z - a.z * b.y),
|
||||
-(a.x * b.z - a.z * b.x),
|
||||
+(a.x * b.y - a.y * b.x));
|
||||
}
|
||||
|
||||
static inline double cross(const vector<2> &a, const vector<2> &b) {
|
||||
// Compute a x b
|
||||
return a.x * b.y - b.x * a.y;
|
||||
}
|
||||
|
||||
static inline double dotcross(const vector<3> &a, const vector<3> &b, const vector<3> &c) {
|
||||
// Compute a . (b x c)
|
||||
return
|
||||
(a.x * b.y * c.z + a.y * b.z * c.x + a.z * b.x * c.y) -
|
||||
(a.x * b.z * c.y + a.y * b.x * c.z + a.z * b.y * c.x);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<unsigned ndim>
|
||||
double distance(const axis_pos &a, const vector<ndim> &b) {
|
||||
return fabs(b[a.axis] - a.pos);
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
double distance2(const axis_pos &a, const vector<ndim> &b) {
|
||||
double r = fabs(b[a.axis] - a.pos);
|
||||
return r * r;
|
||||
}
|
||||
|
||||
template<unsigned ndim> bool operator<(const axis_pos &a, const vector<ndim> &b) { return a.pos < b[a.axis]; }
|
||||
template<unsigned ndim> bool operator<(const vector<ndim> &a, const axis_pos &b) { return a[b.axis] < b.pos; }
|
||||
|
||||
template<unsigned ndim> bool operator<=(const axis_pos &a, const vector<ndim> &b) { return a.pos <= b[a.axis]; }
|
||||
template<unsigned ndim> bool operator<=(const vector<ndim> &a, const axis_pos &b) { return a[b.axis] <= b.pos; }
|
||||
|
||||
template<unsigned ndim> bool operator>(const axis_pos &a, const vector<ndim> &b) { return a.pos > b[a.axis]; }
|
||||
template<unsigned ndim> bool operator>(const vector<ndim> &a, const axis_pos &b) { return a[b.axis] > b.pos; }
|
||||
|
||||
template<unsigned ndim> bool operator>=(const axis_pos &a, const vector<ndim> &b) { return a.pos >= b[a.axis]; }
|
||||
template<unsigned ndim> bool operator>=(const vector<ndim> &a, const axis_pos &b) { return a[b.axis] >= b.pos; }
|
||||
|
||||
template<unsigned ndim> bool operator==(const axis_pos &a, const vector<ndim> &b) { return a.pos == b[a.axis]; }
|
||||
template<unsigned ndim> bool operator==(const vector<ndim> &a, const axis_pos &b) { return a[b.axis] == b.pos; }
|
||||
|
||||
template<unsigned ndim> bool operator!=(const axis_pos &a, const vector<ndim> &b) { return a.pos != b[a.axis]; }
|
||||
template<unsigned ndim> bool operator!=(const vector<ndim> &a, const axis_pos &b) { return a[b.axis] != b.pos; }
|
||||
|
||||
|
||||
|
||||
template<unsigned ndim>
|
||||
bool ray<ndim>::OK() const {
|
||||
return !D.isZero();
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
ray<ndim> rayThrough(const vector<ndim> &a, const vector<ndim> &b) {
|
||||
return ray<ndim>(b - a, a);
|
||||
}
|
||||
|
||||
static inline double distance2(const ray<3> &r, const vector<3> &v) {
|
||||
return cross(r.D, v - r.v).length2() / r.D.length2();
|
||||
}
|
||||
|
||||
static inline double distance(const ray<3> &r, const vector<3> &v) {
|
||||
return sqrt(distance2(r, v));
|
||||
}
|
||||
|
||||
static inline double distance2(const ray<2> &r, const vector<2> &v) {
|
||||
double t = cross(r.D, v - r.v);
|
||||
return (t * t) / r.D.length2();
|
||||
}
|
||||
|
||||
static inline double distance(const ray<2> &r, const vector<2> &v) {
|
||||
return sqrt(distance2(r, v));
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<unsigned ndim>
|
||||
void linesegment<ndim>::update() {
|
||||
midpoint = (v2 + v1) / 2.0;
|
||||
half_length = (v2 - v1) / 2.0;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
bool linesegment<ndim>::OK() const {
|
||||
return !half_length.isZero();
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
void linesegment<ndim>::flip() {
|
||||
std::swap(v1, v2);
|
||||
half_length = (v2 - v1) / 2.0;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
aabb<ndim> linesegment<ndim>::getAABB() const {
|
||||
aabb<ndim> r;
|
||||
r.fit(v1, v2);
|
||||
return r;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
linesegment<ndim>::linesegment(const vector_t &_v1, const vector_t &_v2) : v1(_v1), v2(_v2) {
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<unsigned ndim>
|
||||
double distance2(const linesegment<ndim> &l, const vector<ndim> &v) {
|
||||
vector<ndim> D = l.v2 - l.v1;
|
||||
double t = dot(v - l.v1, D) / dot(D, D);
|
||||
if (t <= 0.0) return (v - l.v1).length2();
|
||||
if (t >= 1.0) return (v - l.v2).length2();
|
||||
vector<ndim> vc = D * t + l.v1;
|
||||
return (v - vc).length2();
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
double distance(const linesegment<ndim> &l, const vector<ndim> &v) {
|
||||
return sqrt(distance2(l, v));
|
||||
}
|
||||
|
||||
|
||||
template<unsigned ndim>
|
||||
void plane<ndim>::negate() {
|
||||
N.negate();
|
||||
d = -d;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
plane<ndim>::plane() {
|
||||
N.setZero();
|
||||
N[0] = 1.0;
|
||||
d= 0.0;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
plane<ndim>::plane(const vector_t &_N, vector_t _p) : N(_N), d(-dot(_p, _N)) {
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
plane<ndim>::plane(const vector_t &_N, double _d) : N(_N), d(_d) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<unsigned ndim>
|
||||
plane<ndim> operator-(const plane<ndim> &p) {
|
||||
return plane<ndim>(-p.N, -p.d);
|
||||
}
|
||||
|
||||
template<unsigned ndim, typename val_t>
|
||||
double distance(const plane<ndim> &plane, const val_t &point) {
|
||||
return dot(plane.N, point) + plane.d;
|
||||
}
|
||||
|
||||
template<unsigned ndim, typename val_t>
|
||||
double distance2(const plane<ndim> &plane, const val_t &point) {
|
||||
double d = distance(plane, point);
|
||||
return d * d;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
vector<ndim> closestPoint(const plane<ndim> &p, const vector<ndim> &v) {
|
||||
return v - p.N * (p.d + dot(p.N, v)) / dot(p.N, p.N);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<unsigned ndim>
|
||||
aabb<ndim> sphere<ndim>::getAABB() const {
|
||||
aabb<ndim> r;
|
||||
r.fit(C - r, C + r);
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
sphere<ndim>::sphere() {
|
||||
C.setZero();
|
||||
r = 1.0;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
sphere<ndim>::sphere(const vector_t &_C, double _r) : C(_C), r(_r) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<unsigned ndim, typename val_t>
|
||||
double distance(const sphere<ndim> &sphere, const val_t &point) {
|
||||
return std::max(0.0, distance(sphere.C, point) - sphere.r);
|
||||
}
|
||||
|
||||
template<unsigned ndim, typename val_t>
|
||||
double distance2(const sphere<ndim> &sphere, const val_t &point) {
|
||||
return std::max(0.0, distance2(sphere.C, point) - sphere.r * sphere.r);
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
vector<ndim> closestPoint(const sphere<ndim> &sphere, const vector<ndim> &point) {
|
||||
return (point - sphere.C).normalized() * sphere.r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<unsigned ndim>
|
||||
aabb<ndim> tri<ndim>::getAABB() const {
|
||||
aabb<ndim> aabb;
|
||||
aabb.fit(v[0], v[1], v[2]);
|
||||
return aabb;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
tri<ndim>::tri(vector_t _v[3]) {
|
||||
std::copy(v, v+3, _v);
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
tri<ndim>::tri(const vector_t &a, const vector_t &b, const vector_t &c) {
|
||||
v[0] = a;
|
||||
v[1] = b;
|
||||
v[2] = c;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<unsigned ndim>
|
||||
std::ostream &operator<<(std::ostream &o, const vector<ndim> &v) {
|
||||
o << v.asStr();
|
||||
return o;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
std::ostream &operator<<(std::ostream &o, const carve::geom::plane<ndim> &p) {
|
||||
o << p.N << ";" << p.d;
|
||||
return o;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
std::ostream &operator<<(std::ostream &o, const carve::geom::sphere<ndim> &sphere) {
|
||||
o << "{sphere " << sphere.C << ";" << sphere.r << "}";
|
||||
return o;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
std::ostream &operator<<(std::ostream &o, const carve::geom::tri<ndim> &tri) {
|
||||
o << "{tri " << tri.v[0] << ";" << tri.v[1] << ";" << tri.v[2] << "}";
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<unsigned ndim>
|
||||
double distance(const tri<ndim> &tri, const vector<ndim> &pt) {
|
||||
return distance(closestPoint(tri, pt), pt);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<unsigned ndim>
|
||||
double distance2(const tri<ndim> &tri, const vector<ndim> &pt) {
|
||||
return distance2(closestPoint(tri, pt), pt);
|
||||
}
|
||||
}
|
||||
}
|
4
extern/carve/include/carve/gnu_cxx.h
vendored
Normal file
4
extern/carve/include/carve/gnu_cxx.h
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
// Copyright 2006 Tobias Sargeant (toby@permuted.net)
|
||||
// All rights reserved.
|
||||
|
||||
#pragma once
|
425
extern/carve/include/carve/heap.hpp
vendored
Normal file
425
extern/carve/include/carve/heap.hpp
vendored
Normal file
@ -0,0 +1,425 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
#pragma once
|
||||
namespace carve {
|
||||
namespace heap {
|
||||
namespace detail {
|
||||
|
||||
|
||||
|
||||
struct ignore_position_t {
|
||||
template<typename value_t>
|
||||
void operator()(value_t &val, size_t idx) const {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename random_access_iter_t,
|
||||
typename distance_t,
|
||||
typename value_t,
|
||||
typename pred_t,
|
||||
typename pos_notifier_t>
|
||||
void _adjust_heap(random_access_iter_t begin,
|
||||
distance_t pos,
|
||||
distance_t len,
|
||||
value_t val,
|
||||
pred_t pred,
|
||||
pos_notifier_t notify) {
|
||||
const distance_t top = pos;
|
||||
|
||||
distance_t child = pos * 2 + 2;
|
||||
while (child < len) {
|
||||
if (pred(begin[child], begin[child - 1])) child--;
|
||||
|
||||
begin[pos] = begin[child];
|
||||
notify(begin[pos], pos);
|
||||
pos = child;
|
||||
child = pos * 2 + 2;
|
||||
}
|
||||
|
||||
if (child == len) {
|
||||
child--;
|
||||
begin[pos] = begin[child];
|
||||
notify(begin[pos], pos);
|
||||
pos = child;
|
||||
}
|
||||
|
||||
distance_t parent = (pos - 1) / 2;
|
||||
while (pos > top && pred(begin[parent], val)) {
|
||||
begin[pos] = begin[parent];
|
||||
notify(begin[pos], pos);
|
||||
pos = parent;
|
||||
parent = (pos - 1) / 2;
|
||||
}
|
||||
|
||||
begin[pos] = val;
|
||||
notify(begin[pos], pos);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename random_access_iter_t,
|
||||
typename distance_t,
|
||||
typename value_t,
|
||||
typename pred_t,
|
||||
typename pos_notifier_t>
|
||||
void _push_heap(random_access_iter_t begin,
|
||||
distance_t pos,
|
||||
value_t val,
|
||||
pred_t pred,
|
||||
pos_notifier_t notify) {
|
||||
distance_t parent = (pos - 1) / 2;
|
||||
while (pos > 0 && pred(begin[parent], val)) {
|
||||
begin[pos] = begin[parent];
|
||||
notify(begin[pos], pos);
|
||||
pos = parent;
|
||||
parent = (pos - 1) / 2;
|
||||
}
|
||||
begin[pos] = val;
|
||||
notify(begin[pos], pos);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename random_access_iter_t,
|
||||
typename distance_t,
|
||||
typename pred_t,
|
||||
typename pos_notifier_t>
|
||||
void _remove_heap(random_access_iter_t begin,
|
||||
distance_t pos,
|
||||
distance_t len,
|
||||
pred_t pred,
|
||||
pos_notifier_t notify) {
|
||||
--len;
|
||||
if (pos != len) {
|
||||
typedef typename std::iterator_traits<random_access_iter_t>::value_type value_t;
|
||||
value_t removed = begin[pos];
|
||||
_adjust_heap(begin, pos, len, begin[len], pred, notify);
|
||||
begin[len] = removed;
|
||||
notify(begin[len], len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename random_access_iter_t,
|
||||
typename distance_t,
|
||||
typename pred_t,
|
||||
typename pos_notifier_t>
|
||||
void _make_heap(random_access_iter_t begin,
|
||||
distance_t len,
|
||||
pred_t pred,
|
||||
pos_notifier_t notify) {
|
||||
for (distance_t pos = len / 2; pos > 0; ) {
|
||||
--pos;
|
||||
_adjust_heap(begin, pos, len, begin[pos], pred, ignore_position_t());
|
||||
}
|
||||
for (distance_t pos = 0; pos < len; ++pos) {
|
||||
notify(begin[pos], pos);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename random_access_iter_t,
|
||||
typename distance_t,
|
||||
typename pred_t>
|
||||
void _make_heap(random_access_iter_t begin,
|
||||
distance_t len,
|
||||
pred_t pred,
|
||||
ignore_position_t) {
|
||||
for (distance_t pos = len / 2; pos > 0; ) {
|
||||
--pos;
|
||||
_adjust_heap(begin, pos, len, begin[pos], pred, ignore_position_t());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename random_access_iter_t,
|
||||
typename distance_t,
|
||||
typename pred_t>
|
||||
bool _is_heap(random_access_iter_t begin,
|
||||
distance_t len,
|
||||
pred_t pred) {
|
||||
distance_t parent = 0;
|
||||
|
||||
for (distance_t child = 1; child < len; ++child) {
|
||||
if (pred(begin[parent], begin[child])) {
|
||||
return false;
|
||||
}
|
||||
if (++child == len) break;
|
||||
if (pred(begin[parent], begin[child])) {
|
||||
return false;
|
||||
}
|
||||
++parent;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename random_access_iter_t>
|
||||
void adjust_heap(random_access_iter_t begin,
|
||||
random_access_iter_t end,
|
||||
random_access_iter_t pos) {
|
||||
typedef typename std::iterator_traits<random_access_iter_t>::value_type value_t;
|
||||
|
||||
detail::_adjust_heap(begin, pos - begin, end - begin, *pos, std::less<value_t>());
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename random_access_iter_t,
|
||||
typename pred_t>
|
||||
void adjust_heap(random_access_iter_t begin,
|
||||
random_access_iter_t end,
|
||||
random_access_iter_t pos,
|
||||
pred_t pred) {
|
||||
detail::_adjust_heap(begin, pos - begin, end - begin, *pos, pred);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename random_access_iter_t,
|
||||
typename pred_t,
|
||||
typename pos_notifier_t>
|
||||
void adjust_heap(random_access_iter_t begin,
|
||||
random_access_iter_t end,
|
||||
random_access_iter_t pos,
|
||||
pred_t pred,
|
||||
pos_notifier_t notify) {
|
||||
detail::_adjust_heap(begin, pos - begin, end - begin, *pos, pred, notify);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename random_access_iter_t>
|
||||
void remove_heap(random_access_iter_t begin,
|
||||
random_access_iter_t end,
|
||||
random_access_iter_t pos) {
|
||||
typedef typename std::iterator_traits<random_access_iter_t>::value_type value_t;
|
||||
|
||||
detail::_remove_heap(begin, pos - begin, end - begin, std::less<value_t>(), detail::ignore_position_t());
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename random_access_iter_t,
|
||||
typename pred_t>
|
||||
void remove_heap(random_access_iter_t begin,
|
||||
random_access_iter_t end,
|
||||
random_access_iter_t pos,
|
||||
pred_t pred) {
|
||||
detail::_remove_heap(begin, pos - begin, end - begin, pred, detail::ignore_position_t());
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename random_access_iter_t,
|
||||
typename pred_t,
|
||||
typename pos_notifier_t>
|
||||
void remove_heap(random_access_iter_t begin,
|
||||
random_access_iter_t end,
|
||||
random_access_iter_t pos,
|
||||
pred_t pred,
|
||||
pos_notifier_t notify) {
|
||||
detail::_remove_heap(begin, pos - begin, end - begin, pred, notify);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename random_access_iter_t>
|
||||
void pop_heap(random_access_iter_t begin,
|
||||
random_access_iter_t end) {
|
||||
typedef typename std::iterator_traits<random_access_iter_t>::value_type value_t;
|
||||
typedef typename std::iterator_traits<random_access_iter_t>::difference_type distance_t;
|
||||
|
||||
detail::_remove_heap(begin, distance_t(0), end - begin, std::less<value_t>(), detail::ignore_position_t());
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename random_access_iter_t,
|
||||
typename pred_t>
|
||||
void pop_heap(random_access_iter_t begin,
|
||||
random_access_iter_t end,
|
||||
pred_t pred) {
|
||||
typedef typename std::iterator_traits<random_access_iter_t>::difference_type distance_t;
|
||||
|
||||
detail::_remove_heap(begin, distance_t(0), end - begin, pred, detail::ignore_position_t());
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename random_access_iter_t,
|
||||
typename pred_t,
|
||||
typename pos_notifier_t>
|
||||
void pop_heap(random_access_iter_t begin,
|
||||
random_access_iter_t end,
|
||||
pred_t pred,
|
||||
pos_notifier_t notify) {
|
||||
typedef typename std::iterator_traits<random_access_iter_t>::difference_type distance_t;
|
||||
|
||||
detail::_remove_heap(begin, distance_t(0), end - begin, pred, notify);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename random_access_iter_t>
|
||||
void push_heap(random_access_iter_t begin,
|
||||
random_access_iter_t end) {
|
||||
typedef typename std::iterator_traits<random_access_iter_t>::value_type value_t;
|
||||
typedef typename std::iterator_traits<random_access_iter_t>::difference_type distance_t;
|
||||
|
||||
distance_t pos = end - begin - 1;
|
||||
detail::_push_heap(begin, pos, begin[pos], std::less<value_t>(), detail::ignore_position_t());
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename random_access_iter_t,
|
||||
typename pred_t>
|
||||
void push_heap(random_access_iter_t begin,
|
||||
random_access_iter_t end,
|
||||
pred_t pred) {
|
||||
typedef typename std::iterator_traits<random_access_iter_t>::difference_type distance_t;
|
||||
|
||||
distance_t pos = end - begin - 1;
|
||||
detail::_push_heap(begin, pos, begin[pos], pred, detail::ignore_position_t());
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename random_access_iter_t,
|
||||
typename pred_t,
|
||||
typename pos_notifier_t>
|
||||
void push_heap(random_access_iter_t begin,
|
||||
random_access_iter_t end,
|
||||
pred_t pred,
|
||||
pos_notifier_t notify) {
|
||||
typedef typename std::iterator_traits<random_access_iter_t>::difference_type distance_t;
|
||||
|
||||
distance_t pos = end - begin - 1;
|
||||
detail::_push_heap(begin, pos, begin[pos], pred, notify);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename random_access_iter_t>
|
||||
void make_heap(random_access_iter_t begin,
|
||||
random_access_iter_t end) {
|
||||
typedef typename std::iterator_traits<random_access_iter_t>::value_type value_t;
|
||||
|
||||
detail::_make_heap(begin, end - begin, std::less<value_t>(), detail::ignore_position_t());
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename random_access_iter_t,
|
||||
typename pred_t>
|
||||
void make_heap(random_access_iter_t begin,
|
||||
random_access_iter_t end,
|
||||
pred_t pred) {
|
||||
detail::_make_heap(begin, end - begin, pred, detail::ignore_position_t());
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename random_access_iter_t,
|
||||
typename pred_t,
|
||||
typename pos_notifier_t>
|
||||
void make_heap(random_access_iter_t begin,
|
||||
random_access_iter_t end,
|
||||
pred_t pred,
|
||||
pos_notifier_t notify) {
|
||||
detail::_make_heap(begin, end - begin, pred, notify);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename random_access_iter_t>
|
||||
bool is_heap(random_access_iter_t begin,
|
||||
random_access_iter_t end) {
|
||||
typedef typename std::iterator_traits<random_access_iter_t>::value_type value_t;
|
||||
|
||||
return detail::_is_heap(begin, end - begin, std::less<value_t>());
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename random_access_iter_t, typename pred_t>
|
||||
bool is_heap(random_access_iter_t begin,
|
||||
random_access_iter_t end,
|
||||
pred_t pred) {
|
||||
return detail::_is_heap(begin, end - begin, pred);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename random_access_iter_t>
|
||||
void sort_heap(random_access_iter_t begin,
|
||||
random_access_iter_t end) {
|
||||
typedef typename std::iterator_traits<random_access_iter_t>::difference_type distance_t;
|
||||
typedef typename std::iterator_traits<random_access_iter_t>::value_type value_t;
|
||||
|
||||
for (distance_t len = end - begin; len > 1; --len) {
|
||||
detail::_remove_heap(begin, distance_t(0), len, std::less<value_t>(), detail::ignore_position_t());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename random_access_iter_t,
|
||||
typename pred_t>
|
||||
void sort_heap(random_access_iter_t begin,
|
||||
random_access_iter_t end,
|
||||
pred_t pred) {
|
||||
typedef typename std::iterator_traits<random_access_iter_t>::difference_type distance_t;
|
||||
|
||||
for (distance_t len = end - begin; len > 1; --len) {
|
||||
detail::_remove_heap(begin, distance_t(0), len, pred, detail::ignore_position_t());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename random_access_iter_t,
|
||||
typename pred_t,
|
||||
typename pos_notifier_t>
|
||||
void sort_heap(random_access_iter_t begin,
|
||||
random_access_iter_t end,
|
||||
pred_t pred,
|
||||
pos_notifier_t notify) {
|
||||
typedef typename std::iterator_traits<random_access_iter_t>::difference_type distance_t;
|
||||
|
||||
for (distance_t len = end - begin; len > 1; --len) {
|
||||
detail::_remove_heap(begin, distance_t(0), len, pred, detail::ignore_position_t());
|
||||
notify(begin[len], len);
|
||||
}
|
||||
notify(begin[0], 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
251
extern/carve/include/carve/input.hpp
vendored
Normal file
251
extern/carve/include/carve/input.hpp
vendored
Normal file
@ -0,0 +1,251 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
#include <carve/poly.hpp>
|
||||
#include <carve/mesh.hpp>
|
||||
#include <carve/polyline.hpp>
|
||||
#include <carve/pointset.hpp>
|
||||
|
||||
|
||||
|
||||
namespace carve {
|
||||
namespace input {
|
||||
|
||||
struct Data {
|
||||
Data() {
|
||||
}
|
||||
|
||||
virtual ~Data() {
|
||||
}
|
||||
|
||||
virtual void transform(const carve::math::Matrix & /* transform */) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct VertexData : public Data {
|
||||
std::vector<carve::geom3d::Vector> points;
|
||||
|
||||
VertexData() : Data() {
|
||||
}
|
||||
|
||||
virtual ~VertexData() {
|
||||
}
|
||||
|
||||
virtual void transform(const carve::math::Matrix &transform) {
|
||||
for (size_t i = 0; i < points.size(); ++i) {
|
||||
points[i] *= transform;
|
||||
}
|
||||
}
|
||||
|
||||
size_t addVertex(carve::geom3d::Vector point) {
|
||||
size_t index = points.size();
|
||||
points.push_back(point);
|
||||
return index;
|
||||
}
|
||||
|
||||
inline void reserveVertices(int count) {
|
||||
points.reserve(count);
|
||||
}
|
||||
|
||||
size_t getVertexCount() const {
|
||||
return points.size();
|
||||
}
|
||||
|
||||
const carve::geom3d::Vector &getVertex(int index) const {
|
||||
return points[index];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct PolyhedronData : public VertexData {
|
||||
std::vector<int> faceIndices;
|
||||
int faceCount;
|
||||
|
||||
PolyhedronData() : VertexData(), faceIndices(), faceCount(0) {
|
||||
}
|
||||
|
||||
virtual ~PolyhedronData() {
|
||||
}
|
||||
|
||||
void reserveFaces(int count, int avgFaceSize) {
|
||||
faceIndices.reserve(faceIndices.size() + count * (1 + avgFaceSize));
|
||||
}
|
||||
|
||||
int getFaceCount() const {
|
||||
return faceCount;
|
||||
}
|
||||
|
||||
template <typename Iter>
|
||||
void addFace(Iter begin, Iter end) {
|
||||
size_t n = std::distance(begin, end);
|
||||
faceIndices.reserve(faceIndices.size() + n + 1);
|
||||
faceIndices.push_back(n);
|
||||
std::copy(begin, end, std::back_inserter(faceIndices));
|
||||
++faceCount;
|
||||
}
|
||||
|
||||
void addFace(int a, int b, int c) {
|
||||
faceIndices.push_back(3);
|
||||
faceIndices.push_back(a);
|
||||
faceIndices.push_back(b);
|
||||
faceIndices.push_back(c);
|
||||
++faceCount;
|
||||
}
|
||||
|
||||
void addFace(int a, int b, int c, int d) {
|
||||
faceIndices.push_back(4);
|
||||
faceIndices.push_back(a);
|
||||
faceIndices.push_back(b);
|
||||
faceIndices.push_back(c);
|
||||
faceIndices.push_back(d);
|
||||
++faceCount;
|
||||
}
|
||||
|
||||
void clearFaces() {
|
||||
faceIndices.clear();
|
||||
faceCount = 0;
|
||||
}
|
||||
|
||||
carve::poly::Polyhedron *create() const {
|
||||
return new carve::poly::Polyhedron(points, faceCount, faceIndices);
|
||||
}
|
||||
|
||||
carve::mesh::MeshSet<3> *createMesh() const {
|
||||
return new carve::mesh::MeshSet<3>(points, faceCount, faceIndices);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct PolylineSetData : public VertexData {
|
||||
typedef std::pair<bool, std::vector<int> > polyline_data_t;
|
||||
std::list<polyline_data_t> polylines;
|
||||
|
||||
PolylineSetData() : VertexData(), polylines() {
|
||||
}
|
||||
|
||||
virtual ~PolylineSetData() {
|
||||
}
|
||||
|
||||
void beginPolyline(bool closed = false) {
|
||||
polylines.push_back(std::make_pair(closed, std::vector<int>()));
|
||||
}
|
||||
|
||||
void reservePolyline(size_t len) {
|
||||
polylines.back().second.reserve(len);
|
||||
}
|
||||
|
||||
void addPolylineIndex(int idx) {
|
||||
polylines.back().second.push_back(idx);
|
||||
}
|
||||
|
||||
carve::line::PolylineSet *create() const {
|
||||
carve::line::PolylineSet *p = new carve::line::PolylineSet(points);
|
||||
|
||||
for (std::list<polyline_data_t>::const_iterator i = polylines.begin();
|
||||
i != polylines.end();
|
||||
++i) {
|
||||
p->addPolyline((*i).first, (*i).second.begin(), (*i).second.end());
|
||||
}
|
||||
return p;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct PointSetData : public VertexData {
|
||||
|
||||
PointSetData() : VertexData() {
|
||||
}
|
||||
|
||||
virtual ~PointSetData() {
|
||||
}
|
||||
|
||||
carve::point::PointSet *create() const {
|
||||
carve::point::PointSet *p = new carve::point::PointSet(points);
|
||||
return p;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class Input {
|
||||
public:
|
||||
std::list<Data *> input;
|
||||
|
||||
Input() {
|
||||
}
|
||||
|
||||
~Input() {
|
||||
for (std::list<Data *>::iterator i = input.begin(); i != input.end(); ++i) {
|
||||
delete (*i);
|
||||
}
|
||||
}
|
||||
|
||||
void addDataBlock(Data *data) {
|
||||
input.push_back(data);
|
||||
}
|
||||
|
||||
void transform(const carve::math::Matrix &transform) {
|
||||
if (transform == carve::math::Matrix::IDENT()) return;
|
||||
for (std::list<Data *>::iterator i = input.begin(); i != input.end(); ++i) {
|
||||
(*i)->transform(transform);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline T *create(Data *d) {
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
inline carve::mesh::MeshSet<3> *Input::create(Data *d) {
|
||||
PolyhedronData *p = dynamic_cast<PolyhedronData *>(d);
|
||||
if (p == NULL) return NULL;
|
||||
return p->createMesh();
|
||||
}
|
||||
|
||||
template<>
|
||||
inline carve::poly::Polyhedron *Input::create(Data *d) {
|
||||
PolyhedronData *p = dynamic_cast<PolyhedronData *>(d);
|
||||
if (p == NULL) return NULL;
|
||||
return p->create();
|
||||
}
|
||||
|
||||
template<>
|
||||
inline carve::line::PolylineSet *Input::create(Data *d) {
|
||||
PolylineSetData *p = dynamic_cast<PolylineSetData *>(d);
|
||||
if (p == NULL) return NULL;
|
||||
return p->create();
|
||||
}
|
||||
|
||||
template<>
|
||||
inline carve::point::PointSet *Input::create(Data *d) {
|
||||
PointSetData *p = dynamic_cast<PointSetData *>(d);
|
||||
if (p == NULL) return NULL;
|
||||
return p->create();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
332
extern/carve/include/carve/interpolator.hpp
vendored
Normal file
332
extern/carve/include/carve/interpolator.hpp
vendored
Normal file
@ -0,0 +1,332 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
#include <carve/geom2d.hpp>
|
||||
#include <carve/poly.hpp>
|
||||
#include <carve/mesh.hpp>
|
||||
#include <carve/csg.hpp>
|
||||
|
||||
namespace carve {
|
||||
namespace interpolate {
|
||||
|
||||
static inline std::vector<double> polyInterpolate(const std::vector<carve::geom2d::P2> &s,
|
||||
const carve::geom2d::P2 &v) {
|
||||
// see hormann et al. 2006
|
||||
const size_t SZ = s.size();
|
||||
std::vector<double> r;
|
||||
std::vector<double> A;
|
||||
std::vector<double> D;
|
||||
|
||||
std::vector<double> result;
|
||||
|
||||
r.resize(SZ);
|
||||
A.resize(SZ);
|
||||
D.resize(SZ);
|
||||
|
||||
result.resize(SZ, 0.0);
|
||||
|
||||
for (size_t i = 0; i < SZ; ++i) {
|
||||
size_t i2 = (i + 1) % SZ;
|
||||
carve::geom2d::P2 si = s[i] - v;
|
||||
carve::geom2d::P2 si2 = s[i2] - v;
|
||||
|
||||
r[i] = sqrt(dot(si, si));
|
||||
A[i] = cross(si, si2) / 2.0;
|
||||
D[i] = dot(si, si2);
|
||||
if (fabs(r[i]) < 1e-16) {
|
||||
result[i] = 1.0;
|
||||
return result;
|
||||
} else if (fabs(A[i]) < 1e-16 && D[i] < 0.0) {
|
||||
double r2 = sqrt(dot(si2, si2));
|
||||
result[i2] = r[i] / (r[i] + r2);
|
||||
result[i] = r2 / (r[i] + r2);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
double w_sum = 0.0;
|
||||
|
||||
for (size_t i = 0; i < SZ; ++i) {
|
||||
size_t i_m = (i + SZ - 1) % SZ;
|
||||
size_t i_p = (i + 1) % SZ;
|
||||
|
||||
double w = 0.0;
|
||||
if (fabs(A[i_m]) > 1e-16)
|
||||
w += (r[i_m] - D[i_m] / r[i]) / A[i_m];
|
||||
if (fabs(A[i]) > 1e-16)
|
||||
w += (r[i_p] - D[i] / r[i]) / A[i];
|
||||
|
||||
result[i] = w;
|
||||
w_sum += w;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < SZ; ++i) {
|
||||
result[i] /= w_sum;
|
||||
}
|
||||
|
||||
// carve::geom2d::P2 test;
|
||||
// for (size_t i = 0; i < SZ; ++i) {
|
||||
// test = test + result[i] * s[i];
|
||||
// }
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename iter_t,
|
||||
typename adapt_t,
|
||||
typename val_t,
|
||||
typename mod_t>
|
||||
val_t interp(iter_t begin,
|
||||
iter_t end,
|
||||
adapt_t adapt,
|
||||
const std::vector<val_t> &vals,
|
||||
double x,
|
||||
double y,
|
||||
mod_t mod = mod_t()) {
|
||||
std::vector<carve::geom2d::P2> s;
|
||||
s.reserve(std::distance(begin, end));
|
||||
std::transform(begin, end, std::back_inserter(s), adapt);
|
||||
std::vector<double> weight = polyInterpolate(s, carve::geom::VECTOR(x, y));
|
||||
|
||||
val_t v;
|
||||
for (size_t z = 0; z < weight.size(); z++) {
|
||||
v += weight[z] * vals[z];
|
||||
}
|
||||
|
||||
return mod(v);
|
||||
}
|
||||
|
||||
template<typename iter_t,
|
||||
typename adapt_t,
|
||||
typename val_t>
|
||||
val_t interp(iter_t begin,
|
||||
iter_t end,
|
||||
adapt_t adapt,
|
||||
const std::vector<val_t> &vals,
|
||||
double x,
|
||||
double y) {
|
||||
return interp(begin, end, adapt, vals, x, y, identity_t<val_t>());
|
||||
}
|
||||
|
||||
template<typename vertex_t,
|
||||
typename adapt_t,
|
||||
typename val_t,
|
||||
typename mod_t>
|
||||
val_t interp(const std::vector<vertex_t> &poly,
|
||||
adapt_t adapt,
|
||||
const std::vector<val_t> &vals,
|
||||
double x,
|
||||
double y,
|
||||
mod_t mod = mod_t()) {
|
||||
return interp(poly.begin(), poly.end(), adapt, vals, x, y, mod);
|
||||
}
|
||||
|
||||
template<typename vertex_t,
|
||||
typename adapt_t,
|
||||
typename val_t>
|
||||
val_t interp(const std::vector<vertex_t> &poly,
|
||||
adapt_t adapt,
|
||||
const std::vector<val_t> &vals,
|
||||
double x,
|
||||
double y) {
|
||||
return interp(poly.begin(), poly.end(), adapt, vals, x, y, identity_t<val_t>());
|
||||
}
|
||||
|
||||
template<typename val_t,
|
||||
typename mod_t>
|
||||
val_t interp(const std::vector<carve::geom2d::P2> &poly,
|
||||
const std::vector<val_t> &vals,
|
||||
double x,
|
||||
double y,
|
||||
mod_t mod = mod_t()) {
|
||||
std::vector<double> weight = polyInterpolate(poly, carve::geom::VECTOR(x, y));
|
||||
|
||||
val_t v;
|
||||
for (size_t z = 0; z < weight.size(); z++) {
|
||||
v += weight[z] * vals[z];
|
||||
}
|
||||
|
||||
return mod(v);
|
||||
}
|
||||
|
||||
template<typename val_t>
|
||||
val_t interp(const std::vector<carve::geom2d::P2> &poly,
|
||||
const std::vector<val_t> &vals,
|
||||
double x,
|
||||
double y) {
|
||||
return interp(poly, vals, x, y, identity_t<val_t>());
|
||||
}
|
||||
|
||||
class Interpolator {
|
||||
public:
|
||||
virtual void interpolate(const carve::mesh::MeshSet<3>::face_t *new_face,
|
||||
const carve::mesh::MeshSet<3>::face_t *orig_face,
|
||||
bool flipped) =0;
|
||||
|
||||
Interpolator() {
|
||||
}
|
||||
|
||||
virtual ~Interpolator() {
|
||||
}
|
||||
|
||||
class Hook : public carve::csg::CSG::Hook {
|
||||
Interpolator *interpolator;
|
||||
public:
|
||||
virtual void resultFace(const carve::mesh::MeshSet<3>::face_t *new_face,
|
||||
const carve::mesh::MeshSet<3>::face_t *orig_face,
|
||||
bool flipped) {
|
||||
interpolator->interpolate(new_face, orig_face, flipped);
|
||||
}
|
||||
|
||||
Hook(Interpolator *_interpolator) : interpolator(_interpolator) {
|
||||
}
|
||||
|
||||
virtual ~Hook() {
|
||||
}
|
||||
};
|
||||
|
||||
void installHooks(carve::csg::CSG &csg) {
|
||||
csg.hooks.registerHook(new Hook(this), carve::csg::CSG::Hooks::RESULT_FACE_BIT);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename attr_t>
|
||||
class FaceVertexAttr : public Interpolator {
|
||||
|
||||
protected:
|
||||
struct fv_hash {
|
||||
size_t operator()(const std::pair<const carve::mesh::MeshSet<3>::face_t *, unsigned> &v) const {
|
||||
return size_t(v.first) ^ size_t(v.second);
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::unordered_map<const carve::mesh::MeshSet<3>::vertex_t *, attr_t> attrvmap_t;
|
||||
typedef std::unordered_map<std::pair<const carve::mesh::MeshSet<3>::face_t *, unsigned>, attr_t, fv_hash> attrmap_t;
|
||||
|
||||
attrmap_t attrs;
|
||||
|
||||
public:
|
||||
bool hasAttribute(const carve::mesh::MeshSet<3>::face_t *f, unsigned v) {
|
||||
return attrs.find(std::make_pair(f, v)) != attrs.end();
|
||||
}
|
||||
|
||||
attr_t getAttribute(const carve::mesh::MeshSet<3>::face_t *f, unsigned v, const attr_t &def = attr_t()) {
|
||||
typename attrmap_t::const_iterator fv = attrs.find(std::make_pair(f, v));
|
||||
if (fv != attrs.end()) {
|
||||
return (*fv).second;
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
void setAttribute(const carve::mesh::MeshSet<3>::face_t *f, unsigned v, const attr_t &attr) {
|
||||
attrs[std::make_pair(f, v)] = attr;
|
||||
}
|
||||
|
||||
virtual void interpolate(const carve::mesh::MeshSet<3>::face_t *new_face,
|
||||
const carve::mesh::MeshSet<3>::face_t *orig_face,
|
||||
bool flipped) {
|
||||
std::vector<attr_t> vertex_attrs;
|
||||
attrvmap_t base_attrs;
|
||||
vertex_attrs.reserve(orig_face->nVertices());
|
||||
|
||||
for (carve::mesh::MeshSet<3>::face_t::const_edge_iter_t e = orig_face->begin(); e != orig_face->end(); ++e) {
|
||||
typename attrmap_t::const_iterator a = attrs.find(std::make_pair(orig_face, e.idx()));
|
||||
if (a == attrs.end()) return;
|
||||
vertex_attrs.push_back((*a).second);
|
||||
base_attrs[e->vert] = vertex_attrs.back();
|
||||
}
|
||||
|
||||
for (carve::mesh::MeshSet<3>::face_t::const_edge_iter_t e = new_face->begin(); e != new_face->end(); ++e) {
|
||||
const carve::mesh::MeshSet<3>::vertex_t *vertex = e->vert;
|
||||
typename attrvmap_t::const_iterator b = base_attrs.find(vertex);
|
||||
if (b != base_attrs.end()) {
|
||||
attrs[std::make_pair(new_face, e.idx())] = (*b).second;
|
||||
} else {
|
||||
carve::geom2d::P2 p = orig_face->project(e->vert->v);
|
||||
attr_t attr = interp(orig_face->begin(),
|
||||
orig_face->end(),
|
||||
orig_face->projector(),
|
||||
vertex_attrs,
|
||||
p.x,
|
||||
p.y);
|
||||
attrs[std::make_pair(new_face, e.idx())] = attr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FaceVertexAttr() : Interpolator() {
|
||||
}
|
||||
|
||||
virtual ~FaceVertexAttr() {
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
template<typename attr_t>
|
||||
class FaceAttr : public Interpolator {
|
||||
|
||||
protected:
|
||||
struct f_hash {
|
||||
size_t operator()(const carve::mesh::MeshSet<3>::face_t * const &f) const {
|
||||
return size_t(f);
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::unordered_map<const carve::mesh::MeshSet<3>::face_t *, attr_t, f_hash> attrmap_t;
|
||||
|
||||
attrmap_t attrs;
|
||||
|
||||
public:
|
||||
bool hasAttribute(const carve::mesh::MeshSet<3>::face_t *f) {
|
||||
return attrs.find(f) != attrs.end();
|
||||
}
|
||||
|
||||
attr_t getAttribute(const carve::mesh::MeshSet<3>::face_t *f, const attr_t &def = attr_t()) {
|
||||
typename attrmap_t::const_iterator i = attrs.find(f);
|
||||
if (i != attrs.end()) {
|
||||
return (*i).second;
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
void setAttribute(const carve::mesh::MeshSet<3>::face_t *f, const attr_t &attr) {
|
||||
attrs[f] = attr;
|
||||
}
|
||||
|
||||
virtual void interpolate(const carve::mesh::MeshSet<3>::face_t *new_face,
|
||||
const carve::mesh::MeshSet<3>::face_t *orig_face,
|
||||
bool flipped) {
|
||||
typename attrmap_t::const_iterator i = attrs.find(orig_face);
|
||||
if (i != attrs.end()) {
|
||||
attrs[new_face] = (*i).second;
|
||||
}
|
||||
}
|
||||
|
||||
FaceAttr() : Interpolator() {
|
||||
}
|
||||
|
||||
virtual ~FaceAttr() {
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
267
extern/carve/include/carve/intersection.hpp
vendored
Normal file
267
extern/carve/include/carve/intersection.hpp
vendored
Normal file
@ -0,0 +1,267 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
#include <carve/collection_types.hpp>
|
||||
#include <carve/iobj.hpp>
|
||||
|
||||
namespace carve {
|
||||
namespace csg {
|
||||
|
||||
/**
|
||||
* \class Intersections
|
||||
* \brief Storage for computed intersections between vertices, edges and faces.
|
||||
*
|
||||
*/
|
||||
struct Intersections : public std::unordered_map<IObj, IObjVMapSmall, IObj_hash> {
|
||||
typedef carve::mesh::MeshSet<3>::vertex_t vertex_t;
|
||||
typedef carve::mesh::MeshSet<3>::edge_t edge_t;
|
||||
typedef carve::mesh::MeshSet<3>::face_t face_t;
|
||||
|
||||
typedef std::unordered_map<IObj, IObjVMapSmall, IObj_hash> super;
|
||||
|
||||
~Intersections() {
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Record the position of intersection between a pair of intersection objects.
|
||||
*
|
||||
* @param a The first intersecting object.
|
||||
* @param b The second intersecting object.
|
||||
* @param p The point of intersection.
|
||||
*/
|
||||
void record(IObj a, IObj b, vertex_t *p) {
|
||||
if (a > b) std::swap(a, b);
|
||||
(*this)[a][b] = p;
|
||||
(*this)[b][a] = p;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Test whether vertex \a v intersects face \a f.
|
||||
*
|
||||
* @param v The vertex to test.
|
||||
* @param f The face to test.
|
||||
*
|
||||
* @return true, if \a v intersects \a f.
|
||||
*/
|
||||
bool intersectsFace(vertex_t *v, face_t *f) const;
|
||||
|
||||
/**
|
||||
* \brief Collect sets of vertices, edges and faces that intersect \a obj
|
||||
*
|
||||
* @param[in] obj The intersection object to search for intersections.
|
||||
* @param[out] collect_v A vector of vertices intersecting \a obj.
|
||||
* @param[out] collect_e A vector of edges intersecting \a obj.
|
||||
* @param[out] collect_f A vector of faces intersecting \a obj.
|
||||
*/
|
||||
void collect(const IObj &obj,
|
||||
std::vector<vertex_t *> *collect_v,
|
||||
std::vector<edge_t *> *collect_e,
|
||||
std::vector<face_t *> *collect_f) const;
|
||||
|
||||
|
||||
/**
|
||||
* \brief Determine whether two intersection objects intersect.
|
||||
*
|
||||
* @param a The first intersection object.
|
||||
* @param b The second intersection object.
|
||||
*
|
||||
* @return true, if \a a and \a b intersect.
|
||||
*/
|
||||
bool intersectsExactly(const IObj &a, const IObj &b) {
|
||||
Intersections::const_iterator i = find(a);
|
||||
if (i == end()) return false;
|
||||
return i->second.find(b) != i->second.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Determine whether an intersection object intersects a vertex.
|
||||
*
|
||||
* @param a The intersection object.
|
||||
* @param v The vertex.
|
||||
*
|
||||
* @return true, if \a a and \a v intersect.
|
||||
*/
|
||||
bool intersects(const IObj &a, vertex_t *v) {
|
||||
Intersections::const_iterator i = find(a);
|
||||
if (i == end()) return false;
|
||||
if (i->second.find(v) != i->second.end()) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Determine whether an intersection object intersects an edge.
|
||||
*
|
||||
* @param a The intersection object.
|
||||
* @param e The edge.
|
||||
*
|
||||
* @return true, if \a a and \a e intersect (either on the edge,
|
||||
* or at either endpoint).
|
||||
*/
|
||||
bool intersects(const IObj &a, edge_t *e) {
|
||||
Intersections::const_iterator i = find(a);
|
||||
if (i == end()) return false;
|
||||
for (super::data_type::const_iterator j = i->second.begin(); j != i->second.end(); ++j) {
|
||||
const IObj &obj = j->first;
|
||||
switch (obj.obtype) {
|
||||
case IObj::OBTYPE_VERTEX:
|
||||
if (obj.vertex == e->v1() || obj.vertex == e->v2()) return true;
|
||||
break;
|
||||
case IObj::OBTYPE_EDGE:
|
||||
if (obj.edge == e) return true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Determine whether an intersection object intersects a face.
|
||||
*
|
||||
* @param a The intersection object.
|
||||
* @param f The face.
|
||||
*
|
||||
* @return true, if \a a and \a f intersect (either on the face,
|
||||
* or at any associated edge or vertex).
|
||||
*/
|
||||
bool intersects(const IObj &a, face_t *f) {
|
||||
Intersections::const_iterator i = find(a);
|
||||
if (i == end()) return false;
|
||||
if (i->second.find(f) != i->second.end()) return true;
|
||||
edge_t *e = f->edge;
|
||||
do {
|
||||
if (i->second.find(e) != i->second.end()) return true;
|
||||
if (i->second.find(e->vert) != i->second.end()) return true;
|
||||
e = e->next;
|
||||
} while (e != f->edge);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Determine whether an edge intersects another edge.
|
||||
*
|
||||
* @param e The edge.
|
||||
* @param f The face.
|
||||
*
|
||||
* @return true, if \a e and \a f intersect.
|
||||
*/
|
||||
bool intersects(edge_t *e1, edge_t *e2) {
|
||||
if (intersects(e1->v1(), e2) || intersects(e1->v2(), e2) || intersects(IObj(e1), e2)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Determine whether an edge intersects a face.
|
||||
*
|
||||
* @param e The edge.
|
||||
* @param f The face.
|
||||
*
|
||||
* @return true, if \a e and \a f intersect.
|
||||
*/
|
||||
bool intersects(edge_t *e, face_t *f) {
|
||||
if (intersects(e->v1(), f) || intersects(e->v2(), f) || intersects(IObj(e), f)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Determine the faces intersected by an edge.
|
||||
*
|
||||
* @tparam face_set_t A collection type holding face_t *
|
||||
* @param[in] e The edge.
|
||||
* @param[out] f The resulting set of faces.
|
||||
*/
|
||||
template<typename face_set_t>
|
||||
void intersectedFaces(edge_t *e, face_set_t &f) const {
|
||||
std::vector<face_t *> intersected_faces;
|
||||
std::vector<edge_t *> intersected_edges;
|
||||
std::vector<vertex_t *> intersected_vertices;
|
||||
|
||||
collect(e, &intersected_vertices, &intersected_edges, &intersected_faces);
|
||||
|
||||
for (unsigned i = 0; i < intersected_vertices.size(); ++i) {
|
||||
facesForVertex(intersected_vertices[i], f);
|
||||
}
|
||||
for (unsigned i = 0; i < intersected_edges.size(); ++i) {
|
||||
facesForEdge(intersected_edges[i], f);
|
||||
}
|
||||
f.insert(intersected_faces.begin(), intersected_faces.end());
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Determine the faces intersected by a vertex.
|
||||
*
|
||||
* @tparam face_set_t A collection type holding face_t *
|
||||
* @param[in] v The vertex.
|
||||
* @param[out] f The resulting set of faces.
|
||||
*/
|
||||
template<typename face_set_t>
|
||||
void intersectedFaces(vertex_t *v, face_set_t &f) const {
|
||||
std::vector<face_t *> intersected_faces;
|
||||
std::vector<edge_t *> intersected_edges;
|
||||
std::vector<vertex_t *> intersected_vertices;
|
||||
|
||||
collect(v, &intersected_vertices, &intersected_edges, &intersected_faces);
|
||||
|
||||
for (unsigned i = 0; i < intersected_vertices.size(); ++i) {
|
||||
facesForVertex(intersected_vertices[i], f);
|
||||
}
|
||||
for (unsigned i = 0; i < intersected_edges.size(); ++i) {
|
||||
facesForEdge(intersected_edges[i], f);
|
||||
}
|
||||
f.insert(intersected_faces.begin(), intersected_faces.end());
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Collect the set of faces that contain all vertices in \a verts.
|
||||
*
|
||||
* @tparam vertex_set_t A collection type holding vertex_t *
|
||||
* @tparam face_set_t A collection type holding face_t *
|
||||
* @param[in] verts A set of vertices.
|
||||
* @param[out] result The resulting set of faces.
|
||||
*/
|
||||
template<typename vertex_set_t, typename face_set_t>
|
||||
void commonFaces(const vertex_set_t &verts, face_set_t &result) {
|
||||
|
||||
std::set<face_t *> ifaces, temp, out;
|
||||
typename vertex_set_t::const_iterator i = verts.begin();
|
||||
if (i == verts.end()) return;
|
||||
intersectedFaces((*i), ifaces);
|
||||
while (++i != verts.end()) {
|
||||
temp.clear();
|
||||
intersectedFaces((*i), temp);
|
||||
|
||||
out.clear();
|
||||
std::set_intersection(temp.begin(), temp.end(),
|
||||
ifaces.begin(), ifaces.end(),
|
||||
set_inserter(out));
|
||||
ifaces.swap(out);
|
||||
}
|
||||
std::copy(ifaces.begin(), ifaces.end(), set_inserter(result));
|
||||
}
|
||||
|
||||
void clear() {
|
||||
super::clear();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
106
extern/carve/include/carve/iobj.hpp
vendored
Normal file
106
extern/carve/include/carve/iobj.hpp
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
|
||||
namespace carve {
|
||||
namespace csg {
|
||||
struct IObj {
|
||||
enum {
|
||||
OBTYPE_NONE = 0,
|
||||
OBTYPE_VERTEX = 1,
|
||||
OBTYPE_EDGE = 2,
|
||||
OBTYPE_FACE = 4
|
||||
} obtype;
|
||||
|
||||
union {
|
||||
carve::mesh::MeshSet<3>::vertex_t *vertex;
|
||||
carve::mesh::MeshSet<3>::edge_t *edge;
|
||||
carve::mesh::MeshSet<3>::face_t *face;
|
||||
intptr_t val;
|
||||
};
|
||||
|
||||
IObj() : obtype(OBTYPE_NONE), val(0) { }
|
||||
IObj(carve::mesh::MeshSet<3>::vertex_t *v) : obtype(OBTYPE_VERTEX), vertex(v) { }
|
||||
IObj(carve::mesh::MeshSet<3>::edge_t *e) : obtype(OBTYPE_EDGE), edge(e) { }
|
||||
IObj(carve::mesh::MeshSet<3>::face_t *f) : obtype(OBTYPE_FACE), face(f) { }
|
||||
char typeChar() const { return "NVExF"[obtype]; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct IObj_hash {
|
||||
inline size_t operator()(const IObj &i) const {
|
||||
return (size_t)i.val;
|
||||
}
|
||||
inline size_t operator()(const std::pair<const IObj, const IObj> &i) const {
|
||||
return (size_t)i.first.val ^ (size_t)i.second.val;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
typedef std::unordered_set<std::pair<const IObj, const IObj>, IObj_hash> IObjPairSet;
|
||||
|
||||
typedef std::unordered_map<IObj, carve::mesh::MeshSet<3>::vertex_t *, IObj_hash> IObjVMap;
|
||||
typedef std::map<IObj, carve::mesh::MeshSet<3>::vertex_t *> IObjVMapSmall;
|
||||
|
||||
class VertexIntersections :
|
||||
public std::unordered_map<carve::mesh::MeshSet<3>::vertex_t *, IObjPairSet> {
|
||||
};
|
||||
|
||||
|
||||
|
||||
static inline bool operator==(const carve::csg::IObj &a, const carve::csg::IObj &b) {
|
||||
return a.obtype == b.obtype && a.val == b.val;
|
||||
}
|
||||
|
||||
static inline bool operator!=(const carve::csg::IObj &a, const carve::csg::IObj &b) {
|
||||
return a.obtype != b.obtype || a.val != b.val;
|
||||
}
|
||||
|
||||
static inline bool operator<(const carve::csg::IObj &a, const carve::csg::IObj &b) {
|
||||
return a.obtype < b.obtype || (a.obtype == b.obtype && a.val < b.val);
|
||||
}
|
||||
|
||||
static inline bool operator<=(const carve::csg::IObj &a, const carve::csg::IObj &b) {
|
||||
return a.obtype < b.obtype || (a.obtype == b.obtype && a.val <= b.val);
|
||||
}
|
||||
|
||||
static inline bool operator>(const carve::csg::IObj &a, const carve::csg::IObj &b) {
|
||||
return a.obtype > b.obtype || (a.obtype == b.obtype && a.val > b.val);
|
||||
}
|
||||
|
||||
static inline bool operator>=(const carve::csg::IObj &a, const carve::csg::IObj &b) {
|
||||
return a.obtype > b.obtype || (a.obtype == b.obtype && a.val >= b.val);
|
||||
}
|
||||
|
||||
static inline std::ostream &operator<<(std::ostream &o, const carve::csg::IObj &a) {
|
||||
switch (a.obtype) {
|
||||
case carve::csg::IObj::OBTYPE_NONE: o << "NONE{}"; break;
|
||||
case carve::csg::IObj::OBTYPE_VERTEX: o << "VERT{" << a.vertex << "}"; break;
|
||||
case carve::csg::IObj::OBTYPE_EDGE: o << "EDGE{" << a.edge << "}"; break;
|
||||
case carve::csg::IObj::OBTYPE_FACE: o << "FACE{" << a.face << "}"; break;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
308
extern/carve/include/carve/kd_node.hpp
vendored
Normal file
308
extern/carve/include/carve/kd_node.hpp
vendored
Normal file
@ -0,0 +1,308 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
#include <carve/geom.hpp>
|
||||
#include <carve/aabb.hpp>
|
||||
|
||||
#include <queue>
|
||||
#include <list>
|
||||
#include <limits>
|
||||
|
||||
namespace carve {
|
||||
namespace geom {
|
||||
template<unsigned ndim,
|
||||
typename data_t,
|
||||
typename inserter_t,
|
||||
typename aabb_calc_t>
|
||||
class kd_node {
|
||||
kd_node(const kd_node &);
|
||||
kd_node &operator=(const kd_node &);
|
||||
|
||||
public:
|
||||
kd_node *c_neg;
|
||||
kd_node *c_pos;
|
||||
kd_node *parent;
|
||||
axis_pos splitpos;
|
||||
|
||||
typedef vector<ndim> vector_t;
|
||||
typedef std::list<data_t> container_t;
|
||||
|
||||
container_t data;
|
||||
|
||||
kd_node(kd_node *_parent = NULL) : c_neg(NULL), c_pos(NULL), parent(_parent), splitpos(0, 0.0) {
|
||||
}
|
||||
|
||||
~kd_node() {
|
||||
if (c_neg) delete c_neg;
|
||||
if (c_pos) delete c_pos;
|
||||
}
|
||||
|
||||
template<typename visitor_t>
|
||||
void closeNodes(const vector_t &p, double d, visitor_t &visit) const {
|
||||
if (c_neg) {
|
||||
double delta = splitpos.pos - p[splitpos.axis];
|
||||
if (delta <= d) c_neg->closeNodes(p, d, visit);
|
||||
if (delta >= -d) c_pos->closeNodes(p, d, visit);
|
||||
} else {
|
||||
visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
void removeData(const data_t &d) {
|
||||
typename container_t::iterator i = std::find(data.begin(), data.end(), d);
|
||||
|
||||
if (i != data.end()) {
|
||||
data.erase(i);
|
||||
}
|
||||
}
|
||||
|
||||
void addData(const data_t &d) {
|
||||
data.push_back(d);
|
||||
}
|
||||
|
||||
void insert(const data_t &data, inserter_t &inserter) {
|
||||
inserter.insert(this, data);
|
||||
}
|
||||
|
||||
void insert(const data_t &data) {
|
||||
inserter_t inserter;
|
||||
insert(data, inserter);
|
||||
}
|
||||
|
||||
void remove(const data_t &data, inserter_t &inserter) {
|
||||
inserter.remove(this, data);
|
||||
}
|
||||
|
||||
void remove(const data_t &data) {
|
||||
inserter_t inserter;
|
||||
remove(data, inserter);
|
||||
}
|
||||
|
||||
carve::geom::aabb<ndim> nodeAABB() const {
|
||||
carve::geom::aabb<ndim> aabb;
|
||||
if (c_neg) {
|
||||
aabb = c_neg->nodeAABB();
|
||||
aabb.unionAABB(c_pos->nodeAABB());
|
||||
} else {
|
||||
if (data.size()) {
|
||||
typename container_t::const_iterator i = data.begin();
|
||||
aabb = aabb_calc_t()(*i);
|
||||
while (i != data.end()) {
|
||||
aabb.unionAABB(aabb_calc_t()(*i));
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return aabb;
|
||||
}
|
||||
|
||||
bool split(axis_pos split_at, inserter_t &inserter) {
|
||||
if (c_neg) {
|
||||
// already split
|
||||
return false;
|
||||
}
|
||||
|
||||
c_neg = new kd_node(this);
|
||||
c_pos = new kd_node(this);
|
||||
|
||||
// choose an axis and split point.
|
||||
splitpos = split_at;
|
||||
|
||||
carve::geom::aabb<ndim> aabb;
|
||||
|
||||
if (splitpos.axis < 0 ||
|
||||
splitpos.axis >= ndim ||
|
||||
splitpos.pos == std::numeric_limits<double>::max()) {
|
||||
// need an aabb
|
||||
if (data.size()) {
|
||||
typename container_t::const_iterator i = data.begin();
|
||||
aabb = aabb_calc_t()(*i);
|
||||
while (i != data.end()) {
|
||||
aabb.unionAABB(aabb_calc_t()(*i));
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (splitpos.axis < 0 || splitpos.axis >= ndim) {
|
||||
|
||||
// choose an axis;
|
||||
|
||||
// if no axis was specified, force calculation of the split position.
|
||||
splitpos.pos = std::numeric_limits<double>::max();
|
||||
|
||||
// choose the axis of the AABB with the biggest extent.
|
||||
splitpos.axis = largestAxis(aabb.extent);
|
||||
|
||||
if (parent && splitpos.axis == parent->splitpos.axis) {
|
||||
// but don't choose the same axis as the parent node;
|
||||
// choose the axis with the second greatest AABB extent.
|
||||
double e = -1.0;
|
||||
int a = -1;
|
||||
for (unsigned i = 0; i < ndim; ++i) {
|
||||
if (i == splitpos.axis) continue;
|
||||
if (e < aabb.extent[i]) { a = i; e = aabb.extent[i]; }
|
||||
}
|
||||
if (a != -1) {
|
||||
splitpos.axis = a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (splitpos.pos == std::numeric_limits<double>::max()) {
|
||||
carve::geom::vector<ndim> min = aabb.min();
|
||||
carve::geom::vector<ndim> max = aabb.max();
|
||||
splitpos.pos = aabb.pos.v[splitpos.axis];
|
||||
}
|
||||
|
||||
inserter.propagate(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool split(axis_pos split_at = axis_pos(-1, std::numeric_limits<double>::max())) {
|
||||
inserter_t inserter;
|
||||
return split(split_at, inserter);
|
||||
}
|
||||
|
||||
void splitn(int num, inserter_t &inserter) {
|
||||
if (num <= 0) return;
|
||||
if (!c_neg) {
|
||||
split(inserter);
|
||||
}
|
||||
if (c_pos) c_pos->splitn(num-1, inserter);
|
||||
if (c_neg) c_neg->splitn(num-1, inserter);
|
||||
}
|
||||
|
||||
void splitn(int num) {
|
||||
inserter_t inserter;
|
||||
splitn(num, inserter);
|
||||
}
|
||||
|
||||
template<typename split_t>
|
||||
void splitn(int num, split_t splitter, inserter_t &inserter) {
|
||||
if (num <= 0) return;
|
||||
if (!c_neg) {
|
||||
split(inserter, splitter(this));
|
||||
}
|
||||
if (c_pos) c_pos->splitn(num-1, inserter, splitter);
|
||||
if (c_neg) c_neg->splitn(num-1, inserter, splitter);
|
||||
}
|
||||
|
||||
template<typename split_t>
|
||||
void splitn(int num, split_t splitter) {
|
||||
inserter_t inserter;
|
||||
splitn(num, splitter, inserter);
|
||||
}
|
||||
|
||||
template<typename pred_t>
|
||||
void splitpred(pred_t pred, inserter_t &inserter, int depth = 0) {
|
||||
if (!c_neg) {
|
||||
axis_pos splitpos(-1, std::numeric_limits<double>::max());
|
||||
if (!pred(this, depth, splitpos)) return;
|
||||
split(splitpos, inserter);
|
||||
}
|
||||
if (c_pos) c_pos->splitpred(pred, inserter, depth + 1);
|
||||
if (c_neg) c_neg->splitpred(pred, inserter, depth + 1);
|
||||
}
|
||||
|
||||
template<typename pred_t>
|
||||
void splitpred(pred_t pred, int depth = 0) {
|
||||
inserter_t inserter;
|
||||
splitpred(pred, inserter, depth);
|
||||
}
|
||||
|
||||
// distance_t must provide:
|
||||
// double operator()(kd_node::data_t, vector<ndim>);
|
||||
// double operator()(axis_pos, vector<ndim>);
|
||||
template<typename distance_t>
|
||||
struct near_point_query {
|
||||
|
||||
// q_t - the priority queue value type.
|
||||
// q_t.first: distance from object to query point.
|
||||
// q_t.second: pointer to object
|
||||
typedef std::pair<double, const typename kd_node::data_t *> q_t;
|
||||
|
||||
// the queue priority should sort from smallest distance to largest, and on equal distance, by object pointer.
|
||||
struct pcmp {
|
||||
bool operator()(const q_t &a, const q_t &b) {
|
||||
return (a.first > b.first) || ((a.first == b.first) && (a.second < b.second));
|
||||
}
|
||||
};
|
||||
|
||||
vector<ndim> point;
|
||||
const kd_node *node;
|
||||
std::priority_queue<q_t, std::vector<q_t>, pcmp> pq;
|
||||
|
||||
distance_t dist;
|
||||
double dist_to_parent_split;
|
||||
|
||||
void addToPQ(kd_node *node) {
|
||||
if (node->c_neg) {
|
||||
addToPQ(node->c_neg);
|
||||
addToPQ(node->c_pos);
|
||||
} else {
|
||||
for (typename kd_node::container_t::const_iterator i = node->data.begin(); i != node->data.end(); ++i) {
|
||||
double d = dist((*i), point);
|
||||
pq.push(std::make_pair(d, &(*i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const typename kd_node::data_t *next() {
|
||||
while (1) {
|
||||
if (pq.size()) {
|
||||
q_t t = pq.top();
|
||||
if (!node->parent || t.first < dist_to_parent_split) {
|
||||
pq.pop();
|
||||
return t.second;
|
||||
}
|
||||
}
|
||||
|
||||
if (!node->parent) return NULL;
|
||||
|
||||
if (node->parent->c_neg == node) {
|
||||
addToPQ(node->parent->c_pos);
|
||||
} else {
|
||||
addToPQ(node->parent->c_neg);
|
||||
}
|
||||
|
||||
node = node->parent;
|
||||
dist_to_parent_split = dist(node->splitpos, point);
|
||||
}
|
||||
}
|
||||
|
||||
near_point_query(const vector<ndim> _point, const kd_node *_node) : point(_point), node(_node), pq(), dist() {
|
||||
while (node->c_neg) {
|
||||
node = (point[node->axis] < node->pos) ? node->c_neg : node->c_pos;
|
||||
}
|
||||
if (node->parent) {
|
||||
dist_to_parent_split = dist(node->parent->splitpos, point);
|
||||
} else {
|
||||
dist_to_parent_split = HUGE_VAL;
|
||||
}
|
||||
addToPQ(node);
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
60
extern/carve/include/carve/math.hpp
vendored
Normal file
60
extern/carve/include/carve/math.hpp
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
|
||||
#include <carve/math_constants.hpp>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
namespace carve {
|
||||
namespace geom {
|
||||
template<unsigned ndim> struct vector;
|
||||
}
|
||||
}
|
||||
|
||||
namespace carve {
|
||||
namespace math {
|
||||
struct Matrix3;
|
||||
int cubic_roots(double c3, double c2, double c1, double c0, double *roots);
|
||||
|
||||
void eigSolveSymmetric(const Matrix3 &m,
|
||||
double &l1, carve::geom::vector<3> &e1,
|
||||
double &l2, carve::geom::vector<3> &e2,
|
||||
double &l3, carve::geom::vector<3> &e3);
|
||||
|
||||
void eigSolve(const Matrix3 &m, double &l1, double &l2, double &l3);
|
||||
|
||||
static inline bool ZERO(double x) { return fabs(x) < carve::EPSILON; }
|
||||
|
||||
static inline double radians(double deg) { return deg * M_PI / 180.0; }
|
||||
static inline double degrees(double rad) { return rad * 180.0 / M_PI; }
|
||||
|
||||
static inline double ANG(double x) {
|
||||
return (x < 0) ? x + M_TWOPI : x;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline const T &clamp(const T &val, const T &min, const T &max) {
|
||||
if (val < min) return min;
|
||||
if (val > max) return max;
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
33
extern/carve/include/carve/math_constants.hpp
vendored
Normal file
33
extern/carve/include/carve/math_constants.hpp
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#ifndef M_SQRT_3
|
||||
#define M_SQRT_3 1.73205080756887729352
|
||||
#endif
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
#ifndef M_TWOPI
|
||||
#define M_TWOPI (M_PI + M_PI)
|
||||
#endif
|
||||
|
262
extern/carve/include/carve/matrix.hpp
vendored
Normal file
262
extern/carve/include/carve/matrix.hpp
vendored
Normal file
@ -0,0 +1,262 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
|
||||
#include <carve/math.hpp>
|
||||
#include <carve/geom.hpp>
|
||||
|
||||
namespace carve {
|
||||
namespace math {
|
||||
|
||||
struct Quaternion {
|
||||
double x, y, z, w;
|
||||
|
||||
Quaternion(double _x, double _y, double _z, double _w) : x(_x), y(_y), z(_z), w(_w) {
|
||||
}
|
||||
|
||||
Quaternion(double angle, const carve::geom::vector<3> &axis) {
|
||||
double s = axis.length();
|
||||
if (!carve::math::ZERO(s)) {
|
||||
double c = 1.0 / s;
|
||||
double omega = -0.5 * angle;
|
||||
s = sin(omega);
|
||||
x = axis.x * c * s;
|
||||
y = axis.y * c * s;
|
||||
z = axis.z * c * s;
|
||||
w = cos(omega);
|
||||
normalize();
|
||||
} else {
|
||||
x = y = z = 0.0;
|
||||
w = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
double lengthSquared() const {
|
||||
return x * x + y * y + z * z + w * w;
|
||||
}
|
||||
|
||||
double length() const {
|
||||
return sqrt(lengthSquared());
|
||||
}
|
||||
|
||||
Quaternion normalized() const {
|
||||
return Quaternion(*this).normalize();
|
||||
}
|
||||
|
||||
Quaternion &normalize() {
|
||||
double l = length();
|
||||
if (l == 0.0) {
|
||||
x = 1.0; y = 0.0; z = 0.0; w = 0.0;
|
||||
} else {
|
||||
x /= l; y /= l; z /= l; w /= l;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
struct Matrix3 {
|
||||
// access: .m[col][row], .v[col * 4 + row], ._cr
|
||||
union {
|
||||
double m[3][3];
|
||||
double v[9];
|
||||
struct {
|
||||
// transposed
|
||||
double _11, _12, _13;
|
||||
double _21, _22, _23;
|
||||
double _31, _32, _33;
|
||||
};
|
||||
};
|
||||
Matrix3(double __11, double __21, double __31,
|
||||
double __12, double __22, double __32,
|
||||
double __13, double __23, double __33) {
|
||||
// nb, args are row major, storage is column major.
|
||||
_11 = __11; _12 = __12; _13 = __13;
|
||||
_21 = __21; _22 = __22; _23 = __23;
|
||||
_31 = __31; _32 = __32; _33 = __33;
|
||||
}
|
||||
Matrix3(double _m[3][3]) {
|
||||
std::memcpy(m, _m, sizeof(m));
|
||||
}
|
||||
Matrix3(double _v[9]) {
|
||||
std::memcpy(v, _v, sizeof(v));
|
||||
}
|
||||
Matrix3() {
|
||||
_11 = 1.00; _12 = 0.00; _13 = 0.00;
|
||||
_21 = 0.00; _22 = 1.00; _23 = 0.00;
|
||||
_31 = 0.00; _32 = 0.00; _33 = 1.00;
|
||||
}
|
||||
};
|
||||
|
||||
struct Matrix {
|
||||
// access: .m[col][row], .v[col * 4 + row], ._cr
|
||||
union {
|
||||
double m[4][4];
|
||||
double v[16];
|
||||
struct {
|
||||
// transposed
|
||||
double _11, _12, _13, _14;
|
||||
double _21, _22, _23, _24;
|
||||
double _31, _32, _33, _34;
|
||||
double _41, _42 ,_43, _44;
|
||||
};
|
||||
};
|
||||
Matrix(double __11, double __21, double __31, double __41,
|
||||
double __12, double __22, double __32, double __42,
|
||||
double __13, double __23, double __33, double __43,
|
||||
double __14, double __24, double __34, double __44) {
|
||||
// nb, args are row major, storage is column major.
|
||||
_11 = __11; _12 = __12; _13 = __13; _14 = __14;
|
||||
_21 = __21; _22 = __22; _23 = __23; _24 = __24;
|
||||
_31 = __31; _32 = __32; _33 = __33; _34 = __34;
|
||||
_41 = __41; _42 = __42; _43 = __43; _44 = __44;
|
||||
}
|
||||
Matrix(double _m[4][4]) {
|
||||
std::memcpy(m, _m, sizeof(m));
|
||||
}
|
||||
Matrix(double _v[16]) {
|
||||
std::memcpy(v, _v, sizeof(v));
|
||||
}
|
||||
Matrix() {
|
||||
_11 = 1.00; _12 = 0.00; _13 = 0.00; _14 = 0.00;
|
||||
_21 = 0.00; _22 = 1.00; _23 = 0.00; _24 = 0.00;
|
||||
_31 = 0.00; _32 = 0.00; _33 = 1.00; _34 = 0.00;
|
||||
_41 = 0.00; _42 = 0.00; _43 = 0.00; _44 = 1.00;
|
||||
}
|
||||
|
||||
static Matrix ROT(const Quaternion &q) {
|
||||
const double w = q.w;
|
||||
const double x = q.x;
|
||||
const double y = q.y;
|
||||
const double z = q.z;
|
||||
return Matrix(1 - 2*y*y - 2*z*z, 2*x*y - 2*z*w, 2*x*z + 2*y*w, 0.0,
|
||||
2*x*y + 2*z*w, 1 - 2*x*x - 2*z*z, 2*y*z - 2*x*w, 0.0,
|
||||
2*x*z - 2*y*w, 2*y*z + 2*x*w, 1 - 2*x*x - 2*y*y, 0.0,
|
||||
0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
static Matrix ROT(double angle, const carve::geom::vector<3> &axis) {
|
||||
return ROT(Quaternion(angle, axis));
|
||||
}
|
||||
static Matrix ROT(double angle, double x, double y, double z) {
|
||||
return ROT(Quaternion(angle, carve::geom::VECTOR(x, y, z)));
|
||||
}
|
||||
static Matrix TRANS(double x, double y, double z) {
|
||||
return Matrix(1.0, 0.0, 0.0, x,
|
||||
0.0, 1.0, 0.0, y,
|
||||
0.0, 0.0, 1.0, z,
|
||||
0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
static Matrix TRANS(const carve::geom::vector<3> &v) {
|
||||
return TRANS(v.x, v.y, v.z);
|
||||
}
|
||||
static Matrix SCALE(double x, double y, double z) {
|
||||
return Matrix(x, 0.0, 0.0, 0.0,
|
||||
0.0, y, 0.0, 0.0,
|
||||
0.0, 0.0, z, 0.0,
|
||||
0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
static Matrix SCALE(const carve::geom::vector<3> &v) {
|
||||
return SCALE(v.x, v.y, v.z);
|
||||
}
|
||||
static Matrix IDENT() {
|
||||
return Matrix(1.0, 0.0, 0.0, 0.0,
|
||||
0.0, 1.0, 0.0, 0.0,
|
||||
0.0, 0.0, 1.0, 0.0,
|
||||
0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
};
|
||||
|
||||
static inline bool operator==(const Matrix &A, const Matrix &B) {
|
||||
for (size_t i = 0; i < 16; ++i) if (A.v[i] != B.v[i]) return false;
|
||||
return true;
|
||||
}
|
||||
static inline bool operator!=(const Matrix &A, const Matrix &B) {
|
||||
return !(A == B);
|
||||
}
|
||||
static inline carve::geom::vector<3> operator*(const Matrix &A, const carve::geom::vector<3> &b) {
|
||||
return carve::geom::VECTOR(
|
||||
A._11 * b.x + A._21 * b.y + A._31 * b.z + A._41,
|
||||
A._12 * b.x + A._22 * b.y + A._32 * b.z + A._42,
|
||||
A._13 * b.x + A._23 * b.y + A._33 * b.z + A._43
|
||||
);
|
||||
}
|
||||
|
||||
static inline carve::geom::vector<3> &operator*=(carve::geom::vector<3> &b, const Matrix &A) {
|
||||
b = A * b;
|
||||
return b;
|
||||
}
|
||||
|
||||
static inline carve::geom::vector<3> operator*(const Matrix3 &A, const carve::geom::vector<3> &b) {
|
||||
return carve::geom::VECTOR(
|
||||
A._11 * b.x + A._21 * b.y + A._31 * b.z,
|
||||
A._12 * b.x + A._22 * b.y + A._32 * b.z,
|
||||
A._13 * b.x + A._23 * b.y + A._33 * b.z
|
||||
);
|
||||
}
|
||||
|
||||
static inline carve::geom::vector<3> &operator*=(carve::geom::vector<3> &b, const Matrix3 &A) {
|
||||
b = A * b;
|
||||
return b;
|
||||
}
|
||||
|
||||
static inline Matrix operator*(const Matrix &A, const Matrix &B) {
|
||||
Matrix c;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
c.m[i][j] = 0.0;
|
||||
for (int k = 0; k < 4; k++) {
|
||||
c.m[i][j] += A.m[k][j] * B.m[i][k];
|
||||
}
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
static inline Matrix3 operator*(const Matrix3 &A, const Matrix3 &B) {
|
||||
Matrix3 c;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
c.m[i][j] = 0.0;
|
||||
for (int k = 0; k < 3; k++) {
|
||||
c.m[i][j] += A.m[k][j] * B.m[i][k];
|
||||
}
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct matrix_transformation {
|
||||
Matrix matrix;
|
||||
|
||||
matrix_transformation(const Matrix &_matrix) : matrix(_matrix) {
|
||||
}
|
||||
|
||||
carve::geom::vector<3> operator()(const carve::geom::vector<3> &vector) const {
|
||||
return matrix * vector;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
845
extern/carve/include/carve/mesh.hpp
vendored
Normal file
845
extern/carve/include/carve/mesh.hpp
vendored
Normal file
@ -0,0 +1,845 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
|
||||
#include <carve/geom.hpp>
|
||||
#include <carve/geom3d.hpp>
|
||||
#include <carve/tag.hpp>
|
||||
#include <carve/djset.hpp>
|
||||
#include <carve/aabb.hpp>
|
||||
#include <carve/rtree.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace carve {
|
||||
namespace poly {
|
||||
class Polyhedron;
|
||||
}
|
||||
|
||||
namespace mesh {
|
||||
|
||||
|
||||
template<unsigned ndim> class Edge;
|
||||
template<unsigned ndim> class Face;
|
||||
template<unsigned ndim> class Mesh;
|
||||
template<unsigned ndim> class MeshSet;
|
||||
|
||||
|
||||
|
||||
// A Vertex may participate in several meshes. If the Mesh belongs
|
||||
// to a MeshSet, then the vertices come from the vertex_storage
|
||||
// member of the MeshSet. This allows one to construct one or more
|
||||
// Meshes out of sets of connected faces (possibly using vertices
|
||||
// from a variety of MeshSets, and other storage), then create a
|
||||
// MeshSet from the Mesh(es), causing the vertices to be
|
||||
// collected, cloned and repointed into the MeshSet.
|
||||
|
||||
// Normally, in a half-edge structure, Vertex would have a member
|
||||
// pointing to an incident edge, allowing the enumeration of
|
||||
// adjacent faces and edges. Because we want to support vertex
|
||||
// sharing between Meshes and groups of Faces, this is made more
|
||||
// complex. If Vertex contained a list of incident edges, one from
|
||||
// each disjoint face set, then this could be done (with the
|
||||
// caveat that you'd need to pass in a Mesh pointer to the
|
||||
// adjacency queries). However, it seems that this would
|
||||
// unavoidably complicate the process of incorporating or removing
|
||||
// a vertex into an edge.
|
||||
|
||||
// In most cases it is expected that a vertex will be arrived at
|
||||
// via an edge or face in the mesh (implicit or explicit) of
|
||||
// interest, so not storing this information will not hurt,
|
||||
// overly.
|
||||
template<unsigned ndim>
|
||||
class Vertex : public tagable {
|
||||
public:
|
||||
typedef carve::geom::vector<ndim> vector_t;
|
||||
typedef MeshSet<ndim> owner_t;
|
||||
typedef carve::geom::aabb<ndim> aabb_t;
|
||||
|
||||
carve::geom::vector<ndim> v;
|
||||
|
||||
Vertex(const vector_t &_v) : tagable(), v(_v) {
|
||||
}
|
||||
|
||||
Vertex() : tagable(), v() {
|
||||
}
|
||||
|
||||
aabb_t getAABB() const {
|
||||
return aabb_t(v, carve::geom::vector<ndim>::ZERO());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct hash_vertex_pair {
|
||||
template<unsigned ndim>
|
||||
size_t operator()(const std::pair<Vertex<ndim> *, Vertex<ndim> *> &pair) const {
|
||||
size_t r = (size_t)pair.first;
|
||||
size_t s = (size_t)pair.second;
|
||||
return r ^ ((s >> 16) | (s << 16));
|
||||
}
|
||||
template<unsigned ndim>
|
||||
size_t operator()(const std::pair<const Vertex<ndim> *, const Vertex<ndim> *> &pair) const {
|
||||
size_t r = (size_t)pair.first;
|
||||
size_t s = (size_t)pair.second;
|
||||
return r ^ ((s >> 16) | (s << 16));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct vertex_distance {
|
||||
template<unsigned ndim>
|
||||
double operator()(const Vertex<ndim> &a, const Vertex<ndim> &b) const {
|
||||
return carve::geom::distance(a.v, b.v);
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
double operator()(const Vertex<ndim> *a, const Vertex<ndim> *b) const {
|
||||
return carve::geom::distance(a->v, b->v);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
namespace detail {
|
||||
template<typename list_t> struct list_iter_t;
|
||||
template<typename list_t, typename mapping_t> struct mapped_list_iter_t;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// The half-edge structure proper (Edge) is maintained by Face
|
||||
// instances. Together with Face instances, the half-edge
|
||||
// structure defines a simple mesh (either one or two faces
|
||||
// incident on each edge).
|
||||
template<unsigned ndim>
|
||||
class Edge : public tagable {
|
||||
public:
|
||||
typedef Vertex<ndim> vertex_t;
|
||||
typedef Face<ndim> face_t;
|
||||
|
||||
vertex_t *vert;
|
||||
face_t *face;
|
||||
Edge *prev, *next, *rev;
|
||||
|
||||
private:
|
||||
static void _link(Edge *a, Edge *b) {
|
||||
a->next = b; b->prev = a;
|
||||
}
|
||||
|
||||
static void _freeloop(Edge *s) {
|
||||
Edge *e = s;
|
||||
do {
|
||||
Edge *n = e->next;
|
||||
delete e;
|
||||
e = n;
|
||||
} while (e != s);
|
||||
}
|
||||
|
||||
static void _setloopface(Edge *s, face_t *f) {
|
||||
Edge *e = s;
|
||||
do {
|
||||
e->face = f;
|
||||
e = e->next;
|
||||
} while (e != s);
|
||||
}
|
||||
|
||||
static size_t _looplen(Edge *s) {
|
||||
Edge *e = s;
|
||||
face_t *f = s->face;
|
||||
size_t c = 0;
|
||||
do {
|
||||
++c;
|
||||
CARVE_ASSERT(e->rev->rev == e);
|
||||
CARVE_ASSERT(e->next->prev == e);
|
||||
CARVE_ASSERT(e->face == f);
|
||||
e = e->next;
|
||||
} while (e != s);
|
||||
return c;
|
||||
}
|
||||
|
||||
public:
|
||||
void validateLoop() {
|
||||
Edge *e = this;
|
||||
face_t *f = face;
|
||||
size_t c = 0;
|
||||
do {
|
||||
++c;
|
||||
CARVE_ASSERT(e->rev == NULL || e->rev->rev == e);
|
||||
CARVE_ASSERT(e->next == e || e->next->vert != e->vert);
|
||||
CARVE_ASSERT(e->prev == e || e->prev->vert != e->vert);
|
||||
CARVE_ASSERT(e->next->prev == e);
|
||||
CARVE_ASSERT(e->prev->next == e);
|
||||
CARVE_ASSERT(e->face == f);
|
||||
e = e->next;
|
||||
} while (e != this);
|
||||
CARVE_ASSERT(f == NULL || c == f->n_edges);
|
||||
}
|
||||
|
||||
size_t loopLen() {
|
||||
return _looplen(this);
|
||||
}
|
||||
|
||||
Edge *mergeFaces();
|
||||
|
||||
Edge *removeHalfEdge();
|
||||
|
||||
// Remove and delete this edge.
|
||||
Edge *removeEdge();
|
||||
|
||||
// Unlink this edge from its containing edge loop. disconnect
|
||||
// rev links. The rev links of the previous edge also change, as
|
||||
// its successor vertex changes.
|
||||
void unlink();
|
||||
|
||||
// Insert this edge into a loop before other. If edge was
|
||||
// already in a loop, it needs to be removed first.
|
||||
void insertBefore(Edge *other);
|
||||
|
||||
// Insert this edge into a loop after other. If edge was
|
||||
// already in a loop, it needs to be removed first.
|
||||
void insertAfter(Edge *other);
|
||||
|
||||
size_t loopSize() const;
|
||||
|
||||
vertex_t *v1() { return vert; }
|
||||
vertex_t *v2() { return next->vert; }
|
||||
|
||||
const vertex_t *v1() const { return vert; }
|
||||
const vertex_t *v2() const { return next->vert; }
|
||||
|
||||
Edge *perimNext() const;
|
||||
Edge *perimPrev() const;
|
||||
|
||||
double length2() const {
|
||||
return (v1()->v - v2()->v).length2();
|
||||
}
|
||||
|
||||
double length() const {
|
||||
return (v1()->v - v2()->v).length();
|
||||
}
|
||||
|
||||
Edge(vertex_t *_vert, face_t *_face);
|
||||
|
||||
~Edge();
|
||||
};
|
||||
|
||||
|
||||
|
||||
// A Face contains a pointer to the beginning of the half-edge
|
||||
// circular list that defines its boundary.
|
||||
template<unsigned ndim>
|
||||
class Face : public tagable {
|
||||
public:
|
||||
typedef Vertex<ndim> vertex_t;
|
||||
typedef Edge<ndim> edge_t;
|
||||
typedef Mesh<ndim> mesh_t;
|
||||
|
||||
typedef typename Vertex<ndim>::vector_t vector_t;
|
||||
typedef carve::geom::aabb<ndim> aabb_t;
|
||||
typedef carve::geom::plane<ndim> plane_t;
|
||||
typedef carve::geom::vector<2> (*project_t)(const vector_t &);
|
||||
typedef vector_t (*unproject_t)(const carve::geom::vector<2> &, const plane_t &);
|
||||
|
||||
struct vector_mapping {
|
||||
typedef typename vertex_t::vector_t value_type;
|
||||
|
||||
value_type operator()(const carve::geom::vector<ndim> &v) const { return v; }
|
||||
value_type operator()(const carve::geom::vector<ndim> *v) const { return *v; }
|
||||
value_type operator()(const Edge<ndim> &e) const { return e.vert->v; }
|
||||
value_type operator()(const Edge<ndim> *e) const { return e->vert->v; }
|
||||
value_type operator()(const Vertex<ndim> &v) const { return v.v; }
|
||||
value_type operator()(const Vertex<ndim> *v) const { return v->v; }
|
||||
};
|
||||
|
||||
struct projection_mapping {
|
||||
typedef carve::geom::vector<2> value_type;
|
||||
project_t proj;
|
||||
projection_mapping(project_t _proj) : proj(_proj) { }
|
||||
value_type operator()(const carve::geom::vector<ndim> &v) const { return proj(v); }
|
||||
value_type operator()(const carve::geom::vector<ndim> *v) const { return proj(*v); }
|
||||
value_type operator()(const Edge<ndim> &e) const { return proj(e.vert->v); }
|
||||
value_type operator()(const Edge<ndim> *e) const { return proj(e->vert->v); }
|
||||
value_type operator()(const Vertex<ndim> &v) const { return proj(v.v); }
|
||||
value_type operator()(const Vertex<ndim> *v) const { return proj(v->v); }
|
||||
};
|
||||
|
||||
edge_t *edge;
|
||||
size_t n_edges;
|
||||
mesh_t *mesh;
|
||||
size_t id;
|
||||
|
||||
plane_t plane;
|
||||
project_t project;
|
||||
unproject_t unproject;
|
||||
|
||||
private:
|
||||
Face &operator=(const Face &other);
|
||||
|
||||
protected:
|
||||
Face() : edge(NULL), n_edges(0), mesh(NULL), id(0), plane(), project(NULL), unproject(NULL) {
|
||||
}
|
||||
|
||||
Face(const Face &other) :
|
||||
edge(NULL), n_edges(other.n_edges), mesh(NULL), id(other.id),
|
||||
plane(other.plane), project(other.project), unproject(other.unproject) {
|
||||
}
|
||||
|
||||
project_t getProjector(bool positive_facing, int axis) const;
|
||||
unproject_t getUnprojector(bool positive_facing, int axis) const;
|
||||
|
||||
public:
|
||||
typedef detail::list_iter_t<Edge<ndim> > edge_iter_t;
|
||||
typedef detail::list_iter_t<const Edge<ndim> > const_edge_iter_t;
|
||||
|
||||
edge_iter_t begin() { return edge_iter_t(edge, 0); }
|
||||
edge_iter_t end() { return edge_iter_t(edge, n_edges); }
|
||||
|
||||
const_edge_iter_t begin() const { return const_edge_iter_t(edge, 0); }
|
||||
const_edge_iter_t end() const { return const_edge_iter_t(edge, n_edges); }
|
||||
|
||||
bool containsPoint(const vector_t &p) const;
|
||||
bool containsPointInProjection(const vector_t &p) const;
|
||||
bool simpleLineSegmentIntersection(
|
||||
const carve::geom::linesegment<ndim> &line,
|
||||
vector_t &intersection) const;
|
||||
IntersectionClass lineSegmentIntersection(
|
||||
const carve::geom::linesegment<ndim> &line,
|
||||
vector_t &intersection) const;
|
||||
|
||||
aabb_t getAABB() const;
|
||||
|
||||
bool recalc();
|
||||
|
||||
void clearEdges();
|
||||
|
||||
// build an edge loop in forward orientation from an iterator pair
|
||||
template<typename iter_t>
|
||||
void loopFwd(iter_t vbegin, iter_t vend);
|
||||
|
||||
// build an edge loop in reverse orientation from an iterator pair
|
||||
template<typename iter_t>
|
||||
void loopRev(iter_t vbegin, iter_t vend);
|
||||
|
||||
// initialize a face from an ordered list of vertices.
|
||||
template<typename iter_t>
|
||||
void init(iter_t begin, iter_t end);
|
||||
|
||||
// initialization of a triangular face.
|
||||
void init(vertex_t *a, vertex_t *b, vertex_t *c);
|
||||
|
||||
// initialization of a quad face.
|
||||
void init(vertex_t *a, vertex_t *b, vertex_t *c, vertex_t *d);
|
||||
|
||||
void getVertices(std::vector<vertex_t *> &verts) const;
|
||||
void getProjectedVertices(std::vector<carve::geom::vector<2> > &verts) const;
|
||||
|
||||
projection_mapping projector() const {
|
||||
return projection_mapping(project);
|
||||
}
|
||||
|
||||
std::pair<double, double> rangeInDirection(const vector_t &v, const vector_t &b) const {
|
||||
edge_t *e = edge;
|
||||
double lo, hi;
|
||||
lo = hi = carve::geom::dot(v, e->vert->v - b);
|
||||
e = e->next;
|
||||
for (; e != edge; e = e->next) {
|
||||
double d = carve::geom::dot(v, e->vert->v - b);
|
||||
lo = std::min(lo, d);
|
||||
hi = std::max(hi, d);
|
||||
}
|
||||
return std::make_pair(lo, hi);
|
||||
}
|
||||
|
||||
size_t nVertices() const {
|
||||
return n_edges;
|
||||
}
|
||||
|
||||
size_t nEdges() const {
|
||||
return n_edges;
|
||||
}
|
||||
|
||||
vector_t centroid() const;
|
||||
|
||||
static Face *closeLoop(edge_t *open_edge);
|
||||
|
||||
Face(edge_t *e) : edge(e), n_edges(0), mesh(NULL) {
|
||||
do {
|
||||
e->face = this;
|
||||
n_edges++;
|
||||
e = e->next;
|
||||
} while (e != edge);
|
||||
recalc();
|
||||
}
|
||||
|
||||
Face(vertex_t *a, vertex_t *b, vertex_t *c) : edge(NULL), n_edges(0), mesh(NULL) {
|
||||
init(a, b, c);
|
||||
recalc();
|
||||
}
|
||||
|
||||
Face(vertex_t *a, vertex_t *b, vertex_t *c, vertex_t *d) : edge(NULL), n_edges(0), mesh(NULL) {
|
||||
init(a, b, c, d);
|
||||
recalc();
|
||||
}
|
||||
|
||||
template<typename iter_t>
|
||||
Face(iter_t begin, iter_t end) : edge(NULL), n_edges(0), mesh(NULL) {
|
||||
init(begin, end);
|
||||
recalc();
|
||||
}
|
||||
|
||||
template<typename iter_t>
|
||||
Face *create(iter_t beg, iter_t end, bool reversed) const;
|
||||
|
||||
Face *clone(const vertex_t *old_base, vertex_t *new_base, std::unordered_map<const edge_t *, edge_t *> &edge_map) const;
|
||||
|
||||
void remove() {
|
||||
edge_t *e = edge;
|
||||
do {
|
||||
if (e->rev) e->rev->rev = NULL;
|
||||
e = e->next;
|
||||
} while (e != edge);
|
||||
}
|
||||
|
||||
void invert() {
|
||||
// We invert the direction of the edges of the face in this
|
||||
// way so that the edge rev pointers (if any) are still
|
||||
// correct. It is expected that invert() will be called on
|
||||
// every other face in the mesh, too, otherwise everything
|
||||
// will get messed up.
|
||||
|
||||
{
|
||||
// advance vertices.
|
||||
edge_t *e = edge;
|
||||
vertex_t *va = e->vert;
|
||||
do {
|
||||
e->vert = e->next->vert;
|
||||
e = e->next;
|
||||
} while (e != edge);
|
||||
edge->prev->vert = va;
|
||||
}
|
||||
|
||||
{
|
||||
// swap prev and next pointers.
|
||||
edge_t *e = edge;
|
||||
do {
|
||||
edge_t *n = e->next;
|
||||
std::swap(e->prev, e->next);
|
||||
e = n;
|
||||
} while (e != edge);
|
||||
}
|
||||
|
||||
plane.negate();
|
||||
|
||||
int da = carve::geom::largestAxis(plane.N);
|
||||
|
||||
project = getProjector(plane.N.v[da] > 0, da);
|
||||
unproject = getUnprojector(plane.N.v[da] > 0, da);
|
||||
}
|
||||
|
||||
void canonicalize();
|
||||
|
||||
~Face() {
|
||||
clearEdges();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
namespace detail {
|
||||
class FaceStitcher {
|
||||
typedef Vertex<3> vertex_t;
|
||||
typedef Edge<3> edge_t;
|
||||
typedef Face<3> face_t;
|
||||
|
||||
typedef std::pair<const vertex_t *, const vertex_t *> vpair_t;
|
||||
typedef std::list<edge_t *> edgelist_t;
|
||||
typedef std::unordered_map<vpair_t, edgelist_t, carve::mesh::hash_vertex_pair> edge_map_t;
|
||||
typedef std::unordered_map<const vertex_t *, std::set<const vertex_t *> > edge_graph_t;
|
||||
|
||||
edge_map_t edges;
|
||||
edge_map_t complex_edges;
|
||||
|
||||
carve::djset::djset face_groups;
|
||||
std::vector<bool> is_open;
|
||||
|
||||
edge_graph_t edge_graph;
|
||||
|
||||
struct EdgeOrderData {
|
||||
size_t group_id;
|
||||
bool is_reversed;
|
||||
carve::geom::vector<3> face_dir;
|
||||
edge_t *edge;
|
||||
|
||||
EdgeOrderData(edge_t *_edge, size_t _group_id, bool _is_reversed) :
|
||||
group_id(_group_id),
|
||||
is_reversed(_is_reversed) {
|
||||
if (is_reversed) {
|
||||
face_dir = -(_edge->face->plane.N);
|
||||
} else {
|
||||
face_dir = (_edge->face->plane.N);
|
||||
}
|
||||
edge = _edge;
|
||||
}
|
||||
|
||||
struct TestGroups {
|
||||
size_t fwd, rev;
|
||||
|
||||
TestGroups(size_t _fwd, size_t _rev) : fwd(_fwd), rev(_rev) {
|
||||
}
|
||||
|
||||
bool operator()(const EdgeOrderData &eo) const {
|
||||
return eo.group_id == (eo.is_reversed ? rev : fwd);
|
||||
}
|
||||
};
|
||||
|
||||
struct Cmp {
|
||||
carve::geom::vector<3> edge_dir;
|
||||
carve::geom::vector<3> base_dir;
|
||||
|
||||
Cmp(const carve::geom::vector<3> &_edge_dir,
|
||||
const carve::geom::vector<3> &_base_dir) :
|
||||
edge_dir(_edge_dir),
|
||||
base_dir(_base_dir) {
|
||||
}
|
||||
bool operator()(const EdgeOrderData &a, const EdgeOrderData &b) const;
|
||||
};
|
||||
};
|
||||
|
||||
void extractConnectedEdges(std::vector<const vertex_t *>::iterator begin,
|
||||
std::vector<const vertex_t *>::iterator end,
|
||||
std::vector<std::vector<Edge<3> *> > &efwd,
|
||||
std::vector<std::vector<Edge<3> *> > &erev);
|
||||
|
||||
size_t faceGroupID(const Face<3> *face);
|
||||
size_t faceGroupID(const Edge<3> *edge);
|
||||
|
||||
void resolveOpenEdges();
|
||||
|
||||
void fuseEdges(std::vector<Edge<3> *> &fwd,
|
||||
std::vector<Edge<3> *> &rev);
|
||||
|
||||
void joinGroups(std::vector<std::vector<Edge<3> *> > &efwd,
|
||||
std::vector<std::vector<Edge<3> *> > &erev,
|
||||
size_t fwd_grp,
|
||||
size_t rev_grp);
|
||||
|
||||
void matchOrderedEdges(const std::vector<std::vector<EdgeOrderData> >::iterator begin,
|
||||
const std::vector<std::vector<EdgeOrderData> >::iterator end,
|
||||
std::vector<std::vector<Edge<3> *> > &efwd,
|
||||
std::vector<std::vector<Edge<3> *> > &erev);
|
||||
|
||||
void reorder(std::vector<EdgeOrderData> &ordering, size_t fwd_grp);
|
||||
|
||||
void orderForwardAndReverseEdges(std::vector<std::vector<Edge<3> *> > &efwd,
|
||||
std::vector<std::vector<Edge<3> *> > &erev,
|
||||
std::vector<std::vector<EdgeOrderData> > &result);
|
||||
|
||||
void edgeIncidentGroups(const vpair_t &e,
|
||||
const edge_map_t &all_edges,
|
||||
std::pair<std::set<size_t>, std::set<size_t> > &groups);
|
||||
|
||||
void buildEdgeGraph(const edge_map_t &all_edges);
|
||||
void extractPath(std::vector<const vertex_t *> &path);
|
||||
void removePath(const std::vector<const vertex_t *> &path);
|
||||
void matchSimpleEdges();
|
||||
void construct();
|
||||
|
||||
template<typename iter_t>
|
||||
void initEdges(iter_t begin, iter_t end);
|
||||
|
||||
template<typename iter_t>
|
||||
void build(iter_t begin, iter_t end, std::vector<Mesh<3> *> &meshes);
|
||||
|
||||
public:
|
||||
template<typename iter_t>
|
||||
void create(iter_t begin, iter_t end, std::vector<Mesh<3> *> &meshes);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
// A Mesh is a connected set of faces. It may be open (some edges
|
||||
// have NULL rev members), or closed. On destruction, a Mesh
|
||||
// should free its Faces (which will in turn free Edges, but not
|
||||
// Vertices). A Mesh is edge-connected, which is to say that each
|
||||
// face in the mesh shares an edge with at least one other face in
|
||||
// the mesh. Touching at a vertex is not sufficient. This means
|
||||
// that the perimeter of an open mesh visits each vertex no more
|
||||
// than once.
|
||||
template<unsigned ndim>
|
||||
class Mesh {
|
||||
public:
|
||||
typedef Vertex<ndim> vertex_t;
|
||||
typedef Edge<ndim> edge_t;
|
||||
typedef Face<ndim> face_t;
|
||||
typedef carve::geom::aabb<ndim> aabb_t;
|
||||
typedef MeshSet<ndim> meshset_t;
|
||||
|
||||
std::vector<face_t *> faces;
|
||||
|
||||
// open_edges is a vector of all the edges in the mesh that
|
||||
// don't have a matching edge in the opposite direction.
|
||||
std::vector<edge_t *> open_edges;
|
||||
|
||||
// closed_edges is a vector of all the edges in the mesh that
|
||||
// have a matching edge in the opposite direction, and whose
|
||||
// address is lower than their counterpart. (i.e. for each pair
|
||||
// of adjoining faces, one of the two half edges is stored in
|
||||
// closed_edges).
|
||||
std::vector<edge_t *> closed_edges;
|
||||
|
||||
bool is_negative;
|
||||
|
||||
meshset_t *meshset;
|
||||
|
||||
protected:
|
||||
Mesh(std::vector<face_t *> &_faces,
|
||||
std::vector<edge_t *> &_open_edges,
|
||||
std::vector<edge_t *> &_closed_edges,
|
||||
bool _is_negative);
|
||||
|
||||
public:
|
||||
Mesh(std::vector<face_t *> &_faces);
|
||||
|
||||
~Mesh();
|
||||
|
||||
template<typename iter_t>
|
||||
static void create(iter_t begin, iter_t end, std::vector<Mesh<ndim> *> &meshes);
|
||||
|
||||
aabb_t getAABB() const {
|
||||
return aabb_t(faces.begin(), faces.end());
|
||||
}
|
||||
|
||||
bool isClosed() const {
|
||||
return open_edges.size() == 0;
|
||||
}
|
||||
|
||||
bool isNegative() const {
|
||||
return is_negative;
|
||||
}
|
||||
|
||||
double volume() const {
|
||||
if (is_negative || !faces.size()) return 0.0;
|
||||
|
||||
double vol = 0.0;
|
||||
typename vertex_t::vector_t origin = faces[0]->edge->vert->v;
|
||||
|
||||
for (size_t f = 0; f < faces.size(); ++f) {
|
||||
face_t *face = faces[f];
|
||||
edge_t *e1 = face->edge;
|
||||
for (edge_t *e2 = e1->next ;e2->next != e1; e2 = e2->next) {
|
||||
vol += carve::geom3d::tetrahedronVolume(e1->vert->v, e2->vert->v, e2->next->vert->v, origin);
|
||||
}
|
||||
}
|
||||
return vol;
|
||||
}
|
||||
|
||||
struct IsClosed {
|
||||
bool operator()(const Mesh &mesh) const { return mesh.isClosed(); }
|
||||
bool operator()(const Mesh *mesh) const { return mesh->isClosed(); }
|
||||
};
|
||||
|
||||
struct IsNegative {
|
||||
bool operator()(const Mesh &mesh) const { return mesh.isNegative(); }
|
||||
bool operator()(const Mesh *mesh) const { return mesh->isNegative(); }
|
||||
};
|
||||
|
||||
void cacheEdges();
|
||||
|
||||
void calcOrientation();
|
||||
|
||||
void recalc() {
|
||||
for (size_t i = 0; i < faces.size(); ++i) faces[i]->recalc();
|
||||
calcOrientation();
|
||||
}
|
||||
|
||||
void invert() {
|
||||
for (size_t i = 0; i < faces.size(); ++i) {
|
||||
faces[i]->invert();
|
||||
}
|
||||
if (isClosed()) is_negative = !is_negative;
|
||||
}
|
||||
|
||||
Mesh *clone(const vertex_t *old_base, vertex_t *new_base) const;
|
||||
};
|
||||
|
||||
// A MeshSet manages vertex storage, and a collection of meshes.
|
||||
// It should be easy to turn a vertex pointer into its index in
|
||||
// its MeshSet vertex_storage.
|
||||
template<unsigned ndim>
|
||||
class MeshSet {
|
||||
MeshSet();
|
||||
MeshSet(const MeshSet &);
|
||||
MeshSet &operator=(const MeshSet &);
|
||||
|
||||
template<typename iter_t>
|
||||
void _init_from_faces(iter_t begin, iter_t end);
|
||||
|
||||
public:
|
||||
typedef Vertex<ndim> vertex_t;
|
||||
typedef Edge<ndim> edge_t;
|
||||
typedef Face<ndim> face_t;
|
||||
typedef Mesh<ndim> mesh_t;
|
||||
typedef carve::geom::aabb<ndim> aabb_t;
|
||||
|
||||
std::vector<vertex_t> vertex_storage;
|
||||
std::vector<mesh_t *> meshes;
|
||||
|
||||
public:
|
||||
template<typename face_type>
|
||||
struct FaceIter : public std::iterator<std::random_access_iterator_tag, face_type> {
|
||||
typedef std::iterator<std::random_access_iterator_tag, face_type> super;
|
||||
typedef typename super::difference_type difference_type;
|
||||
|
||||
const MeshSet<ndim> *obj;
|
||||
size_t mesh, face;
|
||||
|
||||
FaceIter(const MeshSet<ndim> *_obj, size_t _mesh, size_t _face);
|
||||
|
||||
void fwd(size_t n);
|
||||
void rev(size_t n);
|
||||
void adv(int n);
|
||||
|
||||
FaceIter operator++(int) { FaceIter tmp = *this; tmp.fwd(1); return tmp; }
|
||||
FaceIter operator+(int v) { FaceIter tmp = *this; tmp.adv(v); return tmp; }
|
||||
FaceIter &operator++() { fwd(1); return *this; }
|
||||
FaceIter &operator+=(int v) { adv(v); return *this; }
|
||||
|
||||
FaceIter operator--(int) { FaceIter tmp = *this; tmp.rev(1); return tmp; }
|
||||
FaceIter operator-(int v) { FaceIter tmp = *this; tmp.adv(-v); return tmp; }
|
||||
FaceIter &operator--() { rev(1); return *this; }
|
||||
FaceIter &operator-=(int v) { adv(-v); return *this; }
|
||||
|
||||
difference_type operator-(const FaceIter &other) const;
|
||||
|
||||
bool operator==(const FaceIter &other) const {
|
||||
return obj == other.obj && mesh == other.mesh && face == other.face;
|
||||
}
|
||||
bool operator!=(const FaceIter &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
bool operator<(const FaceIter &other) const {
|
||||
CARVE_ASSERT(obj == other.obj);
|
||||
return mesh < other.mesh || (mesh == other.mesh && face < other.face);
|
||||
}
|
||||
bool operator>(const FaceIter &other) const {
|
||||
return other < *this;
|
||||
}
|
||||
bool operator<=(const FaceIter &other) const {
|
||||
return !(other < *this);
|
||||
}
|
||||
bool operator>=(const FaceIter &other) const {
|
||||
return !(*this < other);
|
||||
}
|
||||
|
||||
face_type operator*() const {
|
||||
return obj->meshes[mesh]->faces[face];
|
||||
}
|
||||
};
|
||||
|
||||
typedef FaceIter<const face_t *> const_face_iter;
|
||||
typedef FaceIter<face_t *> face_iter;
|
||||
|
||||
face_iter faceBegin() { return face_iter(this, 0, 0); }
|
||||
face_iter faceEnd() { return face_iter(this, meshes.size(), 0); }
|
||||
|
||||
const_face_iter faceBegin() const { return const_face_iter(this, 0, 0); }
|
||||
const_face_iter faceEnd() const { return const_face_iter(this, meshes.size(), 0); }
|
||||
|
||||
aabb_t getAABB() const {
|
||||
return aabb_t(meshes.begin(), meshes.end());
|
||||
}
|
||||
|
||||
template<typename func_t>
|
||||
void transform(func_t func) {
|
||||
for (size_t i = 0; i < vertex_storage.size(); ++i) {
|
||||
vertex_storage[i].v = func(vertex_storage[i].v);
|
||||
}
|
||||
for (size_t i = 0; i < meshes.size(); ++i) {
|
||||
meshes[i]->recalc();
|
||||
}
|
||||
}
|
||||
|
||||
MeshSet(const std::vector<typename vertex_t::vector_t> &points,
|
||||
size_t n_faces,
|
||||
const std::vector<int> &face_indices);
|
||||
|
||||
// Construct a mesh set from a set of disconnected faces. Takes
|
||||
// posession of the face pointers.
|
||||
MeshSet(std::vector<face_t *> &faces);
|
||||
|
||||
MeshSet(std::list<face_t *> &faces);
|
||||
|
||||
MeshSet(std::vector<vertex_t> &_vertex_storage,
|
||||
std::vector<mesh_t *> &_meshes);
|
||||
|
||||
// This constructor consolidates and rewrites vertex pointers in
|
||||
// each mesh, repointing them to local storage.
|
||||
MeshSet(std::vector<mesh_t *> &_meshes);
|
||||
|
||||
MeshSet *clone() const;
|
||||
|
||||
~MeshSet();
|
||||
|
||||
bool isClosed() const {
|
||||
for (size_t i = 0; i < meshes.size(); ++i) {
|
||||
if (!meshes[i]->isClosed()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void invert() {
|
||||
for (size_t i = 0; i < meshes.size(); ++i) {
|
||||
meshes[i]->invert();
|
||||
}
|
||||
}
|
||||
|
||||
void collectVertices();
|
||||
|
||||
void canonicalize();
|
||||
};
|
||||
|
||||
|
||||
|
||||
carve::PointClass classifyPoint(
|
||||
const carve::mesh::MeshSet<3> *meshset,
|
||||
const carve::geom::RTreeNode<3, carve::mesh::Face<3> *> *face_rtree,
|
||||
const carve::geom::vector<3> &v,
|
||||
bool even_odd = false,
|
||||
const carve::mesh::Mesh<3> *mesh = NULL,
|
||||
const carve::mesh::Face<3> **hit_face = NULL);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
mesh::MeshSet<3> *meshFromPolyhedron(const poly::Polyhedron *, int manifold_id);
|
||||
poly::Polyhedron *polyhedronFromMesh(const mesh::MeshSet<3> *, int manifold_id);
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
#include <carve/mesh_impl.hpp>
|
1015
extern/carve/include/carve/mesh_impl.hpp
vendored
Normal file
1015
extern/carve/include/carve/mesh_impl.hpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
975
extern/carve/include/carve/mesh_ops.hpp
vendored
Normal file
975
extern/carve/include/carve/mesh_ops.hpp
vendored
Normal file
@ -0,0 +1,975 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
|
||||
#include <carve/mesh.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
namespace carve {
|
||||
namespace mesh {
|
||||
namespace detail {
|
||||
// make a triangle out of three edges.
|
||||
template<unsigned ndim>
|
||||
void link(Edge<ndim> *e1, Edge<ndim> *e2, Edge<ndim> *e3, Face<ndim> *f = NULL) {
|
||||
e1->next = e2; e2->next = e3; e3->next = e1;
|
||||
e3->prev = e2; e2->prev = e1; e1->prev = e3;
|
||||
e1->face = e2->face = e3->face = f;
|
||||
if (f) {
|
||||
f->edge = e1;
|
||||
f->recalc();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<unsigned ndim, typename proj_t>
|
||||
double loopArea(carve::mesh::Edge<ndim> *edge, proj_t proj) {
|
||||
double A = 0.0;
|
||||
carve::mesh::Edge<3> *e = edge;
|
||||
do {
|
||||
carve::geom2d::P2 p1 = proj(e->vert->v);
|
||||
carve::geom2d::P2 p2 = proj(e->next->vert->v);
|
||||
A += (p2.y + p1.y) * (p2.x - p1.x);
|
||||
e = e->next;
|
||||
} while (e != edge);
|
||||
return A / 2.0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<unsigned ndim, typename proj_t>
|
||||
struct TriangulationData {
|
||||
typedef Edge<ndim> edge_t;
|
||||
|
||||
struct VertexInfo {
|
||||
double score;
|
||||
carve::geom2d::P2 p;
|
||||
bool convex;
|
||||
bool failed;
|
||||
VertexInfo *next, *prev;
|
||||
edge_t *edge;
|
||||
|
||||
VertexInfo(edge_t *_edge,
|
||||
const carve::geom2d::P2 &_p) :
|
||||
score(0.0), p(_p), convex(false), failed(false), next(NULL), prev(NULL), edge(_edge) {
|
||||
}
|
||||
|
||||
bool isCandidate() const {
|
||||
return convex && !failed;
|
||||
}
|
||||
|
||||
void fail() {
|
||||
failed = true;
|
||||
}
|
||||
|
||||
static bool isLeft(const VertexInfo *a, const VertexInfo *b, const geom2d::P2 &p) {
|
||||
if (a < b) {
|
||||
return carve::geom2d::orient2d(a->p, b->p, p) > 0.0;
|
||||
} else {
|
||||
return carve::geom2d::orient2d(b->p, a->p, p) < 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
// is the ear prev->edge->next convex?
|
||||
bool testForConvexVertex() const {
|
||||
return isLeft(next, prev, p);
|
||||
}
|
||||
|
||||
static double triScore(const geom2d::P2 &a, const geom2d::P2 &b, const geom2d::P2 &c) {
|
||||
// score is in the range: [0, 1]
|
||||
// equilateral triangles score 1
|
||||
// sliver triangles score 0
|
||||
double dab = (a - b).length();
|
||||
double dbc = (b - c).length();
|
||||
double dca = (c - a).length();
|
||||
|
||||
if (dab < 1e-10 || dbc < 1e-10 || dca < 1e-10) return 0.0;
|
||||
|
||||
return std::max(std::min((dab + dbc) / dca, std::min((dab + dca) / dbc, (dbc + dca) / dab)) - 1.0, 0.0);
|
||||
}
|
||||
|
||||
// calculate a score for the ear edge.
|
||||
double calcScore() const {
|
||||
double this_tri = triScore(prev->p, p, next->p);
|
||||
double next_tri = triScore(prev->p, next->p, next->next->p);
|
||||
double prev_tri = triScore(prev->prev->p, prev->p, next->p);
|
||||
|
||||
return this_tri + std::max(next_tri, prev_tri) * .2;
|
||||
}
|
||||
|
||||
void recompute() {
|
||||
convex = testForConvexVertex();
|
||||
failed = false;
|
||||
if (convex) {
|
||||
score = calcScore();
|
||||
} else {
|
||||
score = -1e-5;
|
||||
}
|
||||
}
|
||||
|
||||
static bool inTriangle(const VertexInfo *a,
|
||||
const VertexInfo *b,
|
||||
const VertexInfo *c,
|
||||
const geom2d::P2 &e) {
|
||||
return !isLeft(b, a, e) && !isLeft(c, b, e) && !isLeft(a, c, e);
|
||||
}
|
||||
|
||||
|
||||
bool isClipable() const {
|
||||
for (const VertexInfo *v_test = next->next; v_test != prev; v_test = v_test->next) {
|
||||
if (v_test->convex) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (v_test->p == prev->p || v_test->p == next->p) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (v_test->p == p) {
|
||||
if (v_test->next->p == prev->p && v_test->prev->p == next->p) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (v_test->next->p == prev->p || v_test->prev->p == next->p) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (inTriangle(prev, this, next, v_test->p)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct order_by_score {
|
||||
bool operator()(const VertexInfo *a, const VertexInfo *b) const {
|
||||
return a->score < b->score;
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::pair<VertexInfo *, VertexInfo *> diag_t;
|
||||
|
||||
proj_t proj;
|
||||
|
||||
geom2d::P2 P(const VertexInfo *vi) const {
|
||||
return vi->p;
|
||||
}
|
||||
|
||||
geom2d::P2 P(const edge_t *edge) const {
|
||||
return proj(edge->vert->v);
|
||||
}
|
||||
|
||||
bool isLeft(const edge_t *a, const edge_t *b, const geom2d::P2 &p) const {
|
||||
if (a < b) {
|
||||
return carve::geom2d::orient2d(P(a), P(b), p) > 0.0;
|
||||
} else {
|
||||
return carve::geom2d::orient2d(P(b), P(a), p) < 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
bool testForConvexVertex(const edge_t *vert) const {
|
||||
return isLeft(vert->next, vert->prev, P(vert));
|
||||
}
|
||||
|
||||
bool inCone(const VertexInfo *vert, const geom2d::P2 &p) const {
|
||||
return geom2d::internalToAngle(P(vert->next), P(vert), P(vert->prev), p);
|
||||
}
|
||||
|
||||
int windingNumber(VertexInfo *vert, const carve::geom2d::P2 &point) const {
|
||||
int wn = 0;
|
||||
|
||||
VertexInfo *v = vert;
|
||||
geom2d::P2 v_p = P(vert);
|
||||
do {
|
||||
geom2d::P2 n_p = P(v->next);
|
||||
|
||||
if (v_p.y <= point.y) {
|
||||
if (n_p.y > point.y && carve::geom2d::orient2d(v_p, n_p, point) > 0.0) {
|
||||
++wn;
|
||||
}
|
||||
} else {
|
||||
if (n_p.y <= point.y && carve::geom2d::orient2d(v_p, n_p, point) < 0.0) {
|
||||
--wn;
|
||||
}
|
||||
}
|
||||
v = v->next;
|
||||
v_p = n_p;
|
||||
} while (v != vert);
|
||||
|
||||
return wn;
|
||||
}
|
||||
|
||||
bool diagonalIsCandidate(diag_t diag) const {
|
||||
VertexInfo *v1 = diag.first;
|
||||
VertexInfo *v2 = diag.second;
|
||||
return (inCone(v1, P(v2)) && inCone(v2, P(v1)));
|
||||
}
|
||||
|
||||
bool testDiagonal(diag_t diag) const {
|
||||
// test whether v1-v2 is a valid diagonal.
|
||||
VertexInfo *v1 = diag.first;
|
||||
VertexInfo *v2 = diag.second;
|
||||
geom2d::P2 v1p = P(v1);
|
||||
geom2d::P2 v2p = P(v2);
|
||||
|
||||
bool intersected = false;
|
||||
|
||||
for (VertexInfo *t = v1->next; !intersected && t != v1->prev; t = t->next) {
|
||||
VertexInfo *u = t->next;
|
||||
if (t == v2 || u == v2) continue;
|
||||
|
||||
geom2d::P2 tp = P(t);
|
||||
geom2d::P2 up = P(u);
|
||||
|
||||
double l_a1 = carve::geom2d::orient2d(v1p, v2p, tp);
|
||||
double l_a2 = carve::geom2d::orient2d(v1p, v2p, up);
|
||||
|
||||
double l_b1 = carve::geom2d::orient2d(tp, up, v1p);
|
||||
double l_b2 = carve::geom2d::orient2d(tp, up, v2p);
|
||||
|
||||
if (l_a1 > l_a2) std::swap(l_a1, l_a2);
|
||||
if (l_b1 > l_b2) std::swap(l_b1, l_b2);
|
||||
|
||||
if (l_a1 == 0.0 && l_a2 == 0.0 &&
|
||||
l_b1 == 0.0 && l_b2 == 0.0) {
|
||||
// colinear
|
||||
if (std::max(tp.x, up.x) >= std::min(v1p.x, v2p.x) && std::min(tp.x, up.x) <= std::max(v1p.x, v2p.x)) {
|
||||
// colinear and intersecting
|
||||
intersected = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (l_a2 <= 0.0 || l_a1 >= 0.0 || l_b2 <= 0.0 || l_b1 >= 0.0) {
|
||||
// no intersection
|
||||
continue;
|
||||
}
|
||||
|
||||
intersected = true;
|
||||
}
|
||||
|
||||
if (!intersected) {
|
||||
// test whether midpoint winding == 1
|
||||
|
||||
carve::geom2d::P2 mid = (v1p + v2p) / 2;
|
||||
if (windingNumber(v1, mid) == 1) {
|
||||
// this diagonal is ok
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find the vertex half way around the loop (rounds upwards).
|
||||
VertexInfo *findMidpoint(VertexInfo *vert) const {
|
||||
VertexInfo *v = vert;
|
||||
VertexInfo *r = vert;
|
||||
while (1) {
|
||||
r = r->next;
|
||||
v = v->next; if (v == vert) return r;
|
||||
v = v->next; if (v == vert) return r;
|
||||
}
|
||||
}
|
||||
|
||||
// Test all diagonals with a separation of a-b by walking both
|
||||
// pointers around the loop. In the case where a-b divides the
|
||||
// loop exactly in half, this will test each diagonal twice,
|
||||
// but avoiding this case is not worth the extra effort
|
||||
// required.
|
||||
diag_t scanDiagonals(VertexInfo *a, VertexInfo *b) const {
|
||||
VertexInfo *v1 = a;
|
||||
VertexInfo *v2 = b;
|
||||
|
||||
do {
|
||||
diag_t d(v1, v2);
|
||||
if (diagonalIsCandidate(d) && testDiagonal(d)) {
|
||||
return d;
|
||||
}
|
||||
v1 = v1->next;
|
||||
v2 = v2->next;
|
||||
} while (v1 != a);
|
||||
|
||||
return diag_t(NULL, NULL);
|
||||
}
|
||||
|
||||
diag_t scanAllDiagonals(VertexInfo *a) const {
|
||||
// Rationale: We want to find a diagonal that splits the
|
||||
// loop into two as evenly as possible, to reduce the number
|
||||
// of times that diagonal splitting is required. Start by
|
||||
// scanning all diagonals separated by loop_len / 2, then
|
||||
// decrease the separation until we find something.
|
||||
|
||||
// loops of length 2 or 3 have no possible diagonal.
|
||||
if (a->next == a || a->next->next == a) return diag_t(NULL, NULL);
|
||||
|
||||
VertexInfo *b = findMidpoint(a);
|
||||
while (b != a->next) {
|
||||
diag_t d = scanDiagonals(a, b);
|
||||
if (d != diag_t(NULL, NULL)) return d;
|
||||
b = b->prev;
|
||||
}
|
||||
|
||||
return diag_t(NULL, NULL);
|
||||
}
|
||||
|
||||
diag_t findDiagonal(VertexInfo *vert) const {
|
||||
return scanAllDiagonals(vert);
|
||||
}
|
||||
|
||||
diag_t findHighScoringDiagonal(VertexInfo *vert) const {
|
||||
typedef std::pair<double, diag_t> heap_entry_t;
|
||||
VertexInfo *v1, *v2;
|
||||
std::vector<heap_entry_t> heap;
|
||||
size_t loop_len = 0;
|
||||
|
||||
v1 = vert;
|
||||
do {
|
||||
++loop_len;
|
||||
v1 = v1->next;
|
||||
} while (v1 != vert);
|
||||
|
||||
v1 = vert;
|
||||
do {
|
||||
v2 = v1->next->next;
|
||||
size_t dist = 2;
|
||||
do {
|
||||
if (diagonalIsCandidate(diag_t(v1, v2))) {
|
||||
double score = std::min(dist, loop_len - dist);
|
||||
// double score = (v1->edge->vert->v - v2->edge->vert->v).length2();
|
||||
heap.push_back(heap_entry_t(score, diag_t(v1, v2)));
|
||||
}
|
||||
v2 = v2->next;
|
||||
++dist;
|
||||
} while (v2 != vert && v2 != v1->prev);
|
||||
v1 = v1->next;
|
||||
} while (v1->next->next != vert);
|
||||
|
||||
std::make_heap(heap.begin(), heap.end());
|
||||
|
||||
while (heap.size()) {
|
||||
std::pop_heap(heap.begin(), heap.end());
|
||||
heap_entry_t h = heap.back();
|
||||
heap.pop_back();
|
||||
|
||||
if (testDiagonal(h.second)) return h.second;
|
||||
}
|
||||
|
||||
// couldn't find a diagonal that was ok.
|
||||
return diag_t(NULL, NULL);
|
||||
}
|
||||
|
||||
void splitEdgeLoop(VertexInfo *v1, VertexInfo *v2) {
|
||||
VertexInfo *v1_copy = new VertexInfo(new Edge<ndim>(v1->edge->vert, NULL), v1->p);
|
||||
VertexInfo *v2_copy = new VertexInfo(new Edge<ndim>(v2->edge->vert, NULL), v2->p);
|
||||
|
||||
v1_copy->edge->rev = v2_copy->edge;
|
||||
v2_copy->edge->rev = v1_copy->edge;
|
||||
|
||||
v1_copy->edge->prev = v1->edge->prev;
|
||||
v1_copy->edge->next = v2->edge;
|
||||
|
||||
v2_copy->edge->prev = v2->edge->prev;
|
||||
v2_copy->edge->next = v1->edge;
|
||||
|
||||
v1->edge->prev->next = v1_copy->edge;
|
||||
v1->edge->prev = v2_copy->edge;
|
||||
|
||||
v2->edge->prev->next = v2_copy->edge;
|
||||
v2->edge->prev = v1_copy->edge;
|
||||
|
||||
v1_copy->prev = v1->prev;
|
||||
v1_copy->next = v2;
|
||||
|
||||
v2_copy->prev = v2->prev;
|
||||
v2_copy->next = v1;
|
||||
|
||||
v1->prev->next = v1_copy;
|
||||
v1->prev = v2_copy;
|
||||
|
||||
v2->prev->next = v2_copy;
|
||||
v2->prev = v1_copy;
|
||||
}
|
||||
|
||||
VertexInfo *findDegenerateEar(VertexInfo *edge) {
|
||||
VertexInfo *v = edge;
|
||||
|
||||
if (v->next == v || v->next->next == v) return NULL;
|
||||
|
||||
do {
|
||||
if (P(v) == P(v->next)) {
|
||||
return v;
|
||||
} else if (P(v) == P(v->next->next)) {
|
||||
if (P(v->next) == P(v->next->next->next)) {
|
||||
// a 'z' in the loop: z (a) b a b c -> remove a-b-a -> z (a) a b c -> remove a-a-b (next loop) -> z a b c
|
||||
// z --(a)-- b
|
||||
// /
|
||||
// /
|
||||
// a -- b -- d
|
||||
return v->next;
|
||||
} else {
|
||||
// a 'shard' in the loop: z (a) b a c d -> remove a-b-a -> z (a) a b c d -> remove a-a-b (next loop) -> z a b c d
|
||||
// z --(a)-- b
|
||||
// /
|
||||
// /
|
||||
// a -- c -- d
|
||||
// n.b. can only do this if the shard is pointing out of the polygon. i.e. b is outside z-a-c
|
||||
if (!carve::geom2d::internalToAngle(P(v->next->next->next), P(v), P(v->prev), P(v->next))) {
|
||||
return v->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
v = v->next;
|
||||
} while (v != edge);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Clip off a vertex at vert, producing a triangle (with appropriate rev pointers)
|
||||
template<typename out_iter_t>
|
||||
VertexInfo *clipEar(VertexInfo *vert, out_iter_t out) {
|
||||
CARVE_ASSERT(testForConvexVertex(vert->edge));
|
||||
|
||||
edge_t *p_edge = vert->edge->prev;
|
||||
edge_t *n_edge = vert->edge->next;
|
||||
|
||||
edge_t *p_copy = new edge_t(p_edge->vert, NULL);
|
||||
edge_t *n_copy = new edge_t(n_edge->vert, NULL);
|
||||
|
||||
n_copy->next = p_copy;
|
||||
n_copy->prev = vert->edge;
|
||||
|
||||
p_copy->next = vert->edge;
|
||||
p_copy->prev = n_copy;
|
||||
|
||||
vert->edge->next = n_copy;
|
||||
vert->edge->prev = p_copy;
|
||||
|
||||
p_edge->next = n_edge;
|
||||
n_edge->prev = p_edge;
|
||||
|
||||
if (p_edge->rev) {
|
||||
p_edge->rev->rev = p_copy;
|
||||
}
|
||||
p_copy->rev = p_edge->rev;
|
||||
|
||||
p_edge->rev = n_copy;
|
||||
n_copy->rev = p_edge;
|
||||
|
||||
*out++ = vert->edge;
|
||||
|
||||
if (vert->edge->face) {
|
||||
if (vert->edge->face->edge == vert->edge) {
|
||||
vert->edge->face->edge = n_edge;
|
||||
}
|
||||
vert->edge->face->n_edges--;
|
||||
vert->edge->face = NULL;
|
||||
}
|
||||
|
||||
vert->next->prev = vert->prev;
|
||||
vert->prev->next = vert->next;
|
||||
|
||||
VertexInfo *n = vert->next;
|
||||
delete vert;
|
||||
return n;
|
||||
}
|
||||
|
||||
template<typename out_iter_t>
|
||||
size_t removeDegeneracies(VertexInfo *&begin, out_iter_t out) {
|
||||
VertexInfo *v;
|
||||
size_t count = 0;
|
||||
|
||||
while ((v = findDegenerateEar(begin)) != NULL) {
|
||||
begin = clipEar(v, out);
|
||||
++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
template<typename out_iter_t>
|
||||
bool splitAndResume(VertexInfo *begin, out_iter_t out) {
|
||||
diag_t diag;
|
||||
|
||||
diag = findDiagonal(begin);
|
||||
if (diag == diag_t(NULL, NULL)) {
|
||||
std::cerr << "failed to find diagonal" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// add a splitting edge between v1 and v2.
|
||||
VertexInfo *v1 = diag.first;
|
||||
VertexInfo *v2 = diag.second;
|
||||
|
||||
splitEdgeLoop(v1, v2);
|
||||
|
||||
v1->recompute();
|
||||
v1->next->recompute();
|
||||
|
||||
v2->recompute();
|
||||
v2->next->recompute();
|
||||
|
||||
#if defined(CARVE_DEBUG)
|
||||
dumpPoly(v1->edge, v2->edge);
|
||||
#endif
|
||||
|
||||
#if defined(CARVE_DEBUG)
|
||||
CARVE_ASSERT(!checkSelfIntersection(v1));
|
||||
CARVE_ASSERT(!checkSelfIntersection(v2));
|
||||
#endif
|
||||
|
||||
bool r1 = doTriangulate(v1, out);
|
||||
bool r2 = doTriangulate(v2, out);
|
||||
|
||||
return r1 && r2;
|
||||
}
|
||||
|
||||
template<typename out_iter_t>
|
||||
bool doTriangulate(VertexInfo *begin, out_iter_t out);
|
||||
|
||||
TriangulationData(proj_t _proj) : proj(_proj) {
|
||||
}
|
||||
|
||||
VertexInfo *init(edge_t *begin) {
|
||||
edge_t *e = begin;
|
||||
VertexInfo *head = NULL, *tail = NULL, *v;
|
||||
do {
|
||||
VertexInfo *v = new VertexInfo(e, proj(e->vert->v));
|
||||
if (tail != NULL) {
|
||||
tail->next = v;
|
||||
v->prev = tail;
|
||||
} else {
|
||||
head = v;
|
||||
}
|
||||
tail = v;
|
||||
|
||||
e = e->next;
|
||||
} while (e != begin);
|
||||
tail->next = head;
|
||||
head->prev = tail;
|
||||
|
||||
v = head;
|
||||
do {
|
||||
v->recompute();
|
||||
v = v->next;
|
||||
} while (v != head);
|
||||
return head;
|
||||
}
|
||||
|
||||
class EarQueue {
|
||||
TriangulationData &data;
|
||||
std::vector<VertexInfo *> queue;
|
||||
|
||||
void checkheap() {
|
||||
#ifdef __GNUC__
|
||||
CARVE_ASSERT(std::__is_heap(queue.begin(), queue.end(), order_by_score()));
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
EarQueue(TriangulationData &_data) : data(_data), queue() {
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return queue.size();
|
||||
}
|
||||
|
||||
void push(VertexInfo *v) {
|
||||
#if defined(CARVE_DEBUG)
|
||||
checkheap();
|
||||
#endif
|
||||
queue.push_back(v);
|
||||
std::push_heap(queue.begin(), queue.end(), order_by_score());
|
||||
}
|
||||
|
||||
VertexInfo *pop() {
|
||||
#if defined(CARVE_DEBUG)
|
||||
checkheap();
|
||||
#endif
|
||||
std::pop_heap(queue.begin(), queue.end(), order_by_score());
|
||||
VertexInfo *v = queue.back();
|
||||
queue.pop_back();
|
||||
return v;
|
||||
}
|
||||
|
||||
void remove(VertexInfo *v) {
|
||||
#if defined(CARVE_DEBUG)
|
||||
checkheap();
|
||||
#endif
|
||||
CARVE_ASSERT(std::find(queue.begin(), queue.end(), v) != queue.end());
|
||||
double score = v->score;
|
||||
if (v != queue[0]) {
|
||||
v->score = queue[0]->score + 1;
|
||||
std::make_heap(queue.begin(), queue.end(), order_by_score());
|
||||
}
|
||||
CARVE_ASSERT(v == queue[0]);
|
||||
std::pop_heap(queue.begin(), queue.end(), order_by_score());
|
||||
CARVE_ASSERT(queue.back() == v);
|
||||
queue.pop_back();
|
||||
v->score = score;
|
||||
}
|
||||
|
||||
void changeScore(VertexInfo *v, double s_from, double s_to) {
|
||||
#if defined(CARVE_DEBUG)
|
||||
checkheap();
|
||||
#endif
|
||||
CARVE_ASSERT(std::find(queue.begin(), queue.end(), v) != queue.end());
|
||||
if (s_from != s_to) {
|
||||
v->score = s_to;
|
||||
std::make_heap(queue.begin(), queue.end(), order_by_score());
|
||||
}
|
||||
}
|
||||
|
||||
void update(VertexInfo *v) {
|
||||
VertexInfo pre = *v;
|
||||
v->recompute();
|
||||
VertexInfo post = *v;
|
||||
|
||||
if (pre.isCandidate()) {
|
||||
if (post.isCandidate()) {
|
||||
changeScore(v, pre.score, post.score);
|
||||
} else {
|
||||
remove(v);
|
||||
}
|
||||
} else {
|
||||
if (post.isCandidate()) {
|
||||
push(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
bool checkSelfIntersection(const VertexInfo *vert) {
|
||||
const VertexInfo *v1 = vert;
|
||||
do {
|
||||
const VertexInfo *v2 = vert->next->next;
|
||||
do {
|
||||
carve::geom2d::P2 a = v1->p;
|
||||
carve::geom2d::P2 b = v1->next->p;
|
||||
CARVE_ASSERT(a == proj(v1->edge->vert->v));
|
||||
CARVE_ASSERT(b == proj(v1->edge->next->vert->v));
|
||||
|
||||
carve::geom2d::P2 c = v2->p;
|
||||
carve::geom2d::P2 d = v2->next->p;
|
||||
CARVE_ASSERT(c == proj(v2->edge->vert->v));
|
||||
CARVE_ASSERT(d == proj(v2->edge->next->vert->v));
|
||||
|
||||
bool intersected = false;
|
||||
if (a == c || a == d || b == c || b == d) {
|
||||
} else {
|
||||
intersected = true;
|
||||
|
||||
double l_a1 = carve::geom2d::orient2d(a, b, c);
|
||||
double l_a2 = carve::geom2d::orient2d(a, b, d);
|
||||
if (l_a1 > l_a2) std::swap(l_a1, l_a2);
|
||||
if (l_a2 <= 0.0 || l_a1 >= 0.0) {
|
||||
intersected = false;
|
||||
}
|
||||
|
||||
double l_b1 = carve::geom2d::orient2d(c, d, a);
|
||||
double l_b2 = carve::geom2d::orient2d(c, d, b);
|
||||
if (l_b1 > l_b2) std::swap(l_b1, l_b2);
|
||||
if (l_b2 <= 0.0 || l_b1 >= 0.0) {
|
||||
intersected = false;
|
||||
}
|
||||
|
||||
if (l_a1 == 0.0 && l_a2 == 0.0 && l_b1 == 0.0 && l_b2 == 0.0) {
|
||||
if (std::max(a.x, b.x) >= std::min(c.x, d.x) && std::min(a.x, b.x) <= std::max(c.x, d.x)) {
|
||||
// colinear and intersecting.
|
||||
} else {
|
||||
// colinear but not intersecting.
|
||||
intersected = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (intersected) {
|
||||
carve::geom2d::P2 p[4] = { a, b, c, d };
|
||||
carve::geom::aabb<2> A(p, p+4);
|
||||
A.expand(5);
|
||||
|
||||
std::cerr << "\
|
||||
<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\
|
||||
<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n\
|
||||
<svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n\
|
||||
x=\"" << A.min().x << "px\" y=\"" << A.min().y << "\"\n\
|
||||
width=\"" << A.extent.x * 2 << "\" height=\"" << A.extent.y * 2 << "\"\n\
|
||||
viewBox=\"" << A.min().x << " " << A.min().y << " " << A.max().x << " " << A.max().y << "\"\n\
|
||||
enable-background=\"new " << A.min().x << " " << A.min().y << " " << A.max().x << " " << A.max().y << "\"\n\
|
||||
xml:space=\"preserve\">\n\
|
||||
<line fill=\"none\" stroke=\"#000000\" x1=\"" << a.x << "\" y1=\"" << a.y << "\" x2=\"" << b.x << "\" y2=\"" << b.y << "\"/>\n\
|
||||
<line fill=\"none\" stroke=\"#000000\" x1=\"" << c.x << "\" y1=\"" << c.y << "\" x2=\"" << d.x << "\" y2=\"" << d.y << "\"/>\n\
|
||||
</svg>\n";
|
||||
return true;
|
||||
}
|
||||
v2 = v2->next;
|
||||
} while (v2 != vert);
|
||||
v1 = v1->next;
|
||||
} while (v1 != vert);
|
||||
return false;
|
||||
}
|
||||
|
||||
carve::geom::aabb<2> make2d(const edge_t *edge, std::vector<geom2d::P2> &points) {
|
||||
const edge_t *e = edge;
|
||||
do {
|
||||
points.push_back(P(e));
|
||||
e = e->next;
|
||||
} while(e != edge);
|
||||
return carve::geom::aabb<2>(points.begin(), points.end());
|
||||
}
|
||||
|
||||
void dumpLoop(std::ostream &out,
|
||||
const std::vector<carve::geom2d::P2> &points,
|
||||
const char *fill,
|
||||
const char *stroke,
|
||||
double stroke_width,
|
||||
double offx,
|
||||
double offy,
|
||||
double scale
|
||||
) {
|
||||
out << "<polygon fill=\"" << fill << "\" stroke=\"" << stroke << "\" stroke-width=\"" << stroke_width << "\" points=\"";
|
||||
for (size_t i = 0; i < points.size(); ++i) {
|
||||
if (i) out << ' ';
|
||||
double x, y;
|
||||
x = scale * (points[i].x - offx) + 5;
|
||||
y = scale * (points[i].y - offy) + 5;
|
||||
out << x << ',' << y;
|
||||
}
|
||||
out << "\" />" << std::endl;
|
||||
}
|
||||
|
||||
void dumpPoly(const edge_t *edge, const edge_t *edge2 = NULL, const char *pfx = "poly_") {
|
||||
static int step = 0;
|
||||
std::ostringstream filename;
|
||||
filename << pfx << step++ << ".svg";
|
||||
std::cerr << "dumping to " << filename.str() << std::endl;
|
||||
std::ofstream out(filename.str().c_str());
|
||||
|
||||
std::vector <geom2d::P2> points, points2;
|
||||
|
||||
carve::geom::aabb<2> A = make2d(edge, points);
|
||||
if (edge2) {
|
||||
A.unionAABB(make2d(edge2, points2));
|
||||
}
|
||||
A.expand(5);
|
||||
|
||||
out << "\
|
||||
<?xml version=\"1.0\"?>\n\
|
||||
<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n\
|
||||
<svg\n\
|
||||
x=\"" << A.min().x << "px\" y=\"" << A.min().y << "\"\n\
|
||||
width=\"" << A.extent.x * 2 << "\" height=\"" << A.extent.y * 2 << "\"\n\
|
||||
viewBox=\"" << A.min().x << " " << A.min().y << " " << A.max().x << " " << A.max().y << "\"\n\
|
||||
enable-background=\"new " << A.min().x << " " << A.min().y << " " << A.max().x << " " << A.max().y << "\"\n\
|
||||
xml:space=\"preserve\">\n";
|
||||
|
||||
dumpLoop(out, points, "rgb(0,0,0)", "blue", 0.1, 0, 0, 1);
|
||||
if (points2.size()) dumpLoop(out, points2, "rgb(255,0,0)", "blue", 0.1, 0, 0, 1);
|
||||
|
||||
out << "</svg>" << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
template<unsigned ndim, typename proj_t>
|
||||
template<typename out_iter_t>
|
||||
bool TriangulationData<ndim, proj_t>::doTriangulate(VertexInfo *begin, out_iter_t out) {
|
||||
EarQueue vq(*this);
|
||||
|
||||
#if defined(CARVE_DEBUG)
|
||||
dumpPoly(begin->edge, NULL, "input_");
|
||||
CARVE_ASSERT(!checkSelfIntersection(begin));
|
||||
#endif
|
||||
|
||||
VertexInfo *v = begin, *n, *p;
|
||||
size_t remain = 0;
|
||||
do {
|
||||
if (v->isCandidate()) vq.push(v);
|
||||
v = v->next;
|
||||
remain++;
|
||||
} while (v != begin);
|
||||
|
||||
while (remain > 3 && vq.size()) {
|
||||
{ static int __c = 0; if (++__c % 50 == 0) { break; } }
|
||||
v = vq.pop();
|
||||
if (!v->isClipable()) {
|
||||
v->fail();
|
||||
continue;
|
||||
}
|
||||
|
||||
continue_clipping:
|
||||
n = clipEar(v, out);
|
||||
p = n->prev;
|
||||
begin = n;
|
||||
if (--remain == 3) break;
|
||||
// if (checkSelfIntersection(begin)) {
|
||||
// dumpPoly(begin->edge, NULL, "badclip_");
|
||||
// CARVE_ASSERT(!!!"clip created self intersection");
|
||||
// }
|
||||
|
||||
vq.update(n);
|
||||
vq.update(p);
|
||||
|
||||
if (n->score < p->score) { std::swap(n, p); }
|
||||
if (n->score > 0.25 && n->isCandidate() && n->isClipable()) {
|
||||
vq.remove(n);
|
||||
v = n;
|
||||
goto continue_clipping;
|
||||
}
|
||||
if (p->score > 0.25 && p->isCandidate() && p->isClipable()) {
|
||||
vq.remove(p);
|
||||
v = p;
|
||||
goto continue_clipping;
|
||||
}
|
||||
}
|
||||
|
||||
bool ret = false;
|
||||
|
||||
#if defined(CARVE_DEBUG)
|
||||
dumpPoly(begin->edge, NULL, "remainder_");
|
||||
#endif
|
||||
|
||||
if (remain > 3) {
|
||||
std::vector<carve::geom2d::P2> temp;
|
||||
temp.reserve(remain);
|
||||
VertexInfo *v = begin;
|
||||
do {
|
||||
temp.push_back(P(v));
|
||||
v = v->next;
|
||||
} while (v != begin);
|
||||
|
||||
if (carve::geom2d::signedArea(temp) == 0) {
|
||||
// XXX: this test will fail in cases where the boundary is
|
||||
// twisted so that a negative area balances a positive area.
|
||||
std::cerr << "got to here" << std::endl;
|
||||
dumpPoly(begin->edge, NULL, "interesting_case_");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (remain > 3) {
|
||||
remain -= removeDegeneracies(begin, out);
|
||||
}
|
||||
|
||||
if (remain > 3) {
|
||||
return splitAndResume(begin, out);
|
||||
}
|
||||
|
||||
{ double a = loopArea(begin->edge, proj); CARVE_ASSERT(a <= 0.0); }
|
||||
*out++ = begin->edge;
|
||||
|
||||
v = begin;
|
||||
do {
|
||||
n = v->next;
|
||||
delete v;
|
||||
v = n;
|
||||
} while (v != begin);
|
||||
|
||||
ret = true;
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<unsigned ndim, typename proj_t, typename out_iter_t>
|
||||
void triangulate(Edge<ndim> *edge, proj_t proj, out_iter_t out) {
|
||||
detail::TriangulationData<ndim, proj_t> triangulator(proj);
|
||||
typename detail::TriangulationData<ndim, proj_t>::VertexInfo *v = triangulator.init(edge);
|
||||
triangulator.removeDegeneracies(v, out);
|
||||
triangulator.doTriangulate(v, out);
|
||||
}
|
||||
|
||||
// given edge a-b, part of triangles a-b-c and b-a-d, make triangles c-a-d and b-c-d
|
||||
template<unsigned ndim>
|
||||
void flipTriEdge(Edge<ndim> *edge) {
|
||||
CARVE_ASSERT(edge->rev != NULL);
|
||||
CARVE_ASSERT(edge->face->nEdges() == 3);
|
||||
CARVE_ASSERT(edge->rev->face->nEdges() == 3);
|
||||
|
||||
CARVE_ASSERT(edge->prev != edge);
|
||||
CARVE_ASSERT(edge->next != edge);
|
||||
CARVE_ASSERT(edge->rev->prev != edge->rev);
|
||||
CARVE_ASSERT(edge->rev->next != edge->rev);
|
||||
|
||||
typedef Edge<ndim> edge_t;
|
||||
typedef Face<ndim> face_t;
|
||||
|
||||
edge_t *t1[3], *t2[3];
|
||||
face_t *f1, *f2;
|
||||
|
||||
t1[1] = edge; t2[1] = edge->rev;
|
||||
t1[0] = t1[1]->prev; t1[2] = t1[1]->next;
|
||||
t2[0] = t2[1]->prev; t2[2] = t2[1]->next;
|
||||
|
||||
f1 = t1[1]->face; f2 = t2[1]->face;
|
||||
|
||||
// std::cerr << t1[0]->vert << "->" << t1[1]->vert << "->" << t1[2]->vert << std::endl;
|
||||
// std::cerr << t2[0]->vert << "->" << t2[1]->vert << "->" << t2[2]->vert << std::endl;
|
||||
|
||||
t1[1]->vert = t2[0]->vert;
|
||||
t2[1]->vert = t1[0]->vert;
|
||||
|
||||
// std::cerr << t1[0]->vert << "->" << t2[2]->vert << "->" << t1[1]->vert << std::endl;
|
||||
// std::cerr << t2[0]->vert << "->" << t1[2]->vert << "->" << t2[1]->vert << std::endl;
|
||||
|
||||
detail::link(t1[0], t2[2], t1[1], f1);
|
||||
detail::link(t2[0], t1[2], t2[1], f2);
|
||||
|
||||
if (t1[0]->rev) CARVE_ASSERT(t1[0]->v2() == t1[0]->rev->v1());
|
||||
if (t2[0]->rev) CARVE_ASSERT(t2[0]->v2() == t2[0]->rev->v1());
|
||||
if (t1[2]->rev) CARVE_ASSERT(t1[2]->v2() == t1[2]->rev->v1());
|
||||
if (t2[2]->rev) CARVE_ASSERT(t2[2]->v2() == t2[2]->rev->v1());
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
void splitEdgeLoop(Edge<ndim> *v1, Edge<ndim> *v2) {
|
||||
// v1 and v2 end up on different sides of the split.
|
||||
Edge<ndim> *v1_copy = new Edge<ndim>(v1->vert, NULL);
|
||||
Edge<ndim> *v2_copy = new Edge<ndim>(v2->vert, NULL);
|
||||
|
||||
v1_copy->rev = v2_copy;
|
||||
v2_copy->rev = v1_copy;
|
||||
|
||||
v1_copy->prev = v1->prev;
|
||||
v1_copy->next = v2;
|
||||
|
||||
v2_copy->prev = v2->prev;
|
||||
v2_copy->next = v1;
|
||||
|
||||
v1->prev->next = v1_copy;
|
||||
v1->prev = v2_copy;
|
||||
|
||||
v2->prev->next = v2_copy;
|
||||
v2->prev = v1_copy;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
Edge<ndim> *clipVertex(Edge<ndim> *edge) {
|
||||
Edge<ndim> *prev = edge->prev;
|
||||
Edge<ndim> *next = edge->next;
|
||||
splitEdgeLoop(edge->prev, edge->next);
|
||||
return next;
|
||||
}
|
||||
}
|
||||
}
|
1574
extern/carve/include/carve/mesh_simplify.hpp
vendored
Normal file
1574
extern/carve/include/carve/mesh_simplify.hpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
193
extern/carve/include/carve/octree_decl.hpp
vendored
Normal file
193
extern/carve/include/carve/octree_decl.hpp
vendored
Normal file
@ -0,0 +1,193 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
|
||||
#include <carve/geom3d.hpp>
|
||||
#include <carve/aabb.hpp>
|
||||
|
||||
#include <carve/polyhedron_base.hpp>
|
||||
|
||||
namespace carve {
|
||||
|
||||
namespace csg {
|
||||
|
||||
const double SLACK_FACTOR=1.0009765625;
|
||||
const unsigned FACE_SPLIT_THRESHOLD=50U;
|
||||
const unsigned EDGE_SPLIT_THRESHOLD=50U;
|
||||
const unsigned POINT_SPLIT_THRESHOLD=20U;
|
||||
const unsigned MAX_SPLIT_DEPTH=32;
|
||||
|
||||
class Octree {
|
||||
|
||||
public:
|
||||
class Node {
|
||||
private:
|
||||
Node(const Node &node); // undefined.
|
||||
Node &operator=(const Node &node); // undefined.
|
||||
|
||||
public:
|
||||
Node *parent;
|
||||
Node *children[8];
|
||||
bool is_leaf;
|
||||
|
||||
carve::geom3d::Vector min;
|
||||
carve::geom3d::Vector max;
|
||||
|
||||
std::vector<const carve::poly::Geometry<3>::face_t *> faces;
|
||||
std::vector<const carve::poly::Geometry<3>::edge_t *> edges;
|
||||
std::vector<const carve::poly::Geometry<3>::vertex_t *> vertices;
|
||||
|
||||
carve::geom3d::AABB aabb;
|
||||
|
||||
Node();
|
||||
|
||||
Node(const carve::geom3d::Vector &newMin, const carve::geom3d::Vector &newMax);
|
||||
Node(Node *p, double x1, double y1, double z1, double x2, double y2, double z2);
|
||||
|
||||
~Node();
|
||||
|
||||
bool mightContain(const carve::poly::Geometry<3>::face_t &face);
|
||||
bool mightContain(const carve::poly::Geometry<3>::edge_t &edge);
|
||||
bool mightContain(const carve::poly::Geometry<3>::vertex_t &p);
|
||||
bool hasChildren();
|
||||
bool hasGeometry();
|
||||
|
||||
template <class T>
|
||||
void putInside(const T &input, Node *child, T &output);
|
||||
|
||||
bool split();
|
||||
};
|
||||
|
||||
|
||||
|
||||
Node *root;
|
||||
|
||||
|
||||
|
||||
struct no_filter {
|
||||
bool operator()(const carve::poly::Geometry<3>::edge_t *) { return true; }
|
||||
bool operator()(const carve::poly::Geometry<3>::face_t *) { return true; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
Octree();
|
||||
|
||||
~Octree();
|
||||
|
||||
|
||||
|
||||
void setBounds(const carve::geom3d::Vector &min, const carve::geom3d::Vector &max);
|
||||
void setBounds(carve::geom3d::AABB aabb);
|
||||
|
||||
|
||||
|
||||
void addEdges(const std::vector<carve::poly::Geometry<3>::edge_t > &edges);
|
||||
void addFaces(const std::vector<carve::poly::Geometry<3>::face_t > &faces);
|
||||
void addVertices(const std::vector<const carve::poly::Geometry<3>::vertex_t *> &vertices);
|
||||
|
||||
|
||||
|
||||
static carve::geom3d::AABB makeAABB(const Node *node);
|
||||
|
||||
|
||||
|
||||
void doFindEdges(const carve::geom::aabb<3> &aabb,
|
||||
Node *node,
|
||||
std::vector<const carve::poly::Geometry<3>::edge_t *> &out,
|
||||
unsigned depth) const;
|
||||
void doFindEdges(const carve::geom3d::LineSegment &l,
|
||||
Node *node,
|
||||
std::vector<const carve::poly::Geometry<3>::edge_t *> &out,
|
||||
unsigned depth) const;
|
||||
void doFindEdges(const carve::geom3d::Vector &v,
|
||||
Node *node,
|
||||
std::vector<const carve::poly::Geometry<3>::edge_t *> &out,
|
||||
unsigned depth) const;
|
||||
void doFindFaces(const carve::geom::aabb<3> &aabb,
|
||||
Node *node,
|
||||
std::vector<const carve::poly::Geometry<3>::face_t *> &out,
|
||||
unsigned depth) const;
|
||||
void doFindFaces(const carve::geom3d::LineSegment &l,
|
||||
Node *node,
|
||||
std::vector<const carve::poly::Geometry<3>::face_t *> &out,
|
||||
unsigned depth) const;
|
||||
|
||||
|
||||
|
||||
void doFindVerticesAllowDupes(const carve::geom3d::Vector &v,
|
||||
Node *node,
|
||||
std::vector<const carve::poly::Geometry<3>::vertex_t *> &out,
|
||||
unsigned depth) const;
|
||||
|
||||
void findVerticesNearAllowDupes(const carve::geom3d::Vector &v,
|
||||
std::vector<const carve::poly::Geometry<3>::vertex_t *> &out) const;
|
||||
|
||||
|
||||
|
||||
template<typename filter_t>
|
||||
void doFindEdges(const carve::poly::Geometry<3>::face_t &f, Node *node,
|
||||
std::vector<const carve::poly::Geometry<3>::edge_t *> &out,
|
||||
unsigned depth,
|
||||
filter_t filter) const;
|
||||
|
||||
template<typename filter_t>
|
||||
void findEdgesNear(const carve::poly::Geometry<3>::face_t &f,
|
||||
std::vector<const carve::poly::Geometry<3>::edge_t *> &out,
|
||||
filter_t filter) const;
|
||||
|
||||
void findEdgesNear(const carve::poly::Geometry<3>::face_t &f,
|
||||
std::vector<const carve::poly::Geometry<3>::edge_t *> &out) const {
|
||||
return findEdgesNear(f, out, no_filter());
|
||||
}
|
||||
|
||||
|
||||
|
||||
void findEdgesNear(const carve::geom::aabb<3> &aabb, std::vector<const carve::poly::Geometry<3>::edge_t *> &out) const;
|
||||
void findEdgesNear(const carve::geom3d::LineSegment &l, std::vector<const carve::poly::Geometry<3>::edge_t *> &out) const;
|
||||
void findEdgesNear(const carve::poly::Geometry<3>::edge_t &e, std::vector<const carve::poly::Geometry<3>::edge_t *> &out) const;
|
||||
void findEdgesNear(const carve::geom3d::Vector &v, std::vector<const carve::poly::Geometry<3>::edge_t *> &out) const;
|
||||
|
||||
|
||||
|
||||
void findFacesNear(const carve::geom::aabb<3> &aabb, std::vector<const carve::poly::Geometry<3>::face_t *> &out) const;
|
||||
void findFacesNear(const carve::geom3d::LineSegment &l, std::vector<const carve::poly::Geometry<3>::face_t *> &out) const;
|
||||
void findFacesNear(const carve::poly::Geometry<3>::edge_t &e, std::vector<const carve::poly::Geometry<3>::face_t *> &out) const;
|
||||
|
||||
|
||||
|
||||
static void doSplit(int maxSplit, Node *node);
|
||||
|
||||
|
||||
|
||||
template <typename FUNC>
|
||||
void doIterate(int level, Node *node, const FUNC &f) const;
|
||||
|
||||
template <typename FUNC>
|
||||
void iterateNodes(const FUNC &f) const;
|
||||
|
||||
|
||||
|
||||
void splitTree();
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
79
extern/carve/include/carve/octree_impl.hpp
vendored
Normal file
79
extern/carve/include/carve/octree_impl.hpp
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace carve {
|
||||
namespace csg {
|
||||
template<typename filter_t>
|
||||
void Octree::doFindEdges(const carve::poly::Geometry<3>::face_t &f,
|
||||
Node *node,
|
||||
std::vector<const carve::poly::Geometry<3>::edge_t *> &out,
|
||||
unsigned depth,
|
||||
filter_t filter) const {
|
||||
if (node == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node->aabb.intersects(f.aabb) && node->aabb.intersects(f.plane_eqn)) {
|
||||
if (node->hasChildren()) {
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
doFindEdges(f, node->children[i], out, depth + 1, filter);
|
||||
}
|
||||
} else {
|
||||
if (depth < MAX_SPLIT_DEPTH && node->edges.size() > EDGE_SPLIT_THRESHOLD) {
|
||||
if (!node->split()) {
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
doFindEdges(f, node->children[i], out, depth + 1, filter);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (std::vector<const carve::poly::Geometry<3>::edge_t*>::const_iterator it = node->edges.begin(), e = node->edges.end(); it != e; ++it) {
|
||||
if ((*it)->tag_once()) {
|
||||
if (filter(*it)) {
|
||||
out.push_back(*it);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename filter_t>
|
||||
void Octree::findEdgesNear(const carve::poly::Geometry<3>::face_t &f, std::vector<const carve::poly::Geometry<3>::edge_t *> &out, filter_t filter) const {
|
||||
tagable::tag_begin();
|
||||
doFindEdges(f, root, out, 0, filter);
|
||||
}
|
||||
|
||||
template <typename func_t>
|
||||
void Octree::doIterate(int level, Node *node, const func_t &f) const{
|
||||
f(level, node);
|
||||
if (node->hasChildren()) {
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
doIterate(level + 1, node->children[i], f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename func_t>
|
||||
void Octree::iterateNodes(const func_t &f) const {
|
||||
doIterate(0, root, f);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
24
extern/carve/include/carve/pointset.hpp
vendored
Normal file
24
extern/carve/include/carve/pointset.hpp
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
|
||||
#include <carve/pointset_decl.hpp>
|
||||
#include <carve/pointset_impl.hpp>
|
||||
#include <carve/pointset_iter.hpp>
|
61
extern/carve/include/carve/pointset_decl.hpp
vendored
Normal file
61
extern/carve/include/carve/pointset_decl.hpp
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iterator>
|
||||
#include <list>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
#include <carve/tag.hpp>
|
||||
#include <carve/geom.hpp>
|
||||
#include <carve/kd_node.hpp>
|
||||
#include <carve/geom3d.hpp>
|
||||
#include <carve/aabb.hpp>
|
||||
|
||||
namespace carve {
|
||||
namespace point {
|
||||
|
||||
struct Vertex : public tagable {
|
||||
carve::geom3d::Vector v;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct vec_adapt_vertex_ptr {
|
||||
const carve::geom3d::Vector &operator()(const Vertex * const &v) { return v->v; }
|
||||
carve::geom3d::Vector &operator()(Vertex *&v) { return v->v; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct PointSet {
|
||||
std::vector<Vertex> vertices;
|
||||
carve::geom3d::AABB aabb;
|
||||
|
||||
PointSet(const std::vector<carve::geom3d::Vector> &points);
|
||||
PointSet() {
|
||||
}
|
||||
|
||||
void sortVertices(const carve::geom3d::Vector &axis);
|
||||
|
||||
size_t vertexToIndex_fast(const Vertex *v) const;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
36
extern/carve/include/carve/pointset_impl.hpp
vendored
Normal file
36
extern/carve/include/carve/pointset_impl.hpp
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
#include <carve/tag.hpp>
|
||||
#include <carve/geom.hpp>
|
||||
#include <carve/kd_node.hpp>
|
||||
#include <carve/geom3d.hpp>
|
||||
#include <carve/aabb.hpp>
|
||||
|
||||
namespace carve {
|
||||
namespace point {
|
||||
|
||||
inline size_t PointSet::vertexToIndex_fast(const Vertex *v) const {
|
||||
return v - &vertices[0];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
18
extern/carve/include/carve/pointset_iter.hpp
vendored
Normal file
18
extern/carve/include/carve/pointset_iter.hpp
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
#pragma once
|
||||
|
24
extern/carve/include/carve/poly.hpp
vendored
Normal file
24
extern/carve/include/carve/poly.hpp
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
|
||||
#include <carve/poly_decl.hpp>
|
||||
|
||||
#include <carve/poly_impl.hpp>
|
25
extern/carve/include/carve/poly_decl.hpp
vendored
Normal file
25
extern/carve/include/carve/poly_decl.hpp
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
|
||||
#include <carve/vertex_decl.hpp>
|
||||
#include <carve/edge_decl.hpp>
|
||||
#include <carve/face_decl.hpp>
|
||||
#include <carve/polyhedron_decl.hpp>
|
25
extern/carve/include/carve/poly_impl.hpp
vendored
Normal file
25
extern/carve/include/carve/poly_impl.hpp
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
|
||||
#include <carve/vertex_impl.hpp>
|
||||
#include <carve/edge_impl.hpp>
|
||||
#include <carve/face_impl.hpp>
|
||||
#include <carve/polyhedron_impl.hpp>
|
149
extern/carve/include/carve/polyhedron_base.hpp
vendored
Normal file
149
extern/carve/include/carve/polyhedron_base.hpp
vendored
Normal file
@ -0,0 +1,149 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
|
||||
#include <carve/geom3d.hpp>
|
||||
|
||||
#include <carve/vertex_decl.hpp>
|
||||
#include <carve/edge_decl.hpp>
|
||||
#include <carve/face_decl.hpp>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace carve {
|
||||
namespace poly {
|
||||
|
||||
|
||||
|
||||
struct Object {
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename array_t>
|
||||
ptrdiff_t ptrToIndex_fast(const array_t &a, const typename array_t::value_type *v) {
|
||||
return v - &a[0];
|
||||
}
|
||||
|
||||
template<typename array_t>
|
||||
ptrdiff_t ptrToIndex(const array_t &a, const typename array_t::value_type *v) {
|
||||
if (v < &a.front() || v > &a.back()) return -1;
|
||||
return v - &a[0];
|
||||
}
|
||||
|
||||
|
||||
template<unsigned ndim>
|
||||
struct Geometry : public Object {
|
||||
struct Connectivity {
|
||||
} connectivity;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<>
|
||||
struct Geometry<2> : public Object {
|
||||
typedef Vertex<2> vertex_t;
|
||||
typedef Edge<2> edge_t;
|
||||
|
||||
struct Connectivity {
|
||||
std::vector<std::vector<const edge_t *> > vertex_to_edge;
|
||||
} connectivity;
|
||||
|
||||
std::vector<vertex_t> vertices;
|
||||
std::vector<edge_t> edges;
|
||||
|
||||
ptrdiff_t vertexToIndex_fast(const vertex_t *v) const { return ptrToIndex_fast(vertices, v); }
|
||||
ptrdiff_t vertexToIndex(const vertex_t *v) const { return ptrToIndex(vertices, v); }
|
||||
|
||||
ptrdiff_t edgeToIndex_fast(const edge_t *e) const { return ptrToIndex_fast(edges, e); }
|
||||
ptrdiff_t edgeToIndex(const edge_t *e) const { return ptrToIndex(edges, e); }
|
||||
|
||||
|
||||
|
||||
// *** connectivity queries
|
||||
|
||||
template<typename T>
|
||||
int vertexToEdges(const vertex_t *v, T result) const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<>
|
||||
struct Geometry<3> : public Object {
|
||||
typedef Vertex<3> vertex_t;
|
||||
typedef Edge<3> edge_t;
|
||||
typedef Face<3> face_t;
|
||||
|
||||
struct Connectivity {
|
||||
std::vector<std::vector<const edge_t *> > vertex_to_edge;
|
||||
std::vector<std::vector<const face_t *> > vertex_to_face;
|
||||
std::vector<std::vector<const face_t *> > edge_to_face;
|
||||
} connectivity;
|
||||
|
||||
std::vector<vertex_t> vertices;
|
||||
std::vector<edge_t> edges;
|
||||
std::vector<face_t> faces;
|
||||
|
||||
ptrdiff_t vertexToIndex_fast(const vertex_t *v) const { return ptrToIndex_fast(vertices, v); }
|
||||
ptrdiff_t vertexToIndex(const vertex_t *v) const { return ptrToIndex(vertices, v); }
|
||||
|
||||
ptrdiff_t edgeToIndex_fast(const edge_t *e) const { return ptrToIndex_fast(edges, e); }
|
||||
ptrdiff_t edgeToIndex(const edge_t *e) const { return ptrToIndex(edges, e); }
|
||||
|
||||
ptrdiff_t faceToIndex_fast(const face_t *f) const { return ptrToIndex_fast(faces, f); }
|
||||
ptrdiff_t faceToIndex(const face_t *f) const { return ptrToIndex(faces, f); }
|
||||
|
||||
template<typename order_t>
|
||||
bool orderVertices(order_t order);
|
||||
|
||||
bool orderVertices() { return orderVertices(std::less<vertex_t::vector_t>()); }
|
||||
|
||||
|
||||
|
||||
// *** connectivity queries
|
||||
|
||||
const face_t *connectedFace(const face_t *, const edge_t *) const;
|
||||
|
||||
template<typename T>
|
||||
int _faceNeighbourhood(const face_t *f, int depth, T *result) const;
|
||||
|
||||
template<typename T>
|
||||
int faceNeighbourhood(const face_t *f, int depth, T result) const;
|
||||
|
||||
template<typename T>
|
||||
int faceNeighbourhood(const edge_t *e, int m_id, int depth, T result) const;
|
||||
|
||||
template<typename T>
|
||||
int faceNeighbourhood(const vertex_t *v, int m_id, int depth, T result) const;
|
||||
|
||||
template<typename T>
|
||||
int vertexToEdges(const vertex_t *v, T result) const;
|
||||
|
||||
template<typename T>
|
||||
int edgeToFaces(const edge_t *e, T result) const;
|
||||
|
||||
template<typename T>
|
||||
int vertexToFaces(const vertex_t *v, T result) const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
184
extern/carve/include/carve/polyhedron_decl.hpp
vendored
Normal file
184
extern/carve/include/carve/polyhedron_decl.hpp
vendored
Normal file
@ -0,0 +1,184 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
|
||||
#include <carve/geom3d.hpp>
|
||||
|
||||
#include <carve/polyhedron_base.hpp>
|
||||
#include <carve/octree_decl.hpp>
|
||||
#include <carve/collection_types.hpp>
|
||||
|
||||
#include <assert.h>
|
||||
#include <list>
|
||||
|
||||
|
||||
namespace carve {
|
||||
namespace mesh {
|
||||
template<unsigned ndim>
|
||||
class MeshSet;
|
||||
}
|
||||
|
||||
namespace poly {
|
||||
class Polyhedron;
|
||||
}
|
||||
|
||||
poly::Polyhedron *polyhedronFromMesh(const mesh::MeshSet<3> *, int);
|
||||
|
||||
namespace poly {
|
||||
|
||||
class Polyhedron : public Geometry<3> {
|
||||
private:
|
||||
friend Polyhedron *carve::polyhedronFromMesh(const mesh::MeshSet<3> *, int);
|
||||
|
||||
Polyhedron() {
|
||||
}
|
||||
|
||||
Polyhedron &operator=(const Polyhedron &); // not implemented
|
||||
|
||||
// *** initialization
|
||||
|
||||
bool initSpatialIndex();
|
||||
void initVertexConnectivity();
|
||||
void setFaceAndVertexOwner();
|
||||
|
||||
bool initConnectivity();
|
||||
bool markManifolds();
|
||||
bool calcManifoldEmbedding();
|
||||
|
||||
bool init();
|
||||
void faceRecalc();
|
||||
|
||||
void commonFaceInit(bool _recalc);
|
||||
|
||||
public:
|
||||
static void collectFaceVertices(std::vector<face_t > &faces,
|
||||
std::vector<vertex_t > &vertices,
|
||||
std::unordered_map<const vertex_t *, const vertex_t *> &vmap);
|
||||
|
||||
static void collectFaceVertices(std::vector<face_t > &faces,
|
||||
std::vector<vertex_t > &vertices);
|
||||
|
||||
std::vector<bool> manifold_is_closed;
|
||||
std::vector<bool> manifold_is_negative;
|
||||
|
||||
carve::geom3d::AABB aabb;
|
||||
carve::csg::Octree octree;
|
||||
|
||||
|
||||
|
||||
// *** construction of Polyhedron objects
|
||||
|
||||
Polyhedron(const Polyhedron &);
|
||||
|
||||
// copy a single manifold
|
||||
Polyhedron(const Polyhedron &, int m_id);
|
||||
|
||||
// copy a subset of manifolds
|
||||
Polyhedron(const Polyhedron &, const std::vector<bool> &selected_manifolds);
|
||||
|
||||
Polyhedron(std::vector<face_t > &_faces,
|
||||
std::vector<vertex_t > &_vertices,
|
||||
bool _recalc = false);
|
||||
|
||||
Polyhedron(std::vector<face_t > &_faces,
|
||||
bool _recalc = false);
|
||||
|
||||
Polyhedron(std::list<face_t > &_faces,
|
||||
bool _recalc = false);
|
||||
|
||||
Polyhedron(const std::vector<carve::geom3d::Vector> &vertices,
|
||||
int n_faces,
|
||||
const std::vector<int> &face_indices);
|
||||
|
||||
~Polyhedron();
|
||||
|
||||
|
||||
|
||||
// *** containment queries
|
||||
|
||||
void testVertexAgainstClosedManifolds(const carve::geom3d::Vector &v,
|
||||
std::map<int, PointClass> &result,
|
||||
bool ignore_orentation) const;
|
||||
|
||||
PointClass containsVertex(const carve::geom3d::Vector &v,
|
||||
const face_t **hit_face = NULL,
|
||||
bool even_odd = false,
|
||||
int manifold_id = -1) const;
|
||||
|
||||
|
||||
|
||||
// *** locality queries
|
||||
|
||||
void findEdgesNear(const carve::geom::aabb<3> &aabb, std::vector<const edge_t *> &edges) const;
|
||||
void findEdgesNear(const carve::geom3d::LineSegment &l, std::vector<const edge_t *> &edges) const;
|
||||
void findEdgesNear(const carve::geom3d::Vector &v, std::vector<const edge_t *> &edges) const;
|
||||
void findEdgesNear(const face_t &face, std::vector<const edge_t *> &edges) const;
|
||||
void findEdgesNear(const edge_t &edge, std::vector<const edge_t *> &edges) const;
|
||||
|
||||
void findFacesNear(const carve::geom::aabb<3> &aabb, std::vector<const face_t *> &faces) const;
|
||||
void findFacesNear(const carve::geom3d::LineSegment &l, std::vector<const face_t *> &faces) const;
|
||||
void findFacesNear(const edge_t &edge, std::vector<const face_t *> &faces) const;
|
||||
|
||||
|
||||
|
||||
// *** manifold queries
|
||||
|
||||
inline bool vertexOnManifold(const vertex_t *v, int m_id) const;
|
||||
inline bool edgeOnManifold(const edge_t *e, int m_id) const;
|
||||
|
||||
template<typename T>
|
||||
int vertexManifolds(const vertex_t *v, T result) const;
|
||||
|
||||
template<typename T>
|
||||
int edgeManifolds(const edge_t *e, T result) const;
|
||||
|
||||
size_t manifoldCount() const;
|
||||
|
||||
bool hasOpenManifolds() const;
|
||||
|
||||
|
||||
|
||||
|
||||
// *** transformation
|
||||
|
||||
// flip face directions
|
||||
void invertAll();
|
||||
void invert(const std::vector<bool> &selected_manifolds);
|
||||
|
||||
void invert(int m_id);
|
||||
void invert();
|
||||
|
||||
// matrix transform of vertices
|
||||
void transform(const carve::math::Matrix &xform);
|
||||
|
||||
// arbitrary function transform of vertices
|
||||
template<typename T>
|
||||
void transform(const T &xform);
|
||||
|
||||
void print(std::ostream &) const;
|
||||
|
||||
void canonicalize();
|
||||
};
|
||||
|
||||
std::ostream &operator<<(std::ostream &, const Polyhedron &);
|
||||
|
||||
}
|
||||
|
||||
}
|
287
extern/carve/include/carve/polyhedron_impl.hpp
vendored
Normal file
287
extern/carve/include/carve/polyhedron_impl.hpp
vendored
Normal file
@ -0,0 +1,287 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/timing.hpp>
|
||||
|
||||
#include <assert.h>
|
||||
#include <list>
|
||||
|
||||
namespace carve {
|
||||
namespace poly {
|
||||
|
||||
|
||||
|
||||
template<typename order_t>
|
||||
struct VPtrSort {
|
||||
order_t order;
|
||||
|
||||
VPtrSort(const order_t &_order) : order(_order) {}
|
||||
bool operator()(carve::poly::Polyhedron::vertex_t const *a,
|
||||
carve::poly::Polyhedron::vertex_t const *b) const {
|
||||
return order(a->v, b->v);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename order_t>
|
||||
bool Geometry<3>::orderVertices(order_t order) {
|
||||
static carve::TimingName FUNC_NAME("Geometry<3>::orderVertices()");
|
||||
carve::TimingBlock block(FUNC_NAME);
|
||||
|
||||
std::vector<vertex_t *> vptr;
|
||||
std::vector<vertex_t *> vmap;
|
||||
std::vector<vertex_t> vout;
|
||||
const size_t N = vertices.size();
|
||||
|
||||
vptr.reserve(N);
|
||||
vout.reserve(N);
|
||||
vmap.resize(N);
|
||||
|
||||
for (size_t i = 0; i != N; ++i) {
|
||||
vptr.push_back(&vertices[i]);
|
||||
}
|
||||
std::sort(vptr.begin(), vptr.end(), VPtrSort<order_t>(order));
|
||||
|
||||
for (size_t i = 0; i != N; ++i) {
|
||||
vout.push_back(*vptr[i]);
|
||||
vmap[vertexToIndex_fast(vptr[i])] = &vout[i];
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < faces.size(); ++i) {
|
||||
face_t &f = faces[i];
|
||||
for (size_t j = 0; j < f.nVertices(); ++j) {
|
||||
f.vertex(j) = vmap[vertexToIndex_fast(f.vertex(j))];
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < edges.size(); ++i) {
|
||||
edges[i].v1 = vmap[vertexToIndex_fast(edges[i].v1)];
|
||||
edges[i].v2 = vmap[vertexToIndex_fast(edges[i].v2)];
|
||||
}
|
||||
|
||||
vout.swap(vertices);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
int Geometry<3>::_faceNeighbourhood(const face_t *f, int depth, T *result) const {
|
||||
if (depth < 0 || f->is_tagged()) return 0;
|
||||
|
||||
f->tag();
|
||||
*(*result)++ = f;
|
||||
|
||||
int r = 1;
|
||||
for (size_t i = 0; i < f->edges.size(); ++i) {
|
||||
const std::vector<const face_t *> &edge_faces = connectivity.edge_to_face[edgeToIndex_fast(f->edges[i])];
|
||||
const face_t *f2 = connectedFace(f, f->edges[i]);
|
||||
if (f2) {
|
||||
r += _faceNeighbourhood(f2, depth - 1, (*result));
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
int Geometry<3>::faceNeighbourhood(const face_t *f, int depth, T result) const {
|
||||
tagable::tag_begin();
|
||||
|
||||
return _faceNeighbourhood(f, depth, &result);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
int Geometry<3>::faceNeighbourhood(const edge_t *e, int m_id, int depth, T result) const {
|
||||
tagable::tag_begin();
|
||||
|
||||
int r = 0;
|
||||
const std::vector<const face_t *> &edge_faces = connectivity.edge_to_face[edgeToIndex_fast(e)];
|
||||
for (size_t i = 0; i < edge_faces.size(); ++i) {
|
||||
face_t *f = edge_faces[i];
|
||||
if (f && f->manifold_id == m_id) { r += _faceNeighbourhood(f, depth, &result); }
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
int Geometry<3>::faceNeighbourhood(const vertex_t *v, int m_id, int depth, T result) const {
|
||||
tagable::tag_begin();
|
||||
|
||||
int r = 0;
|
||||
const std::vector<const face_t *> &vertex_faces = connectivity.vertex_to_face[vertexToIndex_fast(v)];
|
||||
for (size_t i = 0; i < vertex_faces.size(); ++i) {
|
||||
face_t *f = vertex_faces[i];
|
||||
if (f && f->manifold_id == m_id) { r += _faceNeighbourhood(f, depth, &result); }
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// accessing connectivity information.
|
||||
template<typename T>
|
||||
int Geometry<3>::vertexToEdges(const vertex_t *v, T result) const {
|
||||
std::vector<const edge_t *> &e = connectivity.vertex_to_edge[vertexToIndex_fast(v)];
|
||||
std::copy(e.begin(), e.end(), result);
|
||||
return e.size();
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
int Geometry<3>::vertexToFaces(const vertex_t *v, T result) const {
|
||||
const std::vector<const face_t *> &vertex_faces = connectivity.vertex_to_face[vertexToIndex_fast(v)];
|
||||
int c = 0;
|
||||
for (size_t i = 0; i < vertex_faces.size(); ++i) {
|
||||
*result++ = vertex_faces[i]; ++c;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
int Geometry<3>::edgeToFaces(const edge_t *e, T result) const {
|
||||
const std::vector<const face_t *> &edge_faces = connectivity.edge_to_face[edgeToIndex_fast(e)];
|
||||
int c = 0;
|
||||
for (size_t i = 0; i < edge_faces.size(); ++i) {
|
||||
if (edge_faces[i] != NULL) { *result++ = edge_faces[i]; ++c; }
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline const Geometry<3>::face_t *Geometry<3>::connectedFace(const face_t *f, const edge_t *e) const {
|
||||
const std::vector<const face_t *> &edge_faces = connectivity.edge_to_face[edgeToIndex_fast(e)];
|
||||
for (size_t i = 0; i < (edge_faces.size() & ~1U); i++) {
|
||||
if (edge_faces[i] == f) return edge_faces[i^1];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline void Polyhedron::invert(int m_id) {
|
||||
std::vector<bool> selected_manifolds(manifold_is_closed.size(), false);
|
||||
if (m_id >=0 && (unsigned)m_id < selected_manifolds.size()) selected_manifolds[m_id] = true;
|
||||
invert(selected_manifolds);
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline void Polyhedron::invert() {
|
||||
invertAll();
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline bool Polyhedron::edgeOnManifold(const edge_t *e, int m_id) const {
|
||||
const std::vector<const face_t *> &edge_faces = connectivity.edge_to_face[edgeToIndex_fast(e)];
|
||||
|
||||
for (size_t i = 0; i < edge_faces.size(); ++i) {
|
||||
if (edge_faces[i] && edge_faces[i]->manifold_id == m_id) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool Polyhedron::vertexOnManifold(const vertex_t *v, int m_id) const {
|
||||
const std::vector<const face_t *> &f = connectivity.vertex_to_face[vertexToIndex_fast(v)];
|
||||
|
||||
for (size_t i = 0; i < f.size(); ++i) {
|
||||
if (f[i]->manifold_id == m_id) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
int Polyhedron::edgeManifolds(const edge_t *e, T result) const {
|
||||
const std::vector<const face_t *> &edge_faces = connectivity.edge_to_face[edgeToIndex_fast(e)];
|
||||
|
||||
for (size_t i = 0; i < (edge_faces.size() & ~1U); i += 2) {
|
||||
const face_t *f1 = edge_faces[i];
|
||||
const face_t *f2 = edge_faces[i+1];
|
||||
assert (f1 || f2);
|
||||
if (f1)
|
||||
*result++ = f1->manifold_id;
|
||||
else if (f2)
|
||||
*result++ = f2->manifold_id;
|
||||
}
|
||||
return edge_faces.size() >> 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
int Polyhedron::vertexManifolds(const vertex_t *v, T result) const {
|
||||
const std::vector<const face_t *> &f = connectivity.vertex_to_face[vertexToIndex_fast(v)];
|
||||
std::set<int> em;
|
||||
|
||||
for (size_t i = 0; i < f.size(); ++i) {
|
||||
em.insert(f[i]->manifold_id);
|
||||
}
|
||||
|
||||
std::copy(em.begin(), em.end(), result);
|
||||
return em.size();
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
void Polyhedron::transform(const T &xform) {
|
||||
for (size_t i = 0; i < vertices.size(); i++) {
|
||||
vertices[i].v = xform(vertices[i].v);
|
||||
}
|
||||
faceRecalc();
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline size_t Polyhedron::manifoldCount() const {
|
||||
return manifold_is_closed.size();
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline bool Polyhedron::hasOpenManifolds() const {
|
||||
for (size_t i = 0; i < manifold_is_closed.size(); ++i) {
|
||||
if (!manifold_is_closed[i]) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &o, const Polyhedron &p) {
|
||||
p.print(o);
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
24
extern/carve/include/carve/polyline.hpp
vendored
Normal file
24
extern/carve/include/carve/polyline.hpp
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
|
||||
#include <carve/polyline_decl.hpp>
|
||||
#include <carve/polyline_impl.hpp>
|
||||
#include <carve/polyline_iter.hpp>
|
151
extern/carve/include/carve/polyline_decl.hpp
vendored
Normal file
151
extern/carve/include/carve/polyline_decl.hpp
vendored
Normal file
@ -0,0 +1,151 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iterator>
|
||||
#include <list>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
#include <carve/tag.hpp>
|
||||
#include <carve/geom.hpp>
|
||||
#include <carve/kd_node.hpp>
|
||||
#include <carve/geom3d.hpp>
|
||||
#include <carve/aabb.hpp>
|
||||
|
||||
namespace carve {
|
||||
namespace line {
|
||||
|
||||
struct PolylineEdge;
|
||||
struct Polyline;
|
||||
struct polyline_vertex_const_iter;
|
||||
struct polyline_vertex_iter;
|
||||
struct polyline_edge_const_iter;
|
||||
struct polyline_edge_iter;
|
||||
|
||||
|
||||
|
||||
struct Vertex : public tagable {
|
||||
carve::geom3d::Vector v;
|
||||
std::list<std::pair<PolylineEdge *, PolylineEdge *> > edge_pairs;
|
||||
|
||||
void addEdgePair(PolylineEdge *in, PolylineEdge *out) {
|
||||
edge_pairs.push_back(std::make_pair(in, out));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct vec_adapt_vertex_ptr {
|
||||
const carve::geom3d::Vector &operator()(const Vertex * const &v) { return v->v; }
|
||||
carve::geom3d::Vector &operator()(Vertex *&v) { return v->v; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct PolylineEdge : public tagable {
|
||||
Polyline *parent;
|
||||
unsigned edgenum;
|
||||
Vertex *v1, *v2;
|
||||
|
||||
PolylineEdge(Polyline *_parent, int _edgenum, Vertex *_v1, Vertex *_v2);
|
||||
|
||||
carve::geom3d::AABB aabb() const;
|
||||
|
||||
inline PolylineEdge *prevEdge() const;
|
||||
inline PolylineEdge *nextEdge() const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct Polyline {
|
||||
bool closed;
|
||||
std::vector<PolylineEdge *> edges;
|
||||
|
||||
Polyline();
|
||||
|
||||
size_t vertexCount() const;
|
||||
|
||||
size_t edgeCount() const;
|
||||
|
||||
const PolylineEdge *edge(size_t e) const;
|
||||
|
||||
PolylineEdge *edge(size_t e);
|
||||
|
||||
const Vertex *vertex(size_t v) const;
|
||||
|
||||
Vertex *vertex(size_t v);
|
||||
|
||||
bool isClosed() const;
|
||||
|
||||
polyline_vertex_const_iter vbegin() const;
|
||||
polyline_vertex_const_iter vend() const;
|
||||
polyline_vertex_iter vbegin();
|
||||
polyline_vertex_iter vend();
|
||||
|
||||
polyline_edge_const_iter ebegin() const;
|
||||
polyline_edge_const_iter eend() const;
|
||||
polyline_edge_iter ebegin();
|
||||
polyline_edge_iter eend();
|
||||
|
||||
carve::geom3d::AABB aabb() const;
|
||||
|
||||
template<typename iter_t>
|
||||
void _init(bool c, iter_t begin, iter_t end, std::vector<Vertex> &vertices);
|
||||
|
||||
template<typename iter_t>
|
||||
void _init(bool closed, iter_t begin, iter_t end, std::vector<Vertex> &vertices, std::forward_iterator_tag);
|
||||
|
||||
template<typename iter_t>
|
||||
void _init(bool closed, iter_t begin, iter_t end, std::vector<Vertex> &vertices, std::random_access_iterator_tag);
|
||||
|
||||
template<typename iter_t>
|
||||
Polyline(bool closed, iter_t begin, iter_t end, std::vector<Vertex> &vertices);
|
||||
|
||||
~Polyline() {
|
||||
for (size_t i = 0; i < edges.size(); ++i) {
|
||||
delete edges[i];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct PolylineSet {
|
||||
typedef std::list<Polyline *> line_list;
|
||||
typedef line_list::iterator line_iter;
|
||||
typedef line_list::const_iterator const_line_iter;
|
||||
|
||||
std::vector<Vertex> vertices;
|
||||
line_list lines;
|
||||
carve::geom3d::AABB aabb;
|
||||
|
||||
PolylineSet(const std::vector<carve::geom3d::Vector> &points);
|
||||
PolylineSet() {
|
||||
}
|
||||
|
||||
template<typename iter_t>
|
||||
void addPolyline(bool closed, iter_t begin, iter_t end);
|
||||
|
||||
void sortVertices(const carve::geom3d::Vector &axis);
|
||||
|
||||
size_t vertexToIndex_fast(const Vertex *v) const;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
160
extern/carve/include/carve/polyline_impl.hpp
vendored
Normal file
160
extern/carve/include/carve/polyline_impl.hpp
vendored
Normal file
@ -0,0 +1,160 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace carve {
|
||||
namespace line {
|
||||
|
||||
inline PolylineEdge::PolylineEdge(Polyline *_parent, int _edgenum, Vertex *_v1, Vertex *_v2) :
|
||||
tagable(), parent(_parent), edgenum(_edgenum), v1(_v1), v2(_v2) {
|
||||
}
|
||||
|
||||
inline carve::geom3d::AABB PolylineEdge::aabb() const {
|
||||
carve::geom3d::AABB a;
|
||||
a.fit(v1->v, v2->v);
|
||||
return a;
|
||||
}
|
||||
|
||||
inline PolylineEdge *PolylineEdge::prevEdge() const {
|
||||
if (edgenum) {
|
||||
return parent->edge(edgenum - 1);
|
||||
} else {
|
||||
if (parent->closed) {
|
||||
return parent->edge(parent->edgeCount() - 1);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline PolylineEdge *PolylineEdge::nextEdge() const {
|
||||
if (edgenum + 1 < parent->edgeCount()) {
|
||||
return parent->edge(edgenum + 1);
|
||||
} else {
|
||||
if (parent->closed) {
|
||||
return parent->edge(0);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline Polyline::Polyline() : edges() {
|
||||
}
|
||||
|
||||
inline size_t Polyline::vertexCount() const {
|
||||
return edgeCount() + (closed ? 0 : 1);
|
||||
}
|
||||
|
||||
inline size_t Polyline::edgeCount() const {
|
||||
return edges.size();
|
||||
}
|
||||
|
||||
inline const PolylineEdge *Polyline::edge(size_t e) const {
|
||||
return edges[e % edges.size()];
|
||||
}
|
||||
|
||||
inline PolylineEdge *Polyline::edge(size_t e) {
|
||||
return edges[e % edges.size()];
|
||||
}
|
||||
|
||||
inline const Vertex *Polyline::vertex(size_t v) const {
|
||||
if (closed) {
|
||||
v %= edgeCount();
|
||||
} else if (v >= edgeCount()) {
|
||||
return v == edgeCount() ? edges.back()->v2 : NULL;
|
||||
}
|
||||
return edges[v]->v1;
|
||||
}
|
||||
|
||||
inline Vertex *Polyline::vertex(size_t v) {
|
||||
if (closed) {
|
||||
v %= edgeCount();
|
||||
} else if (v >= edgeCount()) {
|
||||
return v == edgeCount() ? edges.back()->v2 : NULL;
|
||||
}
|
||||
return edges[v]->v1;
|
||||
}
|
||||
|
||||
inline bool Polyline::isClosed() const {
|
||||
return closed;
|
||||
}
|
||||
|
||||
template<typename iter_t>
|
||||
void Polyline::_init(bool c, iter_t begin, iter_t end, std::vector<Vertex> &vertices) {
|
||||
closed = c;
|
||||
|
||||
PolylineEdge *e;
|
||||
if (begin == end) return;
|
||||
size_t v1 = (int)*begin++;
|
||||
if (begin == end) return;
|
||||
|
||||
while (begin != end) {
|
||||
size_t v2 = (int)*begin++;
|
||||
e = new PolylineEdge(this, edges.size(), &vertices[v1], &vertices[v2]);
|
||||
edges.push_back(e);
|
||||
v1 = v2;
|
||||
}
|
||||
|
||||
if (closed) {
|
||||
e = new PolylineEdge(this, edges.size(), edges.back()->v2, edges.front()->v1);
|
||||
edges.push_back(e);
|
||||
|
||||
edges.front()->v1->addEdgePair(edges.back(), edges.front());
|
||||
for (size_t i = 1; i < edges.size(); ++i) {
|
||||
edges[i]->v1->addEdgePair(edges[i-1], edges[i]);
|
||||
}
|
||||
} else {
|
||||
edges.front()->v1->addEdgePair(NULL, edges.front());
|
||||
for (size_t i = 1; i < edges.size(); ++i) {
|
||||
edges[i]->v1->addEdgePair(edges[i-1], edges[i]);
|
||||
}
|
||||
edges.back()->v2->addEdgePair(edges.back(), NULL);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename iter_t>
|
||||
void Polyline::_init(bool closed, iter_t begin, iter_t end, std::vector<Vertex> &vertices, std::forward_iterator_tag) {
|
||||
_init(closed, begin, end, vertices);
|
||||
}
|
||||
|
||||
template<typename iter_t>
|
||||
void Polyline::_init(bool closed, iter_t begin, iter_t end, std::vector<Vertex> &vertices, std::random_access_iterator_tag) {
|
||||
edges.reserve(end - begin - (closed ? 0 : 1));
|
||||
_init(closed, begin, end, vertices);
|
||||
}
|
||||
|
||||
template<typename iter_t>
|
||||
Polyline::Polyline(bool closed, iter_t begin, iter_t end, std::vector<Vertex> &vertices) {
|
||||
_init(closed, begin, end, vertices, typename std::iterator_traits<iter_t>::iterator_category());
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename iter_t>
|
||||
void PolylineSet::addPolyline(bool closed, iter_t begin, iter_t end) {
|
||||
Polyline *p = new Polyline(closed, begin, end, vertices);
|
||||
lines.push_back(p);
|
||||
}
|
||||
|
||||
inline size_t PolylineSet::vertexToIndex_fast(const Vertex *v) const {
|
||||
return v - &vertices[0];
|
||||
}
|
||||
}
|
||||
}
|
199
extern/carve/include/carve/polyline_iter.hpp
vendored
Normal file
199
extern/carve/include/carve/polyline_iter.hpp
vendored
Normal file
@ -0,0 +1,199 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iterator>
|
||||
#include <list>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <cstddef>
|
||||
|
||||
#include <carve/polyline_decl.hpp>
|
||||
|
||||
namespace carve {
|
||||
namespace line {
|
||||
|
||||
struct polyline_vertex_iter : public std::iterator<std::random_access_iterator_tag, Vertex *> {
|
||||
Polyline *base;
|
||||
size_t idx;
|
||||
|
||||
polyline_vertex_iter(Polyline *_base) : base(_base), idx(0) {
|
||||
}
|
||||
|
||||
polyline_vertex_iter(Polyline *_base, size_t _idx) : base(_base), idx(_idx) {
|
||||
}
|
||||
|
||||
polyline_vertex_iter operator++(int) { return polyline_vertex_iter(base, idx++); }
|
||||
polyline_vertex_iter &operator++() { ++idx; return *this; }
|
||||
polyline_vertex_iter &operator+=(int v) { idx += v; return *this; }
|
||||
|
||||
polyline_vertex_iter operator--(int) { return polyline_vertex_iter(base, idx--); }
|
||||
polyline_vertex_iter &operator--() { --idx; return *this; }
|
||||
polyline_vertex_iter &operator-=(int v) { idx -= v; return *this; }
|
||||
|
||||
Vertex *operator*() const {
|
||||
return base->vertex(idx);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
static inline ptrdiff_t operator-(const polyline_vertex_iter &a, const polyline_vertex_iter &b) { return a.idx - b.idx; }
|
||||
|
||||
static inline bool operator==(const polyline_vertex_iter&a, const polyline_vertex_iter &b) { return a.idx == b.idx; }
|
||||
static inline bool operator!=(const polyline_vertex_iter&a, const polyline_vertex_iter &b) { return a.idx != b.idx; }
|
||||
static inline bool operator<(const polyline_vertex_iter&a, const polyline_vertex_iter &b) { return a.idx < b.idx; }
|
||||
static inline bool operator>(const polyline_vertex_iter&a, const polyline_vertex_iter &b) { return a.idx > b.idx; }
|
||||
static inline bool operator<=(const polyline_vertex_iter&a, const polyline_vertex_iter &b) { return a.idx <= b.idx; }
|
||||
static inline bool operator>=(const polyline_vertex_iter&a, const polyline_vertex_iter &b) { return a.idx >= b.idx; }
|
||||
|
||||
|
||||
|
||||
struct polyline_vertex_const_iter : public std::iterator<std::random_access_iterator_tag, Vertex *> {
|
||||
const Polyline *base;
|
||||
size_t idx;
|
||||
|
||||
polyline_vertex_const_iter(const Polyline *_base) : base(_base), idx(0) {
|
||||
}
|
||||
|
||||
polyline_vertex_const_iter(const Polyline *_base, size_t _idx) : base(_base), idx(_idx) {
|
||||
}
|
||||
|
||||
polyline_vertex_const_iter operator++(int) { return polyline_vertex_const_iter(base, idx++); }
|
||||
polyline_vertex_const_iter &operator++() { ++idx; return *this; }
|
||||
polyline_vertex_const_iter &operator+=(int v) { idx += v; return *this; }
|
||||
|
||||
polyline_vertex_const_iter operator--(int) { return polyline_vertex_const_iter(base, idx--); }
|
||||
polyline_vertex_const_iter &operator--() { --idx; return *this; }
|
||||
polyline_vertex_const_iter &operator-=(int v) { idx -= v; return *this; }
|
||||
|
||||
const Vertex *operator*() const {
|
||||
return base->vertex(idx);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
static inline ptrdiff_t operator-(const polyline_vertex_const_iter &a, const polyline_vertex_const_iter &b) { return a.idx - b.idx; }
|
||||
|
||||
static inline bool operator==(const polyline_vertex_const_iter&a, const polyline_vertex_const_iter &b) { return a.idx == b.idx; }
|
||||
static inline bool operator!=(const polyline_vertex_const_iter&a, const polyline_vertex_const_iter &b) { return a.idx != b.idx; }
|
||||
static inline bool operator<(const polyline_vertex_const_iter&a, const polyline_vertex_const_iter &b) { return a.idx < b.idx; }
|
||||
static inline bool operator>(const polyline_vertex_const_iter&a, const polyline_vertex_const_iter &b) { return a.idx > b.idx; }
|
||||
static inline bool operator<=(const polyline_vertex_const_iter&a, const polyline_vertex_const_iter &b) { return a.idx <= b.idx; }
|
||||
static inline bool operator>=(const polyline_vertex_const_iter&a, const polyline_vertex_const_iter &b) { return a.idx >= b.idx; }
|
||||
|
||||
inline polyline_vertex_const_iter Polyline::vbegin() const {
|
||||
return polyline_vertex_const_iter(this, 0);
|
||||
}
|
||||
inline polyline_vertex_const_iter Polyline::vend() const {
|
||||
return polyline_vertex_const_iter(this, vertexCount());
|
||||
}
|
||||
inline polyline_vertex_iter Polyline::vbegin() {
|
||||
return polyline_vertex_iter(this, 0);
|
||||
}
|
||||
inline polyline_vertex_iter Polyline::vend() {
|
||||
return polyline_vertex_iter(this, vertexCount());
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct polyline_edge_iter : public std::iterator<std::random_access_iterator_tag, PolylineEdge *> {
|
||||
Polyline *base;
|
||||
size_t idx;
|
||||
|
||||
polyline_edge_iter(Polyline *_base) : base(_base), idx(0) {
|
||||
}
|
||||
|
||||
polyline_edge_iter(Polyline *_base, size_t _idx) : base(_base), idx(_idx) {
|
||||
}
|
||||
|
||||
polyline_edge_iter operator++(int) { return polyline_edge_iter(base, idx++); }
|
||||
polyline_edge_iter &operator++() { ++idx; return *this; }
|
||||
polyline_edge_iter &operator+=(int v) { idx += v; return *this; }
|
||||
|
||||
polyline_edge_iter operator--(int) { return polyline_edge_iter(base, idx--); }
|
||||
polyline_edge_iter &operator--() { --idx; return *this; }
|
||||
polyline_edge_iter &operator-=(int v) { idx -= v; return *this; }
|
||||
|
||||
PolylineEdge *operator*() const {
|
||||
return base->edge(idx);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
static inline int operator-(const polyline_edge_iter&a, const polyline_edge_iter &b) { return a.idx - b.idx; }
|
||||
|
||||
static inline bool operator==(const polyline_edge_iter&a, const polyline_edge_iter &b) { return a.idx == b.idx; }
|
||||
static inline bool operator!=(const polyline_edge_iter&a, const polyline_edge_iter &b) { return a.idx != b.idx; }
|
||||
static inline bool operator<(const polyline_edge_iter&a, const polyline_edge_iter &b) { return a.idx < b.idx; }
|
||||
static inline bool operator>(const polyline_edge_iter&a, const polyline_edge_iter &b) { return a.idx > b.idx; }
|
||||
static inline bool operator<=(const polyline_edge_iter&a, const polyline_edge_iter &b) { return a.idx <= b.idx; }
|
||||
static inline bool operator>=(const polyline_edge_iter&a, const polyline_edge_iter &b) { return a.idx >= b.idx; }
|
||||
|
||||
|
||||
|
||||
struct polyline_edge_const_iter : public std::iterator<std::random_access_iterator_tag, PolylineEdge *> {
|
||||
const Polyline *base;
|
||||
size_t idx;
|
||||
|
||||
polyline_edge_const_iter(const Polyline *_base) : base(_base), idx(0) {
|
||||
}
|
||||
|
||||
polyline_edge_const_iter(const Polyline *_base, size_t _idx) : base(_base), idx(_idx) {
|
||||
}
|
||||
|
||||
polyline_edge_const_iter operator++(int) { return polyline_edge_const_iter(base, idx++); }
|
||||
polyline_edge_const_iter &operator++() { ++idx; return *this; }
|
||||
polyline_edge_const_iter &operator+=(int v) { idx += v; return *this; }
|
||||
|
||||
polyline_edge_const_iter operator--(int) { return polyline_edge_const_iter(base, idx--); }
|
||||
polyline_edge_const_iter &operator--() { --idx; return *this; }
|
||||
polyline_edge_const_iter &operator-=(int v) { idx -= v; return *this; }
|
||||
|
||||
const PolylineEdge *operator*() const {
|
||||
return base->edge(idx);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
static inline int operator-(const polyline_edge_const_iter&a, const polyline_edge_const_iter &b) { return a.idx - b.idx; }
|
||||
|
||||
static inline bool operator==(const polyline_edge_const_iter&a, const polyline_edge_const_iter &b) { return a.idx == b.idx; }
|
||||
static inline bool operator!=(const polyline_edge_const_iter&a, const polyline_edge_const_iter &b) { return a.idx != b.idx; }
|
||||
static inline bool operator<(const polyline_edge_const_iter&a, const polyline_edge_const_iter &b) { return a.idx < b.idx; }
|
||||
static inline bool operator>(const polyline_edge_const_iter&a, const polyline_edge_const_iter &b) { return a.idx > b.idx; }
|
||||
static inline bool operator<=(const polyline_edge_const_iter&a, const polyline_edge_const_iter &b) { return a.idx <= b.idx; }
|
||||
static inline bool operator>=(const polyline_edge_const_iter&a, const polyline_edge_const_iter &b) { return a.idx >= b.idx; }
|
||||
|
||||
inline polyline_edge_const_iter Polyline::ebegin() const {
|
||||
return polyline_edge_const_iter(this, 0);
|
||||
}
|
||||
inline polyline_edge_const_iter Polyline::eend() const {
|
||||
return polyline_edge_const_iter(this, edgeCount());
|
||||
}
|
||||
inline polyline_edge_iter Polyline::ebegin() {
|
||||
return polyline_edge_iter(this, 0);
|
||||
}
|
||||
inline polyline_edge_iter Polyline::eend() {
|
||||
return polyline_edge_iter(this, edgeCount());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
100
extern/carve/include/carve/rescale.hpp
vendored
Normal file
100
extern/carve/include/carve/rescale.hpp
vendored
Normal file
@ -0,0 +1,100 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
|
||||
#include <carve/vector.hpp>
|
||||
#include <carve/aabb.hpp>
|
||||
#include <carve/matrix.hpp>
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace carve {
|
||||
namespace rescale {
|
||||
|
||||
template<typename T>
|
||||
T calc_scale(T max) {
|
||||
const int radix = std::numeric_limits<T>::radix;
|
||||
|
||||
T div = T(1);
|
||||
T m = fabs(max);
|
||||
while (div < m) div *= radix;
|
||||
m *= radix;
|
||||
while (div > m) div /= radix;
|
||||
return div;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T calc_delta(T min, T max) {
|
||||
const int radix = std::numeric_limits<T>::radix;
|
||||
|
||||
if (min >= T(0) || max <= T(0)) {
|
||||
bool neg = false;
|
||||
if (max <= T(0)) {
|
||||
min = -min;
|
||||
max = -max;
|
||||
std::swap(min, max);
|
||||
neg = true;
|
||||
}
|
||||
T t = T(1);
|
||||
while (t > max) t /= radix;
|
||||
while (t <= max/radix) t *= radix;
|
||||
volatile T temp = t + min;
|
||||
temp -= t;
|
||||
if (neg) temp = -temp;
|
||||
return temp;
|
||||
} else {
|
||||
return T(0);
|
||||
}
|
||||
}
|
||||
|
||||
struct rescale {
|
||||
double dx, dy, dz, scale;
|
||||
|
||||
void init(double minx, double miny, double minz, double maxx, double maxy, double maxz) {
|
||||
dx = calc_delta(minx, maxx); minx -= dx; maxx -= dx;
|
||||
dy = calc_delta(miny, maxy); miny -= dy; maxy -= dy;
|
||||
dz = calc_delta(minz, maxz); minz -= dz; maxz -= dz;
|
||||
scale = calc_scale(std::max(std::max(fabs(minz), fabs(maxz)),
|
||||
std::max(std::max(fabs(minx), fabs(maxx)),
|
||||
std::max(fabs(miny), fabs(maxy)))));
|
||||
}
|
||||
|
||||
rescale(double minx, double miny, double minz, double maxx, double maxy, double maxz) {
|
||||
init(minx, miny, minz, maxx, maxy, maxz);
|
||||
}
|
||||
rescale(const carve::geom3d::Vector &min, const carve::geom3d::Vector &max) {
|
||||
init(min.x, min.y, min.z, max.x, max.y, max.z);
|
||||
}
|
||||
};
|
||||
|
||||
struct fwd {
|
||||
rescale r;
|
||||
fwd(const rescale &_r) : r(_r) { }
|
||||
carve::geom3d::Vector operator()(const carve::geom3d::Vector &v) const { return carve::geom::VECTOR((v.x - r.dx) / r.scale, (v.y - r.dy) / r.scale, (v.z - r.dz) / r.scale); }
|
||||
};
|
||||
|
||||
struct rev {
|
||||
rescale r;
|
||||
rev(const rescale &_r) : r(_r) { }
|
||||
carve::geom3d::Vector operator()(const carve::geom3d::Vector &v) const { return carve::geom::VECTOR((v.x * r.scale) + r.dx, (v.y * r.scale) + r.dy, (v.z * r.scale) + r.dz); }
|
||||
};
|
||||
|
||||
}
|
||||
}
|
501
extern/carve/include/carve/rtree.hpp
vendored
Normal file
501
extern/carve/include/carve/rtree.hpp
vendored
Normal file
@ -0,0 +1,501 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
|
||||
#include <carve/geom.hpp>
|
||||
#include <carve/aabb.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
#if defined(HAVE_STDINT_H)
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
||||
namespace carve {
|
||||
namespace geom {
|
||||
|
||||
template<unsigned ndim,
|
||||
typename data_t,
|
||||
typename aabb_calc_t = carve::geom::get_aabb<ndim, data_t> >
|
||||
struct RTreeNode {
|
||||
typedef aabb<ndim> aabb_t;
|
||||
typedef vector<ndim> vector_t;
|
||||
typedef RTreeNode<ndim, data_t, aabb_calc_t> node_t;
|
||||
|
||||
aabb_t bbox;
|
||||
node_t *child;
|
||||
node_t *sibling;
|
||||
std::vector<data_t> data;
|
||||
|
||||
aabb_t getAABB() const { return bbox; }
|
||||
|
||||
|
||||
|
||||
struct data_aabb_t {
|
||||
aabb_t bbox;
|
||||
data_t data;
|
||||
|
||||
data_aabb_t() { }
|
||||
data_aabb_t(const data_t &_data) : bbox(aabb_calc_t()(_data)), data(_data) {
|
||||
}
|
||||
|
||||
aabb_t getAABB() const { return bbox; }
|
||||
|
||||
struct cmp {
|
||||
size_t dim;
|
||||
cmp(size_t _dim) : dim(_dim) { }
|
||||
bool operator()(const data_aabb_t &a, const data_aabb_t &b) {
|
||||
return a.bbox.pos.v[dim] < b.bbox.pos.v[dim];
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// Fill an rtree node with a set of (data, aabb) pairs.
|
||||
template<typename iter_t>
|
||||
void _fill(iter_t begin, iter_t end, data_aabb_t) {
|
||||
data.reserve(std::distance(begin, end));
|
||||
for (iter_t i = begin; i != end; ++i) {
|
||||
data.push_back((*i).data);
|
||||
}
|
||||
bbox.fit(begin, end);
|
||||
}
|
||||
|
||||
// Fill an rtree node with a set of data.
|
||||
template<typename iter_t>
|
||||
void _fill(iter_t begin, iter_t end, data_t) {
|
||||
data.reserve(std::distance(begin, end));
|
||||
std::copy(begin, end, std::back_inserter(data));
|
||||
bbox.fit(begin, end, aabb_calc_t());
|
||||
}
|
||||
|
||||
// Fill an rtree node with a set of child nodes.
|
||||
template<typename iter_t>
|
||||
void _fill(iter_t begin, iter_t end, node_t *) {
|
||||
iter_t i = begin;
|
||||
node_t *curr = child = *i;
|
||||
while (++i != end) {
|
||||
curr->sibling = *i;
|
||||
curr = curr->sibling;
|
||||
}
|
||||
bbox.fit(begin, end);
|
||||
}
|
||||
|
||||
// Search the rtree for objects that intersect obj (generally an aabb).
|
||||
// The aabb class must provide a method intersects(obj_t).
|
||||
template<typename obj_t, typename out_iter_t>
|
||||
void search(const obj_t &obj, out_iter_t out) const {
|
||||
if (!bbox.intersects(obj)) return;
|
||||
if (child) {
|
||||
for (node_t *node = child; node; node = node->sibling) {
|
||||
node->search(obj, out);
|
||||
}
|
||||
} else {
|
||||
std::copy(data.begin(), data.end(), out);
|
||||
}
|
||||
}
|
||||
|
||||
// update the bounding box extents of nodes that intersect obj (generally an aabb).
|
||||
// The aabb class must provide a method intersects(obj_t).
|
||||
template<typename obj_t>
|
||||
void updateExtents(const obj_t &obj) {
|
||||
if (!bbox.intersects(obj)) return;
|
||||
|
||||
if (child) {
|
||||
node_t *node = child;
|
||||
node->updateExtents(obj);
|
||||
bbox = node->bbox;
|
||||
for (node = node->sibling; node; node = node->sibling) {
|
||||
node->updateExtents(obj);
|
||||
bbox.unionAABB(node->bbox);
|
||||
}
|
||||
} else {
|
||||
bbox.fit(data.begin(), data.end());
|
||||
}
|
||||
}
|
||||
|
||||
// update the bounding box extents of nodes that intersect obj (generally an aabb).
|
||||
// The aabb class must provide a method intersects(obj_t).
|
||||
bool remove(const data_t &val, const aabb_t &val_aabb) {
|
||||
if (!bbox.intersects(val_aabb)) return false;
|
||||
|
||||
if (child) {
|
||||
node_t *node = child;
|
||||
node->remove(val, val_aabb);
|
||||
bbox = node->bbox;
|
||||
bool removed = false;
|
||||
for (node = node->sibling; node; node = node->sibling) {
|
||||
if (!removed) removed = node->remove(val, val_aabb);
|
||||
bbox.unionAABB(node->bbox);
|
||||
}
|
||||
return removed;
|
||||
} else {
|
||||
typename std::vector<data_t>::iterator i = std::remove(data.begin(), data.end(), val);
|
||||
if (i == data.end()) {
|
||||
return false;
|
||||
}
|
||||
data.erase(i, data.end());
|
||||
bbox.fit(data.begin(), data.end());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename iter_t>
|
||||
RTreeNode(iter_t begin, iter_t end) : bbox(), child(NULL), sibling(NULL), data() {
|
||||
_fill(begin, end, typename std::iterator_traits<iter_t>::value_type());
|
||||
}
|
||||
|
||||
|
||||
|
||||
// functor for ordering nodes by increasing aabb midpoint, along a specified axis.
|
||||
struct aabb_cmp_mid {
|
||||
size_t dim;
|
||||
aabb_cmp_mid(size_t _dim) : dim(_dim) { }
|
||||
|
||||
bool operator()(const node_t *a, const node_t *b) {
|
||||
return a->bbox.mid(dim) < b->bbox.mid(dim);
|
||||
}
|
||||
bool operator()(const data_aabb_t &a, const data_aabb_t &b) {
|
||||
return a.bbox.mid(dim) < b.bbox.mid(dim);
|
||||
}
|
||||
};
|
||||
|
||||
// functor for ordering nodes by increasing aabb minimum, along a specified axis.
|
||||
struct aabb_cmp_min {
|
||||
size_t dim;
|
||||
aabb_cmp_min(size_t _dim) : dim(_dim) { }
|
||||
|
||||
bool operator()(const node_t *a, const node_t *b) {
|
||||
return a->bbox.min(dim) < b->bbox.min(dim);
|
||||
}
|
||||
bool operator()(const data_aabb_t &a, const data_aabb_t &b) {
|
||||
return a.bbox.min(dim) < b.bbox.min(dim);
|
||||
}
|
||||
};
|
||||
|
||||
// functor for ordering nodes by increasing aabb maximum, along a specified axis.
|
||||
struct aabb_cmp_max {
|
||||
size_t dim;
|
||||
aabb_cmp_max(size_t _dim) : dim(_dim) { }
|
||||
|
||||
bool operator()(const node_t *a, const node_t *b) {
|
||||
return a->bbox.max(dim) < b->bbox.max(dim);
|
||||
}
|
||||
bool operator()(const data_aabb_t &a, const data_aabb_t &b) {
|
||||
return a.bbox.max(dim) < b.bbox.max(dim);
|
||||
}
|
||||
};
|
||||
|
||||
// facade for projecting node bounding box onto an axis.
|
||||
struct aabb_extent {
|
||||
size_t dim;
|
||||
aabb_extent(size_t _dim) : dim(_dim) { }
|
||||
|
||||
double min(const node_t *a) { return a->bbox.pos.v[dim] - a->bbox.extent.v[dim]; }
|
||||
double max(const node_t *a) { return a->bbox.pos.v[dim] + a->bbox.extent.v[dim]; }
|
||||
double len(const node_t *a) { return 2.0 * a->bbox.extent.v[dim]; }
|
||||
double min(const data_aabb_t &a) { return a.bbox.pos.v[dim] - a.bbox.extent.v[dim]; }
|
||||
double max(const data_aabb_t &a) { return a.bbox.pos.v[dim] + a.bbox.extent.v[dim]; }
|
||||
double len(const data_aabb_t &a) { return 2.0 * a.bbox.extent.v[dim]; }
|
||||
};
|
||||
|
||||
template<typename iter_t>
|
||||
static void makeNodes(const iter_t begin,
|
||||
const iter_t end,
|
||||
size_t dim_num,
|
||||
uint32_t dim_mask,
|
||||
size_t child_size,
|
||||
std::vector<node_t *> &out) {
|
||||
const size_t N = std::distance(begin, end);
|
||||
|
||||
size_t dim = ndim;
|
||||
double r_best = N+1;
|
||||
|
||||
// find the sparsest remaining dimension to partition by.
|
||||
for (size_t i = 0; i < ndim; ++i) {
|
||||
if (dim_mask & (1U << i)) continue;
|
||||
aabb_extent extent(i);
|
||||
double dmin, dmax, dsum;
|
||||
|
||||
dmin = extent.min(*begin);
|
||||
dmax = extent.max(*begin);
|
||||
dsum = 0.0;
|
||||
for (iter_t j = begin; j != end; ++j) {
|
||||
dmin = std::min(dmin, extent.min(*j));
|
||||
dmax = std::max(dmax, extent.max(*j));
|
||||
dsum += extent.len(*j);
|
||||
}
|
||||
double r = dsum ? dsum / (dmax - dmin) : 0.0;
|
||||
if (r_best > r) {
|
||||
dim = i;
|
||||
r_best = r;
|
||||
}
|
||||
}
|
||||
|
||||
CARVE_ASSERT(dim < ndim);
|
||||
|
||||
// dim = dim_num;
|
||||
|
||||
const size_t P = (N + child_size - 1) / child_size;
|
||||
const size_t n_parts = (size_t)std::ceil(std::pow((double)P, 1.0 / (ndim - dim_num)));
|
||||
|
||||
std::sort(begin, end, aabb_cmp_mid(dim));
|
||||
|
||||
if (dim_num == ndim - 1 || n_parts == 1) {
|
||||
for (size_t i = 0, s = 0, e = 0; i < P; ++i, s = e) {
|
||||
e = N * (i+1) / P;
|
||||
CARVE_ASSERT(e - s <= child_size);
|
||||
out.push_back(new node_t(begin + s, begin + e));
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0, s = 0, e = 0; i < n_parts; ++i, s = e) {
|
||||
e = N * (i+1) / n_parts;
|
||||
makeNodes(begin + s, begin + e, dim_num + 1, dim_mask | (1U << dim), child_size, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static node_t *construct_STR(std::vector<data_aabb_t> &data, size_t leaf_size, size_t internal_size) {
|
||||
std::vector<node_t *> out;
|
||||
makeNodes(data.begin(), data.end(), 0, 0, leaf_size, out);
|
||||
|
||||
while (out.size() > 1) {
|
||||
std::vector<node_t *> next;
|
||||
makeNodes(out.begin(), out.end(), 0, 0, internal_size, next);
|
||||
std::swap(out, next);
|
||||
}
|
||||
|
||||
CARVE_ASSERT(out.size() == 1);
|
||||
return out[0];
|
||||
}
|
||||
|
||||
template<typename iter_t>
|
||||
static node_t *construct_STR(const iter_t &begin,
|
||||
const iter_t &end,
|
||||
size_t leaf_size,
|
||||
size_t internal_size) {
|
||||
std::vector<data_aabb_t> data;
|
||||
data.reserve(std::distance(begin, end));
|
||||
for (iter_t i = begin; i != end; ++i) {
|
||||
data.push_back(*i);
|
||||
}
|
||||
return construct_STR(data, leaf_size, internal_size);
|
||||
}
|
||||
|
||||
|
||||
template<typename iter_t>
|
||||
static node_t *construct_STR(const iter_t &begin1,
|
||||
const iter_t &end1,
|
||||
const iter_t &begin2,
|
||||
const iter_t &end2,
|
||||
size_t leaf_size,
|
||||
size_t internal_size) {
|
||||
std::vector<data_aabb_t> data;
|
||||
data.reserve(std::distance(begin1, end1) + std::distance(begin2, end2));
|
||||
for (iter_t i = begin1; i != end1; ++i) {
|
||||
data.push_back(*i);
|
||||
}
|
||||
for (iter_t i = begin2; i != end2; ++i) {
|
||||
data.push_back(*i);
|
||||
}
|
||||
return construct_STR(data, leaf_size, internal_size);
|
||||
}
|
||||
|
||||
|
||||
struct partition_info {
|
||||
double score;
|
||||
size_t partition_pos;
|
||||
|
||||
partition_info() : score(std::numeric_limits<double>::max()), partition_pos(0) {
|
||||
}
|
||||
partition_info(double _score, size_t _partition_pos) :
|
||||
score(_score),
|
||||
partition_pos(_partition_pos) {
|
||||
}
|
||||
};
|
||||
|
||||
static partition_info findPartition(typename std::vector<data_aabb_t>::iterator base,
|
||||
std::vector<size_t>::iterator begin,
|
||||
std::vector<size_t>::iterator end,
|
||||
size_t part_size) {
|
||||
partition_info best(std::numeric_limits<double>::max(), 0);
|
||||
const size_t N = std::distance(begin, end);
|
||||
|
||||
std::vector<double> rhs_vol(N, 0.0);
|
||||
|
||||
aabb_t rhs = base[begin[N-1]].aabb;
|
||||
rhs_vol[N-1] = rhs.volume();
|
||||
for (size_t i = N - 1; i > 0; ) {
|
||||
rhs.unionAABB(base[begin[--i]].aabb);
|
||||
rhs_vol[i] = rhs.volume();
|
||||
}
|
||||
|
||||
aabb_t lhs = base[begin[0]].aabb;
|
||||
for (size_t i = 1; i < N; ++i) {
|
||||
lhs.unionAABB(base[begin[i]].aabb);
|
||||
if (i % part_size == 0 || (N - i) % part_size == 0) {
|
||||
partition_info curr(lhs.volume() + rhs_vol[i], i);
|
||||
if (best.score > curr.score) best = curr;
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
static void partition(typename std::vector<data_aabb_t>::iterator base,
|
||||
std::vector<size_t>::iterator begin,
|
||||
std::vector<size_t>::iterator end,
|
||||
size_t part_size,
|
||||
std::vector<size_t> &part_num,
|
||||
size_t &part_next) {
|
||||
const size_t N = std::distance(begin, end);
|
||||
|
||||
partition_info best;
|
||||
partition_info curr;
|
||||
size_t part_curr = part_num[*begin];
|
||||
|
||||
std::vector<size_t> tmp(begin, end);
|
||||
|
||||
for (size_t dim = 0; dim < ndim; ++dim) {
|
||||
std::sort(tmp.begin(), tmp.end(), make_index_sort(base, aabb_cmp_min(dim)));
|
||||
curr = findPartition(base, tmp.begin(), tmp.end(), part_size);
|
||||
if (best.score > curr.score) {
|
||||
best = curr;
|
||||
std::copy(tmp.begin(), tmp.end(), begin);
|
||||
}
|
||||
|
||||
std::sort(tmp.begin(), tmp.end(), make_index_sort(base, aabb_cmp_mid(dim)));
|
||||
curr = findPartition(base, tmp.begin(), tmp.end(), part_size);
|
||||
if (best.score > curr.score) {
|
||||
best = curr;
|
||||
std::copy(tmp.begin(), tmp.end(), begin);
|
||||
}
|
||||
|
||||
std::sort(tmp.begin(), tmp.end(), make_index_sort(base, aabb_cmp_max(dim)));
|
||||
curr = findPartition(base, tmp.begin(), tmp.end(), part_size);
|
||||
if (best.score > curr.score) {
|
||||
best = curr;
|
||||
std::copy(tmp.begin(), tmp.end(), begin);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < best.partition_pos; ++j) part_num[begin[j]] = part_curr;
|
||||
for (size_t j = best.partition_pos; j < N; ++j) part_num[begin[j]] = part_next;
|
||||
++part_next;
|
||||
|
||||
if (best.partition_pos > part_size) {
|
||||
partition(base, begin, begin + best.partition_pos, part_size, part_num, part_next);
|
||||
}
|
||||
if (N - best.partition_pos > part_size) {
|
||||
partition(base, begin + best.partition_pos, end, part_size, part_num, part_next);
|
||||
}
|
||||
}
|
||||
|
||||
static size_t makePartitions(typename std::vector<data_aabb_t>::iterator begin,
|
||||
typename std::vector<data_aabb_t>::iterator end,
|
||||
size_t part_size,
|
||||
std::vector<size_t> &part_num) {
|
||||
const size_t N = std::distance(begin, end);
|
||||
std::vector<size_t> idx;
|
||||
idx.reserve(N);
|
||||
for (size_t i = 0; i < N; ++i) { idx.push_back(i); }
|
||||
size_t part_next = 1;
|
||||
|
||||
partition(begin, idx.begin(), idx.end(), part_size, part_num, part_next);
|
||||
return part_next;
|
||||
}
|
||||
|
||||
static node_t *construct_TGS(typename std::vector<data_aabb_t>::iterator begin,
|
||||
typename std::vector<data_aabb_t>::iterator end,
|
||||
size_t leaf_size,
|
||||
size_t internal_size) {
|
||||
size_t N = std::distance(begin, end);
|
||||
|
||||
if (N <= leaf_size) {
|
||||
return new node_t(begin, end);
|
||||
} else {
|
||||
size_t P = (N + internal_size - 1) / internal_size;
|
||||
std::vector<size_t> part_num(N, 0);
|
||||
P = makePartitions(begin, end, P, part_num);
|
||||
|
||||
size_t S = 0, E = 0;
|
||||
std::vector<node_t *> children;
|
||||
for (size_t i = 0; i < P; ++i) {
|
||||
size_t j = S, k = N;
|
||||
while (true) {
|
||||
while (true) {
|
||||
if (j == k) goto done;
|
||||
else if (part_num[j] == i) ++j;
|
||||
else break;
|
||||
}
|
||||
--k;
|
||||
while (true) {
|
||||
if (j == k) goto done;
|
||||
else if (part_num[k] != i) --k;
|
||||
else break;
|
||||
}
|
||||
std::swap(*(begin+j), *(begin+k));
|
||||
std::swap(part_num[j], part_num[k]);
|
||||
++j;
|
||||
}
|
||||
done:
|
||||
E = j;
|
||||
children.push_back(construct_TGS(begin + S, begin + E, leaf_size, internal_size));
|
||||
S = E;
|
||||
}
|
||||
return new node_t(children.begin(), children.end());
|
||||
}
|
||||
}
|
||||
|
||||
template<typename iter_t>
|
||||
static node_t *construct_TGS(const iter_t &begin,
|
||||
const iter_t &end,
|
||||
size_t leaf_size,
|
||||
size_t internal_size) {
|
||||
std::vector<data_aabb_t> data;
|
||||
data.reserve(std::distance(begin, end));
|
||||
for (iter_t i = begin; i != end; ++i) {
|
||||
data.push_back(*i);
|
||||
}
|
||||
return construct_TGS(data.begin(), data.end(), leaf_size, internal_size);
|
||||
}
|
||||
|
||||
template<typename iter_t>
|
||||
static node_t *construct_TGS(const iter_t &begin1,
|
||||
const iter_t &end1,
|
||||
const iter_t &begin2,
|
||||
const iter_t &end2,
|
||||
size_t leaf_size,
|
||||
size_t internal_size) {
|
||||
std::vector<data_aabb_t> data;
|
||||
data.reserve(std::distance(begin1, end1) + std::distance(begin2, end2));
|
||||
for (iter_t i = begin1; i != end1; ++i) {
|
||||
data.push_back(*i);
|
||||
}
|
||||
for (iter_t i = begin2; i != end2; ++i) {
|
||||
data.push_back(*i);
|
||||
}
|
||||
return construct_TGS(data.begin(), data.end(), leaf_size, internal_size);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
264
extern/carve/include/carve/spacetree.hpp
vendored
Normal file
264
extern/carve/include/carve/spacetree.hpp
vendored
Normal file
@ -0,0 +1,264 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
|
||||
#include <carve/geom.hpp>
|
||||
#include <carve/aabb.hpp>
|
||||
#include <carve/vertex_decl.hpp>
|
||||
#include <carve/edge_decl.hpp>
|
||||
#include <carve/face_decl.hpp>
|
||||
|
||||
namespace carve {
|
||||
|
||||
namespace space {
|
||||
|
||||
static inline bool intersection_test(const carve::geom::aabb<3> &aabb, const carve::poly::Face<3> *face) {
|
||||
if (face->nVertices() == 3) {
|
||||
return aabb.intersects(carve::geom::tri<3>(face->vertex(0)->v, face->vertex(1)->v, face->vertex(2)->v));
|
||||
} else {
|
||||
// partial, conservative SAT.
|
||||
return aabb.intersects(face->aabb) && aabb.intersects(face->plane_eqn);
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool intersection_test(const carve::geom::aabb<3> &aabb, const carve::poly::Edge<3> *edge) {
|
||||
return aabb.intersectsLineSegment(edge->v1->v, edge->v2->v);
|
||||
}
|
||||
|
||||
static inline bool intersection_test(const carve::geom::aabb<3> &aabb, const carve::poly::Vertex<3> *vertex) {
|
||||
return aabb.intersects(vertex->v);
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct nodedata_FaceEdge {
|
||||
std::vector<const carve::poly::Face<3> *> faces;
|
||||
std::vector<const carve::poly::Edge<3> *> edges;
|
||||
|
||||
void add(const carve::poly::Face<3> *face) {
|
||||
faces.push_back(face);
|
||||
}
|
||||
|
||||
void add(const carve::poly::Edge<3> *edge) {
|
||||
edges.push_back(edge);
|
||||
}
|
||||
|
||||
template<typename iter_t>
|
||||
void _fetch(iter_t &iter, const carve::poly::Edge<3> *) {
|
||||
std::copy(edges.begin(), edges.end(), iter);
|
||||
}
|
||||
|
||||
template<typename iter_t>
|
||||
void _fetch(iter_t &iter, const carve::poly::Face<3> *) {
|
||||
std::copy(faces.begin(), faces.end(), iter);
|
||||
}
|
||||
|
||||
template<typename node_t>
|
||||
void propagate(node_t *node) {
|
||||
}
|
||||
|
||||
template<typename iter_t>
|
||||
void fetch(iter_t &iter) {
|
||||
return _fetch(iter, std::iterator_traits<iter_t>::value_type);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
const static double SLACK_FACTOR = 1.0009765625;
|
||||
const static unsigned MAX_SPLIT_DEPTH = 32;
|
||||
|
||||
|
||||
|
||||
template<unsigned n_dim, typename nodedata_t>
|
||||
class SpatialSubdivTree {
|
||||
|
||||
typedef carve::geom::aabb<n_dim> aabb_t;
|
||||
typedef carve::geom::vector<n_dim> vector_t;
|
||||
|
||||
public:
|
||||
|
||||
class Node {
|
||||
enum {
|
||||
n_children = 1 << n_dim
|
||||
};
|
||||
|
||||
public:
|
||||
Node *parent;
|
||||
Node *children;
|
||||
|
||||
vector_t min;
|
||||
vector_t max;
|
||||
|
||||
aabb_t aabb;
|
||||
|
||||
nodedata_t data;
|
||||
|
||||
private:
|
||||
Node(const Node &node); // undefined.
|
||||
Node &operator=(const Node &node); // undefined.
|
||||
|
||||
Node() {
|
||||
}
|
||||
|
||||
inline aabb_t makeAABB() const {
|
||||
vector_t centre = 0.5 * (min + max);
|
||||
vector_t size = SLACK_FACTOR * 0.5 * (max - min);
|
||||
return aabb_t(centre, size);
|
||||
}
|
||||
|
||||
void setup(Node *_parent, const vector_t &_min, const vector_t &_max) {
|
||||
parent = _parent;
|
||||
min = _min;
|
||||
max = _max;
|
||||
aabb = makeAABB();
|
||||
}
|
||||
|
||||
void alloc_children() {
|
||||
vector_t mid = 0.5 * (min + max);
|
||||
children = new Node[n_children];
|
||||
for (size_t i = 0; i < (n_children); ++i) {
|
||||
vector_t new_min, new_max;
|
||||
for (size_t c = 0; c < n_dim; ++c) {
|
||||
if (i & (1 << c)) {
|
||||
new_min.v[c] = min.v[c];
|
||||
new_max.v[c] = mid.v[c];
|
||||
} else {
|
||||
new_min.v[c] = mid.v[c];
|
||||
new_max.v[c] = max.v[c];
|
||||
}
|
||||
}
|
||||
children[i].setup(this, new_min, new_max);
|
||||
}
|
||||
}
|
||||
|
||||
void dealloc_children() {
|
||||
delete [] children;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
inline bool isLeaf() const { return children == NULL; }
|
||||
|
||||
Node(Node *_parent, const vector_t &_min, const vector_t &_max) : parent(_parent), children(NULL), min(_min), max(_max) {
|
||||
aabb = makeAABB();
|
||||
}
|
||||
|
||||
~Node() {
|
||||
dealloc_children();
|
||||
}
|
||||
|
||||
bool split() {
|
||||
if (isLeaf()) {
|
||||
alloc_children();
|
||||
data.propagate(this);
|
||||
}
|
||||
return isLeaf();
|
||||
}
|
||||
|
||||
template<typename obj_t>
|
||||
void insert(const obj_t &object) {
|
||||
if (!isLeaf()) {
|
||||
for (size_t i = 0; i < n_children; ++i) {
|
||||
if (intersection_test(children[i].aabb, object)) {
|
||||
children[i].insert(object);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
data.add(object);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename obj_t>
|
||||
void insertVector(typename std::vector<obj_t>::iterator beg, typename std::vector<obj_t>::iterator end) {
|
||||
if (isLeaf()) {
|
||||
while (beg != end) {
|
||||
data.add(*beg);
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < n_children; ++i) {
|
||||
typename std::vector<obj_t>::iterator mid = std::partition(beg, end, std::bind1st(intersection_test, children[i].aabb));
|
||||
children[i].insertVector(beg, mid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename iter_t>
|
||||
void insertMany(iter_t begin, iter_t end) {
|
||||
if (isLeaf()) {
|
||||
}
|
||||
}
|
||||
|
||||
template<typename obj_t, typename iter_t, typename filter_t>
|
||||
void findObjectsNear(const obj_t &object, iter_t &output, filter_t filter) {
|
||||
if (!isLeaf()) {
|
||||
for (size_t i = 0; i < n_children; ++i) {
|
||||
if (intersection_test(children[i].aabb, object)) {
|
||||
children[i].findObjectsNear(object, output, filter);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
data.fetch(output);
|
||||
}
|
||||
|
||||
// bool hasGeometry();
|
||||
|
||||
// template <class T>
|
||||
// void putInside(const T &input, Node *child, T &output);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
Node *root;
|
||||
|
||||
SpatialSubdivTree(const vector_t &_min, const vector_t &_max) : root(new Node(NULL, _min, _max)) {
|
||||
}
|
||||
|
||||
~SpatialSubdivTree() {
|
||||
delete root;
|
||||
}
|
||||
|
||||
struct no_filter {
|
||||
template<typename obj_t>
|
||||
bool operator()(const obj_t &obj) const {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct tag_filter {
|
||||
template<typename obj_t>
|
||||
bool operator()(const obj_t &obj) const {
|
||||
return obj.tag_once();
|
||||
}
|
||||
};
|
||||
|
||||
// in order to be used as an input, aabb_t::intersect(const obj_t &) must exist.
|
||||
template<typename obj_t, typename iter_t, typename filter_t>
|
||||
void findObjectsNear(const obj_t &object, iter_t output, filter_t filter) {
|
||||
if (!intersection_test(root->aabb, object)) return;
|
||||
root->findObjectsNear(root, object, output, filter);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
44
extern/carve/include/carve/tag.hpp
vendored
Normal file
44
extern/carve/include/carve/tag.hpp
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
|
||||
namespace carve {
|
||||
|
||||
class tagable {
|
||||
private:
|
||||
static int s_count;
|
||||
|
||||
protected:
|
||||
mutable int __tag;
|
||||
|
||||
public:
|
||||
tagable(const tagable &) : __tag(s_count - 1) { }
|
||||
tagable &operator=(const tagable &) { return *this; }
|
||||
|
||||
tagable() : __tag(s_count - 1) { }
|
||||
|
||||
void tag() const { __tag = s_count; }
|
||||
void untag() const { __tag = s_count - 1; }
|
||||
bool is_tagged() const { return __tag == s_count; }
|
||||
bool tag_once() const { if (__tag == s_count) return false; __tag = s_count; return true; }
|
||||
|
||||
static void tag_begin() { s_count++; }
|
||||
};
|
||||
}
|
96
extern/carve/include/carve/timing.hpp
vendored
Normal file
96
extern/carve/include/carve/timing.hpp
vendored
Normal file
@ -0,0 +1,96 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
|
||||
#ifndef CARVE_USE_TIMINGS
|
||||
#define CARVE_USE_TIMINGS 0
|
||||
#endif
|
||||
|
||||
namespace carve {
|
||||
|
||||
#if CARVE_USE_TIMINGS
|
||||
|
||||
class TimingName {
|
||||
public:
|
||||
TimingName(const char *name);
|
||||
int id;
|
||||
};
|
||||
|
||||
class TimingBlock {
|
||||
public:
|
||||
/**
|
||||
* Starts timing at the end of this constructor, using the given ID. To
|
||||
* associate an ID with a textual name, use Timing::registerID.
|
||||
*/
|
||||
TimingBlock(int id);
|
||||
TimingBlock(const TimingName &name);
|
||||
~TimingBlock();
|
||||
};
|
||||
|
||||
class Timing {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Starts timing against a particular ID.
|
||||
*/
|
||||
static void start(int id);
|
||||
|
||||
static void start(const TimingName &id) {
|
||||
start(id.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the most recent timing block.
|
||||
*/
|
||||
static double stop();
|
||||
|
||||
/**
|
||||
* This will print out the current state of recorded time blocks. It will
|
||||
* display the tree of timings, as well as the summaries down the bottom.
|
||||
*/
|
||||
static void printTimings();
|
||||
|
||||
/**
|
||||
* Associates a particular ID with a text string. This is used when
|
||||
* printing out the timings.
|
||||
*/
|
||||
static void registerID(int id, const char *name);
|
||||
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
struct TimingName {
|
||||
TimingName(const char *) {}
|
||||
};
|
||||
struct TimingBlock {
|
||||
TimingBlock(int /* id */) {}
|
||||
TimingBlock(const TimingName & /* name */) {}
|
||||
};
|
||||
struct Timing {
|
||||
static void start(int /* id */) {}
|
||||
static void start(const TimingName & /* id */) {}
|
||||
static double stop() { return 0; }
|
||||
static void printTimings() {}
|
||||
static void registerID(int /* id */, const char * /* name */) {}
|
||||
};
|
||||
|
||||
#endif
|
||||
}
|
324
extern/carve/include/carve/tree.hpp
vendored
Normal file
324
extern/carve/include/carve/tree.hpp
vendored
Normal file
@ -0,0 +1,324 @@
|
||||
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
|
||||
#include <carve/matrix.hpp>
|
||||
#include <carve/timing.hpp>
|
||||
#include <carve/rescale.hpp>
|
||||
|
||||
namespace carve {
|
||||
namespace csg {
|
||||
|
||||
class CSG_TreeNode {
|
||||
CSG_TreeNode(const CSG_TreeNode &);
|
||||
CSG_TreeNode &operator=(const CSG_TreeNode &);
|
||||
|
||||
protected:
|
||||
|
||||
public:
|
||||
CSG_TreeNode() {
|
||||
}
|
||||
|
||||
virtual ~CSG_TreeNode() {
|
||||
}
|
||||
|
||||
virtual carve::mesh::MeshSet<3> *eval(bool &is_temp, CSG &csg) =0;
|
||||
|
||||
virtual carve::mesh::MeshSet<3> *eval(CSG &csg) {
|
||||
bool temp;
|
||||
carve::mesh::MeshSet<3> *r = eval(temp, csg);
|
||||
if (!temp) r = r->clone();
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class CSG_TransformNode : public CSG_TreeNode {
|
||||
carve::math::Matrix transform;
|
||||
CSG_TreeNode *child;
|
||||
|
||||
public:
|
||||
CSG_TransformNode(const carve::math::Matrix &_transform, CSG_TreeNode *_child) : transform(_transform), child(_child) {
|
||||
}
|
||||
virtual ~CSG_TransformNode() {
|
||||
delete child;
|
||||
}
|
||||
|
||||
virtual carve::mesh::MeshSet<3> *eval(bool &is_temp, CSG &csg) {
|
||||
carve::mesh::MeshSet<3> *result = child->eval(is_temp, csg);
|
||||
if (!is_temp) {
|
||||
result = result->clone();
|
||||
is_temp = true;
|
||||
}
|
||||
result->transform(carve::math::matrix_transformation(transform));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
class CSG_InvertNode : public CSG_TreeNode {
|
||||
std::vector<bool> selected_meshes;
|
||||
CSG_TreeNode *child;
|
||||
|
||||
public:
|
||||
CSG_InvertNode(CSG_TreeNode *_child) : selected_meshes(), child(_child) {
|
||||
}
|
||||
CSG_InvertNode(int g_id, CSG_TreeNode *_child) : selected_meshes(), child(_child) {
|
||||
selected_meshes.resize(g_id + 1, false);
|
||||
selected_meshes[g_id] = true;
|
||||
}
|
||||
virtual ~CSG_InvertNode() {
|
||||
delete child;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
CSG_InvertNode(T start, T end, CSG_TreeNode *_child) : selected_meshes(), child(_child) {
|
||||
while (start != end) {
|
||||
int g_id = (int)(*start);
|
||||
if (selected_meshes.size() < g_id + 1) selected_meshes.resize(g_id + 1, false);
|
||||
selected_meshes[g_id] = true;
|
||||
++start;
|
||||
}
|
||||
}
|
||||
|
||||
virtual carve::mesh::MeshSet<3> *eval(bool &is_temp, CSG &csg) {
|
||||
bool c_temp;
|
||||
carve::mesh::MeshSet<3> *c = child->eval(c_temp, csg);
|
||||
if (!c_temp) c = c->clone();
|
||||
if (!selected_meshes.size()) {
|
||||
c->invert();
|
||||
} else {
|
||||
for (size_t i = 0; i < c->meshes.size() && i < selected_meshes.size(); ++i) {
|
||||
if (selected_meshes[i]) {
|
||||
c->meshes[i]->invert();
|
||||
}
|
||||
}
|
||||
}
|
||||
is_temp = true;
|
||||
return c;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
class CSG_SelectNode : public CSG_TreeNode {
|
||||
std::vector<bool> selected_meshes;
|
||||
CSG_TreeNode *child;
|
||||
|
||||
public:
|
||||
CSG_SelectNode(int m_id, CSG_TreeNode *_child) : selected_meshes(), child(_child) {
|
||||
selected_meshes.resize(m_id + 1, false);
|
||||
selected_meshes[m_id] = true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
CSG_SelectNode(T start, T end, CSG_TreeNode *_child) : selected_meshes(), child(_child) {
|
||||
while (start != end) {
|
||||
int m_id = (int)(*start);
|
||||
if ((int)selected_meshes.size() < m_id + 1) selected_meshes.resize(m_id + 1, false);
|
||||
selected_meshes[m_id] = true;
|
||||
++start;
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~CSG_SelectNode() {
|
||||
delete child;
|
||||
}
|
||||
|
||||
virtual carve::mesh::MeshSet<3> *eval(bool &is_temp, CSG &csg) {
|
||||
bool c_temp;
|
||||
carve::mesh::MeshSet<3> *c = child->eval(c_temp, csg);
|
||||
if (!c_temp) c = c->clone();
|
||||
size_t i = 0;
|
||||
size_t j = 0;
|
||||
for (size_t i = 0; i < c->meshes.size(); ++i) {
|
||||
if (i >= selected_meshes.size() || !selected_meshes[i]) {
|
||||
delete c->meshes[i];
|
||||
c->meshes[i] = NULL;
|
||||
} else {
|
||||
c->meshes[j++] = c->meshes[i];
|
||||
}
|
||||
}
|
||||
c->meshes.erase(c->meshes.begin() + j, c->meshes.end());
|
||||
c->collectVertices();
|
||||
is_temp = true;
|
||||
return c;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
class CSG_PolyNode : public CSG_TreeNode {
|
||||
carve::mesh::MeshSet<3> *poly;
|
||||
bool del;
|
||||
|
||||
public:
|
||||
CSG_PolyNode(carve::mesh::MeshSet<3> *_poly, bool _del) : poly(_poly), del(_del) {
|
||||
}
|
||||
virtual ~CSG_PolyNode() {
|
||||
static carve::TimingName FUNC_NAME("delete polyhedron");
|
||||
carve::TimingBlock block(FUNC_NAME);
|
||||
|
||||
if (del) {
|
||||
delete poly;
|
||||
}
|
||||
}
|
||||
|
||||
virtual carve::mesh::MeshSet<3> *eval(bool &is_temp, CSG &csg) {
|
||||
is_temp = false;
|
||||
return poly;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class CSG_OPNode : public CSG_TreeNode {
|
||||
CSG_TreeNode *left, *right;
|
||||
CSG::OP op;
|
||||
bool rescale;
|
||||
CSG::CLASSIFY_TYPE classify_type;
|
||||
|
||||
public:
|
||||
CSG_OPNode(CSG_TreeNode *_left,
|
||||
CSG_TreeNode *_right,
|
||||
CSG::OP _op,
|
||||
bool _rescale,
|
||||
CSG::CLASSIFY_TYPE _classify_type = CSG::CLASSIFY_NORMAL) : left(_left), right(_right), op(_op), rescale(_rescale), classify_type(_classify_type) {
|
||||
}
|
||||
|
||||
virtual ~CSG_OPNode() {
|
||||
delete left;
|
||||
delete right;
|
||||
}
|
||||
|
||||
void minmax(double &min_x, double &min_y, double &min_z,
|
||||
double &max_x, double &max_y, double &max_z,
|
||||
const std::vector<carve::geom3d::Vector> &points) {
|
||||
for (unsigned i = 1; i < points.size(); ++i) {
|
||||
min_x = std::min(min_x, points[i].x);
|
||||
max_x = std::max(max_x, points[i].x);
|
||||
min_y = std::min(min_y, points[i].y);
|
||||
max_y = std::max(max_y, points[i].y);
|
||||
min_z = std::min(min_z, points[i].z);
|
||||
max_z = std::max(max_z, points[i].z);
|
||||
}
|
||||
}
|
||||
|
||||
virtual carve::mesh::MeshSet<3> *evalScaled(bool &is_temp, CSG &csg) {
|
||||
carve::mesh::MeshSet<3> *l, *r;
|
||||
bool l_temp, r_temp;
|
||||
|
||||
l = left->eval(l_temp, csg);
|
||||
r = right->eval(r_temp, csg);
|
||||
|
||||
if (!l_temp) { l = l->clone(); }
|
||||
if (!r_temp) { r = r->clone(); }
|
||||
|
||||
carve::geom3d::Vector min, max;
|
||||
carve::geom3d::Vector min_l, max_l;
|
||||
carve::geom3d::Vector min_r, max_r;
|
||||
|
||||
carve::geom::bounds<3>(l->vertex_storage.begin(),
|
||||
l->vertex_storage.end(),
|
||||
carve::mesh::Face<3>::vector_mapping(),
|
||||
min_l,
|
||||
max_l);
|
||||
carve::geom::bounds<3>(r->vertex_storage.begin(),
|
||||
r->vertex_storage.end(),
|
||||
carve::mesh::Face<3>::vector_mapping(),
|
||||
min_r,
|
||||
max_r);
|
||||
|
||||
carve::geom::assign_op(min, min_l, min_r, carve::util::min_functor());
|
||||
carve::geom::assign_op(max, max_l, max_r, carve::util::max_functor());
|
||||
|
||||
carve::rescale::rescale scaler(min.x, min.y, min.z, max.x, max.y, max.z);
|
||||
|
||||
carve::rescale::fwd fwd_r(scaler);
|
||||
carve::rescale::rev rev_r(scaler);
|
||||
|
||||
l->transform(fwd_r);
|
||||
r->transform(fwd_r);
|
||||
|
||||
carve::mesh::MeshSet<3> *result = NULL;
|
||||
{
|
||||
static carve::TimingName FUNC_NAME("csg.compute()");
|
||||
carve::TimingBlock block(FUNC_NAME);
|
||||
result = csg.compute(l, r, op, NULL, classify_type);
|
||||
}
|
||||
|
||||
{
|
||||
static carve::TimingName FUNC_NAME("delete polyhedron");
|
||||
carve::TimingBlock block(FUNC_NAME);
|
||||
|
||||
delete l;
|
||||
delete r;
|
||||
}
|
||||
|
||||
result->transform(rev_r);
|
||||
|
||||
is_temp = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual carve::mesh::MeshSet<3> *evalUnscaled(bool &is_temp, CSG &csg) {
|
||||
carve::mesh::MeshSet<3> *l, *r;
|
||||
bool l_temp, r_temp;
|
||||
|
||||
l = left->eval(l_temp, csg);
|
||||
r = right->eval(r_temp, csg);
|
||||
|
||||
carve::mesh::MeshSet<3> *result = NULL;
|
||||
{
|
||||
static carve::TimingName FUNC_NAME("csg.compute()");
|
||||
carve::TimingBlock block(FUNC_NAME);
|
||||
result = csg.compute(l, r, op, NULL, classify_type);
|
||||
}
|
||||
|
||||
{
|
||||
static carve::TimingName FUNC_NAME("delete polyhedron");
|
||||
carve::TimingBlock block(FUNC_NAME);
|
||||
|
||||
if (l_temp) delete l;
|
||||
if (r_temp) delete r;
|
||||
}
|
||||
|
||||
is_temp = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
virtual carve::mesh::MeshSet<3> *eval(bool &is_temp, CSG &csg) {
|
||||
if (rescale) {
|
||||
return evalScaled(is_temp, csg);
|
||||
} else {
|
||||
return evalUnscaled(is_temp, csg);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
175
extern/carve/include/carve/triangulator.hpp
vendored
Normal file
175
extern/carve/include/carve/triangulator.hpp
vendored
Normal file
@ -0,0 +1,175 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
|
||||
#include <carve/geom2d.hpp>
|
||||
|
||||
namespace carve {
|
||||
namespace triangulate {
|
||||
|
||||
/**
|
||||
* \brief Merge a set of holes into a polygon. (templated)
|
||||
*
|
||||
* Take a polygon loop and a collection of hole loops, and patch
|
||||
* the hole loops into the polygon loop, returning a vector of
|
||||
* vertices from the polygon and holes, which describes a new
|
||||
* polygon boundary with no holes. The new polygon boundary is
|
||||
* constructed via the addition of edges * joining the polygon
|
||||
* loop to the holes.
|
||||
*
|
||||
* This may be applied to arbitrary vertex data (generally
|
||||
* carve::geom3d::Vertex pointers), but a projection function must
|
||||
* be supplied to convert vertices to coordinates in 2-space, in
|
||||
* which the work is performed.
|
||||
*
|
||||
* @tparam project_t A functor which converts vertices to a 2d
|
||||
* projection.
|
||||
* @tparam vert_t The vertex type.
|
||||
* @param project The projection functor.
|
||||
* @param f_loop The polygon loop into which holes are to be
|
||||
* incorporated.
|
||||
* @param h_loops The set of hole loops to be incorporated.
|
||||
*
|
||||
* @return A vector of vertex pointers.
|
||||
*/
|
||||
template<typename project_t, typename vert_t>
|
||||
static std::vector<vert_t>
|
||||
incorporateHolesIntoPolygon(const project_t &project,
|
||||
const std::vector<vert_t> &f_loop,
|
||||
const std::vector<std::vector<vert_t> > &h_loops);
|
||||
|
||||
void
|
||||
incorporateHolesIntoPolygon(const std::vector<std::vector<carve::geom2d::P2> > &poly,
|
||||
std::vector<std::pair<size_t, size_t> > &result,
|
||||
size_t poly_loop,
|
||||
const std::vector<size_t> &hole_loops);
|
||||
|
||||
/**
|
||||
* \brief Merge a set of holes into a polygon. (2d)
|
||||
*
|
||||
* Take a polygon loop and a collection of hole loops, and patch
|
||||
* the hole loops into the polygon loop, returning a vector of
|
||||
* containing the vertices from the polygon and holes which
|
||||
* describes a new polygon boundary with no holes, through the
|
||||
* addition of edges joining the polygon loop to the holes.
|
||||
*
|
||||
* @param poly A vector containing the face loop (the first
|
||||
* element of poly) and the hole loops (second and
|
||||
* subsequent elements of poly).
|
||||
*
|
||||
* @return A vector of pairs of <loop_number, index> that
|
||||
* reference poly and define the result polygon loop.
|
||||
*/
|
||||
std::vector<std::pair<size_t, size_t> > incorporateHolesIntoPolygon(const std::vector<std::vector<carve::geom2d::P2> > &poly);
|
||||
|
||||
std::vector<std::vector<std::pair<size_t, size_t> > > mergePolygonsAndHoles(const std::vector<std::vector<carve::geom2d::P2> > &poly);
|
||||
|
||||
|
||||
struct tri_idx {
|
||||
union {
|
||||
unsigned v[3];
|
||||
struct { unsigned a, b, c; };
|
||||
};
|
||||
|
||||
tri_idx() : a(0), b(0), c(0) {
|
||||
}
|
||||
tri_idx(unsigned _a, unsigned _b, unsigned _c) : a(_a), b(_b), c(_c) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Triangulate a 2-dimensional polygon.
|
||||
*
|
||||
* Given a 2-dimensional polygon described as a vector of 2-d
|
||||
* points, with no holes and no self-crossings, produce a
|
||||
* triangulation using an ear-clipping algorithm.
|
||||
*
|
||||
* @param [in] poly A vector containing the input polygon.
|
||||
* @param [out] result A vector of triangles, represented as
|
||||
* indicies into poly.
|
||||
*/
|
||||
|
||||
|
||||
void triangulate(const std::vector<carve::geom2d::P2> &poly, std::vector<tri_idx> &result);
|
||||
|
||||
/**
|
||||
* \brief Triangulate a polygon (templated).
|
||||
*
|
||||
* @tparam project_t A functor which converts vertices to a 2d
|
||||
* projection.
|
||||
* @tparam vert_t The vertex type.
|
||||
* @param [in] project The projection functor.
|
||||
* @param [in] poly A vector containing the input polygon,
|
||||
* represented as vert_t pointers.
|
||||
* @param [out] result A vector of triangles, represented as
|
||||
* indicies into poly.
|
||||
*/
|
||||
template<typename project_t, typename vert_t>
|
||||
void triangulate(const project_t &project,
|
||||
const std::vector<vert_t> &poly,
|
||||
std::vector<tri_idx> &result);
|
||||
|
||||
/**
|
||||
* \brief Improve a candidate triangulation of poly by minimising
|
||||
* the length of internal edges. (templated)
|
||||
*
|
||||
* @tparam project_t A functor which converts vertices to a 2d
|
||||
* projection.
|
||||
* @tparam vert_t The vertex type.
|
||||
* @param [in] project The projection functor.
|
||||
* @param [in] poly A vector containing the input polygon,
|
||||
* represented as vert_t pointers.
|
||||
* @param [inout] result A vector of triangles, represented as
|
||||
* indicies into poly. On input, this vector
|
||||
* must contain a candidate triangulation of
|
||||
* poly. Calling improve() modifies the
|
||||
* contents of the vector, returning an
|
||||
* improved triangulation.
|
||||
*/
|
||||
template<typename project_t, typename vert_t>
|
||||
void improve(const project_t &project,
|
||||
const std::vector<vert_t> &poly,
|
||||
std::vector<tri_idx> &result);
|
||||
|
||||
/**
|
||||
* \brief Improve a candidate triangulation of poly by minimising
|
||||
* the length of internal edges.
|
||||
*
|
||||
* @param [in] poly A vector containing the input polygon.
|
||||
|
||||
* @param [inout] result A vector of triangles, represented as
|
||||
* indicies into poly. On input, this vector
|
||||
* must contain a candidate triangulation of
|
||||
* poly. Calling improve() modifies the
|
||||
* contents of the vector, returning an
|
||||
* improved triangulation.
|
||||
*/
|
||||
static inline void improve(const std::vector<carve::geom2d::P2> &poly, std::vector<tri_idx> &result) {
|
||||
improve(carve::geom2d::p2_adapt_ident(), poly, result);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include <carve/triangulator_impl.hpp>
|
851
extern/carve/include/carve/triangulator_impl.hpp
vendored
Normal file
851
extern/carve/include/carve/triangulator_impl.hpp
vendored
Normal file
@ -0,0 +1,851 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/geom2d.hpp>
|
||||
|
||||
#if defined(CARVE_DEBUG)
|
||||
# include <iostream>
|
||||
#endif
|
||||
|
||||
namespace carve {
|
||||
namespace triangulate {
|
||||
namespace detail {
|
||||
|
||||
|
||||
|
||||
static inline bool axisOrdering(const carve::geom2d::P2 &a,
|
||||
const carve::geom2d::P2 &b,
|
||||
int axis) {
|
||||
return a.v[axis] < b.v[axis] || (a.v[axis] == b.v[axis] && a.v[1-axis] < b.v[1-axis]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* \class order_h_loops
|
||||
* \brief Provides an ordering of hole loops based upon a single
|
||||
* projected axis.
|
||||
*
|
||||
* @tparam project_t A functor which converts vertices to a 2d
|
||||
* projection.
|
||||
* @tparam hole_t A collection of vertices.
|
||||
*/
|
||||
template<typename project_t, typename vert_t>
|
||||
class order_h_loops {
|
||||
const project_t &project;
|
||||
int axis;
|
||||
public:
|
||||
|
||||
/**
|
||||
*
|
||||
* @param _project The projection functor.
|
||||
* @param _axis The axis of the 2d projection upon which hole
|
||||
* loops are ordered.
|
||||
*/
|
||||
order_h_loops(const project_t &_project, int _axis) : project(_project), axis(_axis) { }
|
||||
|
||||
bool operator()(const vert_t &a,
|
||||
const vert_t &b) const {
|
||||
return axisOrdering(project(a), project(b), axis);
|
||||
}
|
||||
|
||||
bool operator()(
|
||||
const std::pair<const typename std::vector<vert_t> *, typename std::vector<vert_t>::const_iterator> &a,
|
||||
const std::pair<const typename std::vector<vert_t> *, typename std::vector<vert_t>::const_iterator> &b) {
|
||||
return axisOrdering(project(*(a.second)), project(*(b.second)), axis);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* \class heap_ordering
|
||||
* \brief Provides an ordering of vertex indicies in a polygon
|
||||
* loop according to proximity to a vertex.
|
||||
*
|
||||
* @tparam project_t A functor which converts vertices to a 2d
|
||||
* projection.
|
||||
* @tparam vert_t A vertex type.
|
||||
*/
|
||||
template<typename project_t, typename vert_t>
|
||||
class heap_ordering {
|
||||
const project_t &project;
|
||||
const std::vector<vert_t> &loop;
|
||||
const carve::geom2d::P2 p;
|
||||
int axis;
|
||||
|
||||
public:
|
||||
/**
|
||||
*
|
||||
* @param _project A functor which converts vertices to a 2d
|
||||
* projection.
|
||||
* @param _loop The polygon loop which indices address.
|
||||
* @param _vert The vertex from which distance is measured.
|
||||
*
|
||||
*/
|
||||
heap_ordering(const project_t &_project,
|
||||
const std::vector<vert_t> &_loop,
|
||||
vert_t _vert,
|
||||
int _axis) :
|
||||
project(_project),
|
||||
loop(_loop),
|
||||
p(_project(_vert)),
|
||||
axis(_axis) {
|
||||
}
|
||||
|
||||
bool operator()(size_t a, size_t b) const {
|
||||
carve::geom2d::P2 pa = project(loop[a]);
|
||||
carve::geom2d::P2 pb = project(loop[b]);
|
||||
double da = carve::geom::distance2(p, pa);
|
||||
double db = carve::geom::distance2(p, pb);
|
||||
if (da > db) return true;
|
||||
if (da < db) return false;
|
||||
return axisOrdering(pa, pb, axis);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* \brief Given a polygon loop and a hole loop, and attachment
|
||||
* points, insert the hole loop vertices into the polygon loop.
|
||||
*
|
||||
* @param[in,out] f_loop The polygon loop to incorporate the
|
||||
* hole into.
|
||||
* @param f_loop_attach[in] The index of the vertex of the
|
||||
* polygon loop that the hole is to be
|
||||
* attached to.
|
||||
* @param hole_attach[in] A pair consisting of a pointer to a
|
||||
* hole container and an iterator into
|
||||
* that container reflecting the point of
|
||||
* attachment of the hole.
|
||||
*/
|
||||
template<typename vert_t>
|
||||
void patchHoleIntoPolygon(std::vector<vert_t> &f_loop,
|
||||
unsigned f_loop_attach,
|
||||
const std::pair<const std::vector<vert_t> *,
|
||||
typename std::vector<vert_t>::const_iterator> &hole_attach) {
|
||||
// join the vertex curr of the polygon loop to the hole at
|
||||
// h_loop_connect
|
||||
f_loop.insert(f_loop.begin() + f_loop_attach + 1, hole_attach.first->size() + 2, NULL);
|
||||
typename std::vector<vert_t>::iterator f = f_loop.begin() + f_loop_attach;
|
||||
|
||||
typename std::vector<vert_t>::const_iterator h = hole_attach.second;
|
||||
|
||||
while (h != hole_attach.first->end()) {
|
||||
*++f = *h++;
|
||||
}
|
||||
|
||||
h = hole_attach.first->begin();
|
||||
typename std::vector<vert_t>::const_iterator he = hole_attach.second; ++he;
|
||||
while (h != he) {
|
||||
*++f = *h++;
|
||||
}
|
||||
|
||||
*++f = f_loop[f_loop_attach];
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct vertex_info;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* \brief Determine whether c is to the left of a->b.
|
||||
*/
|
||||
static inline bool isLeft(const vertex_info *a,
|
||||
const vertex_info *b,
|
||||
const vertex_info *c);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* \brief Determine whether d is contained in the triangle abc.
|
||||
*/
|
||||
static inline bool pointInTriangle(const vertex_info *a,
|
||||
const vertex_info *b,
|
||||
const vertex_info *c,
|
||||
const vertex_info *d);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* \class vertex_info
|
||||
* \brief Maintains a linked list of untriangulated vertices
|
||||
* during a triangulation operation.
|
||||
*/
|
||||
|
||||
struct vertex_info {
|
||||
vertex_info *prev;
|
||||
vertex_info *next;
|
||||
carve::geom2d::P2 p;
|
||||
size_t idx;
|
||||
double score;
|
||||
bool convex;
|
||||
bool failed;
|
||||
|
||||
vertex_info(const carve::geom2d::P2 &_p, size_t _idx) :
|
||||
prev(NULL), next(NULL),
|
||||
p(_p), idx(_idx),
|
||||
score(0.0), convex(false) {
|
||||
}
|
||||
|
||||
static double triScore(const vertex_info *p, const vertex_info *v, const vertex_info *n);
|
||||
|
||||
double calcScore() const;
|
||||
|
||||
void recompute() {
|
||||
score = calcScore();
|
||||
convex = isLeft(prev, this, next);
|
||||
failed = false;
|
||||
}
|
||||
|
||||
bool isCandidate() const {
|
||||
return convex && !failed;
|
||||
}
|
||||
|
||||
void remove() {
|
||||
next->prev = prev;
|
||||
prev->next = next;
|
||||
}
|
||||
|
||||
bool isClipable() const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
static inline bool isLeft(const vertex_info *a,
|
||||
const vertex_info *b,
|
||||
const vertex_info *c) {
|
||||
if (a->idx < b->idx && b->idx < c->idx) {
|
||||
return carve::geom2d::orient2d(a->p, b->p, c->p) > 0.0;
|
||||
} else if (a->idx < c->idx && c->idx < b->idx) {
|
||||
return carve::geom2d::orient2d(a->p, c->p, b->p) < 0.0;
|
||||
} else if (b->idx < a->idx && a->idx < c->idx) {
|
||||
return carve::geom2d::orient2d(b->p, a->p, c->p) < 0.0;
|
||||
} else if (b->idx < c->idx && c->idx < a->idx) {
|
||||
return carve::geom2d::orient2d(b->p, c->p, a->p) > 0.0;
|
||||
} else if (c->idx < a->idx && a->idx < b->idx) {
|
||||
return carve::geom2d::orient2d(c->p, a->p, b->p) > 0.0;
|
||||
} else {
|
||||
return carve::geom2d::orient2d(c->p, b->p, a->p) < 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static inline bool pointInTriangle(const vertex_info *a,
|
||||
const vertex_info *b,
|
||||
const vertex_info *c,
|
||||
const vertex_info *d) {
|
||||
return !isLeft(a, c, d) && !isLeft(b, a, d) && !isLeft(c, b, d);
|
||||
}
|
||||
|
||||
|
||||
|
||||
size_t removeDegeneracies(vertex_info *&begin, std::vector<carve::triangulate::tri_idx> &result);
|
||||
|
||||
bool splitAndResume(vertex_info *begin, std::vector<carve::triangulate::tri_idx> &result);
|
||||
|
||||
bool doTriangulate(vertex_info *begin, std::vector<carve::triangulate::tri_idx> &result);
|
||||
|
||||
|
||||
|
||||
typedef std::pair<unsigned, unsigned> vert_edge_t;
|
||||
|
||||
|
||||
|
||||
struct hash_vert_edge_t {
|
||||
size_t operator()(const vert_edge_t &e) const {
|
||||
size_t r = (size_t)e.first;
|
||||
size_t s = (size_t)e.second;
|
||||
return r ^ ((s >> 16) | (s << 16));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
static inline vert_edge_t ordered_vert_edge_t(unsigned a, unsigned b) {
|
||||
return (a < b) ? vert_edge_t(a, b) : vert_edge_t(b, a);
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct tri_pair_t {
|
||||
carve::triangulate::tri_idx *a, *b;
|
||||
double score;
|
||||
size_t idx;
|
||||
|
||||
tri_pair_t() : a(NULL), b(NULL), score(0.0) {
|
||||
}
|
||||
|
||||
static inline unsigned N(unsigned i) { return (i+1)%3; }
|
||||
static inline unsigned P(unsigned i) { return (i+2)%3; }
|
||||
|
||||
void findSharedEdge(unsigned &ai, unsigned &bi) const {
|
||||
if (a->v[1] == b->v[0]) { if (a->v[0] == b->v[1]) { ai = 0; bi = 0; } else { ai = 1; bi = 2; } return; }
|
||||
if (a->v[1] == b->v[1]) { if (a->v[0] == b->v[2]) { ai = 0; bi = 1; } else { ai = 1; bi = 0; } return; }
|
||||
if (a->v[1] == b->v[2]) { if (a->v[0] == b->v[0]) { ai = 0; bi = 2; } else { ai = 1; bi = 1; } return; }
|
||||
if (a->v[2] == b->v[0]) { ai = 2; bi = 2; return; }
|
||||
if (a->v[2] == b->v[1]) { ai = 2; bi = 0; return; }
|
||||
if (a->v[2] == b->v[2]) { ai = 2; bi = 1; return; }
|
||||
CARVE_FAIL("should not be reached");
|
||||
}
|
||||
|
||||
void flip(vert_edge_t &old_edge,
|
||||
vert_edge_t &new_edge,
|
||||
vert_edge_t perim[4]);
|
||||
|
||||
template<typename project_t, typename vert_t, typename distance_calc_t>
|
||||
double calc(const project_t &project,
|
||||
const std::vector<vert_t> &poly,
|
||||
distance_calc_t dist) {
|
||||
unsigned ai, bi;
|
||||
unsigned cross_ai, cross_bi;
|
||||
unsigned ea, eb;
|
||||
|
||||
findSharedEdge(ai, bi);
|
||||
|
||||
#if defined(CARVE_DEBUG)
|
||||
if (carve::geom2d::signedArea(project(poly[a->v[0]]), project(poly[a->v[1]]), project(poly[a->v[2]])) > 0.0 ||
|
||||
carve::geom2d::signedArea(project(poly[b->v[0]]), project(poly[b->v[1]]), project(poly[b->v[2]])) > 0.0) {
|
||||
std::cerr << "warning: triangle pair " << this << " contains triangles with incorrect orientation" << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
cross_ai = P(ai);
|
||||
cross_bi = P(bi);
|
||||
|
||||
ea = a->v[cross_ai];
|
||||
eb = b->v[cross_bi];
|
||||
|
||||
double side_1 = carve::geom2d::orient2d(project(poly[ea]), project(poly[eb]), project(poly[a->v[ai]]));
|
||||
double side_2 = carve::geom2d::orient2d(project(poly[ea]), project(poly[eb]), project(poly[a->v[N(ai)]]));
|
||||
|
||||
bool can_flip = (side_1 < 0.0 && side_2 > 0.0) || (side_1 > 0.0 && side_2 < 0.0);
|
||||
|
||||
if (!can_flip) {
|
||||
score = -1;
|
||||
} else {
|
||||
score =
|
||||
dist(poly[a->v[ai]], poly[b->v[bi]]) -
|
||||
dist(poly[a->v[cross_ai]], poly[b->v[cross_bi]]);
|
||||
}
|
||||
return score;
|
||||
}
|
||||
|
||||
template<typename project_t, typename vert_t, typename distance_calc_t>
|
||||
double edgeLen(const project_t &project,
|
||||
const std::vector<vert_t> &poly,
|
||||
distance_calc_t dist) const {
|
||||
unsigned ai, bi;
|
||||
findSharedEdge(ai, bi);
|
||||
return dist(poly[a->v[ai]], poly[b->v[bi]]);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct max_score {
|
||||
bool operator()(const tri_pair_t *a, const tri_pair_t *b) const { return a->score < b->score; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct tri_pairs_t {
|
||||
typedef std::unordered_map<vert_edge_t, tri_pair_t *, hash_vert_edge_t> storage_t;
|
||||
storage_t storage;
|
||||
|
||||
tri_pairs_t() : storage() {
|
||||
};
|
||||
|
||||
~tri_pairs_t() {
|
||||
for (storage_t::iterator i = storage.begin(); i != storage.end(); ++i) {
|
||||
if ((*i).second) delete (*i).second;
|
||||
}
|
||||
}
|
||||
|
||||
void insert(unsigned a, unsigned b, carve::triangulate::tri_idx *t);
|
||||
|
||||
template<typename project_t, typename vert_t, typename distance_calc_t>
|
||||
void updateEdge(tri_pair_t *tp,
|
||||
const project_t &project,
|
||||
const std::vector<vert_t> &poly,
|
||||
distance_calc_t dist,
|
||||
std::vector<tri_pair_t *> &edges,
|
||||
size_t &n) {
|
||||
double old_score = tp->score;
|
||||
double new_score = tp->calc(project, poly, dist);
|
||||
#if defined(CARVE_DEBUG)
|
||||
std::cerr << "tp:" << tp << " old_score: " << old_score << " new_score: " << new_score << std::endl;
|
||||
#endif
|
||||
if (new_score > 0.0 && old_score <= 0.0) {
|
||||
tp->idx = n;
|
||||
edges[n++] = tp;
|
||||
} else if (new_score <= 0.0 && old_score > 0.0) {
|
||||
std::swap(edges[tp->idx], edges[--n]);
|
||||
edges[tp->idx]->idx = tp->idx;
|
||||
}
|
||||
}
|
||||
|
||||
tri_pair_t *get(vert_edge_t &e) {
|
||||
storage_t::iterator i;
|
||||
i = storage.find(e);
|
||||
if (i == storage.end()) return NULL;
|
||||
return (*i).second;
|
||||
}
|
||||
|
||||
template<typename project_t, typename vert_t, typename distance_calc_t>
|
||||
void flip(const project_t &project,
|
||||
const std::vector<vert_t> &poly,
|
||||
distance_calc_t dist,
|
||||
std::vector<tri_pair_t *> &edges,
|
||||
size_t &n) {
|
||||
vert_edge_t old_e, new_e;
|
||||
vert_edge_t perim[4];
|
||||
|
||||
#if defined(CARVE_DEBUG)
|
||||
std::cerr << "improvable edges: " << n << std::endl;
|
||||
#endif
|
||||
|
||||
tri_pair_t *tp = *std::max_element(edges.begin(), edges.begin() + n, max_score());
|
||||
|
||||
#if defined(CARVE_DEBUG)
|
||||
std::cerr << "improving tri-pair: " << tp << " with score: " << tp->score << std::endl;
|
||||
#endif
|
||||
|
||||
tp->flip(old_e, new_e, perim);
|
||||
|
||||
#if defined(CARVE_DEBUG)
|
||||
std::cerr << "old_e: " << old_e.first << "," << old_e.second << " -> new_e: " << new_e.first << "," << new_e.second << std::endl;
|
||||
#endif
|
||||
|
||||
CARVE_ASSERT(storage.find(old_e) != storage.end());
|
||||
storage.erase(old_e);
|
||||
storage[new_e] = tp;
|
||||
|
||||
std::swap(edges[tp->idx], edges[--n]);
|
||||
edges[tp->idx]->idx = tp->idx;
|
||||
|
||||
tri_pair_t *tp2;
|
||||
|
||||
tp2 = get(perim[0]);
|
||||
if (tp2 != NULL) {
|
||||
updateEdge(tp2, project, poly, dist, edges, n);
|
||||
}
|
||||
|
||||
tp2 = get(perim[1]);
|
||||
if (tp2 != NULL) {
|
||||
CARVE_ASSERT(tp2->a == tp->b || tp2->b == tp->b);
|
||||
if (tp2->a == tp->b) { tp2->a = tp->a; } else { tp2->b = tp->a; }
|
||||
updateEdge(tp2, project, poly, dist, edges, n);
|
||||
}
|
||||
|
||||
tp2 = get(perim[2]);
|
||||
if (tp2 != NULL) {
|
||||
updateEdge(tp2, project, poly, dist, edges, n);
|
||||
}
|
||||
|
||||
tp2 = get(perim[3]);
|
||||
if (tp2 != NULL) {
|
||||
CARVE_ASSERT(tp2->a == tp->a || tp2->b == tp->a);
|
||||
if (tp2->a == tp->a) { tp2->a = tp->b; } else { tp2->b = tp->b; }
|
||||
updateEdge(tp2, project, poly, dist, edges, n);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename project_t, typename vert_t, typename distance_calc_t>
|
||||
size_t getInternalEdges(const project_t &project,
|
||||
const std::vector<vert_t> &poly,
|
||||
distance_calc_t dist,
|
||||
std::vector<tri_pair_t *> &edges) {
|
||||
size_t count = 0;
|
||||
|
||||
for (storage_t::iterator i = storage.begin(); i != storage.end();) {
|
||||
tri_pair_t *tp = (*i).second;
|
||||
if (tp->a && tp->b) {
|
||||
tp->calc(project, poly, dist);
|
||||
count++;
|
||||
#if defined(CARVE_DEBUG)
|
||||
std::cerr << "internal edge: " << (*i).first.first << "," << (*i).first.second << " -> " << tp << " " << tp->score << std::endl;
|
||||
#endif
|
||||
++i;
|
||||
} else {
|
||||
delete (*i).second;
|
||||
storage.erase(i++);
|
||||
}
|
||||
}
|
||||
|
||||
edges.resize(count);
|
||||
|
||||
size_t fwd = 0;
|
||||
size_t rev = count;
|
||||
for (storage_t::iterator i = storage.begin(); i != storage.end(); ++i) {
|
||||
tri_pair_t *tp = (*i).second;
|
||||
if (tp && tp->a && tp->b) {
|
||||
if (tp->score > 0.0) {
|
||||
edges[fwd++] = tp;
|
||||
} else {
|
||||
edges[--rev] = tp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CARVE_ASSERT(fwd == rev);
|
||||
|
||||
return fwd;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename project_t, typename vert_t>
|
||||
static bool
|
||||
testCandidateAttachment(const project_t &project,
|
||||
std::vector<vert_t> ¤t_f_loop,
|
||||
size_t curr,
|
||||
carve::geom2d::P2 hole_min) {
|
||||
const size_t SZ = current_f_loop.size();
|
||||
|
||||
size_t prev, next;
|
||||
|
||||
if (curr == 0) {
|
||||
prev = SZ - 1; next = 1;
|
||||
} else if (curr == SZ - 1) {
|
||||
prev = curr - 1; next = 0;
|
||||
} else {
|
||||
prev = curr - 1; next = curr + 1;
|
||||
}
|
||||
|
||||
if (!carve::geom2d::internalToAngle(project(current_f_loop[next]),
|
||||
project(current_f_loop[curr]),
|
||||
project(current_f_loop[prev]),
|
||||
hole_min)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hole_min == project(current_f_loop[curr])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
carve::geom2d::LineSegment2 test(hole_min, project(current_f_loop[curr]));
|
||||
|
||||
size_t v1 = current_f_loop.size() - 1;
|
||||
size_t v2 = 0;
|
||||
double v1_side = carve::geom2d::orient2d(test.v1, test.v2, project(current_f_loop[v1]));
|
||||
double v2_side = 0;
|
||||
|
||||
while (v2 != current_f_loop.size()) {
|
||||
v2_side = carve::geom2d::orient2d(test.v1, test.v2, project(current_f_loop[v2]));
|
||||
|
||||
if (v1_side != v2_side) {
|
||||
// XXX: need to test vertices, not indices, because they may
|
||||
// be duplicated.
|
||||
if (project(current_f_loop[v1]) != project(current_f_loop[curr]) &&
|
||||
project(current_f_loop[v2]) != project(current_f_loop[curr])) {
|
||||
carve::geom2d::LineSegment2 test2(project(current_f_loop[v1]), project(current_f_loop[v2]));
|
||||
if (carve::geom2d::lineSegmentIntersection_simple(test, test2)) {
|
||||
// intersection; failed.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
v1 = v2;
|
||||
v1_side = v2_side;
|
||||
++v2;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename project_t, typename vert_t>
|
||||
static std::vector<vert_t>
|
||||
incorporateHolesIntoPolygon(const project_t &project,
|
||||
const std::vector<vert_t> &f_loop,
|
||||
const std::vector<std::vector<vert_t> > &h_loops) {
|
||||
typedef std::vector<vert_t> hole_t;
|
||||
typedef typename std::vector<vert_t>::const_iterator vert_iter;
|
||||
typedef typename std::vector<std::vector<vert_t> >::const_iterator hole_iter;
|
||||
|
||||
size_t N = f_loop.size();
|
||||
|
||||
// work out how much space to reserve for the patched in holes.
|
||||
for (hole_iter i = h_loops.begin(); i != h_loops.end(); ++i) {
|
||||
N += 2 + (*i).size();
|
||||
}
|
||||
|
||||
// this is the vector that we will build the result in.
|
||||
std::vector<vert_t> current_f_loop;
|
||||
current_f_loop.reserve(N);
|
||||
|
||||
std::vector<size_t> f_loop_heap;
|
||||
f_loop_heap.reserve(N);
|
||||
|
||||
for (unsigned i = 0; i < f_loop.size(); ++i) {
|
||||
current_f_loop.push_back(f_loop[i]);
|
||||
}
|
||||
|
||||
std::vector<std::pair<const std::vector<vert_t> *, vert_iter> > h_loop_min_vertex;
|
||||
|
||||
h_loop_min_vertex.reserve(h_loops.size());
|
||||
|
||||
// find the major axis for the holes - this is the axis that we
|
||||
// will sort on for finding vertices on the polygon to join
|
||||
// holes up to.
|
||||
//
|
||||
// it might also be nice to also look for whether it is better
|
||||
// to sort ascending or descending.
|
||||
//
|
||||
// another trick that could be used is to modify the projection
|
||||
// by 90 degree rotations or flipping about an axis. just as
|
||||
// long as we keep the carve::geom3d::Vector pointers for the
|
||||
// real data in sync, everything should be ok. then we wouldn't
|
||||
// need to accomodate axes or sort order in the main loop.
|
||||
|
||||
// find the bounding box of all the holes.
|
||||
bool first = true;
|
||||
double min_x, min_y, max_x, max_y;
|
||||
for (hole_iter i = h_loops.begin(); i != h_loops.end(); ++i) {
|
||||
const hole_t &hole(*i);
|
||||
for (vert_iter j = hole.begin(); j != hole.end(); ++j) {
|
||||
carve::geom2d::P2 curr = project(*j);
|
||||
if (first) {
|
||||
min_x = max_x = curr.x;
|
||||
min_y = max_y = curr.y;
|
||||
first = false;
|
||||
} else {
|
||||
min_x = std::min(min_x, curr.x);
|
||||
min_y = std::min(min_y, curr.y);
|
||||
max_x = std::max(max_x, curr.x);
|
||||
max_y = std::max(max_y, curr.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// choose the axis for which the bbox is largest.
|
||||
int axis = (max_x - min_x) > (max_y - min_y) ? 0 : 1;
|
||||
|
||||
// for each hole, find the minimum vertex in the chosen axis.
|
||||
for (hole_iter i = h_loops.begin(); i != h_loops.end(); ++i) {
|
||||
const hole_t &hole = *i;
|
||||
vert_iter best_i = std::min_element(hole.begin(), hole.end(), detail::order_h_loops<project_t, vert_t>(project, axis));
|
||||
h_loop_min_vertex.push_back(std::make_pair(&hole, best_i));
|
||||
}
|
||||
|
||||
// sort the holes by the minimum vertex.
|
||||
std::sort(h_loop_min_vertex.begin(), h_loop_min_vertex.end(), detail::order_h_loops<project_t, vert_t>(project, axis));
|
||||
|
||||
// now, for each hole, find a vertex in the current polygon loop that it can be joined to.
|
||||
for (unsigned i = 0; i < h_loop_min_vertex.size(); ++i) {
|
||||
const size_t N_f_loop = current_f_loop.size();
|
||||
|
||||
// the index of the vertex in the hole to connect.
|
||||
vert_iter h_loop_connect = h_loop_min_vertex[i].second;
|
||||
|
||||
carve::geom2d::P2 hole_min = project(*h_loop_connect);
|
||||
|
||||
f_loop_heap.clear();
|
||||
// we order polygon loop vertices that may be able to be connected
|
||||
// to the hole vertex by their distance to the hole vertex
|
||||
detail::heap_ordering<project_t, vert_t> _heap_ordering(project, current_f_loop, *h_loop_connect, axis);
|
||||
|
||||
for (size_t j = 0; j < N_f_loop; ++j) {
|
||||
// it is guaranteed that there exists a polygon vertex with
|
||||
// coord < the min hole coord chosen, which can be joined to
|
||||
// the min hole coord without crossing the polygon
|
||||
// boundary. also, because we merge holes in ascending
|
||||
// order, it is also true that this join can never cross
|
||||
// another hole (and that doesn't need to be tested for).
|
||||
if (project(current_f_loop[j]).v[axis] <= hole_min.v[axis]) {
|
||||
f_loop_heap.push_back(j);
|
||||
std::push_heap(f_loop_heap.begin(), f_loop_heap.end(), _heap_ordering);
|
||||
}
|
||||
}
|
||||
|
||||
// we are going to test each potential (according to the
|
||||
// previous test) polygon vertex as a candidate join. we order
|
||||
// by closeness to the hole vertex, so that the join we make
|
||||
// is as small as possible. to test, we need to check the
|
||||
// joining line segment does not cross any other line segment
|
||||
// in the current polygon loop (excluding those that have the
|
||||
// vertex that we are attempting to join with as an endpoint).
|
||||
size_t attachment_point = current_f_loop.size();
|
||||
|
||||
while (f_loop_heap.size()) {
|
||||
std::pop_heap(f_loop_heap.begin(), f_loop_heap.end(), _heap_ordering);
|
||||
size_t curr = f_loop_heap.back();
|
||||
f_loop_heap.pop_back();
|
||||
// test the candidate join from current_f_loop[curr] to hole_min
|
||||
|
||||
if (!detail::testCandidateAttachment(project, current_f_loop, curr, hole_min)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
attachment_point = curr;
|
||||
break;
|
||||
}
|
||||
|
||||
if (attachment_point == current_f_loop.size()) {
|
||||
CARVE_FAIL("didn't manage to link up hole!");
|
||||
}
|
||||
|
||||
detail::patchHoleIntoPolygon(current_f_loop, attachment_point, h_loop_min_vertex[i]);
|
||||
}
|
||||
|
||||
return current_f_loop;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename project_t, typename vert_t>
|
||||
void triangulate(const project_t &project,
|
||||
const std::vector<vert_t> &poly,
|
||||
std::vector<tri_idx> &result) {
|
||||
std::vector<detail::vertex_info *> vinfo;
|
||||
const size_t N = poly.size();
|
||||
|
||||
result.clear();
|
||||
if (N < 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
result.reserve(poly.size() - 2);
|
||||
|
||||
if (N == 3) {
|
||||
result.push_back(tri_idx(0, 1, 2));
|
||||
return;
|
||||
}
|
||||
|
||||
vinfo.resize(N);
|
||||
|
||||
vinfo[0] = new detail::vertex_info(project(poly[0]), 0);
|
||||
for (size_t i = 1; i < N-1; ++i) {
|
||||
vinfo[i] = new detail::vertex_info(project(poly[i]), i);
|
||||
vinfo[i]->prev = vinfo[i-1];
|
||||
vinfo[i-1]->next = vinfo[i];
|
||||
}
|
||||
vinfo[N-1] = new detail::vertex_info(project(poly[N-1]), N-1);
|
||||
vinfo[N-1]->prev = vinfo[N-2];
|
||||
vinfo[N-1]->next = vinfo[0];
|
||||
vinfo[0]->prev = vinfo[N-1];
|
||||
vinfo[N-2]->next = vinfo[N-1];
|
||||
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
vinfo[i]->recompute();
|
||||
}
|
||||
|
||||
detail::vertex_info *begin = vinfo[0];
|
||||
|
||||
removeDegeneracies(begin, result);
|
||||
doTriangulate(begin, result);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename project_t, typename vert_t, typename distance_calc_t>
|
||||
void improve(const project_t &project,
|
||||
const std::vector<vert_t> &poly,
|
||||
distance_calc_t dist,
|
||||
std::vector<tri_idx> &result) {
|
||||
detail::tri_pairs_t tri_pairs;
|
||||
|
||||
#if defined(CARVE_DEBUG)
|
||||
bool warn = false;
|
||||
for (size_t i = 0; i < result.size(); ++i) {
|
||||
tri_idx &t = result[i];
|
||||
if (carve::geom2d::signedArea(project(poly[t.a]), project(poly[t.b]), project(poly[t.c])) > 0) {
|
||||
warn = true;
|
||||
}
|
||||
}
|
||||
if (warn) {
|
||||
std::cerr << "carve::triangulate::improve(): Some triangles are incorrectly oriented. Results may be incorrect." << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (size_t i = 0; i < result.size(); ++i) {
|
||||
tri_idx &t = result[i];
|
||||
tri_pairs.insert(t.a, t.b, &t);
|
||||
tri_pairs.insert(t.b, t.c, &t);
|
||||
tri_pairs.insert(t.c, t.a, &t);
|
||||
}
|
||||
|
||||
std::vector<detail::tri_pair_t *> edges;
|
||||
size_t n = tri_pairs.getInternalEdges(project, poly, dist, edges);
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
edges[i]->idx = i;
|
||||
}
|
||||
|
||||
// procedure:
|
||||
// while a tri pair with a positive score exists:
|
||||
// p = pair with highest positive score
|
||||
// flip p, rewriting its two referenced triangles.
|
||||
// negate p's score
|
||||
// for each q in the up-to-four adjoining tri pairs:
|
||||
// update q's tri ptr, if changed, and its score.
|
||||
|
||||
#if defined(CARVE_DEBUG)
|
||||
double initial_score = 0;
|
||||
for (size_t i = 0; i < edges.size(); ++i) {
|
||||
initial_score += edges[i]->edgeLen(project, poly, dist);
|
||||
}
|
||||
std::cerr << "initial score: " << initial_score << std::endl;
|
||||
#endif
|
||||
|
||||
while (n) {
|
||||
tri_pairs.flip(project, poly, dist, edges, n);
|
||||
}
|
||||
|
||||
#if defined(CARVE_DEBUG)
|
||||
double final_score = 0;
|
||||
for (size_t i = 0; i < edges.size(); ++i) {
|
||||
final_score += edges[i]->edgeLen(project, poly, dist);
|
||||
}
|
||||
std::cerr << "final score: " << final_score << std::endl;
|
||||
#endif
|
||||
|
||||
#if defined(CARVE_DEBUG)
|
||||
if (!warn) {
|
||||
for (size_t i = 0; i < result.size(); ++i) {
|
||||
tri_idx &t = result[i];
|
||||
CARVE_ASSERT (carve::geom2d::signedArea(project(poly[t.a]), project(poly[t.b]), project(poly[t.c])) <= 0.0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename project_t, typename vert_t>
|
||||
void improve(const project_t &project,
|
||||
const std::vector<vert_t> &poly,
|
||||
std::vector<tri_idx> &result) {
|
||||
improve(project, poly, carve::geom::distance_functor(), result);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
31
extern/carve/include/carve/util.hpp
vendored
Normal file
31
extern/carve/include/carve/util.hpp
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace carve {
|
||||
namespace util {
|
||||
struct min_functor {
|
||||
template<typename T>
|
||||
const T &operator()(const T &a, const T &b) const { return std::min(a, b); }
|
||||
};
|
||||
struct max_functor {
|
||||
template<typename T>
|
||||
const T &operator()(const T &a, const T &b) const { return std::max(a, b); }
|
||||
};
|
||||
}
|
||||
}
|
17
extern/carve/include/carve/vcpp_config.h
vendored
Normal file
17
extern/carve/include/carve/vcpp_config.h
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
/* include/carve/config.h. Generated from config.h.in by configure. */
|
||||
#pragma once
|
||||
|
||||
#include <math.h>
|
||||
|
||||
/* Define if using boost collections. Preferred, because the visual C++ unordered collections are slow and memory hungry. */
|
||||
#define HAVE_BOOST_UNORDERED_COLLECTIONS
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning(disable:4201)
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
static inline double round(double value) {
|
||||
return (value >= 0) ? floor(value + 0.5) : ceil(value - 0.5);
|
||||
}
|
163
extern/carve/include/carve/vector.hpp
vendored
Normal file
163
extern/carve/include/carve/vector.hpp
vendored
Normal file
@ -0,0 +1,163 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
|
||||
#include <carve/math_constants.hpp>
|
||||
#include <carve/geom.hpp>
|
||||
#include <carve/geom3d.hpp>
|
||||
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
namespace carve {
|
||||
namespace geom3d {
|
||||
|
||||
struct hash_vector_ptr {
|
||||
size_t operator()(const Vector * const &v) const {
|
||||
return (size_t)v;
|
||||
}
|
||||
size_t operator()(const std::pair<const Vector *, const Vector *> &v) const {
|
||||
size_t r = (size_t)v.first;
|
||||
size_t s = (size_t)v.second;
|
||||
return r ^ ((s >> 16) | (s << 16));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct vec_adapt_ident {
|
||||
const Vector &operator()(const Vector &v) const { return v; }
|
||||
Vector &operator()(Vector &v) const { return v; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct vec_adapt_ptr {
|
||||
const Vector &operator()(const Vector * const &v) const { return *v; }
|
||||
Vector &operator()(Vector *&v) const { return *v; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct vec_adapt_pair_first {
|
||||
template<typename pair_t> const Vector &operator()(const pair_t &v) const { return v.first; }
|
||||
template<typename pair_t> Vector &operator()(pair_t &v) const { return v.first; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct vec_adapt_pair_second {
|
||||
template<typename pair_t> const Vector &operator()(const pair_t &v) const { return v.second; }
|
||||
template<typename pair_t> Vector &operator()(pair_t &v) const { return v.second; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename adapt_t>
|
||||
struct vec_cmp_lt_x {
|
||||
adapt_t adapt;
|
||||
vec_cmp_lt_x(adapt_t _adapt = adapt_t()) : adapt(_adapt) {}
|
||||
template<typename input_t> bool operator()(const input_t &a, const input_t &b) const { return adapt(a).x < adapt(b).x; }
|
||||
};
|
||||
template<typename adapt_t> vec_cmp_lt_x<adapt_t> vec_lt_x(adapt_t &adapt) { return vec_cmp_lt_x<adapt_t>(adapt); }
|
||||
|
||||
|
||||
|
||||
template<typename adapt_t>
|
||||
struct vec_cmp_lt_y {
|
||||
adapt_t adapt;
|
||||
vec_cmp_lt_y(adapt_t _adapt = adapt_t()) : adapt(_adapt) {}
|
||||
template<typename input_t> bool operator()(const input_t &a, const input_t &b) const { return adapt(a).y < adapt(b).y; }
|
||||
};
|
||||
template<typename adapt_t> vec_cmp_lt_y<adapt_t> vec_lt_y(adapt_t &adapt) { return vec_cmp_lt_y<adapt_t>(adapt); }
|
||||
|
||||
|
||||
|
||||
template<typename adapt_t>
|
||||
struct vec_cmp_lt_z {
|
||||
adapt_t adapt;
|
||||
vec_cmp_lt_z(adapt_t _adapt = adapt_t()) : adapt(_adapt) {}
|
||||
template<typename input_t> bool operator()(const input_t &a, const input_t &b) const { return adapt(a).z < adapt(b).z; }
|
||||
};
|
||||
template<typename adapt_t> vec_cmp_lt_z<adapt_t> vec_lt_z(adapt_t &adapt) { return vec_cmp_lt_z<adapt_t>(adapt); }
|
||||
|
||||
|
||||
|
||||
template<typename adapt_t>
|
||||
struct vec_cmp_gt_x {
|
||||
adapt_t adapt;
|
||||
vec_cmp_gt_x(adapt_t _adapt = adapt_t()) : adapt(_adapt) {}
|
||||
template<typename input_t> bool operator()(const input_t &a, const input_t &b) const { return adapt(a).x > adapt(b).x; }
|
||||
};
|
||||
template<typename adapt_t> vec_cmp_gt_x<adapt_t> vec_gt_x(adapt_t &adapt) { return vec_cmp_gt_x<adapt_t>(adapt); }
|
||||
|
||||
|
||||
|
||||
template<typename adapt_t>
|
||||
struct vec_cmp_gt_y {
|
||||
adapt_t adapt;
|
||||
vec_cmp_gt_y(adapt_t _adapt = adapt_t()) : adapt(_adapt) {}
|
||||
template<typename input_t> bool operator()(const input_t &a, const input_t &b) const { return adapt(a).y > adapt(b).y; }
|
||||
};
|
||||
template<typename adapt_t> vec_cmp_gt_y<adapt_t> vec_gt_y(adapt_t &adapt) { return vec_cmp_gt_y<adapt_t>(adapt); }
|
||||
|
||||
|
||||
|
||||
template<typename adapt_t>
|
||||
struct vec_cmp_gt_z {
|
||||
adapt_t adapt;
|
||||
vec_cmp_gt_z(adapt_t _adapt = adapt_t()) : adapt(_adapt) {}
|
||||
template<typename input_t> bool operator()(const input_t &a, const input_t &b) const { return adapt(a).z > adapt(b).z; }
|
||||
};
|
||||
template<typename adapt_t> vec_cmp_gt_z<adapt_t> vec_gt_z(adapt_t &adapt) { return vec_cmp_gt_z<adapt_t>(adapt); }
|
||||
|
||||
|
||||
|
||||
template<typename iter_t, typename adapt_t>
|
||||
void sortInDirectionOfRay(const Vector &ray_dir, iter_t begin, iter_t end, adapt_t adapt) {
|
||||
switch (carve::geom::largestAxis(ray_dir)) {
|
||||
case 0:
|
||||
if (ray_dir.x > 0) {
|
||||
std::sort(begin, end, vec_lt_x(adapt));
|
||||
} else {
|
||||
std::sort(begin, end, vec_gt_x(adapt));
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (ray_dir.y > 0) {
|
||||
std::sort(begin, end, vec_lt_y(adapt));
|
||||
} else {
|
||||
std::sort(begin, end, vec_gt_y(adapt));
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (ray_dir.z > 0) {
|
||||
std::sort(begin, end, vec_lt_z(adapt));
|
||||
} else {
|
||||
std::sort(begin, end, vec_gt_z(adapt));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
111
extern/carve/include/carve/vertex_decl.hpp
vendored
Normal file
111
extern/carve/include/carve/vertex_decl.hpp
vendored
Normal file
@ -0,0 +1,111 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
|
||||
#include <carve/geom2d.hpp>
|
||||
#include <carve/vector.hpp>
|
||||
#include <carve/matrix.hpp>
|
||||
#include <carve/geom3d.hpp>
|
||||
#include <carve/aabb.hpp>
|
||||
#include <carve/tag.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
namespace carve {
|
||||
namespace poly {
|
||||
|
||||
|
||||
|
||||
struct Object;
|
||||
|
||||
|
||||
|
||||
template<unsigned ndim>
|
||||
class Vertex : public tagable {
|
||||
public:
|
||||
typedef carve::geom::vector<ndim> vector_t;
|
||||
typedef Object obj_t;
|
||||
|
||||
vector_t v;
|
||||
obj_t *owner;
|
||||
|
||||
Vertex() : tagable(), v() {
|
||||
}
|
||||
|
||||
~Vertex() {
|
||||
}
|
||||
|
||||
Vertex(const vector_t &_v) : tagable(), v(_v) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct hash_vertex_ptr {
|
||||
template<unsigned ndim>
|
||||
size_t operator()(const Vertex<ndim> * const &v) const {
|
||||
return (size_t)v;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
size_t operator()(const std::pair<const Vertex<ndim> *, const Vertex<ndim> *> &v) const {
|
||||
size_t r = (size_t)v.first;
|
||||
size_t s = (size_t)v.second;
|
||||
return r ^ ((s >> 16) | (s << 16));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<unsigned ndim>
|
||||
double distance(const Vertex<ndim> *v1, const Vertex<ndim> *v2) {
|
||||
return distance(v1->v, v2->v);
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
double distance(const Vertex<ndim> &v1, const Vertex<ndim> &v2) {
|
||||
return distance(v1.v, v2.v);
|
||||
}
|
||||
|
||||
struct vec_adapt_vertex_ref {
|
||||
template<unsigned ndim>
|
||||
const typename Vertex<ndim>::vector_t &operator()(const Vertex<ndim> &v) const { return v.v; }
|
||||
|
||||
template<unsigned ndim>
|
||||
typename Vertex<ndim>::vector_t &operator()(Vertex<ndim> &v) const { return v.v; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct vec_adapt_vertex_ptr {
|
||||
template<unsigned ndim>
|
||||
const typename Vertex<ndim>::vector_t &operator()(const Vertex<ndim> *v) const { return v->v; }
|
||||
|
||||
template<unsigned ndim>
|
||||
typename Vertex<ndim>::vector_t &operator()(Vertex<ndim> *v) const { return v->v; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
24
extern/carve/include/carve/vertex_impl.hpp
vendored
Normal file
24
extern/carve/include/carve/vertex_impl.hpp
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace carve {
|
||||
namespace poly {
|
||||
|
||||
}
|
||||
}
|
55
extern/carve/include/carve/win32.h
vendored
Executable file
55
extern/carve/include/carve/win32.h
vendored
Executable file
@ -0,0 +1,55 @@
|
||||
// Copyright 2006 Tobias Sargeant (toby@permuted.net)
|
||||
// All rights reserved.
|
||||
#pragma once
|
||||
|
||||
#pragma warning (disable : 4996)
|
||||
#pragma warning (disable : 4786)
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if !defined(__MINGW32__)
|
||||
inline int strcasecmp(const char *a, const char *b) {
|
||||
return _stricmp(a,b);
|
||||
}
|
||||
#endif
|
||||
|
||||
inline void srandom(unsigned long input) {
|
||||
srand(input);
|
||||
}
|
||||
|
||||
inline long random() {
|
||||
return rand();
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# include <carve/cbrt.h>
|
||||
|
||||
#if _MSC_VER < 1300
|
||||
// intptr_t is an integer type that is big enough to hold a pointer
|
||||
// It is not defined in VC6 so include a definition here for the older compiler
|
||||
typedef long intptr_t;
|
||||
typedef unsigned long uintptr_t;
|
||||
#endif
|
||||
|
||||
# if _MSC_VER < 1600
|
||||
// stdint.h is not available before VS2010
|
||||
#if defined(_WIN32) && !defined(__MINGW32__)
|
||||
/* The __intXX are built-in types of the visual complier! So we don't
|
||||
need to include anything else here.
|
||||
This typedefs should be in sync with types from MEM_sys_types.h */
|
||||
|
||||
typedef signed __int8 int8_t;
|
||||
typedef signed __int16 int16_t;
|
||||
typedef signed __int32 int32_t;
|
||||
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
#endif
|
||||
typedef __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
# else
|
||||
# include <stdint.h>
|
||||
# endif
|
||||
#endif
|
29
extern/carve/lib/aabb.cpp
vendored
Normal file
29
extern/carve/lib/aabb.cpp
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
# include <carve_config.h>
|
||||
#endif
|
||||
|
||||
#include <carve/aabb.hpp>
|
||||
#include <carve/geom3d.hpp>
|
||||
|
||||
namespace carve {
|
||||
namespace geom3d {
|
||||
}
|
||||
}
|
||||
|
29
extern/carve/lib/carve.cpp
vendored
Normal file
29
extern/carve/lib/carve.cpp
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
# include <carve_config.h>
|
||||
#endif
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
|
||||
#define DEF_EPSILON 1.4901161193847656e-08
|
||||
|
||||
namespace carve {
|
||||
double EPSILON = DEF_EPSILON;
|
||||
double EPSILON2 = DEF_EPSILON * DEF_EPSILON;
|
||||
}
|
100
extern/carve/lib/convex_hull.cpp
vendored
Normal file
100
extern/carve/lib/convex_hull.cpp
vendored
Normal file
@ -0,0 +1,100 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
# include <carve_config.h>
|
||||
#endif
|
||||
|
||||
#include <carve/csg.hpp>
|
||||
#include <carve/convex_hull.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace {
|
||||
|
||||
bool grahamScan(const std::vector<carve::geom2d::P2> &points,
|
||||
int vpp, int vp,
|
||||
const std::vector<int> &ordered,
|
||||
int start,
|
||||
std::vector<int> &result, int _i = 0) {
|
||||
carve::geom2d::P2 v1 = points[vp] - points[vpp];
|
||||
if (start == (int)ordered.size()) return true;
|
||||
|
||||
for (int i = start; i < (int)ordered.size(); ++i) {
|
||||
int v = ordered[i];
|
||||
carve::geom2d::P2 v2 = points[v] - points[vp];
|
||||
|
||||
double cp = v1.x * v2.y - v2.x * v1.y;
|
||||
if (cp < 0) return false;
|
||||
|
||||
int j = i + 1;
|
||||
while (j < (int)ordered.size() && points[ordered[j]] == points[v]) j++;
|
||||
|
||||
result.push_back(v);
|
||||
if (grahamScan(points, vp, v, ordered, j, result, _i + 1)) return true;
|
||||
result.pop_back();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace carve {
|
||||
namespace geom {
|
||||
|
||||
std::vector<int> convexHull(const std::vector<carve::geom2d::P2> &points) {
|
||||
double max_x = points[0].x;
|
||||
unsigned max_v = 0;
|
||||
|
||||
for (unsigned i = 1; i < points.size(); ++i) {
|
||||
if (points[i].x > max_x) {
|
||||
max_x = points[i].x;
|
||||
max_v = i;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::pair<double, double> > angle_dist;
|
||||
std::vector<int> ordered;
|
||||
angle_dist.reserve(points.size());
|
||||
ordered.reserve(points.size() - 1);
|
||||
for (unsigned i = 0; i < points.size(); ++i) {
|
||||
if (i == max_v) continue;
|
||||
angle_dist[i] = std::make_pair(carve::math::ANG(carve::geom2d::atan2(points[i] - points[max_v])), distance2(points[i], points[max_v]));
|
||||
ordered.push_back(i);
|
||||
}
|
||||
|
||||
std::sort(ordered.begin(),
|
||||
ordered.end(),
|
||||
make_index_sort(angle_dist.begin()));
|
||||
|
||||
std::vector<int> result;
|
||||
result.push_back(max_v);
|
||||
result.push_back(ordered[0]);
|
||||
|
||||
if (!grahamScan(points, max_v, ordered[0], ordered, 1, result)) {
|
||||
result.clear();
|
||||
throw carve::exception("convex hull failed!");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
93
extern/carve/lib/csg.cpp
vendored
Normal file
93
extern/carve/lib/csg.cpp
vendored
Normal file
@ -0,0 +1,93 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
# include <carve_config.h>
|
||||
#endif
|
||||
|
||||
#include <carve/csg.hpp>
|
||||
#include "csg_detail.hpp"
|
||||
|
||||
|
||||
const char *carve::csg::ENUM(carve::csg::FaceClass f) {
|
||||
if (f == FACE_ON_ORIENT_OUT) return "FACE_ON_ORIENT_OUT";
|
||||
if (f == FACE_OUT) return "FACE_OUT";
|
||||
if (f == FACE_IN) return "FACE_IN";
|
||||
if (f == FACE_ON_ORIENT_IN) return "FACE_ON_ORIENT_IN";
|
||||
return "???";
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *carve::csg::ENUM(carve::PointClass p) {
|
||||
if (p == POINT_UNK) return "POINT_UNK";
|
||||
if (p == POINT_OUT) return "POINT_OUT";
|
||||
if (p == POINT_ON) return "POINT_ON";
|
||||
if (p == POINT_IN) return "POINT_IN";
|
||||
if (p == POINT_VERTEX) return "POINT_VERTEX";
|
||||
if (p == POINT_EDGE) return "POINT_EDGE";
|
||||
return "???";
|
||||
}
|
||||
|
||||
|
||||
|
||||
void carve::csg::detail::LoopEdges::addFaceLoop(FaceLoop *fl) {
|
||||
carve::mesh::MeshSet<3>::vertex_t *v1, *v2;
|
||||
v1 = fl->vertices[fl->vertices.size() - 1];
|
||||
for (unsigned j = 0; j < fl->vertices.size(); ++j) {
|
||||
v2 = fl->vertices[j];
|
||||
(*this)[std::make_pair(v1, v2)].push_back(fl);
|
||||
v1 = v2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void carve::csg::detail::LoopEdges::sortFaceLoopLists() {
|
||||
for (super::iterator i = begin(), e = end(); i != e; ++i) {
|
||||
(*i).second.sort();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void carve::csg::detail::LoopEdges::removeFaceLoop(FaceLoop *fl) {
|
||||
carve::mesh::MeshSet<3>::vertex_t *v1, *v2;
|
||||
v1 = fl->vertices[fl->vertices.size() - 1];
|
||||
for (unsigned j = 0; j < fl->vertices.size(); ++j) {
|
||||
v2 = fl->vertices[j];
|
||||
iterator l(find(std::make_pair(v1, v2)));
|
||||
if (l != end()) {
|
||||
(*l).second.remove(fl);
|
||||
if (!(*l).second.size()) {
|
||||
erase(l);
|
||||
}
|
||||
}
|
||||
v1 = v2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
carve::csg::FaceClass carve::csg::FaceLoopGroup::classificationAgainst(const carve::mesh::MeshSet<3>::mesh_t *mesh) const {
|
||||
for (std::list<ClassificationInfo>::const_iterator i = classification.begin(); i != classification.end(); ++i) {
|
||||
if ((*i).intersected_mesh == mesh) {
|
||||
return (*i).classification;
|
||||
}
|
||||
}
|
||||
return FACE_UNCLASSIFIED;
|
||||
}
|
371
extern/carve/lib/csg_collector.cpp
vendored
Normal file
371
extern/carve/lib/csg_collector.cpp
vendored
Normal file
@ -0,0 +1,371 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
# include <carve_config.h>
|
||||
#endif
|
||||
|
||||
#include <carve/csg.hpp>
|
||||
#include <iostream>
|
||||
#include "intersect_debug.hpp"
|
||||
|
||||
#if defined(CARVE_DEBUG_WRITE_PLY_DATA)
|
||||
void writePLY(const std::string &out_file, const carve::mesh::MeshSet<3> *poly, bool ascii);
|
||||
#endif
|
||||
|
||||
|
||||
namespace carve {
|
||||
namespace csg {
|
||||
namespace {
|
||||
|
||||
class BaseCollector : public CSG::Collector {
|
||||
BaseCollector();
|
||||
BaseCollector(const BaseCollector &);
|
||||
BaseCollector &operator=(const BaseCollector &);
|
||||
|
||||
protected:
|
||||
struct face_data_t {
|
||||
carve::mesh::MeshSet<3>::face_t *face;
|
||||
const carve::mesh::MeshSet<3>::face_t *orig_face;
|
||||
bool flipped;
|
||||
face_data_t(carve::mesh::MeshSet<3>::face_t *_face,
|
||||
const carve::mesh::MeshSet<3>::face_t *_orig_face,
|
||||
bool _flipped) : face(_face), orig_face(_orig_face), flipped(_flipped) {
|
||||
};
|
||||
};
|
||||
|
||||
std::list<face_data_t> faces;
|
||||
|
||||
const carve::mesh::MeshSet<3> *src_a;
|
||||
const carve::mesh::MeshSet<3> *src_b;
|
||||
|
||||
BaseCollector(const carve::mesh::MeshSet<3> *_src_a,
|
||||
const carve::mesh::MeshSet<3> *_src_b) : CSG::Collector(), src_a(_src_a), src_b(_src_b) {
|
||||
}
|
||||
|
||||
virtual ~BaseCollector() {
|
||||
}
|
||||
|
||||
void FWD(const carve::mesh::MeshSet<3>::face_t *orig_face,
|
||||
const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &vertices,
|
||||
carve::geom3d::Vector /* normal */,
|
||||
bool /* poly_a */,
|
||||
FaceClass face_class,
|
||||
CSG::Hooks &hooks) {
|
||||
std::vector<carve::mesh::MeshSet<3>::face_t *> new_faces;
|
||||
new_faces.reserve(1);
|
||||
new_faces.push_back(orig_face->create(vertices.begin(), vertices.end(), false));
|
||||
hooks.processOutputFace(new_faces, orig_face, false);
|
||||
for (size_t i = 0; i < new_faces.size(); ++i) {
|
||||
faces.push_back(face_data_t(new_faces[i], orig_face, false));
|
||||
}
|
||||
|
||||
#if defined(CARVE_DEBUG) && defined(DEBUG_PRINT_RESULT_FACES)
|
||||
std::cerr << "+" << ENUM(face_class) << " ";
|
||||
for (unsigned i = 0; i < vertices.size(); ++i) std::cerr << " " << vertices[i] << ":" << *vertices[i];
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
void REV(const carve::mesh::MeshSet<3>::face_t *orig_face,
|
||||
const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &vertices,
|
||||
carve::geom3d::Vector /* normal */,
|
||||
bool /* poly_a */,
|
||||
FaceClass face_class,
|
||||
CSG::Hooks &hooks) {
|
||||
// normal = -normal;
|
||||
std::vector<carve::mesh::MeshSet<3>::face_t *> new_faces;
|
||||
new_faces.reserve(1);
|
||||
new_faces.push_back(orig_face->create(vertices.begin(), vertices.end(), true));
|
||||
hooks.processOutputFace(new_faces, orig_face, true);
|
||||
for (size_t i = 0; i < new_faces.size(); ++i) {
|
||||
faces.push_back(face_data_t(new_faces[i], orig_face, true));
|
||||
}
|
||||
|
||||
#if defined(CARVE_DEBUG) && defined(DEBUG_PRINT_RESULT_FACES)
|
||||
std::cerr << "-" << ENUM(face_class) << " ";
|
||||
for (unsigned i = 0; i < vertices.size(); ++i) std::cerr << " " << vertices[i] << ":" << *vertices[i];
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual void collect(const carve::mesh::MeshSet<3>::face_t *orig_face,
|
||||
const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &vertices,
|
||||
carve::geom3d::Vector normal,
|
||||
bool poly_a,
|
||||
FaceClass face_class,
|
||||
CSG::Hooks &hooks) =0;
|
||||
|
||||
virtual void collect(FaceLoopGroup *grp, CSG::Hooks &hooks) {
|
||||
std::list<ClassificationInfo> &cinfo = (grp->classification);
|
||||
|
||||
if (cinfo.size() == 0) {
|
||||
std::cerr << "WARNING! group " << grp << " has no classification info!" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
FaceClass fc = FACE_UNCLASSIFIED;
|
||||
|
||||
unsigned fc_closed_bits = 0;
|
||||
unsigned fc_open_bits = 0;
|
||||
unsigned fc_bits = 0;
|
||||
|
||||
for (std::list<ClassificationInfo>::const_iterator i = grp->classification.begin(), e = grp->classification.end(); i != e; ++i) {
|
||||
|
||||
if ((*i).intersected_mesh == NULL) {
|
||||
// classifier only returns global info
|
||||
fc_closed_bits = class_to_class_bit((*i).classification);
|
||||
break;
|
||||
}
|
||||
|
||||
if ((*i).classification == FACE_UNCLASSIFIED) continue;
|
||||
if ((*i).intersectedMeshIsClosed()) {
|
||||
fc_closed_bits |= class_to_class_bit((*i).classification);
|
||||
} else {
|
||||
fc_open_bits |= class_to_class_bit((*i).classification);
|
||||
}
|
||||
}
|
||||
|
||||
if (fc_closed_bits) {
|
||||
fc_bits = fc_closed_bits;
|
||||
} else {
|
||||
fc_bits = fc_open_bits;
|
||||
}
|
||||
|
||||
fc = class_bit_to_class(fc_bits);
|
||||
|
||||
// handle the complex cases where a group is classified differently with respect to two or more closed manifolds.
|
||||
if (fc == FACE_UNCLASSIFIED) {
|
||||
unsigned inout_bits = fc_bits & FACE_NOT_ON_BIT;
|
||||
unsigned on_bits = fc_bits & FACE_ON_BIT;
|
||||
|
||||
// both in and out. indicates an invalid manifold embedding.
|
||||
if (inout_bits == (FACE_IN_BIT | FACE_OUT_BIT)) goto out;
|
||||
|
||||
// on, both orientations. could be caused by two manifolds touching at a face.
|
||||
if (on_bits == (FACE_ON_ORIENT_IN_BIT | FACE_ON_ORIENT_OUT_BIT)) goto out;
|
||||
|
||||
// in or out, but also on (with orientation). the on classification takes precedence.
|
||||
fc = class_bit_to_class(on_bits);
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
if (fc == FACE_UNCLASSIFIED) {
|
||||
std::cerr << "group " << grp << " is unclassified!" << std::endl;
|
||||
|
||||
#if defined(CARVE_DEBUG_WRITE_PLY_DATA)
|
||||
static int uc_count = 0;
|
||||
|
||||
std::vector<carve::mesh::MeshSet<3>::face_t *> faces;
|
||||
|
||||
for (FaceLoop *f = grp->face_loops.head; f; f = f->next) {
|
||||
carve::mesh::MeshSet<3>::face_t *temp = f->orig_face->create(f->vertices.begin(), f->vertices.end(), false);
|
||||
faces.push_back(temp);
|
||||
}
|
||||
|
||||
carve::mesh::MeshSet<3> *p = new carve::mesh::MeshSet<3>(faces);
|
||||
|
||||
std::ostringstream filename;
|
||||
filename << "classifier_fail_" << ++uc_count << ".ply";
|
||||
std::string out(filename.str().c_str());
|
||||
::writePLY(out, p, false);
|
||||
|
||||
delete p;
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool is_poly_a = grp->src == src_a;
|
||||
|
||||
for (FaceLoop *f = grp->face_loops.head; f; f = f->next) {
|
||||
collect(f->orig_face, f->vertices, f->orig_face->plane.N, is_poly_a, fc, hooks);
|
||||
}
|
||||
}
|
||||
|
||||
virtual carve::mesh::MeshSet<3> *done(CSG::Hooks &hooks) {
|
||||
std::vector<carve::mesh::MeshSet<3>::face_t *> f;
|
||||
f.reserve(faces.size());
|
||||
for (std::list<face_data_t>::iterator i = faces.begin(); i != faces.end(); ++i) {
|
||||
f.push_back((*i).face);
|
||||
}
|
||||
|
||||
carve::mesh::MeshSet<3> *p = new carve::mesh::MeshSet<3>(f);
|
||||
|
||||
if (hooks.hasHook(carve::csg::CSG::Hooks::RESULT_FACE_HOOK)) {
|
||||
for (std::list<face_data_t>::iterator i = faces.begin(); i != faces.end(); ++i) {
|
||||
hooks.resultFace((*i).face, (*i).orig_face, (*i).flipped);
|
||||
}
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class AllCollector : public BaseCollector {
|
||||
public:
|
||||
AllCollector(const carve::mesh::MeshSet<3> *_src_a,
|
||||
const carve::mesh::MeshSet<3> *_src_b) : BaseCollector(_src_a, _src_b) {
|
||||
}
|
||||
virtual ~AllCollector() {
|
||||
}
|
||||
virtual void collect(FaceLoopGroup *grp, CSG::Hooks &hooks) {
|
||||
for (FaceLoop *f = grp->face_loops.head; f; f = f->next) {
|
||||
FWD(f->orig_face, f->vertices, f->orig_face->plane.N, f->orig_face->mesh->meshset == src_a, FACE_OUT, hooks);
|
||||
}
|
||||
}
|
||||
virtual void collect(const carve::mesh::MeshSet<3>::face_t *orig_face,
|
||||
const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &vertices,
|
||||
carve::geom3d::Vector normal,
|
||||
bool poly_a,
|
||||
FaceClass face_class,
|
||||
CSG::Hooks &hooks) {
|
||||
FWD(orig_face, vertices, normal, poly_a, face_class, hooks);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class UnionCollector : public BaseCollector {
|
||||
public:
|
||||
UnionCollector(const carve::mesh::MeshSet<3> *_src_a,
|
||||
const carve::mesh::MeshSet<3> *_src_b) : BaseCollector(_src_a, _src_b) {
|
||||
}
|
||||
virtual ~UnionCollector() {
|
||||
}
|
||||
virtual void collect(const carve::mesh::MeshSet<3>::face_t *orig_face,
|
||||
const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &vertices,
|
||||
carve::geom3d::Vector normal,
|
||||
bool poly_a,
|
||||
FaceClass face_class,
|
||||
CSG::Hooks &hooks) {
|
||||
if (face_class == FACE_OUT || (poly_a && face_class == FACE_ON_ORIENT_OUT)) {
|
||||
FWD(orig_face, vertices, normal, poly_a, face_class, hooks);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class IntersectionCollector : public BaseCollector {
|
||||
public:
|
||||
IntersectionCollector(const carve::mesh::MeshSet<3> *_src_a,
|
||||
const carve::mesh::MeshSet<3> *_src_b) : BaseCollector(_src_a, _src_b) {
|
||||
}
|
||||
virtual ~IntersectionCollector() {
|
||||
}
|
||||
virtual void collect(const carve::mesh::MeshSet<3>::face_t *orig_face,
|
||||
const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &vertices,
|
||||
carve::geom3d::Vector normal,
|
||||
bool poly_a,
|
||||
FaceClass face_class,
|
||||
CSG::Hooks &hooks) {
|
||||
if (face_class == FACE_IN || (poly_a && face_class == FACE_ON_ORIENT_OUT)) {
|
||||
FWD(orig_face, vertices, normal, poly_a, face_class, hooks);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class SymmetricDifferenceCollector : public BaseCollector {
|
||||
public:
|
||||
SymmetricDifferenceCollector(const carve::mesh::MeshSet<3> *_src_a,
|
||||
const carve::mesh::MeshSet<3> *_src_b) : BaseCollector(_src_a, _src_b) {
|
||||
}
|
||||
virtual ~SymmetricDifferenceCollector() {
|
||||
}
|
||||
virtual void collect(const carve::mesh::MeshSet<3>::face_t *orig_face,
|
||||
const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &vertices,
|
||||
carve::geom3d::Vector normal,
|
||||
bool poly_a,
|
||||
FaceClass face_class,
|
||||
CSG::Hooks &hooks) {
|
||||
if (face_class == FACE_OUT) {
|
||||
FWD(orig_face, vertices, normal, poly_a, face_class, hooks);
|
||||
} else if (face_class == FACE_IN) {
|
||||
REV(orig_face, vertices, normal, poly_a, face_class, hooks);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class AMinusBCollector : public BaseCollector {
|
||||
public:
|
||||
AMinusBCollector(const carve::mesh::MeshSet<3> *_src_a,
|
||||
const carve::mesh::MeshSet<3> *_src_b) : BaseCollector(_src_a, _src_b) {
|
||||
}
|
||||
virtual ~AMinusBCollector() {
|
||||
}
|
||||
virtual void collect(const carve::mesh::MeshSet<3>::face_t *orig_face,
|
||||
const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &vertices,
|
||||
carve::geom3d::Vector normal,
|
||||
bool poly_a,
|
||||
FaceClass face_class,
|
||||
CSG::Hooks &hooks) {
|
||||
if ((face_class == FACE_OUT || face_class == FACE_ON_ORIENT_IN) && poly_a) {
|
||||
FWD(orig_face, vertices, normal, poly_a, face_class, hooks);
|
||||
} else if (face_class == FACE_IN && !poly_a) {
|
||||
REV(orig_face, vertices, normal, poly_a, face_class, hooks);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class BMinusACollector : public BaseCollector {
|
||||
public:
|
||||
BMinusACollector(const carve::mesh::MeshSet<3> *_src_a,
|
||||
const carve::mesh::MeshSet<3> *_src_b) : BaseCollector(_src_a, _src_b) {
|
||||
}
|
||||
virtual ~BMinusACollector() {
|
||||
}
|
||||
virtual void collect(const carve::mesh::MeshSet<3>::face_t *orig_face,
|
||||
const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &vertices,
|
||||
carve::geom3d::Vector normal,
|
||||
bool poly_a,
|
||||
FaceClass face_class,
|
||||
CSG::Hooks &hooks) {
|
||||
if ((face_class == FACE_OUT || face_class == FACE_ON_ORIENT_IN) && !poly_a) {
|
||||
FWD(orig_face, vertices, normal, poly_a, face_class, hooks);
|
||||
} else if (face_class == FACE_IN && poly_a) {
|
||||
REV(orig_face, vertices, normal, poly_a, face_class, hooks);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
CSG::Collector *makeCollector(CSG::OP op,
|
||||
const carve::mesh::MeshSet<3> *poly_a,
|
||||
const carve::mesh::MeshSet<3> *poly_b) {
|
||||
switch (op) {
|
||||
case CSG::UNION: return new UnionCollector(poly_a, poly_b);
|
||||
case CSG::INTERSECTION: return new IntersectionCollector(poly_a, poly_b);
|
||||
case CSG::A_MINUS_B: return new AMinusBCollector(poly_a, poly_b);
|
||||
case CSG::B_MINUS_A: return new BMinusACollector(poly_a, poly_b);
|
||||
case CSG::SYMMETRIC_DIFFERENCE: return new SymmetricDifferenceCollector(poly_a, poly_b);
|
||||
case CSG::ALL: return new AllCollector(poly_a, poly_b);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
24
extern/carve/lib/csg_collector.hpp
vendored
Normal file
24
extern/carve/lib/csg_collector.hpp
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
namespace carve {
|
||||
namespace csg {
|
||||
CSG::Collector *makeCollector(CSG::OP op,
|
||||
const carve::mesh::MeshSet<3> *poly_a,
|
||||
const carve::mesh::MeshSet<3> *poly_b);
|
||||
}
|
||||
}
|
52
extern/carve/lib/csg_data.hpp
vendored
Normal file
52
extern/carve/lib/csg_data.hpp
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/csg.hpp>
|
||||
|
||||
#include "csg_detail.hpp"
|
||||
|
||||
struct carve::csg::detail::Data {
|
||||
// * @param[out] vmap A mapping from vertex pointer to intersection point.
|
||||
// * @param[out] emap A mapping from edge pointer to intersection points.
|
||||
// * @param[out] fmap A mapping from face pointer to intersection points.
|
||||
// * @param[out] fmap_rev A mapping from intersection points to face pointers.
|
||||
// map from intersected vertex to intersection point.
|
||||
VVMap vmap;
|
||||
|
||||
// map from intersected edge to intersection points.
|
||||
EVSMap emap;
|
||||
|
||||
// map from intersected face to intersection points.
|
||||
FVSMap fmap;
|
||||
|
||||
// map from intersection point to intersected faces.
|
||||
VFSMap fmap_rev;
|
||||
|
||||
// created by divideEdges().
|
||||
// holds, for each edge, a
|
||||
EVVMap divided_edges;
|
||||
|
||||
// created by faceSplitEdges.
|
||||
FV2SMap face_split_edges;
|
||||
|
||||
// mapping from vertex to edge for potentially intersected
|
||||
// faces. Saves building the vertex to edge map for all faces of
|
||||
// both meshes.
|
||||
VEVecMap vert_to_edges;
|
||||
};
|
71
extern/carve/lib/csg_detail.hpp
vendored
Normal file
71
extern/carve/lib/csg_detail.hpp
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <carve/carve.hpp>
|
||||
|
||||
#include <carve/polyhedron_base.hpp>
|
||||
|
||||
namespace carve {
|
||||
namespace csg {
|
||||
namespace detail {
|
||||
|
||||
typedef std::unordered_set<carve::mesh::MeshSet<3>::vertex_t *> VSet;
|
||||
typedef std::unordered_set<carve::mesh::MeshSet<3>::face_t *> FSet;
|
||||
|
||||
typedef std::set<carve::mesh::MeshSet<3>::vertex_t *> VSetSmall;
|
||||
typedef std::set<csg::V2> V2SetSmall;
|
||||
typedef std::set<carve::mesh::MeshSet<3>::face_t *> FSetSmall;
|
||||
|
||||
typedef std::unordered_map<carve::mesh::MeshSet<3>::vertex_t *, VSetSmall> VVSMap;
|
||||
typedef std::unordered_map<carve::mesh::MeshSet<3>::edge_t *, VSetSmall> EVSMap;
|
||||
typedef std::unordered_map<carve::mesh::MeshSet<3>::face_t *, VSetSmall> FVSMap;
|
||||
|
||||
typedef std::unordered_map<carve::mesh::MeshSet<3>::vertex_t *, FSetSmall> VFSMap;
|
||||
typedef std::unordered_map<carve::mesh::MeshSet<3>::face_t *, V2SetSmall> FV2SMap;
|
||||
|
||||
typedef std::unordered_map<
|
||||
carve::mesh::MeshSet<3>::edge_t *,
|
||||
std::vector<carve::mesh::MeshSet<3>::vertex_t *> > EVVMap;
|
||||
|
||||
typedef std::unordered_map<carve::mesh::MeshSet<3>::vertex_t *,
|
||||
std::vector<carve::mesh::MeshSet<3>::edge_t *> > VEVecMap;
|
||||
|
||||
|
||||
class LoopEdges : public std::unordered_map<V2, std::list<FaceLoop *> > {
|
||||
typedef std::unordered_map<V2, std::list<FaceLoop *> > super;
|
||||
|
||||
public:
|
||||
void addFaceLoop(FaceLoop *fl);
|
||||
void sortFaceLoopLists();
|
||||
void removeFaceLoop(FaceLoop *fl);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static inline std::ostream &operator<<(std::ostream &o, const carve::csg::detail::FSet &s) {
|
||||
const char *sep="";
|
||||
for (carve::csg::detail::FSet::const_iterator i = s.begin(); i != s.end(); ++i) {
|
||||
o << sep << *i; sep=",";
|
||||
}
|
||||
return o;
|
||||
}
|
23
extern/carve/lib/edge.cpp
vendored
Normal file
23
extern/carve/lib/edge.cpp
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
# include <carve_config.h>
|
||||
#endif
|
||||
|
||||
#include <carve/poly.hpp>
|
||||
|
278
extern/carve/lib/face.cpp
vendored
Normal file
278
extern/carve/lib/face.cpp
vendored
Normal file
@ -0,0 +1,278 @@
|
||||
// Begin License:
|
||||
// Copyright (C) 2006-2011 Tobias Sargeant (tobias.sargeant@gmail.com).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of the Carve CSG Library (http://carve-csg.com/)
|
||||
//
|
||||
// This file may be used under the terms of the GNU General Public
|
||||
// License version 2.0 as published by the Free Software Foundation
|
||||
// and appearing in the file LICENSE.GPL2 included in the packaging of
|
||||
// this file.
|
||||
//
|
||||
// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
||||
// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE.
|
||||
// End:
|
||||
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
# include <carve_config.h>
|
||||
#endif
|
||||
|
||||
#include <carve/poly.hpp>
|
||||
|
||||
double CALC_X(const carve::geom::plane<3> &p, double y, double z) { return -(p.d + p.N.y * y + p.N.z * z) / p.N.x; }
|
||||
double CALC_Y(const carve::geom::plane<3> &p, double x, double z) { return -(p.d + p.N.x * x + p.N.z * z) / p.N.y; }
|
||||
double CALC_Z(const carve::geom::plane<3> &p, double x, double y) { return -(p.d + p.N.x * x + p.N.y * y) / p.N.z; }
|
||||
|
||||
namespace carve {
|
||||
namespace poly {
|
||||
|
||||
carve::geom2d::P2 _project_1(const carve::geom3d::Vector &v) {
|
||||
return carve::geom::VECTOR(v.z, v.y);
|
||||
}
|
||||
|
||||
carve::geom2d::P2 _project_2(const carve::geom3d::Vector &v) {
|
||||
return carve::geom::VECTOR(v.x, v.z);
|
||||
}
|
||||
|
||||
carve::geom2d::P2 _project_3(const carve::geom3d::Vector &v) {
|
||||
return carve::geom::VECTOR(v.y, v.x);
|
||||
}
|
||||
|
||||
carve::geom2d::P2 _project_4(const carve::geom3d::Vector &v) {
|
||||
return carve::geom::VECTOR(v.y, v.z);
|
||||
}
|
||||
|
||||
carve::geom2d::P2 _project_5(const carve::geom3d::Vector &v) {
|
||||
return carve::geom::VECTOR(v.z, v.x);
|
||||
}
|
||||
|
||||
carve::geom2d::P2 _project_6(const carve::geom3d::Vector &v) {
|
||||
return carve::geom::VECTOR(v.x, v.y);
|
||||
}
|
||||
|
||||
|
||||
carve::geom3d::Vector _unproject_1(const carve::geom2d::P2 &p, const carve::geom3d::Plane &plane_eqn) {
|
||||
return carve::geom::VECTOR(CALC_X(plane_eqn, p.y, p.x), p.y, p.x);
|
||||
}
|
||||
|
||||
carve::geom3d::Vector _unproject_2(const carve::geom2d::P2 &p, const carve::geom3d::Plane &plane_eqn) {
|
||||
return carve::geom::VECTOR(p.x, CALC_Y(plane_eqn, p.x, p.y), p.y);
|
||||
}
|
||||
|
||||
carve::geom3d::Vector _unproject_3(const carve::geom2d::P2 &p, const carve::geom3d::Plane &plane_eqn) {
|
||||
return carve::geom::VECTOR(p.y, p.x, CALC_Z(plane_eqn, p.y, p.x));
|
||||
}
|
||||
|
||||
carve::geom3d::Vector _unproject_4(const carve::geom2d::P2 &p, const carve::geom3d::Plane &plane_eqn) {
|
||||
return carve::geom::VECTOR(CALC_X(plane_eqn, p.x, p.y), p.x, p.y);
|
||||
}
|
||||
|
||||
carve::geom3d::Vector _unproject_5(const carve::geom2d::P2 &p, const carve::geom3d::Plane &plane_eqn) {
|
||||
return carve::geom::VECTOR(p.y, CALC_Y(plane_eqn, p.y, p.x), p.x);
|
||||
}
|
||||
|
||||
carve::geom3d::Vector _unproject_6(const carve::geom2d::P2 &p, const carve::geom3d::Plane &plane_eqn) {
|
||||
return carve::geom::VECTOR(p.x, p.y, CALC_Z(plane_eqn, p.x, p.y));
|
||||
}
|
||||
|
||||
static carve::geom2d::P2 (*project_tab[2][3])(const carve::geom3d::Vector &) = {
|
||||
{ &_project_1, &_project_2, &_project_3 },
|
||||
{ &_project_4, &_project_5, &_project_6 }
|
||||
};
|
||||
|
||||
static carve::geom3d::Vector (*unproject_tab[2][3])(const carve::geom2d::P2 &, const carve::geom3d::Plane &) = {
|
||||
{ &_unproject_1, &_unproject_2, &_unproject_3 },
|
||||
{ &_unproject_4, &_unproject_5, &_unproject_6 }
|
||||
};
|
||||
|
||||
// only implemented for 3d.
|
||||
template<unsigned ndim>
|
||||
typename Face<ndim>::project_t Face<ndim>::getProjector(bool positive_facing, int axis) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
template<>
|
||||
Face<3>::project_t Face<3>::getProjector(bool positive_facing, int axis) {
|
||||
return project_tab[positive_facing ? 1 : 0][axis];
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
typename Face<ndim>::unproject_t Face<ndim>::getUnprojector(bool positive_facing, int axis) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
template<>
|
||||
Face<3>::unproject_t Face<3>::getUnprojector(bool positive_facing, int axis) {
|
||||
return unproject_tab[positive_facing ? 1 : 0][axis];
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<unsigned ndim>
|
||||
Face<ndim>::Face(const std::vector<const vertex_t *> &_vertices,
|
||||
bool delay_recalc) : tagable() {
|
||||
vertices = _vertices;
|
||||
edges.resize(nVertices(), NULL);
|
||||
if (!delay_recalc && !recalc()) { }
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
Face<ndim>::Face(const vertex_t *a,
|
||||
const vertex_t *b,
|
||||
const vertex_t *c,
|
||||
bool delay_recalc) : tagable() {
|
||||
vertices.reserve(3);
|
||||
vertices.push_back(a);
|
||||
vertices.push_back(b);
|
||||
vertices.push_back(c);
|
||||
edges.resize(3, NULL);
|
||||
if (!delay_recalc && !recalc()) { }
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
Face<ndim>::Face(const vertex_t *a,
|
||||
const vertex_t *b,
|
||||
const vertex_t *c,
|
||||
const vertex_t *d,
|
||||
bool delay_recalc) : tagable() {
|
||||
vertices.reserve(4);
|
||||
vertices.push_back(a);
|
||||
vertices.push_back(b);
|
||||
vertices.push_back(c);
|
||||
vertices.push_back(d);
|
||||
edges.resize(4, NULL);
|
||||
if (!delay_recalc && !recalc()) { }
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
void Face<ndim>::invert() {
|
||||
size_t n_verts = vertices.size();
|
||||
std::reverse(vertices.begin(), vertices.end());
|
||||
|
||||
if (project != NULL) {
|
||||
plane_eqn.negate();
|
||||
|
||||
int da = carve::geom::largestAxis(plane_eqn.N);
|
||||
|
||||
project = getProjector(plane_eqn.N.v[da] > 0, da);
|
||||
unproject = getUnprojector(plane_eqn.N.v[da] > 0, da);
|
||||
}
|
||||
|
||||
std::reverse(edges.begin(), edges.end() - 1);
|
||||
for (size_t i = 0; i < n_verts; i++) {
|
||||
const vertex_t *v1 = vertices[i];
|
||||
const vertex_t *v2 = vertices[(i+1) % n_verts];
|
||||
CARVE_ASSERT((edges[i]->v1 == v1 && edges[i]->v2 == v2) || (edges[i]->v1 == v2 && edges[i]->v2 == v1));
|
||||
}
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
bool Face<ndim>::recalc() {
|
||||
aabb.fit(vertices.begin(), vertices.end(), vec_adapt_vertex_ptr());
|
||||
|
||||
if (!carve::geom3d::fitPlane(vertices.begin(), vertices.end(), vec_adapt_vertex_ptr(), plane_eqn)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int da = carve::geom::largestAxis(plane_eqn.N);
|
||||
project = getProjector(false, da);
|
||||
|
||||
double A = carve::geom2d::signedArea(vertices, projector());
|
||||
if ((A < 0.0) ^ (plane_eqn.N.v[da] < 0.0)) {
|
||||
plane_eqn.negate();
|
||||
}
|
||||
|
||||
project = getProjector(plane_eqn.N.v[da] > 0, da);
|
||||
unproject = getUnprojector(plane_eqn.N.v[da] > 0, da);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
Face<ndim> *Face<ndim>::init(const Face *base, const std::vector<const vertex_t *> &_vertices, bool flipped) {
|
||||
return init(base, _vertices.begin(), _vertices.end(), flipped);
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
bool Face<ndim>::containsPoint(const vector_t &p) const {
|
||||
if (!carve::math::ZERO(carve::geom::distance(plane_eqn, p))) return false;
|
||||
// return pointInPolySimple(vertices, projector(), (this->*project)(p));
|
||||
return carve::geom2d::pointInPoly(vertices, projector(), face::project(this, p)).iclass != POINT_OUT;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
bool Face<ndim>::containsPointInProjection(const vector_t &p) const {
|
||||
return carve::geom2d::pointInPoly(vertices, projector(), face::project(this, p)).iclass != POINT_OUT;
|
||||
}
|
||||
|
||||
template<unsigned ndim>
|
||||
bool Face<ndim>::simpleLineSegmentIntersection(const carve::geom::linesegment<ndim> &line,
|
||||
vector_t &intersection) const {
|
||||
if (!line.OK()) return false;
|
||||
|
||||
carve::geom3d::Vector p;
|
||||
IntersectionClass intersects = carve::geom3d::lineSegmentPlaneIntersection(plane_eqn,
|
||||
line,
|
||||
p);
|
||||
if (intersects == INTERSECT_NONE || intersects == INTERSECT_BAD) {
|
||||
return false;
|
||||
}
|
||||
|
||||
carve::geom2d::P2 proj_p(face::project(this, p));
|
||||
if (carve::geom2d::pointInPolySimple(vertices, projector(), proj_p)) {
|
||||
intersection = p;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// XXX: should try to return a pre-existing vertex in the case of a
|
||||
// line-vertex intersection. as it stands, this code isn't used,
|
||||
// so... meh.
|
||||
template<unsigned ndim>
|
||||
IntersectionClass Face<ndim>::lineSegmentIntersection(const carve::geom::linesegment<ndim> &line,
|
||||
vector_t &intersection) const {
|
||||
if (!line.OK()) return INTERSECT_NONE;
|
||||
|
||||
|
||||
carve::geom3d::Vector p;
|
||||
IntersectionClass intersects = carve::geom3d::lineSegmentPlaneIntersection(plane_eqn,
|
||||
line,
|
||||
p);
|
||||
if (intersects == INTERSECT_NONE || intersects == INTERSECT_BAD) {
|
||||
return intersects;
|
||||
}
|
||||
|
||||
carve::geom2d::P2 proj_p(face::project(this, p));
|
||||
|
||||
carve::geom2d::PolyInclusionInfo pi = carve::geom2d::pointInPoly(vertices, projector(), proj_p);
|
||||
switch (pi.iclass) {
|
||||
case POINT_VERTEX:
|
||||
intersection = p;
|
||||
return INTERSECT_VERTEX;
|
||||
|
||||
case POINT_EDGE:
|
||||
intersection = p;
|
||||
return INTERSECT_EDGE;
|
||||
|
||||
case POINT_IN:
|
||||
intersection = p;
|
||||
return INTERSECT_FACE;
|
||||
|
||||
case POINT_OUT:
|
||||
return INTERSECT_NONE;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return INTERSECT_NONE;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// explicit instantiations.
|
||||
template class carve::poly::Face<3>;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user